Loading...
Searching...
No Matches
Example LXe

Introduction

This example demonstrates usage of optical physics.

Geometry and primary particle

The main volume is a box of LXe. PMTs are placed around the outside. There may be a reflective sphere placed inside the box, and a wavelength shifting slab and fibers.

The geometry implementation is different from many of the other examples. See the discussion below.

G4ParticleGun creates the primary particle. The type of particle is selectable by the user.

Physics

The physics list is FTFP_BERT, with G4EmStandard_option4 electromagnetic physics and G4OpticalPhysics.

Physics Macro files

cerenkov.mac disables scintillation, so the optical photons that are produced are Cerenkov photons.

wls.mac implements a scintillating slab and wavelength shifting fibers.

List of built-in histograms

1 "hits per event" 2 "hits per event above threshold" 3 "scintillation photons per event" 4 "Cerenkov photons per event" 5 "absorbed photons per event" 6 "photons absorbed at boundary per event" 7 "energy deposition in scintillator per event"

How to start?

  • execute LXe in 'batch' mode from macro files, e.g. $ ./LXe cerenkov.mac
  • execute LXe in 'interactive' mode with visualization, e.g. $ ./LXe Then type commands, for instance Session: /run/beamOn 1

Macros included

Several macros are include in the distribution:

cerenkov.mac: Shoot a 200 MeV mu+ and only allow it to take one step. The Cerenkov cone and PMTs hit are visible. (Reduce the number of particles for visualization.) LXe.mac: Shoot a 511 keV gamma with the default geometry. photon.mac: Primary beam is an optical photon, with the default geometry. wls.mac: Geometry includes 15 WLS fibers. A 511 keV electron is the primary.

Detailed Explanation of Geometry Implementation

The way the geometry is constructed is an experiment for a new, more object oriented, way to construct geometry. It separates the concept of how a volume is built from where it is placed. Each major volume in the geometry is defined as a class derived from G4PVPlacement. In this example, just the main LXe volume, the WLS scintillator slab, and the WLS fibers were chosen. To place one of these volumes, simply create an instance of it with the appropriate rotation, translation, and mother volumes.

    LXeMainVolume(G4RotationMatrix *pRot,
                  const G4ThreeVector &tlate,
                  G4LogicalVolume *pMotherLogical,
                  G4bool pMany,
                  G4int pCopyNo,
                  LXeDetectorConstruction* c);

Also necessary are the pMany and pCopyNo variables with the same usage as in G4PVPlacement. Additionally, the detector construction must be passed to the main volume as a way to communicate the many parameters to the volume and its sub-volumes. The communication is done from the CopyValues() function which retrieves the information from the detector constructor.

Notably, the name and logical volume parameters are no longer part of the constructor. This is because they are both to be decided by the volume itself. The volume must specify its own name and a temporary logical volume. The constructor will then procede to define its logical volume in the normal way. Once complete, the logical volume can be assigned to the physical volume using the SetLogicalVolume() function.

To handle instances of the same type of volume, a new logical volume should not be defined for each one. Instead, the logical volume is kept as a static member and defined only once.

    if (!housing_log || updated) {
      //...
      //Define logical volume
      //...
    }
    SetLogicalVolume(housing_log);

The updated variable is to signal that the volume needs to be updated and a new logical volume made.

Modifying the geometry at runtime

This example allows the user to modify the geometry definition at runtime. This is accomplished through LXeDetectorMessenger, a derived class of G4UImessenger. The commands it adds change variables stored in LXeDetectorConstructor that are used when constructing the geometry.

    void LXeDetectorConstruction::UpdateGeometry(){
      // clean-up previous geometry
      G4SolidStore::GetInstance()->Clean();
      G4LogicalVolumeStore::GetInstance()->Clean();
      G4PhysicalVolumeStore::GetInstance()->Clean();

      //define new one
      G4RunManager::GetRunManager()->DefineWorldVolume(ConstructDetector());
      G4RunManager::GetRunManager()->GeometryHasBeenModified();
    }

PMT sensitive detector

The PMT sensitive detector cannot be triggered like a normal sensitive detector because the sensitive volume does not allow photons to pass through it. Rather, it detects them in the OpBoundary process based on an efficiency set on the skin of the volume.

    G4OpticalSurface* photocath_opsurf=
       new G4OpticalSurface("photocath_opsurf",glisur,polished,
                             dielectric_metal);
    G4double photocath_EFF[num]={1.,1.};
    G4double photocath_REFL[num]={0.,0.};
    G4MaterialPropertiesTable* photocath_mt = new G4MaterialPropertiesTable();
    photocath_mt->AddProperty("EFFICIENCY",Ephoton,photocath_EFF,num);
    photocath_mt->AddProperty("REFLECTIVITY",Ephoton,photocath_REFL,num);
    photocath_opsurf->SetMaterialPropertiesTable(photocath_mt);
    new G4LogicalSkinSurface("photocath_surf",photocath_log,photocath_opsurf);

A normal sensitive detector would have its ProcessHits function called for each step by a particle inside the volume. So, to record these hits with a sensitive detector we watched the status of the OpBoundary process from the stepping manager whenever a photon hit the sensitive volume of the pmt. If the status was 'Detection', we retrieve the sensitive detector from G4SDManager and call its ProcessHits function.

    boundaryStatus=boundary->GetStatus();
    //Check to see if the particle was actually at a boundary
    //Otherwise the boundary status may not be valid
    //Prior to Geant4.6.0-p1 this would not have been enough to check
    if(thePostPoint->GetStepStatus()==fGeomBoundary){
      switch(boundaryStatus){
      //...    
        case Detection: //Note, this assumes that the volume causing detection
                        //is the photocathode because it is the only one with
                  //non-zero efficiency
    {
      //Trigger sensitive detector manually since photon is
      //absorbed but status was Detection
      G4SDManager* SDman = G4SDManager::GetSDMpointer();
      G4String sdName="/LXeDet/pmtSD";
      LXePMTSD* pmtSD = (LXePMTSD*)SDman
        ->FindSensitiveDetector(sdName);
      if(pmtSD)
        pmtSD->ProcessHits_constStep(theStep,NULL);
      break;
    }
        //...
      }

Selectively drawing trajectories or highlighting volumes

In a simulation such as this one, where an average of 6000 trajectories are generated in a small space, there is little use in drawing all of them. There are two ways to select which ones to draw. The first of which is to decide while looping through the trajectory container which ones to draw and only call DrawTrajectory on the important ones. However, trajectories only contain a small portion of the information from the track it represents. This may not be enough to decide if a trajectory is worth drawing.

The alternative is to define your own trajectory class to store additional information to help decide if it should be drawn. To use your custom trajectory you must create it in the PreUserTrackingAction:

fpTrackingManager->SetTrajectory(new LXeTrajectory(aTrack));

Then at any point you can get access to the trajectory you can update the extra information within it. When it comes to drawing, you can then use this to decide if you want to call DrawTrajectory. Or you can call DrawTrajectory for all trajectories and have the logic decide how and if a trajectory should be drawn inside the DrawTrajectory function itself.

Selectively highlighting volumes is useful to show which volumes were hit. To do this, you simply need a pointer to the physical volume. With that, you can modify its vis attributes and instruct the vis manager to redraw the volume with the new vis attributes.

    G4VisAttributes attribs(G4Colour(1.,0.,0.));
    attribs.SetForceSolid(true);
    G4RotationMatrix rot;
    if(physVol->GetRotation())//If a rotation is defined use it
      rot=*(physVol->GetRotation());
    G4Transform3D trans(rot,physVol->GetTranslation());//Create transform
    pVVisManager->Draw(*physVol,attribs,trans);//Draw it

In this case, it is done in Draw function of a PMT hit but it can be placed anywhere. The logic to decide if it should be drawn or not may be similar to the logic used in choosing which trajectories to draw.

See /LXe/detector/volumes/sphere in "UI commands" below for info on what trajectories are drawn in this simulation.

Saving random engine seeds

At times it may be necessary to review a particular event of interest. To do this without redoing an entire run, which may take a long time, you must store the random engine seed from the beginning of the event. The run manager has some functions that help in this task.

G4RunManager::SetRandomNumberStore(G4bool)

When set to true, this causes the run manager to write the seed for the beginning of the current run to CurrentRun.rndm and the current event to CurrentEvent.rndm. However, at the beginning of each event this file will be overwritten with the new event. To keep a copy for a particular event there is a function to copy this file to "run###evt###.rndm".

G4RunManager::rndmSaveThisEvent()

This can be done for every event so you can review any event you like but this may be awkward for runs with very large numbers of events. Instead, implement some form of logic in EndOfEventAction to decide if the event is worth saving. If it is, then call rndmSaveThisEvent(). By default, these files are stored in the current working directory. There is a function to change this as well. Typically you would call that at the same time SetRandomNumberStore. The directory to save in must exist first. GEANT4 will not create it for you.

G4RunManager::SetRandomNumberStoreDir(G4String)

UI commands

Directories:

/LXe/ - All custom commands belong below this directory
/LXe/detector/ - Geometry related commands
/LXe/detector/volumes/ - Commands to enable/disable volumes in the geometry

Commands:

/LXe/saveThreshold <int, default = 4500>

-Specifies a threshold for saving the random seed for an event. If the number of photons generated in an event is below this number then the random seed is saved to "./random/run###evt###.rndm". See "Saving random engine seeds".

/LXe/eventVerbose <int, default = 1>

-Enables end of event verbose data to be printed. This includes information counted and calculated by the user action classes.

/LXe/pmtThreshold <int, default = 1>

-Sets the PMT threshold in # of photons being detected by the PMT. PMTs below with fewer hits than the threshold will not count as being hit and will also not be highlighted at the end of the event.

/LXe/oneStepPrimaries <bool>

-This causes primary particles to be killed after going only one step inside the scintillator volume. This is useful to view the photons generated during the initial conversion of the primary particle.

/LXe/forceDrawPhotons <bool>

-Forces all optical photon trajectories to be drawn at the end of the event regardless of the scheme mentioned in /LXe/detector/volumes/sphere below.

/LXe/forceDrawNoPhotons <bool>

-Forces all optical photon trajectories to NOT be drawn at the end of the event regardless of the scheme mentioned in /LXe/detector/volumes/sphere below. -If /LXe/forceDrawPhotons is set to true, this has no effect.

/LXe/detector/dimensions <double x y z> <unit, default = cm>

-Sets the dimensions of the main scintillator volume.

/LXe/detector/housingThickness <double>

-Sets the thickness of the housing surrounding the main detector volume.

/LXe/detector/pmtRadius <double> <unit, default = cm>

-Sets the radius of the PMTs

/LXe/detector/nx
/LXe/detector/ny
/LXe/detector/nz

-Sets the number of PMTs placed in a row along each axis.

/LXe/detector/reflectivity <double>

-Sets the reflectivity of the inside of the aluminum housing. The geometry uses a default value of 1.00 for a fully reflective surface.

/LXe/detector/nfibers <int>

-Sets the number of WLS fibers placed in the WLS scintillator slab. The geometry uses a default value of 15 fibers.

/LXe/detector/scintYieldFactor <double>

-Sets the yield factor for the scintillation process. This is cumulative with the yield factor set on individual materials. Set to 0 to produce no scintillation photons.

/LXe/detector/defaults

-Resets all detector values customizable with commands above to their defaults.

/LXe/detector/volumes/sphere <bool>

-Enables/disables the sphere placed inside the main scintillator volume. When the sphere is enabled, only photons that hit the sphere and hit a PMT are drawn. If it is disabled, then all photons that hit PMTs are drawn.

/LXe/detector/volumes/wls <bool>

-Enables/disables the WLS scintillator slab containing WLS fibers. By default this is not part of the geometry. Enabling it will place it behind the LXe scintillator volume.

/LXe/detector/volumes/lxe <bool>

-Enables/disables the main LXe scintillator volume. By default this is part of the geometry.


Applications | User Support | Publications | Collaboration