From 760b181687ef0813f54aaac03c0efe8f9cfe58a8 Mon Sep 17 00:00:00 2001
From: Xythere <xytherex@gmail.com>
Date: Fri, 13 Dec 2024 15:48:26 +0100
Subject: [PATCH] Adding LEPS planar Germanium detector

---
 NPSimulation/Detectors/LEPS/CMakeLists.txt |   2 +
 NPSimulation/Detectors/LEPS/LEPS.cc        | 297 +++++++++++++++++++++
 NPSimulation/Detectors/LEPS/LEPS.hh        | 110 ++++++++
 3 files changed, 409 insertions(+)
 create mode 100644 NPSimulation/Detectors/LEPS/CMakeLists.txt
 create mode 100644 NPSimulation/Detectors/LEPS/LEPS.cc
 create mode 100644 NPSimulation/Detectors/LEPS/LEPS.hh

diff --git a/NPSimulation/Detectors/LEPS/CMakeLists.txt b/NPSimulation/Detectors/LEPS/CMakeLists.txt
new file mode 100644
index 000000000..b9415317c
--- /dev/null
+++ b/NPSimulation/Detectors/LEPS/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(NPSLEPS SHARED  LEPS.cc)
+target_link_libraries(NPSLEPS NPSCore ${ROOT_LIBRARIES} ${Geant4_LIBRARIES} ${NPLib_LIBRARIES} -lNPLEPS)
diff --git a/NPSimulation/Detectors/LEPS/LEPS.cc b/NPSimulation/Detectors/LEPS/LEPS.cc
new file mode 100644
index 000000000..978d235d1
--- /dev/null
+++ b/NPSimulation/Detectors/LEPS/LEPS.cc
@@ -0,0 +1,297 @@
+/*****************************************************************************
+ * Copyright (C) 2009-2024   this file is part of the NPTool Project       *
+ *                                                                           *
+ * For the licensing terms see $NPTOOL/Licence/NPTool_Licence                *
+ * For the list of contributors see $NPTOOL/Licence/Contributors             *
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Original Author: Leo Plagnol  contact address: plagnol@ijclab.in2p3.fr                        *
+ *                                                                           *
+ * Creation Date  : March 2024                                           *
+ * Last update    :                                                          *
+ *---------------------------------------------------------------------------*
+ * Decription:                                                               *
+ *  This class describe  LEPS simulation                             *
+ *                                                                           *
+ *---------------------------------------------------------------------------*
+ * Comment:                                                                  *
+ *                                                                           *
+ *****************************************************************************/
+
+// C++ headers
+#include <sstream>
+#include <cmath>
+#include <limits>
+//G4 Geometry object
+#include "G4Tubs.hh"
+#include "G4Box.hh"
+#include "G4Polycone.hh"
+
+//G4 sensitive
+#include "G4SDManager.hh"
+#include "G4MultiFunctionalDetector.hh"
+
+//G4 various object
+#include "G4Material.hh"
+#include "G4Transform3D.hh"
+#include "G4PVPlacement.hh"
+#include "G4VisAttributes.hh"
+#include "G4Colour.hh"
+
+// NPTool header
+#include "LEPS.hh"
+#include "CalorimeterScorers.hh"
+#include "InteractionScorers.hh"
+#include "RootOutput.h"
+#include "MaterialManager.hh"
+#include "NPSDetectorFactory.hh"
+#include "NPOptionManager.h"
+#include "NPSHitsMap.hh"
+// CLHEP header
+#include "CLHEP/Random/RandGauss.h"
+
+using namespace std;
+using namespace CLHEP;
+
+
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+namespace LEPS_NS{
+  // Energy and time Resolution
+  const double EnergyThreshold = 0.01*MeV;
+  const double ResoTime = 0*ns ;
+  // const double ResoEnergy = 0.34*keV ; // 0.8 keV FWHM, quite optimist
+  const double ResoEnergy = 1e-9*keV ; 
+  const double Radius = 50*mm ; 
+  const double Width = 100*mm ;
+  const double Thickness = 300*mm ;
+  const string Material_Shell = "Al";
+  const double radii_internal[16] = {50/2*mm-1*mm, 50/2*mm-1*mm, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  const double radii_external[16] = {50/2*mm, 50/2.*mm, 52/2.*mm, 52/2.*mm, 33.7/2.*mm, 33.7/2.*mm, 95/2.*mm, 95/2.*mm, 33.7/2.*mm, 33.7/2.*mm, 95/2.*mm, 95/2.*mm, 33/2.*mm, 33/2.*mm, 222/2.*mm, 222/2.*mm};
+  const double length_external[16] = {0, 85*mm, 85*mm, 157*mm, 157*mm, 207*mm, 207*mm, 208*mm, 208*mm, 298*mm, 298*mm, 393*mm, 393*mm, 453*mm, 453*mm, 720*mm};
+}
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+// LEPS Specific Method
+LEPS::LEPS(){
+  m_Event = new TLEPSData() ;
+  m_LEPSScorer = 0;
+}
+
+LEPS::~LEPS(){
+}
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+void LEPS::AddDetector(G4ThreeVector POS, string  Shape){
+  // Convert the POS value to R theta Phi as Spherical coordinate is easier in G4 
+  m_R.push_back(POS.mag());
+  m_Theta.push_back(POS.theta());
+  m_Phi.push_back(POS.phi());
+  m_Shape.push_back(Shape);
+}
+
+
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+void LEPS::AddDetector(double  R, double  Theta, double  Phi, string  Shape){
+  m_R.push_back(R);
+  m_Theta.push_back(Theta);
+  m_Phi.push_back(Phi);
+  m_Shape.push_back(Shape);
+}
+
+
+G4LogicalVolume* LEPS::BuildDetector(G4int DetNumber, G4ThreeVector Det_pos, G4RotationMatrix* Det_rot, G4LogicalVolume* world){
+  // Materials
+  G4Material* DetectorMaterial = MaterialManager::getInstance()->GetMaterialFromLibrary(LEPS_NS::Material_Shell);
+  G4Material* m_MaterialVacuum = MaterialManager::getInstance()->GetMaterialFromLibrary("Vacuum");
+  G4Material* m_MaterialCarbon = MaterialManager::getInstance()->GetMaterialFromLibrary("C");
+  G4Material* m_MaterialGermanium = MaterialManager::getInstance()->GetMaterialFromLibrary("Germanium");
+
+  G4VisAttributes* light_GreyAtt = new G4VisAttributes(G4Colour(0.5, 0.5, 0.5, 0.7));
+  G4VisAttributes* RedAtt = new G4VisAttributes(G4Colour(1.0, 0.0, 0.0, 0.6));
+  G4VisAttributes* GreenAtt = new G4VisAttributes(G4Colour(0.0, 1.0, 0.0, 0.6));
+
+  // Global volume
+  // Origin axis at the front of detector
+  G4Tubs* solidLEPS = new G4Tubs("solidLEPS", 0, 25, 720*0.5*mm, 0, 360*deg);
+  G4LogicalVolume* logicLEPS = new G4LogicalVolume(solidLEPS, m_MaterialVacuum, "logicLEPS", 0, 0);
+  new G4PVPlacement(G4Transform3D(*Det_rot, Det_pos), logicLEPS, "LEPS", world, false, DetNumber);
+  logicLEPS->SetVisAttributes(G4VisAttributes::GetInvisible());
+
+  // Enveloppe
+  G4Polycone* LEPS_Cyl = new G4Polycone("LEPS_Cyl", 0, 360*deg, 16, LEPS_NS::length_external, LEPS_NS::radii_internal, LEPS_NS::radii_external);
+  G4LogicalVolume* vol_LEPS = new G4LogicalVolume(LEPS_Cyl, DetectorMaterial, "logic_LEPS_Cyl", 0, 0, 0);
+  G4ThreeVector LEPS_cyl_Pos = G4ThreeVector(0, 0, 0);
+  new G4PVPlacement(0, LEPS_cyl_Pos, vol_LEPS, "LEPS_cyl", logicLEPS, false, DetNumber);
+  vol_LEPS->SetVisAttributes(light_GreyAtt);
+
+  // Carbon window
+  G4Tubs* LEPS_CWindow = new G4Tubs("LEPS_CWindow", 0, 24, 0.6*0.5*mm, 0, 360*deg);
+  G4LogicalVolume* vol_CWindow = new G4LogicalVolume(LEPS_CWindow, m_MaterialCarbon, "logic_LEPS_Window", 0, 0, 0);
+  G4ThreeVector CWindow_Pos = G4ThreeVector(0, 0, 0);
+  // G4ThreeVector CWindow_Pos = G4ThreeVector(0, 0, 720*0.5*mm);
+  new G4PVPlacement(0, CWindow_Pos, vol_CWindow, "LEPS_CWindow", logicLEPS, false, DetNumber);
+  vol_CWindow->SetVisAttributes(GreenAtt);
+  
+  // Germanium crystal
+  G4Tubs* LEPS_crys = new G4Tubs("LEPS_crys",0 , 13*mm, 10.2*0.5*mm, 0, 360*deg);
+  G4LogicalVolume* vol_crys = new G4LogicalVolume(LEPS_crys, m_MaterialGermanium, "logic_LEPS_crys", 0, 0, 0);
+  G4ThreeVector crys_Pos = G4ThreeVector(0, 0, 0.6*1.5*mm+11*0.5*mm);
+  new G4PVPlacement(0, crys_Pos, vol_crys, "LEPS_crys", logicLEPS, false, DetNumber);
+  vol_crys->SetVisAttributes(RedAtt);
+
+  vol_crys->SetSensitiveDetector(m_LEPSScorer);
+  
+  return vol_LEPS;
+}
+
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+// Virtual Method of NPS::VDetector class
+
+// Read stream at Configfile to pick-up parameters of detector (Position,...)
+// Called in DetecorConstruction::ReadDetextorConfiguration Method
+void LEPS::ReadConfiguration(NPL::InputParser parser){
+  vector<NPL::InputBlock*> blocks = parser.GetAllBlocksWithToken("LEPS");
+  if(NPOptionManager::getInstance()->GetVerboseLevel())
+    cout << "//// " << blocks.size() << " detectors found " << endl; 
+
+  vector<string> cart = {"POS","Shape"};
+  vector<string> sphe = {"R","Theta","Phi","Shape"};
+
+  for(unsigned int i = 0 ; i < blocks.size() ; i++){
+    if(blocks[i]->HasTokenList(cart)){
+      if(NPOptionManager::getInstance()->GetVerboseLevel())
+        cout << endl << "////  LEPS " << i+1 <<  endl;
+    
+      G4ThreeVector Pos = NPS::ConvertVector(blocks[i]->GetTVector3("POS","mm"));
+      string Shape = blocks[i]->GetString("Shape");
+      AddDetector(Pos,Shape);
+    }
+    else if(blocks[i]->HasTokenList(sphe)){
+      if(NPOptionManager::getInstance()->GetVerboseLevel())
+        cout << endl << "////  LEPS " << i+1 <<  endl;
+      double R = blocks[i]->GetDouble("R","mm");
+      double Theta = blocks[i]->GetDouble("Theta","deg");
+      double Phi = blocks[i]->GetDouble("Phi","deg");
+      string Shape = blocks[i]->GetString("Shape");
+      AddDetector(R,Theta,Phi,Shape);
+    }
+    else{
+      cout << "ERROR: check your input file formatting " << endl;
+      exit(1);
+    }
+  }
+}
+
+
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+
+// Construct detector and inialise sensitive part.
+// Called After DetecorConstruction::AddDetector Method
+void LEPS::ConstructDetector(G4LogicalVolume* world){
+  for (unsigned short i = 0 ; i < m_R.size() ; i++) {
+
+    G4double wX = m_R[i] * sin(m_Theta[i] ) * cos(m_Phi[i] ) ;
+    G4double wY = m_R[i] * sin(m_Theta[i] ) * sin(m_Phi[i] ) ;
+    G4double wZ = m_R[i] * cos(m_Theta[i] ) ;
+    G4ThreeVector Det_pos = G4ThreeVector(wX, wY, wZ) ;
+    // So the face of the detector is at R instead of the middle
+    // Det_pos+=Det_pos.unit()*LEPS_NS::Thickness*0.5;
+    // Building Detector reference frame
+    G4double ii = cos(m_Theta[i]) * cos(m_Phi[i]);
+    G4double jj = cos(m_Theta[i]) * sin(m_Phi[i]);
+    G4double kk = -sin(m_Theta[i]);
+    G4ThreeVector Y(ii,jj,kk);
+    G4ThreeVector w = Det_pos.unit();
+    G4ThreeVector u = w.cross(Y);
+    G4ThreeVector v = w.cross(u);
+    v = v.unit();
+    u = u.unit();
+
+    G4RotationMatrix* Rot = new G4RotationMatrix(u,v,w);
+
+    BuildDetector(i+1, Det_pos, Rot, world);
+  }
+}
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+// Add Detector branch to the EventTree.
+// Called After DetecorConstruction::AddDetector Method
+void LEPS::InitializeRootOutput(){
+  RootOutput *pAnalysis = RootOutput::getInstance();
+  TTree *pTree = pAnalysis->GetTree();
+  if(!pTree->FindBranch("LEPS")){
+    pTree->Branch("LEPS", "TLEPSData", &m_Event) ;
+  }
+  pTree->SetBranchAddress("LEPS", &m_Event) ;
+}
+
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+// Read sensitive part and fill the Root tree.
+// Called at in the EventAction::EndOfEventAvtion
+void LEPS::ReadSensitive(const G4Event* ){
+  m_Event->Clear();
+
+  ///////////
+  // Calorimeter scorer
+  CalorimeterScorers::PS_Calorimeter* Scorer= (CalorimeterScorers::PS_Calorimeter*) m_LEPSScorer->GetPrimitive(0);
+
+  unsigned int size = Scorer->GetMult(); 
+  for(unsigned int i = 0 ; i < size ; i++){
+    vector<unsigned int> level = Scorer->GetLevel(i); 
+    double Energy = RandGauss::shoot(Scorer->GetEnergy(i),LEPS_NS::ResoEnergy);
+    if(Energy>LEPS_NS::EnergyThreshold){
+      double Time = RandGauss::shoot(Scorer->GetTime(i),LEPS_NS::ResoTime);
+      int DetectorNbr = level[0];
+      m_Event->SetEnergy(DetectorNbr,Energy);
+      m_Event->SetTime(DetectorNbr,Time); 
+    }
+  }
+}
+
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+////////////////////////////////////////////////////////////////   
+void LEPS::InitializeScorers() { 
+  // This check is necessary in case the geometry is reloaded
+  bool already_exist = false; 
+  m_LEPSScorer = CheckScorer("LEPSScorer",already_exist) ;
+
+  if(already_exist) 
+    return ;
+
+  // Otherwise the scorer is initialised
+  vector<int> level; level.push_back(0);
+  G4VPrimitiveScorer* Calorimeter= new CalorimeterScorers::PS_Calorimeter("Calorimeter",level, 0) ;
+  G4VPrimitiveScorer* Interaction= new InteractionScorers::PS_Interactions("Interaction",ms_InterCoord, 0) ;
+  //and register it to the multifunctionnal detector
+  m_LEPSScorer->RegisterPrimitive(Calorimeter);
+  m_LEPSScorer->RegisterPrimitive(Interaction);
+  G4SDManager::GetSDMpointer()->AddNewDetector(m_LEPSScorer) ;
+}
+
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+////////////////////////////////////////////////////////////////////////////////
+//            Construct Method to be pass to the DetectorFactory              //
+////////////////////////////////////////////////////////////////////////////////
+NPS::VDetector* LEPS::Construct(){
+  return  (NPS::VDetector*) new LEPS();
+}
+
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+////////////////////////////////////////////////////////////////////////////////
+//            Registering the construct method to the factory                 //
+////////////////////////////////////////////////////////////////////////////////
+extern"C" {
+  class proxy_nps_LEPS{
+    public:
+      proxy_nps_LEPS(){
+        NPS::DetectorFactory::getInstance()->AddToken("LEPS","LEPS");
+        NPS::DetectorFactory::getInstance()->AddDetector("LEPS",LEPS::Construct);
+      }
+  };
+
+  proxy_nps_LEPS p_nps_LEPS;
+}
diff --git a/NPSimulation/Detectors/LEPS/LEPS.hh b/NPSimulation/Detectors/LEPS/LEPS.hh
new file mode 100644
index 000000000..cc4cca08d
--- /dev/null
+++ b/NPSimulation/Detectors/LEPS/LEPS.hh
@@ -0,0 +1,110 @@
+#ifndef LEPS_h
+#define LEPS_h 1
+/*****************************************************************************
+ * Copyright (C) 2009-2024   this file is part of the NPTool Project       *
+ *                                                                           *
+ * For the licensing terms see $NPTOOL/Licence/NPTool_Licence                *
+ * For the list of contributors see $NPTOOL/Licence/Contributors             *
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Original Author: Leo Plagnol  contact address: plagnol@ijclab.in2p3.fr                        *
+ *                                                                           *
+ * Creation Date  : March 2024                                           *
+ * Last update    :                                                          *
+ *---------------------------------------------------------------------------*
+ * Decription:                                                               *
+ *  This class describe  LEPS simulation                             *
+ *                                                                           *
+ *---------------------------------------------------------------------------*
+ * Comment:                                                                  *
+ *                                                                           *
+ *****************************************************************************/
+
+// C++ header
+#include <string>
+#include <vector>
+using namespace std;
+
+// G4 headers
+#include "G4ThreeVector.hh"
+#include "G4RotationMatrix.hh"
+#include "G4LogicalVolume.hh"
+#include "G4MultiFunctionalDetector.hh"
+
+// NPTool header
+#include "NPSVDetector.hh"
+#include "TLEPSData.h"
+#include "NPInputParser.h"
+
+class LEPS : public NPS::VDetector{
+  ////////////////////////////////////////////////////
+  /////// Default Constructor and Destructor /////////
+  ////////////////////////////////////////////////////
+  public:
+    LEPS() ;
+    virtual ~LEPS() ;
+
+    ////////////////////////////////////////////////////
+    /////// Specific Function of this Class ///////////
+    ////////////////////////////////////////////////////
+  public:
+    // Cartesian
+    void AddDetector(G4ThreeVector POS, string Shape);
+    // Spherical
+    void AddDetector(double R,double Theta,double Phi,string Shape);  
+
+
+    G4LogicalVolume* BuildDetector(G4int, G4ThreeVector, G4RotationMatrix*, G4LogicalVolume*);
+  
+  private:
+    
+    ////////////////////////////////////////////////////
+    //////  Inherite from NPS::VDetector class /////////
+    ////////////////////////////////////////////////////
+  public:
+    // Read stream at Configfile to pick-up parameters of detector (Position,...)
+    // Called in DetecorConstruction::ReadDetextorConfiguration Method
+    void ReadConfiguration(NPL::InputParser) ;
+
+    // Construct detector and inialise sensitive part.
+    // Called After DetecorConstruction::AddDetector Method
+    void ConstructDetector(G4LogicalVolume* world) ;
+
+    // Add Detector branch to the EventTree.
+    // Called After DetecorConstruction::AddDetector Method
+    void InitializeRootOutput() ;
+
+    // Read sensitive part and fill the Root tree.
+    // Called at in the EventAction::EndOfEventAvtion
+    void ReadSensitive(const G4Event* event) ;
+
+  public:   // Scorer
+    //   Initialize all Scorer used by the MUST2Array
+    void InitializeScorers() ;
+
+    //   Associated Scorer
+    G4MultiFunctionalDetector* m_LEPSScorer ;
+    ////////////////////////////////////////////////////
+    ///////////Event class to store Data////////////////
+    ////////////////////////////////////////////////////
+  private:
+    TLEPSData* m_Event ;
+
+    ////////////////////////////////////////////////////
+    ///////////////Private intern Data//////////////////
+    ////////////////////////////////////////////////////
+  private: // Geometry
+    // Detector Coordinate 
+    vector<double>  m_R; 
+    vector<double>  m_Theta;
+    vector<double>  m_Phi; 
+    
+    //   Shape type
+    vector<string> m_Shape ;
+   
+  // Needed for dynamic loading of the library
+  public:
+    static NPS::VDetector* Construct();
+};
+#endif
-- 
GitLab