<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://pct.wiki.uib.no/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ilkerm</id>
	<title>pCT - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://pct.wiki.uib.no/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ilkerm"/>
	<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/Special:Contributions/Ilkerm"/>
	<updated>2026-05-24T22:17:57Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.44.2</generator>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=270</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=270"/>
		<updated>2017-03-20T13:06:58Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* The range-energy look-up-table */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLSX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/placement/setTranslation 0 0 50. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -15. cm&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
It is possible to repeat volumes. The simple method is to use a linear replicator:&lt;br /&gt;
   /gate/phantom/repeaters/insert linear&lt;br /&gt;
   /gate/phantom/linear/autoCenter false&lt;br /&gt;
   /gate/phantom/linear/setRepeatNumber 10&lt;br /&gt;
   /gate/phantom/linear/setRepeatVector 0 0 35. cm&lt;br /&gt;
The autoCenter command: The original volume is anchored (false), instead of the center-of-mass of all copies being centered at that position (true).&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
If you want to define hierarchically repeated structures, such as layers or individually simulated pixels, they should be defined as a &#039;&#039;level&#039;&#039;:&lt;br /&gt;
   /gate/scanner/level1/attach phantom&lt;br /&gt;
   /gate/scanner/level2/attach repeatedStructureWithinPhantom&lt;br /&gt;
&lt;br /&gt;
And now you can use the ROOT leaf &#039;&#039;level1ID&#039;&#039; and &#039;&#039;level2ID&#039;&#039; to identify the volume.&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to the LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
If you want the visualization to be persistent, use instead&lt;br /&gt;
   $ Gate&lt;br /&gt;
   ... [TEXT]&lt;br /&gt;
   Idle&amp;gt; /control/execute waterphantom.mac&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TF1.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, 150, 250); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
* Range estimation&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The full tracking workflow is implemented in the function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C::getTracks()&amp;lt;/code&amp;gt;, and the tracking and range estimation workflow is found in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::drawBraggPeakGraphFit()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMm)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Putting it all together so far ===&lt;br /&gt;
It is not easy to track a large number of proton histories simultaneously, so one may want to loop this analysis, appending the result (the tracks) to a larger Tracks list. This can be done with the code below:&lt;br /&gt;
&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   Tracks * allTracks = new Tracks();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
      cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
      Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
      Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
      Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
      tracks-&amp;gt;extrapolateToLayer0();&lt;br /&gt;
      tracks-&amp;gt;splitSharedClusters();&lt;br /&gt;
      tracks-&amp;gt;removeTracksLeavingDetector();&lt;br /&gt;
      tracks-&amp;gt;removeTracksEndingInBadChannnels();&lt;br /&gt;
    &lt;br /&gt;
      for (int j=0; j&amp;lt;tracks-&amp;gt;GetEntriesFast(); j++) {&lt;br /&gt;
         if (!tracks-&amp;gt;At(j)) continue;&lt;br /&gt;
         allTracks-&amp;gt;appendTrack(tracks-&amp;gt;At(j));&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete tracks;&lt;br /&gt;
      delete hits;&lt;br /&gt;
      delete clusters;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=269</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=269"/>
		<updated>2017-03-20T11:03:06Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Test case: Finding the range and straggling of a proton beam */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLSX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/placement/setTranslation 0 0 50. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -15. cm&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
It is possible to repeat volumes. The simple method is to use a linear replicator:&lt;br /&gt;
   /gate/phantom/repeaters/insert linear&lt;br /&gt;
   /gate/phantom/linear/autoCenter false&lt;br /&gt;
   /gate/phantom/linear/setRepeatNumber 10&lt;br /&gt;
   /gate/phantom/linear/setRepeatVector 0 0 35. cm&lt;br /&gt;
The autoCenter command: The original volume is anchored (false), instead of the center-of-mass of all copies being centered at that position (true).&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
If you want to define hierarchically repeated structures, such as layers or individually simulated pixels, they should be defined as a &#039;&#039;level&#039;&#039;:&lt;br /&gt;
   /gate/scanner/level1/attach phantom&lt;br /&gt;
   /gate/scanner/level2/attach repeatedStructureWithinPhantom&lt;br /&gt;
&lt;br /&gt;
And now you can use the ROOT leaf &#039;&#039;level1ID&#039;&#039; and &#039;&#039;level2ID&#039;&#039; to identify the volume.&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to the LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
If you want the visualization to be persistent, use instead&lt;br /&gt;
   $ Gate&lt;br /&gt;
   ... [TEXT]&lt;br /&gt;
   Idle&amp;gt; /control/execute waterphantom.mac&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TF1.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, 150, 250); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
* Range estimation&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The full tracking workflow is implemented in the function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C::getTracks()&amp;lt;/code&amp;gt;, and the tracking and range estimation workflow is found in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::drawBraggPeakGraphFit()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Putting it all together so far ===&lt;br /&gt;
It is not easy to track a large number of proton histories simultaneously, so one may want to loop this analysis, appending the result (the tracks) to a larger Tracks list. This can be done with the code below:&lt;br /&gt;
&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   Tracks * allTracks = new Tracks();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
      cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
      Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
      Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
      Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
      tracks-&amp;gt;extrapolateToLayer0();&lt;br /&gt;
      tracks-&amp;gt;splitSharedClusters();&lt;br /&gt;
      tracks-&amp;gt;removeTracksLeavingDetector();&lt;br /&gt;
      tracks-&amp;gt;removeTracksEndingInBadChannnels();&lt;br /&gt;
    &lt;br /&gt;
      for (int j=0; j&amp;lt;tracks-&amp;gt;GetEntriesFast(); j++) {&lt;br /&gt;
         if (!tracks-&amp;gt;At(j)) continue;&lt;br /&gt;
         allTracks-&amp;gt;appendTrack(tracks-&amp;gt;At(j));&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete tracks;&lt;br /&gt;
      delete hits;&lt;br /&gt;
      delete clusters;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=268</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=268"/>
		<updated>2017-03-20T10:52:57Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Putting it all together so far */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLSX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/placement/setTranslation 0 0 50. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -15. cm&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
It is possible to repeat volumes. The simple method is to use a linear replicator:&lt;br /&gt;
   /gate/phantom/repeaters/insert linear&lt;br /&gt;
   /gate/phantom/linear/autoCenter false&lt;br /&gt;
   /gate/phantom/linear/setRepeatNumber 10&lt;br /&gt;
   /gate/phantom/linear/setRepeatVector 0 0 35. cm&lt;br /&gt;
The autoCenter command: The original volume is anchored (false), instead of the center-of-mass of all copies being centered at that position (true).&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
If you want to define hierarchically repeated structures, such as layers or individually simulated pixels, they should be defined as a &#039;&#039;level&#039;&#039;:&lt;br /&gt;
   /gate/scanner/level1/attach phantom&lt;br /&gt;
   /gate/scanner/level2/attach repeatedStructureWithinPhantom&lt;br /&gt;
&lt;br /&gt;
And now you can use the ROOT leaf &#039;&#039;level1ID&#039;&#039; and &#039;&#039;level2ID&#039;&#039; to identify the volume.&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to the LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
If you want the visualization to be persistent, use instead&lt;br /&gt;
   $ Gate&lt;br /&gt;
   ... [TEXT]&lt;br /&gt;
   Idle&amp;gt; /control/execute waterphantom.mac&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
* Range estimation&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The full tracking workflow is implemented in the function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C::getTracks()&amp;lt;/code&amp;gt;, and the tracking and range estimation workflow is found in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::drawBraggPeakGraphFit()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Putting it all together so far ===&lt;br /&gt;
It is not easy to track a large number of proton histories simultaneously, so one may want to loop this analysis, appending the result (the tracks) to a larger Tracks list. This can be done with the code below:&lt;br /&gt;
&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   Tracks * allTracks = new Tracks();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
      cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
      Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
      Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
      Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
      tracks-&amp;gt;extrapolateToLayer0();&lt;br /&gt;
      tracks-&amp;gt;splitSharedClusters();&lt;br /&gt;
      tracks-&amp;gt;removeTracksLeavingDetector();&lt;br /&gt;
      tracks-&amp;gt;removeTracksEndingInBadChannnels();&lt;br /&gt;
    &lt;br /&gt;
      for (int j=0; j&amp;lt;tracks-&amp;gt;GetEntriesFast(); j++) {&lt;br /&gt;
         if (!tracks-&amp;gt;At(j)) continue;&lt;br /&gt;
         allTracks-&amp;gt;appendTrack(tracks-&amp;gt;At(j));&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete tracks;&lt;br /&gt;
      delete hits;&lt;br /&gt;
      delete clusters;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=267</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=267"/>
		<updated>2017-03-20T10:52:45Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Putting it all together so far */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLSX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/placement/setTranslation 0 0 50. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -15. cm&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
It is possible to repeat volumes. The simple method is to use a linear replicator:&lt;br /&gt;
   /gate/phantom/repeaters/insert linear&lt;br /&gt;
   /gate/phantom/linear/autoCenter false&lt;br /&gt;
   /gate/phantom/linear/setRepeatNumber 10&lt;br /&gt;
   /gate/phantom/linear/setRepeatVector 0 0 35. cm&lt;br /&gt;
The autoCenter command: The original volume is anchored (false), instead of the center-of-mass of all copies being centered at that position (true).&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
If you want to define hierarchically repeated structures, such as layers or individually simulated pixels, they should be defined as a &#039;&#039;level&#039;&#039;:&lt;br /&gt;
   /gate/scanner/level1/attach phantom&lt;br /&gt;
   /gate/scanner/level2/attach repeatedStructureWithinPhantom&lt;br /&gt;
&lt;br /&gt;
And now you can use the ROOT leaf &#039;&#039;level1ID&#039;&#039; and &#039;&#039;level2ID&#039;&#039; to identify the volume.&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to the LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
If you want the visualization to be persistent, use instead&lt;br /&gt;
   $ Gate&lt;br /&gt;
   ... [TEXT]&lt;br /&gt;
   Idle&amp;gt; /control/execute waterphantom.mac&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
* Range estimation&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The full tracking workflow is implemented in the function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C::getTracks()&amp;lt;/code&amp;gt;, and the tracking and range estimation workflow is found in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::drawBraggPeakGraphFit()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Putting it all together so far ===&lt;br /&gt;
It is not easy to track a large number of proton histories simultaneously, so one may want to loop this analysis, appending the result (the tracks) to a larger Tracks list. This can be done with the code below:&lt;br /&gt;
&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   Tracks * allTracks = new Tracks();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
      cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
      Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
      Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
      Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
      tracks-&amp;gt;extrapolateToLayer0();&lt;br /&gt;
      tracks-&amp;gt;splitSharedClusters();&lt;br /&gt;
      tracks-&amp;gt;removeTracksLeavingDetector();&lt;br /&gt;
      tracks-&amp;gt;removeTracksEndingInBadChannnels();&lt;br /&gt;
&lt;br /&gt;
      for (int j=0; j&amp;lt;tracks-&amp;gt;GetEntriesFast(); j++) {&lt;br /&gt;
         if (!tracks-&amp;gt;At(j)) continue;&lt;br /&gt;
         allTracks-&amp;gt;appendTrack(tracks-&amp;gt;At(j));&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      delete tracks;&lt;br /&gt;
      delete hits;&lt;br /&gt;
      delete clusters;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=266</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=266"/>
		<updated>2017-03-20T10:52:34Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Running the DTC Toolkit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLSX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/placement/setTranslation 0 0 50. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -15. cm&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
It is possible to repeat volumes. The simple method is to use a linear replicator:&lt;br /&gt;
   /gate/phantom/repeaters/insert linear&lt;br /&gt;
   /gate/phantom/linear/autoCenter false&lt;br /&gt;
   /gate/phantom/linear/setRepeatNumber 10&lt;br /&gt;
   /gate/phantom/linear/setRepeatVector 0 0 35. cm&lt;br /&gt;
The autoCenter command: The original volume is anchored (false), instead of the center-of-mass of all copies being centered at that position (true).&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
If you want to define hierarchically repeated structures, such as layers or individually simulated pixels, they should be defined as a &#039;&#039;level&#039;&#039;:&lt;br /&gt;
   /gate/scanner/level1/attach phantom&lt;br /&gt;
   /gate/scanner/level2/attach repeatedStructureWithinPhantom&lt;br /&gt;
&lt;br /&gt;
And now you can use the ROOT leaf &#039;&#039;level1ID&#039;&#039; and &#039;&#039;level2ID&#039;&#039; to identify the volume.&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to the LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
If you want the visualization to be persistent, use instead&lt;br /&gt;
   $ Gate&lt;br /&gt;
   ... [TEXT]&lt;br /&gt;
   Idle&amp;gt; /control/execute waterphantom.mac&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
* Range estimation&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The full tracking workflow is implemented in the function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C::getTracks()&amp;lt;/code&amp;gt;, and the tracking and range estimation workflow is found in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::drawBraggPeakGraphFit()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Putting it all together so far ===&lt;br /&gt;
It is not easy to track a large number of proton histories simultaneously, so one may want to loop this analysis, appending the result (the tracks) to a larger Tracks list. This can be done with the code below:&lt;br /&gt;
&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   Tracks * allTracks = new Tracks();&lt;br /&gt;
&lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
      cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
      Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
      Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
      Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
      tracks-&amp;gt;extrapolateToLayer0();&lt;br /&gt;
      tracks-&amp;gt;splitSharedClusters();&lt;br /&gt;
      tracks-&amp;gt;removeTracksLeavingDetector();&lt;br /&gt;
      tracks-&amp;gt;removeTracksEndingInBadChannnels();&lt;br /&gt;
&lt;br /&gt;
      for (int j=0; j&amp;lt;tracks-&amp;gt;GetEntriesFast(); j++) {&lt;br /&gt;
         if (!tracks-&amp;gt;At(j)) continue;&lt;br /&gt;
         allTracks-&amp;gt;appendTrack(tracks-&amp;gt;At(j));&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      delete tracks;&lt;br /&gt;
      delete hits;&lt;br /&gt;
      delete clusters;&lt;br /&gt;
   }&lt;br /&gt;
   &lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=265</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=265"/>
		<updated>2017-03-20T10:47:23Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Proton track reconstruction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLSX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/placement/setTranslation 0 0 50. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -15. cm&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
It is possible to repeat volumes. The simple method is to use a linear replicator:&lt;br /&gt;
   /gate/phantom/repeaters/insert linear&lt;br /&gt;
   /gate/phantom/linear/autoCenter false&lt;br /&gt;
   /gate/phantom/linear/setRepeatNumber 10&lt;br /&gt;
   /gate/phantom/linear/setRepeatVector 0 0 35. cm&lt;br /&gt;
The autoCenter command: The original volume is anchored (false), instead of the center-of-mass of all copies being centered at that position (true).&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
If you want to define hierarchically repeated structures, such as layers or individually simulated pixels, they should be defined as a &#039;&#039;level&#039;&#039;:&lt;br /&gt;
   /gate/scanner/level1/attach phantom&lt;br /&gt;
   /gate/scanner/level2/attach repeatedStructureWithinPhantom&lt;br /&gt;
&lt;br /&gt;
And now you can use the ROOT leaf &#039;&#039;level1ID&#039;&#039; and &#039;&#039;level2ID&#039;&#039; to identify the volume.&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to the LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
If you want the visualization to be persistent, use instead&lt;br /&gt;
   $ Gate&lt;br /&gt;
   ... [TEXT]&lt;br /&gt;
   Idle&amp;gt; /control/execute waterphantom.mac&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
* Range estimation&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The full tracking workflow is implemented in the function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C::getTracks()&amp;lt;/code&amp;gt;, and the tracking and range estimation workflow is found in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::drawBraggPeakGraphFit()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Putting it all together so far ===&lt;br /&gt;
It is not easy to track a large number of proton histories simultaneously, so one may want to loop this analysis, appending the result (the tracks) to a larger Tracks list. This can be done with the code below:&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=264</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=264"/>
		<updated>2017-03-20T10:44:27Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Review of the analysis code by Helge Pettersen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLSX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/placement/setTranslation 0 0 50. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -15. cm&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
It is possible to repeat volumes. The simple method is to use a linear replicator:&lt;br /&gt;
   /gate/phantom/repeaters/insert linear&lt;br /&gt;
   /gate/phantom/linear/autoCenter false&lt;br /&gt;
   /gate/phantom/linear/setRepeatNumber 10&lt;br /&gt;
   /gate/phantom/linear/setRepeatVector 0 0 35. cm&lt;br /&gt;
The autoCenter command: The original volume is anchored (false), instead of the center-of-mass of all copies being centered at that position (true).&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
If you want to define hierarchically repeated structures, such as layers or individually simulated pixels, they should be defined as a &#039;&#039;level&#039;&#039;:&lt;br /&gt;
   /gate/scanner/level1/attach phantom&lt;br /&gt;
   /gate/scanner/level2/attach repeatedStructureWithinPhantom&lt;br /&gt;
&lt;br /&gt;
And now you can use the ROOT leaf &#039;&#039;level1ID&#039;&#039; and &#039;&#039;level2ID&#039;&#039; to identify the volume.&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to the LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
If you want the visualization to be persistent, use instead&lt;br /&gt;
   $ Gate&lt;br /&gt;
   ... [TEXT]&lt;br /&gt;
   Idle&amp;gt; /control/execute waterphantom.mac&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
* Range estimation&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The full tracking workflow is implemented in the function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C::getTracks()&amp;lt;/code&amp;gt;, and the tracking and range estimation workflow is found in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::drawBraggPeakGraphFit()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=262</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=262"/>
		<updated>2017-03-20T10:25:15Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Physics */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLSX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
It is possible to repeat volumes. The simple method is to use a linear replicator:&lt;br /&gt;
   /gate/phantom/repeaters/insert linear&lt;br /&gt;
   /gate/phantom/linear/autoCenter false&lt;br /&gt;
   /gate/phantom/linear/setRepeatNumber 10&lt;br /&gt;
   /gate/phantom/linear/setRepeatVector 0 0 35. cm&lt;br /&gt;
The autoCenter command: The original volume is anchored (false), instead of the center-of-mass of all copies being centered at that position (true).&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
If you want to define hierarchically repeated structures, such as layers or individually simulated pixels, they should be defined as a &#039;&#039;level&#039;&#039;:&lt;br /&gt;
   /gate/scanner/level1/attach phantom&lt;br /&gt;
   /gate/scanner/level2/attach repeatedStructureWithinPhantom&lt;br /&gt;
&lt;br /&gt;
And now you can use the ROOT leaf &#039;&#039;level1ID&#039;&#039; and &#039;&#039;level2ID&#039;&#039; to identify the volume.&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to the LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
If you want the visualization to be persistent, use instead&lt;br /&gt;
   $ Gate&lt;br /&gt;
   ... [TEXT]&lt;br /&gt;
   Idle&amp;gt; /control/execute waterphantom.mac&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=261</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=261"/>
		<updated>2017-03-20T10:24:21Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Geometry */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLSX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
It is possible to repeat volumes. The simple method is to use a linear replicator:&lt;br /&gt;
   /gate/phantom/repeaters/insert linear&lt;br /&gt;
   /gate/phantom/linear/autoCenter false&lt;br /&gt;
   /gate/phantom/linear/setRepeatNumber 10&lt;br /&gt;
   /gate/phantom/linear/setRepeatVector 0 0 35. cm&lt;br /&gt;
The autoCenter command: The original volume is anchored (false), instead of the center-of-mass of all copies being centered at that position (true).&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
If you want to define hierarchically repeated structures, such as layers or individually simulated pixels, they should be defined as a &#039;&#039;level&#039;&#039;:&lt;br /&gt;
   /gate/scanner/level1/attach phantom&lt;br /&gt;
   /gate/scanner/level2/attach repeatedStructureWithinPhantom&lt;br /&gt;
&lt;br /&gt;
And now you can use the ROOT leaf &#039;&#039;level1ID&#039;&#039; and &#039;&#039;level2ID&#039;&#039; to identify the volume.&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
If you want the visualization to be persistent, use instead&lt;br /&gt;
   $ Gate&lt;br /&gt;
   ... [TEXT]&lt;br /&gt;
   Idle&amp;gt; /control/execute waterphantom.mac&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=260</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=260"/>
		<updated>2017-03-20T09:33:48Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Running short simulations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLSX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
It is possible to repeat volumes. The simple method is to use a linear replicator:&lt;br /&gt;
   /gate/phantom/repeaters/insert linear&lt;br /&gt;
   /gate/phantom/linear/autoCenter false&lt;br /&gt;
   /gate/phantom/linear/setRepeatNumber 10&lt;br /&gt;
   /gate/phantom/linear/setRepeatVector 0 0 35. cm&lt;br /&gt;
The autoCenter command: The original volume is anchored (false), instead of the center-of-mass of all copies being centered at that position (true).&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
If you want to define hierarchically repeated structures, such as layers or individually simulated pixels, they should be defined as a &#039;&#039;level&#039;&#039;:&lt;br /&gt;
   /gate/scanner/level1/attach phantom&lt;br /&gt;
   /gate/scanner/level2/attach repeatedStructureWithinPhantom&lt;br /&gt;
&lt;br /&gt;
And now you can use the ROOT leaf &#039;&#039;level1ID&#039;&#039; and &#039;&#039;level2ID&#039;&#039; to identify the volume.&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
If you want the visualization to be persistent, use instead&lt;br /&gt;
   $ Gate&lt;br /&gt;
   ... [TEXT]&lt;br /&gt;
   Idle&amp;gt; /control/execute waterphantom.mac&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=259</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=259"/>
		<updated>2017-03-20T09:27:18Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Geometry */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLSX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
It is possible to repeat volumes. The simple method is to use a linear replicator:&lt;br /&gt;
   /gate/phantom/repeaters/insert linear&lt;br /&gt;
   /gate/phantom/linear/autoCenter false&lt;br /&gt;
   /gate/phantom/linear/setRepeatNumber 10&lt;br /&gt;
   /gate/phantom/linear/setRepeatVector 0 0 35. cm&lt;br /&gt;
The autoCenter command: The original volume is anchored (false), instead of the center-of-mass of all copies being centered at that position (true).&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
If you want to define hierarchically repeated structures, such as layers or individually simulated pixels, they should be defined as a &#039;&#039;level&#039;&#039;:&lt;br /&gt;
   /gate/scanner/level1/attach phantom&lt;br /&gt;
   /gate/scanner/level2/attach repeatedStructureWithinPhantom&lt;br /&gt;
&lt;br /&gt;
And now you can use the ROOT leaf &#039;&#039;level1ID&#039;&#039; and &#039;&#039;level2ID&#039;&#039; to identify the volume.&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=258</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=258"/>
		<updated>2017-03-20T09:26:00Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Geometry */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLSX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
It is possible to repeat volumes. The simple method is to use a linear replicator:&lt;br /&gt;
   /gate/phantom/repeaters/insert linear&lt;br /&gt;
   /gate/phantom/linear/autoCenter false # The following copies are placed behind the already defined phantom, instead of all copies being centered at that position&lt;br /&gt;
   /gate/phantom/linear/setRepeatNumber 10&lt;br /&gt;
   /gate/phantom/linear/setRepeatVector 0 0 35. cm&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
If you want to define hierarchically repeated structures, such as layers or individually simulated pixels, they should be defined as a &#039;&#039;level&#039;&#039;:&lt;br /&gt;
   /gate/scanner/level1/attach phantom&lt;br /&gt;
   /gate/scanner/level2/attach repeatedStructureWithinPhantom&lt;br /&gt;
&lt;br /&gt;
And now you can use the ROOT leaf &#039;&#039;level1ID&#039;&#039; and &#039;&#039;level2ID&#039;&#039; to identify the volume.&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=257</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=257"/>
		<updated>2017-03-20T09:23:41Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Sensitive Detectors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLSX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
If you want to define hierarchically repeated structures, such as layers or individually simulated pixels, they should be defined as a &#039;&#039;level&#039;&#039;:&lt;br /&gt;
   /gate/scanner/level1/attach phantom&lt;br /&gt;
   /gate/scanner/level2/attach repeatedStructureWithinPhantom&lt;br /&gt;
&lt;br /&gt;
And now you can use the ROOT leaf &#039;&#039;level1ID&#039;&#039; and &#039;&#039;level2ID&#039;&#039; to identify the volume.&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=256</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=256"/>
		<updated>2017-03-20T09:18:06Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Visualization */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLSX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=255</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=255"/>
		<updated>2017-03-20T09:14:34Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Visualization */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=254</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=254"/>
		<updated>2017-03-20T08:18:58Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Running the DTC Toolkit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: To load all the required files / your own code, include your C++ sources files in the &amp;lt;code&amp;gt;DTCToolkit/Load.C&amp;lt;/code&amp;gt; file, after Analysis.C has loaded:&lt;br /&gt;
   ...&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/Analysis.C+&amp;quot;);&lt;br /&gt;
   gROOT-&amp;gt;LoadMacro(&amp;quot;Analysis/YourFile.C+&amp;quot;); // Remember to add a + to compile your code&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=253</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=253"/>
		<updated>2017-03-19T10:18:04Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Residual range calculation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:residualRangeHistogram.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=File:ResidualRangeHistogram.JPG&amp;diff=252</id>
		<title>File:ResidualRangeHistogram.JPG</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=File:ResidualRangeHistogram.JPG&amp;diff=252"/>
		<updated>2017-03-19T10:17:57Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: File uploaded with MsUpload&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;File uploaded with MsUpload&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=251</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=251"/>
		<updated>2017-03-19T10:17:10Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Individual tracks: Energy loss fitting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyLossFit.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|500px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=File:EnergyLossFit.JPG&amp;diff=250</id>
		<title>File:EnergyLossFit.JPG</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=File:EnergyLossFit.JPG&amp;diff=250"/>
		<updated>2017-03-19T10:17:03Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: File uploaded with MsUpload&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;File uploaded with MsUpload&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=249</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=249"/>
		<updated>2017-03-19T10:15:27Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Residual range calculation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|500px]]&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=248</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=248"/>
		<updated>2017-03-19T10:12:08Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* (3D reconstruction / MLP estimation) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
When the volume reconstruction is implemented, it is to be put here:&lt;br /&gt;
# Calculate the residual range and incoming vectors of all protons&lt;br /&gt;
# Find the Most Likely Path (MLP) of each proton&lt;br /&gt;
# Divide the proton&#039;s average energy loss along the MLP&lt;br /&gt;
# Then, with a measure of a number of energy loss values in each voxel, perform some kind of average scheme to find the best value.&lt;br /&gt;
&lt;br /&gt;
Instead, we now treat the complete detector as a single unit / voxel, and find the best SUM of all energy loss values (translated into range). The average scheme used in this case is described below, however this might be different than the best one for the above case.&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=247</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=247"/>
		<updated>2017-03-19T10:08:13Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Residual range calculation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
To calculate the most likely residual range from a collection of individual residual ranges is not a simple task!&lt;br /&gt;
It depends on the average scheme, the distance between the layers, the range straggling etc. Different solutions have been attempted:&lt;br /&gt;
* In cases where the distance between the layers is large compared to the straggling, a histogram bin sum based on the depth of the first layer identified as containing a certain number of proton track endpoints is used. It is the method detailed in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and it is implemented in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doNGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In cases where the distance between the layers is small compared to the straggling, a single Gaussian function is fitted on top of all the proton track endpoints, and the histogram bin sum average value is calculated from minus 4 sigma to plus 4 sigma. This code is located in &amp;lt;code&amp;gt;DTCToolkit/Analysis/Analysis.C::doSimpleGaussianFit(*histogram, *means, *sigmas)&amp;lt;/code&amp;gt;. This is the version used for the geometry optimization project.&lt;br /&gt;
&lt;br /&gt;
With a histogram &amp;lt;code&amp;gt;hRanges&amp;lt;/code&amp;gt; containing all the different proton track end points, use&lt;br /&gt;
   float means[10] = {};&lt;br /&gt;
   float sigmas[10] = {};&lt;br /&gt;
   TF1 *gaussFit = doSimpleGaussianFit(hRanges, means, sigmas);&lt;br /&gt;
   printf(&amp;quot;The resulting range of the proton beam if %.2f +- %.2f mm.\n&amp;quot;, means[9], sigmas[9]);&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=246</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=246"/>
		<updated>2017-03-19T09:59:12Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Inverse pixel diffusion calculation (MC and exp. data) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|400px]]&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/Tools.C::getEdepFromCS(n)&amp;lt;/code&amp;gt; contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=245</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=245"/>
		<updated>2017-03-19T09:55:41Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
[[File:Skjermbilde.JPG|500px]]&lt;br /&gt;
&lt;br /&gt;
The function HelperFunctions/Tools.C::getEdepFromCS(n) contains the parameterization:&lt;br /&gt;
   Float_t getEdepFromCS(Int_t cs) {&lt;br /&gt;
      return -3.92 + 3.9 * cs - 0.0149 * pow(cs,2) + 0.00122 * pow(cs,3) - 1.4998e-5 * pow(cs,4);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=File:Skjermbilde.JPG&amp;diff=244</id>
		<title>File:Skjermbilde.JPG</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=File:Skjermbilde.JPG&amp;diff=244"/>
		<updated>2017-03-19T09:52:43Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: File uploaded with MsUpload&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;File uploaded with MsUpload&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=243</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=243"/>
		<updated>2017-03-19T09:49:52Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Pixel diffusion modelling (MC only) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
==== Inverse pixel diffusion calculation (MC and exp. data) ====&lt;br /&gt;
This process has been inversed in a Python script, and performed with a large number of input cluster sizes. The result is a parameterization between the proton&#039;s energy loss in a layer, and the number of activated pixels:&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=242</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=242"/>
		<updated>2017-03-19T09:47:44Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Individual tracks: Energy loss fitting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
To obtain the most likely residual range / stopping range from a Track object, use&lt;br /&gt;
   track-&amp;gt;doRangeFit();&lt;br /&gt;
   float residualRange = track-&amp;gt;getFitParameterRange();&lt;br /&gt;
&lt;br /&gt;
What happens here is that a TGraph with the ranges and in-layer energy losses of all the Cluster objects is constructed. A differentiated Bragg Curve is fitted to this TGraph:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; f(z) = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;math&amp;gt;p,\alpha&amp;lt;/math&amp;gt; being the parameters found during the full-scoring MC simulations. The value &amp;lt;math&amp;gt;R_0&amp;lt;/math&amp;gt;, or &amp;lt;code&amp;gt;track::getFitParameterRange&amp;lt;/code&amp;gt; is stored.&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=241</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=241"/>
		<updated>2017-03-19T09:36:01Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Proton track reconstruction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
The process of track reconstruction is described fully in [[http://dx.doi.org/10.1016/j.nima.2017.02.007]].&lt;br /&gt;
&lt;br /&gt;
From a collection of cluster objects, &amp;lt;code&amp;gt;Clusters * clusters&amp;lt;/code&amp;gt;, use the following code to get a collection of the Track objects connecting them across the layers.&lt;br /&gt;
   Tracks * tracks = clusters-&amp;gt;findCalorimeterTracks();&lt;br /&gt;
&lt;br /&gt;
Some optimization schemes can be applied to the tracks in order to increase their accuracy:&lt;br /&gt;
   tracks-&amp;gt;extrapolateToLayer0(); // If a track was found starting from the second layer, we want to know the extrapolated vector in the first layer&lt;br /&gt;
   tracks-&amp;gt;splitSharedClusters(); // If two tracks meet at the same position in a layer, and they share a single cluster, split the cluster into two and give each part to each of the tracks&lt;br /&gt;
   tracks-&amp;gt;removeTracksLeavingDetector(); // If a track exits laterally from the detector before coming to a stop, remove it&lt;br /&gt;
   tracks-&amp;gt;removeTracksEndingInBadChannnels(); // ONLY EXP DATA: Use a mask containing all the bad chips to see if a track ends in there. Remove it if it does.&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=240</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=240"/>
		<updated>2017-03-19T08:27:43Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Displaying the results */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit/Scripts/optimization] $ root plotRangesAndStraggling.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=239</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=239"/>
		<updated>2017-03-19T08:26:48Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* How does the DTC Toolkit calculate resolution? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
&lt;br /&gt;
== Geometry optimization: How does the DTC Toolkit calculate resolution? ==&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit] $ root Scripts/makePlots.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=238</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=238"/>
		<updated>2017-03-19T08:23:48Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Cluster identification */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/math&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
&lt;br /&gt;
=== How does the DTC Toolkit calculate resolution? ===&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit] $ root Scripts/makePlots.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=237</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=237"/>
		<updated>2017-03-19T08:23:31Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Cluster identification */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
Cluster identification is the process to find all connected hits (activated pixels) from a single proton in a single layer. It can be done by several algorithms, simple looped neighboring, DBSCAN, ...&lt;br /&gt;
The process is such:&lt;br /&gt;
# All hits are found from the diffused 2D histograms and stored as &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects with &amp;lt;math&amp;gt;(x,y,layer)&amp;lt;/code&amp;gt; in a TClonesArray list.&lt;br /&gt;
# This list is indexed by layer number (a new list with the index the first Hit in each layer) to optimize any search&lt;br /&gt;
# The cluster finding algorithm is applied. For every Hit, the Hit list is looped through to find any connected hits. The search is optimized by use of another index list on the vertical position of the Hits. All connected hits (vertical, horizontal and diagonal) are collected in a single Cluster object with &amp;lt;math&amp;gt;(x,y,layer,cluster size)&amp;lt;/math&amp;gt;, where the cluster size is the number of its connected pixels.&lt;br /&gt;
&lt;br /&gt;
This task is simply performed on a diffused &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;:&lt;br /&gt;
   Hits *hits = cf-&amp;gt;findHits();&lt;br /&gt;
   Clusters *clusters = hits-&amp;gt;findClustersFromHits();&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
&lt;br /&gt;
=== How does the DTC Toolkit calculate resolution? ===&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit] $ root Scripts/makePlots.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=236</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=236"/>
		<updated>2017-03-19T08:09:59Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Data readout: MC, MC + truth, experimental */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
Please note the phenomenological difference between experimental data and MC:&lt;br /&gt;
* Exp. data has some noise, represented as &amp;quot;hot&amp;quot; pixels and 1-pixel clusters&lt;br /&gt;
* Exp. data has diffused, spread-out, clusters from physics processes&lt;br /&gt;
* Monte Carlo data has no such noise, and proton hits are represented as 1-pixel clusters (with edep information)&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
&lt;br /&gt;
=== How does the DTC Toolkit calculate resolution? ===&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit] $ root Scripts/makePlots.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=235</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=235"/>
		<updated>2017-03-19T07:54:33Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Running the DTC Toolkit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
&lt;br /&gt;
=== How does the DTC Toolkit calculate resolution? ===&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit] $ root Scripts/makePlots.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=234</id>
		<title>Software tutorial at IFT</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Software_tutorial_at_IFT&amp;diff=234"/>
		<updated>2017-03-19T07:53:34Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* Pixel diffusion modelling (MC only) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction and overview ==&lt;br /&gt;
This page is meant as a recipe for the software day at IFT, March 20 2017. We have decided that this should take place on Monday, March 20 between 09.00 am and 3.00 pm at the Department of Physics and Technology (our usual meeting room in the 5th floor).&lt;br /&gt;
&lt;br /&gt;
There are certain steps you need to take prior to the meeting. We do not wish to loose time on installation and configuration of the software needed. Thus, it is imperative that you come with your laptops which already have the following installed and configured properly:&lt;br /&gt;
 &lt;br /&gt;
# [[ROOT installation]]&lt;br /&gt;
# [[Geant 4 installation]]&lt;br /&gt;
# [[Gate installation]]&lt;br /&gt;
# [[DTC toolkit|DTC Toolkit for reconstruction]]&lt;br /&gt;
 &lt;br /&gt;
Agenda for the day is as follows:&lt;br /&gt;
 &lt;br /&gt;
#       An introduction to GATE macros, i.e. GATE input scripts&lt;br /&gt;
#       Setting up a simple simulation geometry in GATE using a proton bencil beam and a water phantom&lt;br /&gt;
#       Running short simulations&lt;br /&gt;
#       Examination of the GATE-output files&lt;br /&gt;
 &lt;br /&gt;
We think that the above mentioned mini introduction to GATE should take no longer than 1 – 1.5 hours. Rest of the day, we will focus on a more in-depth review of the analysis code written by Helge P.&lt;br /&gt;
#       Setting up a tracking calorimeter geometry in GATE&lt;br /&gt;
#       Running short simulations with the detector geometry&lt;br /&gt;
#       Using the results of the MC simulations, a short «hands-on» introduction to Helge P.’s analysis code written in the Root framework&lt;br /&gt;
#       A review of all the different modules in the above mentioned analysis code&lt;br /&gt;
 &lt;br /&gt;
The final goals of the day will be:&lt;br /&gt;
#       Setting up a GATE simulation of an example tracking calorimeter including geometry, material specifications and proton beam definition&lt;br /&gt;
#       Being able to work with the GATE output files (identifying primary protons, secondary particles, calculating deposited dose etc…)&lt;br /&gt;
#       Being able to run a complete analysis using the Root-analysis code written by Helge P.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As always, check the [[Software for design optimization|User guide and tutorial]] for the DTC Toolkit to find a Wiki-friendly guide.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== GATE ==&lt;br /&gt;
&#039;&#039;Simulations of Preclinical and Clinical Scans in Emission Tomography, Transmission Tomography and Radiation Therapy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Geant4 is a C++ library, where an application / simulation is built by writing certain C++ classes (geometry, beam, scoring, output, physics), and compiling the binaries from where the simulations are run. Only certain modifications to the simulations can be made with the binaries, such as beam settings, certain physics settings as well as geometry objects pre-defined to be variable.&lt;br /&gt;
&lt;br /&gt;
GATE is an application written for Geant4. It was originally meant for PET and SPECT uses, however it is very flexible so many different kinds of detectors can be designed. To run GATE, only macro files written in the Geant4 scripting language (with some GATE specific commands) are needed to build the geometry, scoring, physics and beam. The output is also defined in the macro files, either to ASCII files or to ROOT files.&lt;br /&gt;
&lt;br /&gt;
In each simulation, the user has to: &lt;br /&gt;
# define the scanner geometry &lt;br /&gt;
# set up the physics processes &lt;br /&gt;
# initialize the simulation &lt;br /&gt;
# set up the detector model &lt;br /&gt;
# define the source(s) &lt;br /&gt;
# specify the data output format&lt;br /&gt;
# start the acquisition&lt;br /&gt;
&lt;br /&gt;
=== Introduction to GATE macros ===&lt;br /&gt;
Gate, just as GEANT4, is a program in which the user interface is based on scripts. To perform actions, the user must either enter commands in interactive mode, or build up macro files containing an ordered collection of commands.&lt;br /&gt;
&lt;br /&gt;
Each command performs a particular function, and may require one or more parameters. The Gate commands are organized following a tree structure, with respect to the function they represent. For example, all geometry-control commands start with geometry, and they will all be found under the &#039;&#039;/geometry/&#039;&#039; branch of the tree structure.&lt;br /&gt;
&lt;br /&gt;
When Gate is run, the &#039;&#039;&#039;Idle&amp;gt;&#039;&#039;&#039; prompt appears. At this stage the command interpreter is active; i.e. all the Gate commands entered will be interpreted and processed on-line. All functions in Gate can be accessed to using command lines. The geometry of the system, the description of the radioactive source(s), the physical interactions considered, etc., can be parameterized using command lines, which are translated to the Gate kernel by the command interpreter. In this way, the simulation is defined one step at a time, and the actual construction of the geometry and definition of the simulation can be seen on-line. If the effect is not as expected, the user can decide to re-adjust the desired parameter by re-entering the appropriate command on-line. Although entering commands step by step can be useful when the user is experimenting with the software or when he/she is not sure how to construct the geometry, there remains a need for storing the set of commands that led to a successful simulation. &lt;br /&gt;
&lt;br /&gt;
Macros are ASCII files (with &#039;.mac&#039; extension) in which each line contains a command or a comment. Commands are GEANT4 or Gate scripted commands; comments start with the character &#039; #&#039;. Macros can be executed from within the command interpreter in Gate, or by passing it as a command-line parameter to Gate, or by calling it from another macro. A macro or set of macros must include all commands describing the different components of a simulation in the right order. Usually these components are visualization, definitions of volumes (geometry), systems, digitizer, physics, initialization, source, output and start. These steps are described in the next sections. A single simulation may be split into several macros, for instance one for the geometry, one for the physics, etc. Usually, there is a master macro which calls the more specific macros. Splitting macros allows the user to re-use one or more of these macros in several other simulations, and/or to organize the set of all commands. To execute a macro (mymacro.mac in this example) from the Linux prompt, just type :&lt;br /&gt;
&lt;br /&gt;
 Gate mymacro.mac &lt;br /&gt;
&lt;br /&gt;
To execute a macro from inside the Gate environment, type after the &amp;quot;Idle&amp;gt;&amp;quot; prompt:&lt;br /&gt;
 Idle&amp;gt;/control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
And finally, to execute a macro from inside another macro, simply write in the master macro:&lt;br /&gt;
 /control/execute mymacro.mac &lt;br /&gt;
&lt;br /&gt;
=== Setting up a simple simulation geometry in GATE using a pencil beam and a water phantom ===&lt;br /&gt;
&lt;br /&gt;
==== Visualization ====&lt;br /&gt;
First we may want to set up a visualization engine to see what&#039;s going on. This is optional, and runs in batch mode should not be visualized! Here we use the opengl visualizer OGLX, but different kinds of visualization engines are discussed in the GATE Wiki [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Visualization]]&lt;br /&gt;
   /vis/open/OGLX&lt;br /&gt;
   /vis/viewer/reset&lt;br /&gt;
   /vis/viewer/set/viewpointThetaPhi 60 60&lt;br /&gt;
   /vis/viewer/zoom 1&lt;br /&gt;
   /vis/viewer/set/style surface&lt;br /&gt;
   /vis/drawVolume&lt;br /&gt;
   /tracking/storeTrajectory 1&lt;br /&gt;
   /vis/scene/endOfEventAction accumulate&lt;br /&gt;
   /vis/viewer/update&lt;br /&gt;
Most of these commands are self explainatory. By using the storeTrajectory command, all particles are displayed together with the geometry.&lt;br /&gt;
&lt;br /&gt;
==== Materials database ====&lt;br /&gt;
The default material assigned to a new volume is Air. The list of available materials is defined in the GateMaterials.db file. It&#039;s included in the Gate folder, and should be copied to the active directory. It is easy to add new materials to the file, just have a look at the file.&lt;br /&gt;
   /gate/geometry/setMaterialDatabase MyMaterialDatabase.db&lt;br /&gt;
&lt;br /&gt;
==== Geometry ====&lt;br /&gt;
Apart from specialized geometries such as PET, SPECT, CT, the general geometry is called as &#039;&#039;scanner&#039;&#039;. It must be placed within the &#039;&#039;world&#039;&#039; volume, and all parts of the detector (to be scored) be placed within the &#039;&#039;scanner&#039;&#039; volume.&lt;br /&gt;
&lt;br /&gt;
[[File:geometry_hiarerachy.png|400px]]&lt;br /&gt;
&lt;br /&gt;
To construct a simple water phantom geometry of 30x30x30 cm, use the following commands:&lt;br /&gt;
   /gate/world/geometry/setXLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setYLength 1000. cm&lt;br /&gt;
   /gate/world/geometry/setZLength 1000. cm&lt;br /&gt;
So we&#039;ve defined a world geometry of 1 m&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;. It must be larger than all its daughter volumes. Let&#039;s put the &#039;&#039;scanner&#039;&#039; volume inside the &#039;&#039;world&#039;&#039; volume. Since it&#039;s not already defined (the &#039;&#039;world&#039;&#039; volume was), we must insert a &#039;&#039;box&#039;&#039; object (with parameters XLength, YLength, ZLength as the side measurements of the box):&lt;br /&gt;
   /gate/world/daughters/name scanner&lt;br /&gt;
   /gate/world/daughters/insert box&lt;br /&gt;
   /gate/scanner/geometry/setXLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setYLength 100. cm&lt;br /&gt;
   /gate/scanner/geometry/setZLength 100. cm&lt;br /&gt;
   /gate/scanner/vis/forceWireframe&lt;br /&gt;
Inside this scanner volume (the default material is Air), let&#039;s finally put the water phantom (to start at &amp;lt;math&amp;gt;z=0&amp;lt;/math&amp;gt;):&lt;br /&gt;
   /gate/scanner/daughters/name phantom&lt;br /&gt;
   /gate/scanner/daughters/insert box&lt;br /&gt;
   /gate/phantom/geometry/setXLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setYLength 30. cm&lt;br /&gt;
   /gate/phantom/geometry/setZLength 30. cm&lt;br /&gt;
   /gate/phantom/placement/setTranslation 0 0 -35. cm # - 100/2 + 30/2&lt;br /&gt;
   /gate/phantom/setMaterial Water&lt;br /&gt;
   /gate/phantom/vis/forceWireframe&lt;br /&gt;
&lt;br /&gt;
==== Sensitive Detectors ====&lt;br /&gt;
The scoring system in Geant4/GATE is based around &#039;&#039;Sensitive Detectors&#039;&#039; (SD). If a volume is a daughter volume (or granddaughter, ...), it may be assigned as a SD. This process is super simple in GATE:&lt;br /&gt;
   /gate/phantom/attachCrystalSD&lt;br /&gt;
&lt;br /&gt;
==== Physics ====&lt;br /&gt;
There are many physics lists to choose from in Geant4/GATE. For proton therapy and detector simulations, I most often use a combination of a low-energy-friendly hadronic list and the variable-steplength (for Bragg Peak accuracy) electromagnetic list.&lt;br /&gt;
From the Geant4 reference physics webpage [[http://geant4.cern.ch/support/physicsLists/referencePL/referencePL.shtml]]:&lt;br /&gt;
* QGSP: QGSP is the basic physics list applying the quark gluon string model for high energy interactions of protons, neutrons, pions, and Kaons and nuclei. The high energy interaction creates an exited nucleus, which is passed to the precompound model modeling the nuclear de-excitation.&lt;br /&gt;
* QGSP_BIC: Like QGSP, but using Geant4 Binary cascade for primary protons and neutrons with energies below ~10GeV, thus replacing the use of the LEP model for protons and neutrons In comparison to teh LEP model, Binary cascade better describes production of secondary particles produced in interactions of protons and neutrons with nuclei.&lt;br /&gt;
* emstandard_opt3 designed for any applications required higher accuracy of electrons, hadrons and ion tracking without magnetic field. It is used in extended electromagnetic examples and in the QGSP_BIC_EMY reference Physics List. The corresponding physics&lt;br /&gt;
&lt;br /&gt;
The physics list to use all of these is called &#039;&#039;QGSP_BIC_EMY&#039;&#039;. It is loaded with the command&lt;br /&gt;
   /gate/physics/addPhysicsList QGSP_BIC_EMY&lt;br /&gt;
&lt;br /&gt;
In addition, in order to accurately represent the water in the water phantom, we define the current recommended value for the mean ionization potential for water, which is &amp;lt;math&amp;gt;75\ \mathrm{eV}&amp;lt;/math&amp;gt;. This can be performed for all materials, and it will override Bragg&#039;s additivity rule.&lt;br /&gt;
   /gate/geometry/setIonisationPotential Water 75 eV&lt;br /&gt;
&lt;br /&gt;
==== Initialization ====&lt;br /&gt;
After the geometry and physics has been set, initialize the run!&lt;br /&gt;
   /gate/run/initialize&lt;br /&gt;
&lt;br /&gt;
==== Proton beam ====&lt;br /&gt;
   /gate/source/addSource PBS PencilBeam&lt;br /&gt;
   /gate/source/PBS/setParticleType proton&lt;br /&gt;
   /gate/source/PBS/setEnergy 188.0 MeV&lt;br /&gt;
   /gate/source/PBS/setSigmaEnergy 1.0 MeV&lt;br /&gt;
   /gate/source/PBS/setPosition 0 0 -10. mm&lt;br /&gt;
   /gate/source/PBS/setSigmaX 2 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaY 4 mm&lt;br /&gt;
   /gate/source/PBS/setSigmaTheta 3.3 mrad&lt;br /&gt;
   /gate/source/PBS/setSigmaPhi 3.8 mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaEmittance 15 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseXThetaRotationNorm negative&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiEmittance 20 mm*mrad&lt;br /&gt;
   /gate/source/PBS/setEllipseYPhiRotationNorm negative&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
It is tricky to use this beam since all parameters need to match, so an &#039;&#039;&#039;alternative&#039;&#039;&#039; is to use a uniform General Particle Source:&lt;br /&gt;
   /gate/source/addSource uniformBeam gps&lt;br /&gt;
   /gate/source/uniformBeam/gps/particle proton&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/type Gauss&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/mono 188 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/ene/sigma 1 MeV&lt;br /&gt;
   /gate/source/uniformBeam/gps/type Plane&lt;br /&gt;
   /gate/source/uniformBeam/gps/shape Square&lt;br /&gt;
   /gate/source/uniformBeam/gps/direction 0 0 1&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfx 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/halfy 0 mm&lt;br /&gt;
   /gate/source/uniformBeam/gps/centre 0 0 -1 cm&lt;br /&gt;
   /gate/application/setTotalNumberOfPrimaries 5000&lt;br /&gt;
&lt;br /&gt;
==== Output ====&lt;br /&gt;
For this tutorial, we will use the ROOT output.&lt;br /&gt;
   /gate/output/root/enable&lt;br /&gt;
   /gate/output/root/setFileName gate_simulation&lt;br /&gt;
&lt;br /&gt;
==== Running the simulation ====&lt;br /&gt;
To finalize the macro file, start the randomization engine and run!&lt;br /&gt;
   /gate/random/setEngineName MersenneTwister&lt;br /&gt;
   /gate/random/setEngineSeed auto&lt;br /&gt;
   /gate/application/start&lt;br /&gt;
&lt;br /&gt;
=== Running short simulations ===&lt;br /&gt;
To run a simulation, create a macro file with the lines as descibed above, and run it with&lt;br /&gt;
   $ Gate waterphantom.mac&lt;br /&gt;
The terminal output describes the geometry, physics, etc. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It is also possible to use aliases in the macro file. For example, to simplify the energy selection, substitute with the line&lt;br /&gt;
   /gate/source/PBS/setEnergy {energy} MeV&lt;br /&gt;
and run the macro with&lt;br /&gt;
   $ Gate -a &#039;[energy,175]&#039; waterphantom.mac&lt;br /&gt;
Multiple aliases can be stacked:&lt;br /&gt;
   $ Gate -a &#039;[energy,175] [phantomsize,45]&#039; waterphantom.mac&lt;br /&gt;
if you have defined multiple alises in the macro file. It is sadly not possible to do calculations in the macro language, so you have to do that through bash (&amp;lt;code&amp;gt;newvalue=`echo &amp;quot;$oldvalue/2&amp;quot; | bc`&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Examination of the GATE output files ===&lt;br /&gt;
The ROOT output file(s) from the simulation can be opened several ways:&lt;br /&gt;
* By using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; to look at scoring variable distributions&lt;br /&gt;
* By using loading the ROOT Tree into a C++ program and looping over events (interactions)&lt;br /&gt;
&lt;br /&gt;
==== Using the built-in &amp;lt;code&amp;gt;TBrowser&amp;lt;/code&amp;gt; ====&lt;br /&gt;
The hierarchy for the files are shown in the image below:&lt;br /&gt;
&lt;br /&gt;
[[File:root_file_hierarchy.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
In Gate, the TTree is called &#039;&#039;Hits&#039;&#039;, and the leaves are named after the different variables that are automatically scored:&lt;br /&gt;
   PDGEncoding      - The Particle ID&lt;br /&gt;
   trackID          - Track number following a mother particle&lt;br /&gt;
   parentID         - The parent track&#039;s event ID. 0 if the current particle is a beam particle&lt;br /&gt;
   time             - Time in simulation (for ToF in PET, etc.)&lt;br /&gt;
   edep             - Deposited energy in this event / interaction&lt;br /&gt;
   stepLength       - The length of the current step&lt;br /&gt;
   posX             - Global X position of event&lt;br /&gt;
   posY             - Global Y position of event&lt;br /&gt;
   posZ             - Global Z position of event&lt;br /&gt;
   localPosX        - Local (in mother volume) X position of event&lt;br /&gt;
   localPosY        - Local (in mother volume) Y position of event&lt;br /&gt;
   localPosZ        - Local (in mother volume) Z position of event&lt;br /&gt;
   baseID           - ID of mother volume &#039;&#039;scanner&#039;&#039;, == 0 if only one &#039;&#039;scanner&#039;&#039; defined&lt;br /&gt;
   level1ID         - ID of 1st level of volume hierarchy&lt;br /&gt;
   level2ID         - ID of 2nd level of volume hierarchy&lt;br /&gt;
   level3ID         - ID of 3rd level of volume hierarchy&lt;br /&gt;
   level4ID         - ID of 4th level of volume hierarchy&lt;br /&gt;
   sourcePosX       - Global X position of source particle&lt;br /&gt;
   sourcePosY       - Global Y position of source particle&lt;br /&gt;
   sourcePosZ       - Global X position of source particle&lt;br /&gt;
   eventID          - History number (important!!)&lt;br /&gt;
   volumeID         - ID of current volume (useful to isolate particles in a specific part of a fully scored volume)&lt;br /&gt;
   processName      - A string containing the name of the interaction type:&lt;br /&gt;
      - hIoni: Ionization by hadron&lt;br /&gt;
      - Transportation: No special interactions (usually from step limiter)&lt;br /&gt;
      - eIoni: Ionization by electron&lt;br /&gt;
      - ProtonInelastic: Inelastic nuclear interaction of proton&lt;br /&gt;
      - compt: Compton scattering&lt;br /&gt;
      - ionIoni: Ionization by ion&lt;br /&gt;
      - msc: Multiple Coulomb Scattering process&lt;br /&gt;
      - hadElastic: Elastic hadron / proton scattering&lt;br /&gt;
&lt;br /&gt;
An example of the distribution of eventID (in histogram form, this is the number of interactions per particle (if bin size = 1))&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] new TBrowser&lt;br /&gt;
&lt;br /&gt;
[[File:root.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
Or for the Z distribution (see the Bragg Peak)&lt;br /&gt;
&lt;br /&gt;
[[File:root2.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
==== Opening the files in C++ ====&lt;br /&gt;
It is quite simple to open the generated ROOT files in a C++ program.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;openROOTFile.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile *f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree *tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      &lt;br /&gt;
      // Declare the variables (leafs) to be readout&lt;br /&gt;
      Float_t x,y,z,edep;&lt;br /&gt;
      Int_t eventID, parentID;&lt;br /&gt;
      &lt;br /&gt;
      // Make a connection between the declared variables and the leafs&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posX&amp;quot;, &amp;amp;x);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posY&amp;quot;, &amp;amp;y);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;edep&amp;quot;, &amp;amp;edep);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      // Loop over all the entries in the tree&lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (eventID &amp;gt; 2) break; // To limit the output!&lt;br /&gt;
         if (parentID != 0) continue; // Only show results from primary particles&lt;br /&gt;
   &lt;br /&gt;
         printf(&amp;quot;Primary particle with event ID %d has an interaction with %.2f MeV energy loss at (x,y,z) = (%.2f, %.2f, %.2f).\n&amp;quot;, eventID, edep, x, y, z);&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      delete f;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Then you can run the program with&lt;br /&gt;
   $ root&lt;br /&gt;
   ROOT [0] .L openROOTFile.C+ // The + tells ROOT to compile the code&lt;br /&gt;
   ROOT [1] Run();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please note that it is also possible to make a complete class to read out the root files using ROOT&#039;s &amp;lt;code&amp;gt;MakeClass&amp;lt;/code&amp;gt; function. See [[http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2:Data_output#How_to_analyze_the_Root_output]].&lt;br /&gt;
&lt;br /&gt;
==== Test case: Finding the range and straggling of a proton beam ====&lt;br /&gt;
   #include &amp;lt;TTree.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TH1F.h&amp;gt;&lt;br /&gt;
   #include &amp;lt;TFile.h&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   using namespace std;&lt;br /&gt;
   &lt;br /&gt;
   void Run() {&lt;br /&gt;
      TFile  * f = new TFile(&amp;quot;gate_simulation.root&amp;quot;);&lt;br /&gt;
      TTree  * tree = (TTree*) f-&amp;gt;Get(&amp;quot;Hits&amp;quot;); // The TTree in the GATE file is called &#039;&#039;Hits&#039;&#039;&lt;br /&gt;
      TH1F   * rangeHistogram = new TH1F(&amp;quot;rangeHistogram&amp;quot;, &amp;quot;Stopping position for protons&amp;quot;; 800, 0, 400); // Histogram 1D with Float values&lt;br /&gt;
   &lt;br /&gt;
      Float_t  z;&lt;br /&gt;
      Int_t    eventID, parentID;¨&lt;br /&gt;
   &lt;br /&gt;
      Int_t    lastEventID = -1;&lt;br /&gt;
      Float_t  lastZ = -1;&lt;br /&gt;
      &lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;posZ&amp;quot;, &amp;amp;z);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;eventID&amp;quot;, &amp;amp;eventID);&lt;br /&gt;
      tree-&amp;gt;SetBranchAddress(&amp;quot;parentID&amp;quot;, &amp;amp;parentID);&lt;br /&gt;
      &lt;br /&gt;
      for (Int_t i=0, i &amp;lt; tree-&amp;gt;GetEntries(); ++i) {&lt;br /&gt;
         tree-&amp;gt;GetEntry(i);&lt;br /&gt;
         if (parentID != 0) continue;&lt;br /&gt;
         &lt;br /&gt;
         // Check if this is the first event of a primary particle&lt;br /&gt;
         if (eventID != lastEventID &amp;amp;&amp;amp; lastEventID &amp;gt;= 0) {&lt;br /&gt;
            rangeHistogram-&amp;gt;Fill(lastZ);&lt;br /&gt;
         }&lt;br /&gt;
   &lt;br /&gt;
         // Store the current variables&lt;br /&gt;
         lastZ = z;&lt;br /&gt;
         lastEventID = eventID;&lt;br /&gt;
      }&lt;br /&gt;
   &lt;br /&gt;
      rangeHistogram-&amp;gt;Draw();&lt;br /&gt;
    &lt;br /&gt;
      // Make a Gaussian fit to the range&lt;br /&gt;
      TF1 * fit = new TF1(&amp;quot;fit&amp;quot;, &amp;quot;gaus&amp;quot;);&lt;br /&gt;
      rangeHistogram-&amp;gt;Fit(&amp;quot;fit&amp;quot;, &amp;quot;&amp;quot;, 350, 400); // Most probable values for fit is in this range, ROOT is quite sensitive to Gaussians occupying only a small part of the histogram, so give narrow fit range&lt;br /&gt;
   &lt;br /&gt;
      printf(&amp;quot;The range of the proton beam is %.3f +- %.3f mm.\n&amp;quot;, fit-&amp;gt;GetParameter(1), fit-&amp;gt;GetParameter(2));  &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
This time, the program will yield the following output (from a 250 MeV beam):&lt;br /&gt;
   The range of the proton beam is 378.225 mm +- 3.791 mm&lt;br /&gt;
&lt;br /&gt;
With the following histogram (I&#039;ve added some color and a SetOptFit to the legend)&lt;br /&gt;
&lt;br /&gt;
[[File:ranges.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
== Review of the analysis code by Helge Pettersen ==&lt;br /&gt;
&lt;br /&gt;
Overview:&lt;br /&gt;
* Generating the GATE simulation files&lt;br /&gt;
* Perfoming GATE simulations&lt;br /&gt;
* Interlude - Tuning the analysis for the wanted geometry.&lt;br /&gt;
** Making range-energy tables, finding the straggling, etc.&lt;br /&gt;
* Tracking analysis: This can be done both simplified and full&lt;br /&gt;
** Simplified: No double-modelling of the pixel diffusion process (use MC provded energy loss), no track reconstruction (use eventID tag to connect tracks from same primary).&lt;br /&gt;
* The 3D reconstruction of phantoms using tracker planes has not yet been implemented&lt;br /&gt;
&lt;br /&gt;
The analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
== GATE simulations ==&lt;br /&gt;
==== Geometry scheme ====&lt;br /&gt;
The simplified simulation geometry for the future DTC simulations has been proposed as:&lt;br /&gt;
&lt;br /&gt;
[[File:geometry.PNG|600px]]&lt;br /&gt;
&lt;br /&gt;
It is partly based on the ALPIDE design, and the FoCal design. The GATE geometry corresponding to this scheme is based on the following hierarchy:&lt;br /&gt;
   World -&amp;gt; Scanner1 -&amp;gt; Layer -&amp;gt; Module + Absorber + Air gap&lt;br /&gt;
                                 Module = Active sensor + Passive sensor + Glue + PCB + Glue&lt;br /&gt;
         -&amp;gt; Scanner2 -&amp;gt; [Layer] * Number Of Layers&lt;br /&gt;
&lt;br /&gt;
The idea is that Scanner1 represents the first layer (where e.g. there is no absorber, only air), and that Scanner2 represents all the following (similar) layers which are repeated.&lt;br /&gt;
&lt;br /&gt;
==== Generating the macro files ====&lt;br /&gt;
To generate the geometry files to run in Gate, a Python script is supplied.&lt;br /&gt;
It is located within the &#039;&#039;gate/python&#039;&#039; subfolder.&lt;br /&gt;
    [gate/python] $ python gate/python/makeGeometryDTC.py&lt;br /&gt;
[[File:GATE geometry builder.PNG||500px]]&lt;br /&gt;
&lt;br /&gt;
Choose the wanted characteristics of the detector, and use &#039;&#039;write files&#039;&#039; in order to create the geometry file Module.mac, which is automatically included in Main.mac.&lt;br /&gt;
Note that the option &amp;quot;Use water degrader phantom&amp;quot; should be checked (as is the default behavior)!&lt;br /&gt;
&lt;br /&gt;
=== Creating the full simulations files for a range-energy look-up-table ===&lt;br /&gt;
In this step, 5000-10000 particles are usually sufficient in order to get accurate results.&lt;br /&gt;
To loop through different energy degrader thicknesses, run the script &#039;&#039;runDegraderFull.sh&#039;&#039;:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
The brackets indicate the folder in the Github repository to run the code from.&lt;br /&gt;
&lt;br /&gt;
For example, with a 3 mm degrader, and simulating a 250 MeV beam passing through a phantom of 50, 55, 60, 65 and 70 mm water:&lt;br /&gt;
    [gate/python] $ sh runDegraderFull.sh 3 50 5 70&lt;br /&gt;
This is a parallel process, so don&#039;t do too much together. I&#039;ve found that on my 4 core i5, 100 parallel simulations are OK (of course they only get a few % CPU each), but with &amp;gt;200 the virtual machine stops working... So turn on overnight, but know your limits!&lt;br /&gt;
&lt;br /&gt;
=== Creating the chip-readout simulations files for resolution calculation ===&lt;br /&gt;
In this step a higher number of particles is desired. I usually use 25000 since we need O(100) simulations. A sub 1-mm step size will really tell us if we manage to detect such small changes in a beam energy.&lt;br /&gt;
&lt;br /&gt;
And loop through the different absorber thicknesses:&lt;br /&gt;
    [gate/python] $ sh runDegrader.sh &amp;lt;absorber thickness&amp;gt; &amp;lt;degraderthickness from&amp;gt; &amp;lt;degraderthickness stepsize&amp;gt; &amp;lt;degraderthickness to&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating the basis for range-energy calculations ===&lt;br /&gt;
==== The range-energy look-up-table ====&lt;br /&gt;
Now we have ROOT output files from Gate, all degraded differently through a varying water phantom and therefore stopping at different places in the DTC.&lt;br /&gt;
We want to follow all the tracks to see where they end, and make a histogram over their stopping positions. This is of course performed from a looped script, but to give a small recipe:&lt;br /&gt;
# Retrieve the first interaction of the first particle. Note its event ID (history number) and edep (energy loss for that particular interaction)&lt;br /&gt;
# Repeat until the particle is outside the phantom. This can be found from the volume ID or the z position (the first interaction with {math|z&amp;gt;0}). Sum all the found edep values, and this is the energy loss inside the phantom. Now we have the &amp;quot;initial&amp;quot; energy of the proton before it hits the DTC&lt;br /&gt;
# Follow the particle, noting its z position. When the event ID changes, the next particle is followed, and save the last z position of where the proton stopped in a histogram&lt;br /&gt;
# Do a Gaussian fit of the histogram after all the particles have been followed. The mean value is the range of the beam with that particular &amp;quot;initial&amp;quot; energy. The spread is the range straggling. Note that the range straggling is more or less constant, but the contributions to the range straggling from the phantom and DTC, respectively, are varying linearly. &lt;br /&gt;
&lt;br /&gt;
This recipe has been implemented in &amp;lt;code&amp;gt;DTCToolkit/Scripts/findRange.C&amp;lt;/code&amp;gt;. Test run the code on a few of the cases (smallest and biggest phantom size ++) to see that&lt;br /&gt;
# The correct start- and end points of the histogram looks sane. If not, this can be corrected for by looking how &amp;lt;code&amp;gt;xfrom&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xto&amp;lt;/code&amp;gt; is calculated and playing with the calculation.&lt;br /&gt;
# The mean value and straggling is calculated correctly&lt;br /&gt;
# The energy loss is calculated correctly&lt;br /&gt;
You can run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; in root by compiling and giving it three arguments; Energy of the protons, absorber thickness, and the degrader thickness you wish to inspect. &lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findRange.C+&lt;br /&gt;
    // void findRange(Int_t energy, Int_t absorberThickness, Int_t degraderThickness)&lt;br /&gt;
    ROOT [2] findRange f(250, 3, 50); f.Run();&lt;br /&gt;
&lt;br /&gt;
The output should look like this: Correctly places Gaussian fits is a good sign.&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
If you&#039;re happy with this, then a new script will run &amp;lt;code&amp;gt;findRange.C&amp;lt;/code&amp;gt; on all the different ROOT files generated earlier.&lt;br /&gt;
    [DTCToolkit/Scripts] $ root &lt;br /&gt;
    ROOT [1] .L findManyRangesDegrader.C&lt;br /&gt;
    // void findManyRanges(Int_t degraderFrom, Int_t degraderIncrement, Int_t degraderTo, Int_t absorberThicknessMmFrom, Int_t absorberThicknessMmIncrement, Int_t absorberThicknessMmTo)&lt;br /&gt;
    ROOT [2] findManyRanges(50, 5, 70, 3, 1, 3)&lt;br /&gt;
&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU.&lt;br /&gt;
The output is stored in &amp;lt;code&amp;gt;DTCToolkit/Output/findManyRangesDegrader.csv&amp;lt;/code&amp;gt;.&lt;br /&gt;
It is a good idea to look through this file, to check that the values are not very jumpy (Gaussian fits gone wrong).&lt;br /&gt;
&lt;br /&gt;
We need the initial energy and range in ascending order. The findManyRangesDegrader.csv files contains more rows such as initial energy straggling and range straggling for other calcualations. This is sadly a bit tricky, but do (assuming a 3 mm absorber geometry):&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit] $ cat OutputFiles/findManyRangesDegrader.csv | awk &#039;{print ($6 &amp;quot; &amp;quot; $3)}&#039; | sort -n &amp;gt; Data/Ranges/3mm_Al.csv&lt;br /&gt;
&lt;br /&gt;
NB: If there are many different absorber geometries in findManyRangesDegrader, either copy the interesting ones or use &amp;lt;code&amp;gt;| grep &amp;quot; X &amp;quot; |&amp;lt;/code&amp;gt; to only keep X mm geometry&lt;br /&gt;
&lt;br /&gt;
When this is performed, the range-energy table for that particular geometry has been created, and is ready to use in the analysis. Note that since the calculation is based on cubic spline interpolations, it cannot extrapolate -- so have a larger span in the full Monte Carlo simulation data than with the chip readout. For more information about that process, see this document: [[:File:Comparison of different calculation methods of proton ranges.pdf]]&lt;br /&gt;
&lt;br /&gt;
=== Range straggling parameterization and &amp;lt;math&amp;gt;R_0 = \alpha E^p&amp;lt;/math&amp;gt; ===&lt;br /&gt;
It is important to know the amount of range straggling in the detector, and the amount of energy straggling after the degrader. In addition, to calculate the parameters &amp;lt;math&amp;gt;\alpha, p&amp;lt;/math&amp;gt; from the somewhat inaccurate Bragg-Kleeman equation &amp;lt;math&amp;gt;R_0 = \alpha E ^ p&amp;lt;/math&amp;gt;, in order to correctly model the &amp;quot;depth-dose curve&amp;quot; &amp;lt;math&amp;gt;dE / dz = p^{-1} \alpha^{-1/p} (R_0 - z)^{1/p-1}&amp;lt;/math&amp;gt;. This is done by fitting the Bragg-Kleeman equation to the range-energy look up tables found by using &amp;lt;code&amp;gt;DTCToolkit/Scripts/findManyRangesDegrader.C&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To find all this, run the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/findAPAndStraggling.C&amp;lt;/code&amp;gt;. This script will loop through all available data lines in the &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/findManyRangesDegrader.csv&amp;lt;/code&amp;gt; file that has the correct absorber thickness, so you need to clean the file first (or just delete it before running &amp;lt;code&amp;gt;findManyRangesDegrader.C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
   [DTCToolkit/Scripts] $ root&lt;br /&gt;
   ROOT [0] .L findAPAndStraggling.C+&lt;br /&gt;
   // void findAPAndStraggling(int absorberthickness)&lt;br /&gt;
   ROOT [1] findAPAndStraggling(3)&lt;br /&gt;
&lt;br /&gt;
The output from this function should be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:findAPAndStraggling.JPG|700px]]&lt;br /&gt;
&lt;br /&gt;
In addition, the following parameters should be extracted:&lt;br /&gt;
&lt;br /&gt;
    Bragg-Kleeman parameters: R = 0.011626 E ^ 1.743151&lt;br /&gt;
    Straggling = 1.8568 + 0.000856 R&lt;br /&gt;
&lt;br /&gt;
=== Configuring the DTC Toolkit to run with correct geometry ===&lt;br /&gt;
The values from &amp;lt;code&amp;gt;findManyRanges.C&amp;lt;/code&amp;gt; should already be in &amp;lt;code&amp;gt;DTCToolkit/Data/Ranges/3mm_Al.csv&amp;lt;/code&amp;gt; (or the corresponding material / thickness). Check that the file is correctly loaded in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;. The values from &amp;lt;code&amp;gt;findAPAndStraggling.C&amp;lt;/code&amp;gt; are put into the same file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/MaterialConstants.C&amp;lt;/code&amp;gt;:&lt;br /&gt;
    81  void createSplines() {&lt;br /&gt;
    ...   &lt;br /&gt;
    107    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    108       in.open(&amp;quot;Data/Ranges/3mm_Al.csv&amp;quot;);&lt;br /&gt;
    109    }&lt;br /&gt;
    ...&lt;br /&gt;
    192    else if (kAbsorbatorThickness = 3) {&lt;br /&gt;
    193       alpha_aluminum = 0.011626;&lt;br /&gt;
    194       p_aluminum = 1.743151;&lt;br /&gt;
    195       straggling_a = 1.8568;&lt;br /&gt;
    196       straggling_b = 0.000856;&lt;br /&gt;
    197    }&lt;br /&gt;
&lt;br /&gt;
Or in the corresponding material (alpha_pmma, alpha_carbon, etc.) and absorbatorthickness lines. &lt;br /&gt;
&lt;br /&gt;
And in the file &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt;, put the \alpha, p parameters.&lt;br /&gt;
&lt;br /&gt;
    144   else if (absorberThickness == 3) {&lt;br /&gt;
    145      a_dtc = 0.011626;&lt;br /&gt;
    146      p_dtc = 1.743151;&lt;br /&gt;
    147    }&lt;br /&gt;
&lt;br /&gt;
Then, look in the file &amp;lt;code&amp;gt;DTCToolkit/GlobalConstants/Constants.h&amp;lt;/code&amp;gt; and check that the correct absorber thickness values etc. are set:&lt;br /&gt;
   ...&lt;br /&gt;
   39 Bool_t useDegrader = true;&lt;br /&gt;
   ...&lt;br /&gt;
   52 const Float_t kAbsorberThickness = 3;&lt;br /&gt;
   ...&lt;br /&gt;
   59 Int_t kEventsPerRun = 100000;&lt;br /&gt;
   ...&lt;br /&gt;
   66 const Int_t kMaterial = kAluminum;&lt;br /&gt;
&lt;br /&gt;
Since we don&#039;t use tracking but only MC truth in the optimization, the number kEventsPerRun (&amp;lt;math&amp;gt;n_p&amp;lt;/math&amp;gt; in the NIMA article) should be higher than the number of primaries per energy.&lt;br /&gt;
&lt;br /&gt;
== Running the DTC Toolkit ==&lt;br /&gt;
As mentioned, the analysis toolchain has the following components:&lt;br /&gt;
&lt;br /&gt;
[[File:analysis_chain.PNG|800px]]&lt;br /&gt;
&lt;br /&gt;
The following section will detail how to perform these separate steps. A quick review of the classes available:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
=== Data readout: MC, MC + truth, experimental ===&lt;br /&gt;
In the class &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt; there are several functions to read data in ROOT format.&lt;br /&gt;
   int   getMCFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, [..]) &amp;lt;- MC to 2D hit histograms&lt;br /&gt;
   void  getMCClusters(int runNumber, Clusters *clustersToFill); &amp;lt;-- MC directly to clusters w/edep and eventID&lt;br /&gt;
   void  getDataFrame(int runNumber, CalorimeterFrame *calorimeterFrameToFill, int energy); &amp;lt;- experimental data to 2D hit histograms&lt;br /&gt;
&lt;br /&gt;
To e.g. obtain the experimental data, use&lt;br /&gt;
   DataInterface *di = new DataInterface();&lt;br /&gt;
   CalorimeterFrame *cf = new CalorimeterFrame();&lt;br /&gt;
   &lt;br /&gt;
   for (int i=0; i&amp;lt;numberOfRuns; i++) { // One run is &amp;quot;readout + track reconstruction&lt;br /&gt;
      di-&amp;gt;getDataFrame(i, cf, energy);&lt;br /&gt;
      // From here the object cf will contain one 2D hit histogram for each of the layers&lt;br /&gt;
      // The number of events to readout in one run: kEventsPerRun (in GlobalConstants/Constants.h)&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Examples of the usage of these functions are located in &amp;lt;code&amp;gt;DTCToolkit/HelperFunctions/getTracks.C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Pixel diffusion modelling (MC only) ===&lt;br /&gt;
To model the pixel diffusion process, i.e. the the diffusion of the electron-hole pair charges generated from the proton track towards nearby pixels, an empirical model has been implemented. It is described in the NIMA article [[http://dx.doi.org/10.1016/j.nima.2017.02.007]], and also in the source code in  &amp;lt;code&amp;gt;DTCToolkit/Classes/Layer/Layer.C::diffuseLayer&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To perform this operation on a filled &amp;lt;code&amp;gt;CalorimeterFrame *cf&amp;lt;/code&amp;gt;, use&lt;br /&gt;
   TRandom3 *gRandom = new TRandom3(0); // use #import &amp;lt;TRandom3.h&amp;gt;&lt;br /&gt;
   cf-&amp;gt;diffuseFrame(gRandom);&lt;br /&gt;
&lt;br /&gt;
=== Inverse diffusion: Energy loss calculation ===&lt;br /&gt;
&lt;br /&gt;
=== Cluster identification ===&lt;br /&gt;
&lt;br /&gt;
=== Proton track reconstruction ===&lt;br /&gt;
&lt;br /&gt;
=== Individual tracks: Energy loss fitting ===&lt;br /&gt;
&lt;br /&gt;
=== (3D reconstruction / MLP estimation) ===&lt;br /&gt;
&lt;br /&gt;
=== Residual range calculation ===&lt;br /&gt;
&lt;br /&gt;
=== How does the DTC Toolkit calculate resolution? ===&lt;br /&gt;
The resolution in this case is defined as the width of the final range histogram for all protons.&lt;br /&gt;
The goal is to match the range straggling which manifests itself in the Gaussian distribution of the range of all protons in the DTC, from the full Monte Carlo simulations:&lt;br /&gt;
&lt;br /&gt;
[[File:findRanges_onlyrange.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
To characterize the resolution, a realistic analysis is performed. Instead of scoring the complete detector volume, including the massive energy absorbers, only the sensor chips placed at intervals (&amp;lt;math&amp;gt;\Delta z = 0.375\ \textrm{mm} + d_{\textrm{absorber}}&amp;lt;/math&amp;gt;) are scored. Tracks are compiled by using the eventID tag from GATE, so that the track reconstruction efficiency is 100%. Each track is then put in a depth / edep graph, and a Bragg curve is fitted on the data:&lt;br /&gt;
&lt;br /&gt;
[[File:BK fit.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
The distribution of all fitted ranges (simple to calculate from fitted energy) should match the distribution above - with a perfect system. All degradations during analysis, sampling error, sparse sampling, mis-fitting etc. will ensure that the peak is broadened.&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis.JPG|300px]]&lt;br /&gt;
&lt;br /&gt;
PS: Please forgive me the fact that the first figure is given in projected range, the second figure is given in initial energy and the third figure is given in projected water equivalent range...... They are converted losslessly since LUTs are used.&lt;br /&gt;
&lt;br /&gt;
=== Finding the resolution ===&lt;br /&gt;
To find this resolution, or degradation in the straggling width, for a single energy, run the DTC toolkit analysis.&lt;br /&gt;
   [DTCToolkit] $ root Load.C&lt;br /&gt;
   // drawBraggPeakGraphFit(Int_t Runs, Int_t dataType = kMC, Bool_t recreate = 0, Float_t energy = 188, Float_t degraderThickness = 0)&lt;br /&gt;
   ROOT [0] drawBraggPeakGraphFit(1, 0, 1, 250, 34)&lt;br /&gt;
This is a serial process, so don&#039;t worry about your CPU when analysing all ROOT files in one go.&lt;br /&gt;
With the result&lt;br /&gt;
&lt;br /&gt;
[[File:distribution_after_analysis2.JPG|600px]]&lt;br /&gt;
&lt;br /&gt;
The following parameters are then stored in &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Absorber thickness || Degrader thickness || Nominal WEPL range || Calculated WEPL range || Nominal WEPL straggling || Calculated WEPL straggling&lt;br /&gt;
|-&lt;br /&gt;
| 3 (mm) || 34 (mm)  || 345 (mm WEPL)  || 345.382 (mm WEPL)  || 2.9 (mm WEPL) || 6.78 (mm WEPL)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To perform the analysis on all different degrader thicknesses, use the script &amp;lt;code&amp;gt;DTCToolkit/makeFitResultPlotsDegrader.sh&amp;lt;/code&amp;gt; (arguments: degrader from, degrader step and degrader to):&lt;br /&gt;
    [DTCToolkit] $ sh makeFitResultsPlotsDegrader.sh 1 1 380&lt;br /&gt;
This may take a few minutes...&lt;br /&gt;
When it&#039;s finished, it&#039;s important to look through the file results_makebraggpeakfit.csv to identify all problem energies, as this is a more complicated analysis than the range finder above.&lt;br /&gt;
If any is identified, run the drawBraggPeakGraphFit at that specific degrader thickness to see where the problems are.&lt;br /&gt;
&lt;br /&gt;
=== Displaying the results ===&lt;br /&gt;
If there are no problems, use the script &amp;lt;code&amp;gt;DTCToolkit/Scripts/makePlots.C&amp;lt;/code&amp;gt; to plot the contents of the file &amp;lt;code&amp;gt;DTCToolkit/OutputFiles/results_makebraggpeakfit.csv&amp;lt;/code&amp;gt;:&lt;br /&gt;
   [DTCToolkit] $ root Scripts/makePlots.C&lt;br /&gt;
The output is a map of the accuracy of the range determination, and a comparison between the range resolution (#sigma of the range determination) and its lower limit, the range straggling.&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_accuracy.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
[[File:makePlots_resolution.JPG|800px]]&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Hands on&amp;quot; to the analysis code ===&lt;br /&gt;
=== A review of the different modules in the code ===&lt;br /&gt;
The Digital Tracking Calorimeter Toolkit is located at Helge&#039;s github (but should be moved to the Gitlab when ready).&lt;br /&gt;
:* https://github.com/HelgeEgil/focal&lt;br /&gt;
To clone the project, run&lt;br /&gt;
    git clone https://github.com/HelgeEgil/focal&lt;br /&gt;
in a new folder to contain the project. The folder structure will be&lt;br /&gt;
    DTCToolkit/                 &amp;lt;- the reconstruction and analysis code&lt;br /&gt;
    DTCToolkit/Analysis         &amp;lt;- User programs for running the code&lt;br /&gt;
    DTCToolkit/Classes          &amp;lt;- All the classes needed for the project&lt;br /&gt;
    DTCToolkit/Data             &amp;lt;- Data files: Range-energy look up tables, Monte Carlo code, LET data from experiments, the beam data from Groningen, ...&lt;br /&gt;
    DTCToolkit/GlobalConstants  &amp;lt;- Constants to adjust how the programs are run. Material parameters, geometry, ...&lt;br /&gt;
    DTCToolkit/HelperFunctions  &amp;lt;- Small programs to help running the code.&lt;br /&gt;
    DTCToolkit/OutputFiles      &amp;lt;- All output files (csv, jpg, ...) should be put here&lt;br /&gt;
    DTCToolkit/RootFiles        &amp;lt;- ROOT specific configuration files.&lt;br /&gt;
    DTCToolkit/Scripts          &amp;lt;- Independent scripts for helping the analysis. E.g. to create Range-energy look up tables from Monte Carlo data&lt;br /&gt;
    gate/                       &amp;lt;- All Gate-related files&lt;br /&gt;
    gate/python                 &amp;lt;- The DTC geometry builder&lt;br /&gt;
    projects/                   &amp;lt;- Other projects related to WP1&lt;br /&gt;
&lt;br /&gt;
The best way to learn how to use the code is to look at the user programs, e.g. Analysis.C::DrawBraggPeakGraphFit which is the function used to create the Bragg Peak model fits and beam range estimation used in the 2017 NIMA article. From here it is possible to follow what the code does.&lt;br /&gt;
It is also a good idea to read through what the different classes are and how they interact:&lt;br /&gt;
* &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;: A (int x,int y,int layer, float edep) object from a pixel hit. edep information only from MC&lt;br /&gt;
* &amp;lt;code&amp;gt;Hits&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of Hit objects&lt;br /&gt;
* &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt;: A (float x, float y, int layer, float clustersize) object from a cluster of &amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt;s The (x,y) position is the mean position of all involved hits.&lt;br /&gt;
* &amp;lt;code&amp;gt;Clusters&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Cluster&amp;lt;/code&amp;gt; objects... But only one per layer, and is connected through a physical proton track. Many helpful member functions to calculate track properties.&lt;br /&gt;
* &amp;lt;code&amp;gt;Tracks&amp;lt;/code&amp;gt;: A &amp;lt;code&amp;gt;TClonesArray&amp;lt;/code&amp;gt; collection of &amp;lt;code&amp;gt;Track&amp;lt;/code&amp;gt; objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;: The contents of a single detector layer. Is stored as a &amp;lt;code&amp;gt;TH2F&amp;lt;/code&amp;gt; histogram, and has a &amp;lt;code&amp;gt;Layer::findHits&amp;lt;/code&amp;gt; function to find hits, as well as the cluster diffusion model &amp;lt;code&amp;gt;Layer::diffuseLayer&amp;lt;/code&amp;gt;. It is controlled from a &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt; object.&lt;br /&gt;
* &amp;lt;code&amp;gt;CalorimeterFrame&amp;lt;/code&amp;gt;: The collection of all &amp;lt;code&amp;gt;Layer&amp;lt;/code&amp;gt;s in the detector.&lt;br /&gt;
* &amp;lt;code&amp;gt;DataInterface&amp;lt;/code&amp;gt;: The class to talk to DTC data, either through semi-&amp;lt;code&amp;gt;Hit&amp;lt;/code&amp;gt; objects as retrieved from Utrecht from the Groningen beam test, or from ROOT files as generated in Gate.&lt;br /&gt;
&lt;br /&gt;
To run the code, do&lt;br /&gt;
    [DTCToolkit] $ root Load.C&lt;br /&gt;
and ROOT will run the script &amp;lt;code&amp;gt;Load.C&amp;lt;/code&amp;gt; which loads all code and starts the interpreter. From here it is possible to directly run scripts as defined in the &amp;lt;code&amp;gt;Analysis.C&amp;lt;/code&amp;gt; file:&lt;br /&gt;
    ROOT [1] drawBraggPeakGraphFit(...)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DISCLAIMER: Some of the materials have been copied from the GATE v7.2 User&#039;s guide: http://wiki.opengatecollaboration.org/index.php/Users_Guide_V7.2&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Meetings&amp;diff=61</id>
		<title>Meetings</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Meetings&amp;diff=61"/>
		<updated>2016-12-22T13:26:34Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Common meetings ==&lt;br /&gt;
Time, place, Vidyo link&lt;br /&gt;
&lt;br /&gt;
for each: date, notes and slides&lt;br /&gt;
&lt;br /&gt;
=== 2016-12-22 ===&lt;br /&gt;
Agenda:&lt;br /&gt;
* Status update from the WPs&lt;br /&gt;
&lt;br /&gt;
* [[Media:Mrichter_wp7-status.pdf | WP7 slides]]&lt;br /&gt;
&lt;br /&gt;
* [[Media:pCT_meeting_22_12_2016_Ilker_Meric.pdf | WP1 slides]]&lt;br /&gt;
&lt;br /&gt;
== Workpackage meetings ==&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=Meetings&amp;diff=60</id>
		<title>Meetings</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=Meetings&amp;diff=60"/>
		<updated>2016-12-22T13:24:41Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: /* 2016-12-22 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Common meetings ==&lt;br /&gt;
Time, place, Vidyo link&lt;br /&gt;
&lt;br /&gt;
for each: date, notes and slides&lt;br /&gt;
&lt;br /&gt;
=== 2016-12-22 ===&lt;br /&gt;
Agenda:&lt;br /&gt;
* Status update from the WPs&lt;br /&gt;
&lt;br /&gt;
* [[Media:Mrichter_wp7-status.pdf | WP7 slides]]&lt;br /&gt;
&lt;br /&gt;
 *[[Media:pct_meeting_22_12_2016_Ilker_Meric.pdf | WP1 slides]]&lt;br /&gt;
&lt;br /&gt;
== Workpackage meetings ==&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=File:PCT_meeting_22_12_2016_Ilker_Meric.pdf&amp;diff=59</id>
		<title>File:PCT meeting 22 12 2016 Ilker Meric.pdf</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=File:PCT_meeting_22_12_2016_Ilker_Meric.pdf&amp;diff=59"/>
		<updated>2016-12-22T13:22:54Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: Ilkerm uploaded a new version of File:PCT meeting 22 12 2016 Ilker Meric.pdf&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;File uploaded with MsUpload&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
	<entry>
		<id>https://pct.wiki.uib.no/index.php?title=File:PCT_meeting_22_12_2016_Ilker_Meric.pdf&amp;diff=58</id>
		<title>File:PCT meeting 22 12 2016 Ilker Meric.pdf</title>
		<link rel="alternate" type="text/html" href="https://pct.wiki.uib.no/index.php?title=File:PCT_meeting_22_12_2016_Ilker_Meric.pdf&amp;diff=58"/>
		<updated>2016-12-22T13:18:01Z</updated>

		<summary type="html">&lt;p&gt;Ilkerm: File uploaded with MsUpload&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;File uploaded with MsUpload&lt;/div&gt;</summary>
		<author><name>Ilkerm</name></author>
	</entry>
</feed>