diff --git a/CMakeLists.txt b/CMakeLists.txt index ae953a5..d486aba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ hk_add_tool(HKG4TrackingAction) hk_add_tool(HKG4StackingAction) hk_add_tool(HKG4PhysicsList) hk_add_tool(HKG4SteppingAction) -hk_add_tool(HKG4PrimaryGeneratorAction) +hk_add_tool(GhostG4PrimaryGeneratorAction) hk_add_tool(HKG4EventAction) hk_add_tool(HKG4RunAction) hk_add_tool(HKGFileWriterBase) diff --git a/GhostG4PrimaryGeneratorAction/GhostG4PrimaryGeneratorAction.cpp b/GhostG4PrimaryGeneratorAction/GhostG4PrimaryGeneratorAction.cpp new file mode 100644 index 0000000..fa6662f --- /dev/null +++ b/GhostG4PrimaryGeneratorAction/GhostG4PrimaryGeneratorAction.cpp @@ -0,0 +1,38 @@ +#include "GhostG4PrimaryGeneratorAction.h" +#include "PGAKinFile.h" + +#include "WCSimPrimaryGeneratorAction.hh" + +Ghost::G4::GhostG4PrimaryGeneratorAction::GhostG4PrimaryGeneratorAction() : Tool() {} + +bool Ghost::G4::GhostG4PrimaryGeneratorAction::Initialise(std::string configfile, DataModel& data) { + + if(configfile != "") + m_variables.Initialise(configfile); + // m_variables.Print(); + + m_data = &data; + m_log = m_data->Log; + + if(!m_variables.Get("verbose", m_verbose)) + m_verbose = 1; + + if(0) + m_data->m_p_run_manager->SetUserAction( + new WCSimPrimaryGeneratorAction(static_cast( + m_data->m_p_run_manager->GetUserDetectorConstruction()))); + else { + m_data->m_p_run_manager->SetUserAction(new Ghost::G4::PGAKinFile()); + } + return true; +} + +bool Ghost::G4::GhostG4PrimaryGeneratorAction::Execute() { + + return true; +} + +bool Ghost::G4::GhostG4PrimaryGeneratorAction::Finalise() { + + return true; +} diff --git a/GhostG4PrimaryGeneratorAction/GhostG4PrimaryGeneratorAction.h b/GhostG4PrimaryGeneratorAction/GhostG4PrimaryGeneratorAction.h new file mode 100644 index 0000000..32f8356 --- /dev/null +++ b/GhostG4PrimaryGeneratorAction/GhostG4PrimaryGeneratorAction.h @@ -0,0 +1,38 @@ +#ifndef GhostG4PrimaryGeneratorAction_H +#define GhostG4PrimaryGeneratorAction_H + +#include +#include + +#include +#include "Tool.h" + +/** + * \class GhostG4PrimaryGeneratorAction + * + * This is a blank template for a Tool used by the script to generate a new custom tool. Please fill out the + * description and author information. + * + * $Author: B.Richards $ + * $Date: 2019/05/28 10:44:00 $ + */ + +namespace Ghost::G4 { + class GhostG4PrimaryGeneratorAction : public Tool { + + public: + + GhostG4PrimaryGeneratorAction(); ///< Simple constructor + bool Initialise( + std::string configfile, + DataModel& data); ///< Initialise Function for setting up Tool resources. @param + ///< configfile The path and name of the dynamic configuration file + ///< to read in. @param data A reference to the transient data + ///< class used to pass information between Tools. + bool Execute(); ///< Execute function used to perform Tool purpose. + bool Finalise(); ///< Finalise funciton used to clean up resources. + + private: + }; +} // namespace Ghost::G4 +#endif diff --git a/GhostG4PrimaryGeneratorAction/InitialParticleInfo.h b/GhostG4PrimaryGeneratorAction/InitialParticleInfo.h new file mode 100644 index 0000000..34ce81f --- /dev/null +++ b/GhostG4PrimaryGeneratorAction/InitialParticleInfo.h @@ -0,0 +1,58 @@ +#ifndef InitialParticleInfo_h +#define InitialParticleInfo_h + +#include "G4ThreeVector.hh" +#include "G4ParticleDefinition.hh" + +namespace Ghost::G4 { + struct InitialParticleInfo { + unsigned int m_vertex_num; + double m_time; + double m_kinetic_energy; + G4ThreeVector m_direction; + G4ThreeVector m_position; + G4ParticleDefinition * m_p_particle_definition; + int m_particle_pdg; + int m_particle_charge; + + //! Use this constructor if you don't require telling Geant4 about your particle + InitialParticleInfo(unsigned int vertex_num, + double time, + double kinetic_energy, + G4ThreeVector direction, + G4ThreeVector position, + int pdg) + : m_vertex_num(vertex_num), + m_time(time), + m_kinetic_energy(kinetic_energy), + m_direction(direction), + m_position(position), + m_p_particle_definition(nullptr), + m_particle_pdg(pdg), + m_particle_charge(INT_MAX) + { + } + + //! Use this constructor if you need to tell Geant4 about your particle + InitialParticleInfo(unsigned int vertex_num, + double time, + double kinetic_energy, + G4ThreeVector direction, + G4ThreeVector position, + G4ParticleDefinition * particle_pdg) + : m_vertex_num(vertex_num), + m_time(time), + m_kinetic_energy(kinetic_energy), + m_direction(direction), + m_position(position), + m_p_particle_definition(particle_pdg), + m_particle_charge(INT_MAX) + { + m_particle_pdg = m_p_particle_definition->GetPDGEncoding(); + } + + ~InitialParticleInfo() {} + }; +}// namespace Ghost::G4 + +#endif diff --git a/GhostG4PrimaryGeneratorAction/PGAKinFile.cpp b/GhostG4PrimaryGeneratorAction/PGAKinFile.cpp new file mode 100644 index 0000000..82cf7e5 --- /dev/null +++ b/GhostG4PrimaryGeneratorAction/PGAKinFile.cpp @@ -0,0 +1,190 @@ +#include "PGAKinFile.h" +#include "WCSimDetectorConstruction.hh" +#include "WCSimPrimaryGeneratorMessenger.hh" +#include "G4RunManager.hh" +#include "G4Event.hh" +#include "G4ParticleGun.hh" +#include "G4ParticleTable.hh" +#include "G4IonTable.hh" +#include "G4ParticleDefinition.hh" +#include "G4IonTable.hh" +#include "G4ThreeVector.hh" +#include "G4Vector3D.hh" +#include "G4EventManager.hh" +#include "globals.hh" +#include +#include +#include "Randomize.hh" +#include +#include +#include +#include +#include +#include + +#include "Utilities.h" + +#include "G4PhysicalConstants.hh" +#include "G4SystemOfUnits.hh" + +Ghost::G4::PGAKinFile::PGAKinFile() + : m_input_filename("test.kin") +{ + m_input_file = Ghost::Utils::OpenFileStream(m_input_filename); + + m_generator_name = "muline"; +} + +Ghost::G4::PGAKinFile::~PGAKinFile() +{ + m_input_file.close(); +} + +void Ghost::G4::PGAKinFile::FillParticleVectors() +{ + // We will need a particle table + G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable(); + G4IonTable* ionTable = G4IonTable::GetIonTable(); + + // The original documentation describing the nuance text format can be found here: + // http://neutrino.phy.duke.edu/nuance-format/ + // + // Information specific to WCSim can be found in the file Nuance_MC_Format.txt in + // the doc/ directory. + // The format must be strictly adhered to for it to be processed correctly. + // The lines and their meanings from begin through info are fixed, and then + // a variable number of tracks may follow. + // + std::vector token = Ghost::Utils::readInLine(m_input_file, m_line_size, m_line_buffer); + int iVertex=0; + + if (token.size() == 0 || token[0] == "stop") { + G4cout << "End of nuance vector file - run terminated..."<< G4endl; + G4RunManager::GetRunManager()-> AbortRun(); + } + else if (token[0] != "begin") { + G4cout << "unexpected line begins with \"" << token[0] + << "\"we were expecting \" begin \"" << G4endl; + } + else { // normal parsing begins here + // Read the nuance line + // should be nuance + // but could be just + // nuance + // if value is given set mode to equal it. + + token = Ghost::Utils::readInLine(m_input_file, m_line_size, m_line_buffer); + while(token[0]=="nuance" && iVertex < MAX_N_VERTICES) { + int VertexIntMode = 0; + if(token.size()>1) + VertexIntMode = Ghost::Utils::atoi(token[1]); + + // Read the Vertex line + // - this contains position and time + token = Ghost::Utils::readInLine(m_input_file, m_line_size, m_line_buffer); + G4ThreeVector VertexPosition(Ghost::Utils::atof(token[1])*cm, + Ghost::Utils::atof(token[2])*cm, + Ghost::Utils::atof(token[3])*cm); + G4double VertexTime=Ghost::Utils::atof(token[4])*m_vertex_time_unit; + + // Next we read the incoming neutrino and target + + // First, the neutrino line + token=Ghost::Utils::readInLine(m_input_file, m_line_size, m_line_buffer); + + int BeamPDG = Ghost::Utils::atoi(token[1]); + double BeamEnergy = Ghost::Utils::atof(token[2])*MeV; + G4ThreeVector BeamDirection(Ghost::Utils::atof(token[3]), + Ghost::Utils::atof(token[4]), + Ghost::Utils::atof(token[5])); + G4cout << "Neutrino generated is = "<< BeamPDG<<", Enu = " << BeamEnergy << " and interacts through mode = " << VertexIntMode << G4endl; + InitialParticleInfo beam(iVertex, VertexTime, BeamEnergy, BeamDirection, VertexPosition, BeamPDG); + AddParticleToSave(beam); + + // Now read the target line(s) + // There can be some cases (2p2h i.e. neut mode = 2) where there are 2 targets. The while loop is added for this purpose. + while ( token=Ghost::Utils::readInLine(m_input_file, m_line_size, m_line_buffer), + token[0] == "track" ) { + int TargetPDG = Ghost::Utils::atoi(token[1]); + double TargetEnergy = Ghost::Utils::atof(token[2])*MeV; + G4ThreeVector TargetDirection(Ghost::Utils::atof(token[3]), + Ghost::Utils::atof(token[4]), + Ghost::Utils::atof(token[5])); + G4cout << "Target hit is = "<< TargetPDG <<", E = " << TargetEnergy << G4endl; + InitialParticleInfo target(iVertex, VertexTime, TargetEnergy, TargetDirection, VertexPosition, TargetPDG); + AddParticleToSave(target); + }//loop over target lines + + // The info line is read in the exiting step of the while loop aboe + // The info line is (almost) a dummy + G4cout << "Vector File Record Number " << token[2] << G4endl; + int VectorRecordNumber = Ghost::Utils::atoi(token[2]); + + // Now read the outgoing particles + // These we will simulate. + while ( token=Ghost::Utils::readInLine(m_input_file, m_line_size, m_line_buffer), + token[0] == "track" ) { + // We are only interested in the particles + // that leave the nucleus, tagged by "0" + if ( token[6] == "0") { + G4int pdgid = Ghost::Utils::atoi(token[1]); + G4double energy_total = Ghost::Utils::atof(token[2])*MeV; + G4ThreeVector dir = G4ThreeVector(Ghost::Utils::atof(token[3]), + Ghost::Utils::atof(token[4]), + Ghost::Utils::atof(token[5])); + + G4ParticleDefinition * particle_definition = nullptr; + int particle_charge = INT_MAX; + //must handle the case of an ion seperatly from other particles + //check PDG code if we have an ion. + //PDG code format for ions ±10LZZZAAAI + if(abs(pdgid) >= 1000000000){ + //ion + char strPDG[11]; + char strA[10]={0}; + char strZ[10]={0}; + long int A=0,Z=0; + sprintf(strPDG,"%i",abs(pdgid)); + //stop GCC complaining about string truncation + // - we're copying from the middle of a long string + // - we do terminate the string correctly below +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-truncation" + strncpy(strZ, &strPDG[3], 3); +#pragma GCC diagnostic pop + strncpy(strA, &strPDG[6], 3); + strA[3]='\0'; + strZ[3]='\0'; + A=Ghost::Utils::atoi(strA); + Z=Ghost::Utils::atoi(strZ); + particle_definition = ionTable->GetIon(Z, A, 0.); + particle_charge = 0; + }//ion + else { + //not ion + particle_definition = particleTable->FindParticle(pdgid); + }//not ion + + G4double mass = particle_definition->GetPDGMass(); + + G4double ekin = energy_total - mass; + + G4cout << "Generating particle = "<< pdgid << ", E = " << energy_total << " MeV, Ec = " << ekin << " MeV, and dir = " << dir[0] << ", " << dir[1] << ", " << dir[2] << G4endl; + + InitialParticleInfo particle(iVertex, VertexTime, ekin, dir, VertexPosition, particle_definition); + AddParticleToSimulate(particle); + }//token[6] == "0" (particle exiting nucleus) + }//loop over "track" lines + iVertex++; + if(iVertex > MAX_N_VERTICES) + G4cout<<" CAN NOT DEAL WITH MORE THAN "<SetVectorFileName(m_input_filename); + wcopt->SetGeneratorType(GetGeneratorTypeString()); +} diff --git a/GhostG4PrimaryGeneratorAction/PGAKinFile.h b/GhostG4PrimaryGeneratorAction/PGAKinFile.h new file mode 100644 index 0000000..4a4723c --- /dev/null +++ b/GhostG4PrimaryGeneratorAction/PGAKinFile.h @@ -0,0 +1,74 @@ +#ifndef PGAKinFile_h +#define PGAKinFile_h + +#include "PrimaryGeneratorActionBase.h" + +#include "G4ThreeVector.hh" +#include "G4ParticleDefinition.hh" +#include "G4String.hh" + +#include "WCSimRootOptions.hh" +#include "jhfNtuple.h" + +#include + +class G4ParticleGun; +class G4Event; + +namespace Ghost::G4 { + class PGAKinFile : public PrimaryGeneratorActionBase { + public: + PGAKinFile(); + ~PGAKinFile(); + + void FillParticleVectors() override; + + /* + // Gun, laser & gps setting calls these functions to fill jhfNtuple and Root tree + void SetVtx(G4ThreeVector i) { vtxs[0] = i; nvtxs = 1; }; + void SetBeamEnergy(G4double i, G4int n = 0) { beamenergies[n] = i;}; + void SetBeamDir(G4ThreeVector i, G4int n = 0) { beamdirs[n] = i;}; + void SetBeamPDG(G4int i, G4int n = 0) { beampdgs[n] = i;}; + void SetNvtxs(G4int i) { nvtxs = i; }; + void SetVtxs(G4int i, G4ThreeVector v) { vtxs[i] = v; }; + + // These go with jhfNtuple + G4int GetVecRecNumber() const {return vecRecNumber;} + G4int GetMode(int vertex = 0) const {return mode[vertex];}; + //InteractionType_t GetMode(int vertex = 0) {return mode[vertex];}; + G4int GetNvtxs() const {return nvtxs;}; + G4int GetVtxVol(G4int n = 0) const {return vtxsvol[n];}; + G4ThreeVector GetVtx(G4int n = 0) const {return vtxs[n];} + G4double GetVertexTime(G4int n = 0) const {return vertexTimes[n];} + G4int GetNpar() const {return npar;}; + G4int GetBeamPDG(G4int n = 0) const {return beampdgs[n];}; + G4double GetBeamEnergy(G4int n = 0) const {return beamenergies[n];}; + G4ThreeVector GetBeamDir(G4int n = 0) const {return beamdirs[n];}; + G4int GetTargetPDG(G4int n = 0) const {return targetpdgs[n];}; + G4double GetTargetEnergy(G4int n = 0) const {return targetenergies[n];}; + G4ThreeVector GetTargetDir(G4int n = 0) const {return targetdirs[n];}; + + // older ... + G4double GetNuEnergy() const {return nuEnergy;}; + G4double GetEnergy() const {return energy;}; + G4double GetXPos() const {return xPos;}; + G4double GetYPos() const {return yPos;}; + G4double GetZPos() const {return zPos;}; + G4double GetXDir() const {return xDir;}; + G4double GetYDir() const {return yDir;}; + G4double GetZDir() const {return zDir;}; + */ + + void SaveOptionsToOutput(WCSimRootOptions * wcopt) const override; + + private: + + std::fstream m_input_file; + G4String m_input_filename; + //! Maximum length of the input line + 1 + static const int m_line_size=1000; + //! Buffer for reading the input file line by line + char m_line_buffer[m_line_size]; + }; +} //namespace Ghost::G4 +#endif diff --git a/GhostG4PrimaryGeneratorAction/PrimaryGeneratorActionBase.cpp b/GhostG4PrimaryGeneratorAction/PrimaryGeneratorActionBase.cpp new file mode 100644 index 0000000..3b1bdd7 --- /dev/null +++ b/GhostG4PrimaryGeneratorAction/PrimaryGeneratorActionBase.cpp @@ -0,0 +1,38 @@ +#include "PrimaryGeneratorActionBase.h" + +Ghost::G4::PrimaryGeneratorActionBase::PrimaryGeneratorActionBase() + : m_generator_name("UNKNOWNGENERATOR"), + m_event_num(0), + m_vertex_time_unit(CLHEP::nanosecond) +{ + m_particle_gun = std::make_unique(); +} + +Ghost::G4::PrimaryGeneratorActionBase::~PrimaryGeneratorActionBase() { +} + +void Ghost::G4::PrimaryGeneratorActionBase::GeneratePrimaries(G4Event* anEvent) { + G4cout << "Generating primary particles from generator: " << m_generator_name + << " for event " << m_event_num << G4endl; + + ClearParticleVectors(); + FillParticleVectors(); + + G4cout << "There are " << GetNParticlesToBeSimulated() + << " (" << GetNParticlesToBeSaved() << ")" + << " particles to be simulated (saved)" << G4endl; + + for(const InitialParticleInfo & particle : m_particles_to_save) { + G4cerr << "Need to implement saving particles" << G4endl; + }//loop over particles to save + + for(const InitialParticleInfo & particle : m_particles_to_simulate) { + m_particle_gun->SetParticleDefinition(particle.m_p_particle_definition); + m_particle_gun->SetParticleTime(particle.m_time * m_vertex_time_unit); + m_particle_gun->SetParticleEnergy(particle.m_kinetic_energy); + m_particle_gun->SetParticleMomentumDirection(particle.m_direction); + m_particle_gun->SetParticlePosition(particle.m_position); + + m_particle_gun->GeneratePrimaryVertex(anEvent); +}//loop over particles to simulate +} diff --git a/GhostG4PrimaryGeneratorAction/PrimaryGeneratorActionBase.h b/GhostG4PrimaryGeneratorAction/PrimaryGeneratorActionBase.h new file mode 100644 index 0000000..f41bbb3 --- /dev/null +++ b/GhostG4PrimaryGeneratorAction/PrimaryGeneratorActionBase.h @@ -0,0 +1,93 @@ +#ifndef PrimaryGeneratorActionBase_h +#define PrimaryGeneratorActionBase_h + +#include "G4VUserPrimaryGeneratorAction.hh" +#include "G4ParticleGun.hh" +#include "G4String.hh" + +#include "InitialParticleInfo.h" + +#include "WCSimRootOptions.hh" + +namespace Ghost::G4 { + + class PrimaryGeneratorActionBase : public G4VUserPrimaryGeneratorAction { + public: + PrimaryGeneratorActionBase(); + ~PrimaryGeneratorActionBase(); + + //! Generates primary to simulate through Geant4 + virtual void GeneratePrimaries(G4Event* anEvent); + + //! Get the number of particles to be simulated in this event + size_t GetNParticlesToBeSimulated() const {return m_particles_to_simulate.size();} + + //! Get the number of particles to be saved in this event + size_t GetNParticlesToBeSaved() const {return m_particles_to_save.size();} + + //! Get the generator name + G4String GetGeneratorTypeString() const {return m_generator_name;} + + protected: + //! Add a particle to the list of initial particles that Geant4 will simulate + void AddParticleToSimulate(InitialParticleInfo & pinfo) {m_particles_to_simulate.push_back(pinfo);} + + //! Add a particle to the list of initial particles that Geant4 won't simulate + void AddParticleToSave(InitialParticleInfo & pinfo) {m_particles_to_save.push_back(pinfo);} + + //! Build you event here. This should be calls of AddParticleToSimulate and AddParticleToSave + virtual void FillParticleVectors() = 0; + + //! Store the particles we want to simulate with Geant4 + std::vector m_particles_to_simulate; + + //! Store any particles we want to save, but not simulate + /** + * e.g. Beam, target, pre-FSI + */ + std::vector m_particles_to_save; + + //! The name of the generator. Will be replaced with an enum + [[deprecated]] G4String m_generator_name; + + //! Store config info in the WCSimRootOptions. Will be replaced with a common way to store things in the DataModel + [[deprecated]] virtual void SaveOptionsToOutput(WCSimRootOptions * wcopt) const = 0; + + //! Event number counter. + int m_event_num; + + //! The time unit we're using. + G4double m_vertex_time_unit; + + private: + //! How we actually generate particles to simulate through Geant4 + std::unique_ptr m_particle_gun; + + void ClearParticleVectors() { + m_particles_to_simulate.clear(); + m_particles_to_save.clear(); + } + + public: + + //! Set the time unit + void SetVertexTimeUnit(G4String choice) { + if(choice == "ns" || choice=="nanosecond") + m_vertex_time_unit=CLHEP::nanosecond; + else if(choice == "s" || choice=="second") + m_vertex_time_unit=CLHEP::second; + else if (choice == "ms" || choice=="millisecond") + m_vertex_time_unit=CLHEP::millisecond; + else if (choice=="microsecond") + m_vertex_time_unit=CLHEP::microsecond; + else if(choice=="ps" || choice=="picosecond") + m_vertex_time_unit=CLHEP::picosecond; + else + m_vertex_time_unit=CLHEP::nanosecond; + } + //! Get the time unit + G4double GetVertexTimeUnit() const { return m_vertex_time_unit; } + + }; +} //namespace Ghost::G4 +#endif diff --git a/HKG4PrimaryGeneratorAction/README.md b/GhostG4PrimaryGeneratorAction/README.md similarity index 100% rename from HKG4PrimaryGeneratorAction/README.md rename to GhostG4PrimaryGeneratorAction/README.md diff --git a/HKG4PhysicsList/HKG4PhysicsList.cpp b/HKG4PhysicsList/HKG4PhysicsList.cpp index 80ad3cf..cf4937b 100644 --- a/HKG4PhysicsList/HKG4PhysicsList.cpp +++ b/HKG4PhysicsList/HKG4PhysicsList.cpp @@ -1,14 +1,11 @@ #include "HKG4PhysicsList.h" - #include "Utilities.h" #include "WCSimRunAction.hh" -using namespace HK::Ghost::G4; - -HKG4PhysicsList::HKG4PhysicsList() : Tool() {} +Ghost::G4::HKG4PhysicsList::HKG4PhysicsList() : Tool() {} -bool HKG4PhysicsList::Initialise(std::string configfile, DataModel& data) { +bool Ghost::G4::HKG4PhysicsList::Initialise(std::string configfile, DataModel& data) { if(configfile != "") m_variables.Initialise(configfile); @@ -20,11 +17,9 @@ bool HKG4PhysicsList::Initialise(std::string configfile, DataModel& data) { if(!m_variables.Get("verbose", m_verbose)) m_verbose = 1; - // m_p_UI = G4UImanager::GetUIpointer(); - - std::string wcsim_dir = utils::GetEnvironmentVariableWithDefault("WCSIM_BUILD_DIR", "./"); + std::string wcsim_dir = Ghost::Utils::GetEnvironmentVariableWithDefault("WCSIM_BUILD_DIR", "./"); std::string wcsim_mac_job_opt_filename = - HK::Ghost::utils::GetConfigFilename(m_variables, + Ghost::Utils::GetConfigFilename(m_variables, "wcsim_mac_job_opt_filename", (wcsim_dir + "/macros/jobOptions.mac").c_str()); @@ -44,14 +39,14 @@ bool HKG4PhysicsList::Initialise(std::string configfile, DataModel& data) { return true; } -bool HKG4PhysicsList::Execute() { +bool Ghost::G4::HKG4PhysicsList::Execute() { auto p_run_action = static_cast(m_data->m_p_run_manager->GetUserRunAction()); *m_log << ML(0) << "WCSimRunAction pointer is " << p_run_action << " in Exectute()" << std::endl; return true; } -bool HKG4PhysicsList::Finalise() { +bool Ghost::G4::HKG4PhysicsList::Finalise() { auto p_run_action = static_cast(m_data->m_p_run_manager->GetUserRunAction()); if(p_run_action == nullptr) diff --git a/HKG4PhysicsList/HKG4PhysicsList.h b/HKG4PhysicsList/HKG4PhysicsList.h index bd05704..eba90b9 100644 --- a/HKG4PhysicsList/HKG4PhysicsList.h +++ b/HKG4PhysicsList/HKG4PhysicsList.h @@ -16,36 +16,29 @@ * * This is a blank template for a Tool used by the script to generate a new custom tool. Please fill out the * description and author information. - * - * $Author: B.Richards $ - * $Date: 2019/05/28 10:44:00 $ */ -namespace HK { - namespace Ghost { - namespace G4 { +namespace Ghost::G4 { - class HKG4PhysicsList : public Tool { + class HKG4PhysicsList : public Tool { - public: + public: - HKG4PhysicsList(); ///< Simple constructor - bool Initialise( - std::string configfile, - DataModel& data); ///< Initialise Function for setting up Tool resources. @param - ///< configfile The path and name of the dynamic configuration file - ///< to read in. @param data A reference to the transient data - ///< class used to pass information between Tools. - bool Execute(); ///< Execute function used to perform Tool purpose. - bool Finalise(); ///< Finalise funciton used to clean up resources. + HKG4PhysicsList(); ///< Simple constructor + bool Initialise( + std::string configfile, + DataModel& data); ///< Initialise Function for setting up Tool resources. @param + ///< configfile The path and name of the dynamic configuration file + ///< to read in. @param data A reference to the transient data + ///< class used to pass information between Tools. + bool Execute(); ///< Execute function used to perform Tool purpose. + bool Finalise(); ///< Finalise funciton used to clean up resources. - private: + private: - WCSimPhysicsListFactory* m_p_phys_factory; - G4UImanager* m_p_UI; - }; - } // namespace G4 - } // namespace Ghost -} // namespace HK + WCSimPhysicsListFactory* m_p_phys_factory; + G4UImanager* m_p_UI; + }; +} // namespace Ghost::G4 #endif diff --git a/HKG4PrimaryGeneratorAction/HKG4PrimaryGeneratorAction.cpp b/HKG4PrimaryGeneratorAction/HKG4PrimaryGeneratorAction.cpp deleted file mode 100644 index fb5104b..0000000 --- a/HKG4PrimaryGeneratorAction/HKG4PrimaryGeneratorAction.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "HKG4PrimaryGeneratorAction.h" - -#include "WCSimPrimaryGeneratorAction.hh" - -using namespace HK::Ghost::G4; - -HKG4PrimaryGeneratorAction::HKG4PrimaryGeneratorAction() : Tool() {} - -bool HKG4PrimaryGeneratorAction::Initialise(std::string configfile, DataModel& data) { - - if(configfile != "") - m_variables.Initialise(configfile); - // m_variables.Print(); - - m_data = &data; - m_log = m_data->Log; - - if(!m_variables.Get("verbose", m_verbose)) - m_verbose = 1; - - m_data->m_p_run_manager->SetUserAction( - new WCSimPrimaryGeneratorAction(static_cast( - m_data->m_p_run_manager->GetUserDetectorConstruction()))); - - return true; -} - -bool HKG4PrimaryGeneratorAction::Execute() { - - return true; -} - -bool HKG4PrimaryGeneratorAction::Finalise() { - - return true; -} diff --git a/HKG4PrimaryGeneratorAction/HKG4PrimaryGeneratorAction.h b/HKG4PrimaryGeneratorAction/HKG4PrimaryGeneratorAction.h deleted file mode 100644 index 7dcc18e..0000000 --- a/HKG4PrimaryGeneratorAction/HKG4PrimaryGeneratorAction.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef HKG4PrimaryGeneratorAction_H -#define HKG4PrimaryGeneratorAction_H - -#include -#include - -#include -#include "Tool.h" - -/** - * \class HKG4PrimaryGeneratorAction - * - * This is a blank template for a Tool used by the script to generate a new custom tool. Please fill out the - * description and author information. - * - * $Author: B.Richards $ - * $Date: 2019/05/28 10:44:00 $ - */ - -namespace HK { - namespace Ghost { - namespace G4 { - class HKG4PrimaryGeneratorAction : public Tool { - - public: - - HKG4PrimaryGeneratorAction(); ///< Simple constructor - bool Initialise( - std::string configfile, - DataModel& data); ///< Initialise Function for setting up Tool resources. @param - ///< configfile The path and name of the dynamic configuration file - ///< to read in. @param data A reference to the transient data - ///< class used to pass information between Tools. - bool Execute(); ///< Execute function used to perform Tool purpose. - bool Finalise(); ///< Finalise funciton used to clean up resources. - - private: - }; - } // namespace G4 - } // namespace Ghost -} // namespace HK - -#endif diff --git a/WCSim_exe/WCSim_exe.cpp b/WCSim_exe/WCSim_exe.cpp index 8dfc9d0..75cce73 100644 --- a/WCSim_exe/WCSim_exe.cpp +++ b/WCSim_exe/WCSim_exe.cpp @@ -1,23 +1,12 @@ #include "WCSim_exe.h" #include "WCSimDetectorConstruction.hh" -#include "WCSimEventAction.hh" -#include "WCSimPhysicsListFactory.hh" -#include "WCSimPrimaryGeneratorAction.hh" -#include "WCSimRandomParameters.hh" -#include "WCSimRunAction.hh" -#include "WCSimStackingAction.hh" -#include "WCSimSteppingAction.hh" -// #include "WCSimTrackingAction.hh" -#include "WCSimTuningParameters.hh" -#include "../src/Utilities.h" +#include "Utilities.h" -using namespace HK::Ghost::G4; +Ghost::G4::WCSim_exe::WCSim_exe() : Tool() {} -WCSim_exe::WCSim_exe() : Tool() {} - -bool WCSim_exe::Initialise(std::string configfile, DataModel& data) { +bool Ghost::G4::WCSim_exe::Initialise(std::string configfile, DataModel& data) { if(configfile != "") m_variables.Initialise(configfile); @@ -33,16 +22,12 @@ bool WCSim_exe::Initialise(std::string configfile, DataModel& data) { m_verbose = 1; // get all the mac files - std::string wcsim_dir = HK::Ghost::utils::GetEnvironmentVariableWithDefault("WCSIM_BUILD_DIR", "./"); - /*std::string wcsim_mac_job_opt_filename = - HK::Ghost::utils::GetConfigFilename(m_variables, "wcsim_mac_job_opt_filename", (wcsim_dir + - "/macros/jobOptions.mac").c_str()); - */ + std::string wcsim_dir = Ghost::Utils::GetEnvironmentVariableWithDefault("WCSIM_BUILD_DIR", "./"); std::string wcsim_mac_tuning_filename = - HK::Ghost::utils::GetConfigFilename(m_variables, + Ghost::Utils::GetConfigFilename(m_variables, "wcsim_mac_tuning_filename", (wcsim_dir + "/macros/tuning_parameters.mac").c_str()); - m_wcsim_mac_filename = HK::Ghost::utils::GetConfigFilename(m_variables, + m_wcsim_mac_filename = Ghost::Utils::GetConfigFilename(m_variables, "wcsim_mac_filename", (wcsim_dir + "/WCSim.mac").c_str()); @@ -82,34 +67,18 @@ bool WCSim_exe::Initialise(std::string configfile, DataModel& data) { m_data->m_p_run_manager->SetUserInitialization(WCSimdetector); - *m_log << ML(0) << "TODO: Add tuningpars->SaveOptionsToOutput(myRunAction->GetRootOptions());" << endl; - - // Set user action classes - // WCSimPrimaryGeneratorAction* myGeneratorAction = new WCSimPrimaryGeneratorAction(WCSimdetector); - // m_data->m_p_run_manager->SetUserAction(myGeneratorAction); - - // WCSimRunAction* myRunAction = new WCSimRunAction(WCSimdetector, randomparameters); - - // save all the options from WCSimTuningParameters & WCSimPhysicsListFactory - //(set in tuning_parameters.mac & jobOptions*.mac) - // tuningpars->SaveOptionsToOutput(myRunAction->GetRootOptions()); - // physFactory->SaveOptionsToOutput(myRunAction->GetRootOptions()); + *m_log << ML(0) << "TODO: Add tuningpars->SaveOptionsToOutput(myRunAction->GetRootOptions());" << std::endl; - // m_data->m_p_run_manager->SetUserAction(myRunAction); - - // m_data->m_p_run_manager->SetUserAction(new WCSimEventAction(myRunAction, WCSimdetector, - // myGeneratorAction)); m_data->m_p_run_manager->SetUserAction(new WCSimTrackingAction); - - // m_data->m_p_run_manager->SetUserAction(new WCSimStackingAction(WCSimdetector)); - - // m_data->m_p_run_manager->SetUserAction(new WCSimSteppingAction(myRunAction, WCSimdetector)); + // save all the options from WCSimTuningParameters + //(set in tuning_parameters.mac) + //tuningpars->SaveOptionsToOutput(myRunAction->GetRootOptions()); m_initialised = false; return true; } -bool WCSim_exe::Execute() { +bool Ghost::G4::WCSim_exe::Execute() { if(!m_initialised) { // Initialize G4 kernel @@ -118,6 +87,11 @@ bool WCSim_exe::Execute() { m_p_UI->ApplyCommand("/control/execute " + m_wcsim_mac_filename); m_initialised = true; + + *m_log << ML(1) << std::endl << std::endl + << "******************************" << std::endl + << "Have initalised the Geant run manager" << std::endl + << "******************************" << std::endl << std::endl; } if(m_current_event < m_number_of_events) { @@ -125,11 +99,12 @@ bool WCSim_exe::Execute() { } m_current_event++; if(m_current_event >= m_number_of_events) + *m_log << ML(1) << "Finished reading events. Stopping loop" << std::endl; m_data->vars.Set("StopLoop", 1); return true; } -bool WCSim_exe::Finalise() { +bool Ghost::G4::WCSim_exe::Finalise() { delete m_data->m_p_run_manager; return true; diff --git a/WCSim_exe/WCSim_exe.h b/WCSim_exe/WCSim_exe.h index e8f7973..674943a 100644 --- a/WCSim_exe/WCSim_exe.h +++ b/WCSim_exe/WCSim_exe.h @@ -19,33 +19,29 @@ * $Date: 2023/08/08 14:31:00 $ */ -namespace HK { - namespace Ghost { - namespace G4 { - class WCSim_exe : public Tool { - - public: - - WCSim_exe(); ///< Simple constructor - bool Initialise( - std::string configfile, - DataModel& data); ///< Initialise Function for setting up Tool resources. @param - ///< configfile The path and name of the dynamic configuration file - ///< to read in. @param data A reference to the transient data - ///< class used to pass information between Tools. - bool Execute(); ///< Execute function used to perform Tool purpose. - bool Finalise(); ///< Finalise funciton used to clean up resources. - - private: - - // G4RunManager* m_p_run_manager; - G4UImanager* m_p_UI; - bool m_initialised; - std::string m_wcsim_mac_filename; - long m_number_of_events; - long m_current_event; - }; - } // namespace G4 - } // namespace Ghost -} // namespace HK +namespace Ghost::G4 { + class WCSim_exe : public Tool { + + public: + + WCSim_exe(); ///< Simple constructor + bool Initialise( + std::string configfile, + DataModel& data); ///< Initialise Function for setting up Tool resources. @param + ///< configfile The path and name of the dynamic configuration file + ///< to read in. @param data A reference to the transient data + ///< class used to pass information between Tools. + bool Execute(); ///< Execute function used to perform Tool purpose. + bool Finalise(); ///< Finalise funciton used to clean up resources. + + private: + + // G4RunManager* m_p_run_manager; + G4UImanager* m_p_UI; + bool m_initialised; + std::string m_wcsim_mac_filename; + long m_number_of_events; + long m_current_event; + }; +} // namespace Ghost::G4 #endif diff --git a/newTool.sh b/newTool.sh index fd555fe..3a3f364 100755 --- a/newTool.sh +++ b/newTool.sh @@ -6,85 +6,95 @@ then if [ "$1" == "" ] then - dialog --inputbox "Enter new Tool name:" 0 0 2>answer - - if [ $? -eq 0 ] - then - dir=`cat answer` + dialog --inputbox "Enter new Tool name:" 0 0 2>answer + + if [ $? -eq 0 ] + then + dir=`cat answer` - if [ "$dir" == "" ] - then - rm -f answer + if [ "$dir" == "" ] + then + rm -f answer clear - echo -e "\e[38;5;196mERROR!!! no Tool name given \e[0m" + echo -e "\e[38;5;196mERROR!!! no Tool name given \e[0m" exit - fi - - dialog --radiolist "Select Tool Template:" 0 0 0 \ - "" . on \ - `for template in \`ls template/* | grep .cpp | sed s:template/MyTool:: | sed s:.cpp::\` + fi + + dialog --radiolist "Select Tool Template:" 0 0 0 \ + "" . on \ + `for template in \`ls template/* | grep .cpp | sed s:template/MyTool:: | sed s:.cpp::\` do echo $template . off done ` 2>answer - - if [ $? -eq 0 ] - then - template=`cat answer` - - else - rm -f answer - clear - exit - fi - else + + if [ $? -eq 0 ] + then + template=`cat answer` + + else + rm -f answer + clear + exit + fi + else rm -f answer clear exit - fi - rm -f answer - clear - - if [ "$template" == "" ] - then - template="" - fi - + fi + rm -f answer + clear + + if [ "$template" == "" ] + then + template="" + fi + else - - dir=$1 - template=$2 + + dir=$1 + template=$2 + if [ -z "$3" ]; then + namespace="" + else; + namespace="$3::" + fi fi else dir=$1 template=$2 + if [ -z "$3" ]; then + namespace="" + else; + namespace="$3::" + fi fi - if [ "$dir" != "" ] - then - - if [ -d $dir ] - then - echo -e "\e[38;5;196mERROR!!! Tool directory already exists \e[0m" - else - - mkdir $dir - more template/MyTool$template.h | sed s:MyTool$template:$dir:g | sed s:MYTOOL${template}_H:${dir}_H:g > ./$dir/$dir.h - more template/MyTool$template.cpp | sed s:MyTool$template:$dir:g | sed s:MyTool$template\(\):$dir\(\):g > ./$dir/$dir.cpp - more template/README.md | sed s:MyTool:$dir:g | sed s:MyTool\(\):$dir\(\):g > ./$dir/README.md - fi - else - - echo -e "\e[38;5;196mError no name given \e[0m: usage = \"./newTool.sh \e[38;5;226m \e[38;5;46m \e[0m\" if is blank then blank template is used" - echo -e "Valid tools template names are:" - echo -e "\e[38;5;46m" - for name in `ls template/ |grep '\.h' |grep -v "h~" |sed s:"\.h"::|sed s:"MyTool"::` - do - echo $name - done - echo -e "\e[0m" - fi +if [ "$dir" != "" ] +then + + if [ -d $dir ] + then + echo -e "\e[38;5;196mERROR!!! Tool directory already exists \e[0m" + else + + mkdir $dir + more template/MyTool$template.h | sed s:MyTool$template:$dir:g | sed s:MYTOOL${template}_H:${dir}_H:g | sed s!NAMESPACE!${namespace}:g > ./$dir/$dir.h + more template/MyTool$template.cpp | sed s:MyTool$template:$dir:g | sed s:MyTool$template\(\):$dir\(\):g | sed s!NAMESPACE!${namespace}:g > ./$dir/$dir.cpp + more template/README.md | sed s:MyTool:$dir:g | sed s:MyTool\(\):$dir\(\):g > ./$dir/README.md + fi +else + + echo -e "\e[38;5;196mError no name given \e[0m: usage = \"./newTool.sh \e[38;5;226m \e[38;5;46m \e[0m\ \" if is blank then blank template is used. If is blank, then tool will be put in the base Ghost namespace" + echo -e "Valid tools template names are:" + echo -e "\e[38;5;46m" + for name in `ls template/ |grep '\.h' |grep -v "h~" |sed s:"\.h"::|sed s:"MyTool"::` + do + echo $name + done + echo -e "\e[0m" +fi diff --git a/src/Utilities.cpp b/src/Utilities.cpp index 9449da9..10fa80f 100644 --- a/src/Utilities.cpp +++ b/src/Utilities.cpp @@ -3,7 +3,7 @@ #include #include -bool HK::Ghost::utils::FileExists(const char* filename) { +bool Ghost::Utils::FileExists(const char* filename) { bool exists = access(filename, F_OK) != -1; if(!exists) { std::cerr << filename << " not found or inaccessible." << std::endl; @@ -11,7 +11,7 @@ bool HK::Ghost::utils::FileExists(const char* filename) { return exists; } -std::string HK::Ghost::utils::GetEnvironmentVariableWithDefault(const char* variable, +std::string Ghost::Utils::GetEnvironmentVariableWithDefault(const char* variable, const char* default_value) { std::string env; char* env_temp = std::getenv(variable); @@ -27,14 +27,14 @@ std::string HK::Ghost::utils::GetEnvironmentVariableWithDefault(const char* vari return env; } -std::string HK::Ghost::utils::GetConfigFilename(Store& variables, +std::string Ghost::Utils::GetConfigFilename(Store& variables, const char* config_param, const char* default_filename) { std::string filename; if(!variables.Get(config_param, filename)) filename = default_filename; - if(!utils::FileExists(filename.c_str())) { + if(!Ghost::Utils::FileExists(filename.c_str())) { std::cerr << "File: " << filename << " not found." << std::endl << "Please give a valid option in the config file to: " << config_param << std::endl << "Exiting..." << std::endl; @@ -43,3 +43,62 @@ std::string HK::Ghost::utils::GetConfigFilename(Store& variables, std::cout << "Using filename: " << filename << " for parameter: " << config_param << std::endl; return filename; } + +std::fstream Ghost::Utils::OpenFileStream(std::string fileName) { + std::fstream inputFile; + inputFile.open(fileName, std::fstream::in); + if ( !inputFile.is_open() ) { + std::cout << "File " << fileName << " not found" << std::endl; + throw std::ios_base::failure(""); + } + return inputFile; +} + +std::vector Ghost::Utils::readInLine(std::fstream& inFile, int lineSize, char* inBuf) { + // Read in line break it up into tokens + // Any line starting with # is ignored + while(true) { + if (inFile.getline(inBuf,lineSize)) { + if(inBuf[0]!='#') { + return Ghost::Utils::tokenize(" $\r", inBuf); + } + } + else { + if(inFile.fail()) + std::cerr << "Failed to read line. Is the buffer size large enough?" << std::endl; + std::vector nullLine; + return nullLine; + } + } +} + +// Returns a vector with the tokens +std::vector Ghost::Utils::tokenize( std::string separators, std::string input ) { + std::size_t startToken = 0, endToken; // Pointers to the token pos + std::vector tokens; // Vector to keep the tokens + + if( separators.size() > 0 && input.size() > 0 ) { + while( startToken < input.size() ) { + // Find the start of token + startToken = input.find_first_not_of( separators, startToken ); + + // If found... + if( startToken != input.npos ) { + // Find end of token + endToken = input.find_first_of( separators, startToken ); + if( endToken == input.npos ) + // If there was no end of token, assign it to the end of string + endToken = input.size(); + + // Extract token + tokens.push_back( input.substr( startToken, endToken - startToken ) ); + + // Update startToken + startToken = endToken; + } // if token is found + } // while we've not completed tokenising the string + } // if input is valid + + return tokens; +} + diff --git a/src/Utilities.h b/src/Utilities.h index 8063e5e..3456d18 100644 --- a/src/Utilities.h +++ b/src/Utilities.h @@ -2,36 +2,65 @@ #include "Store.h" -namespace HK { - namespace Ghost { - namespace utils { - //! Get an environment variable, falling back to a default value - /*! - \param variable The name of the environment variable - \param default_value The default value, to use if the environment variable isn't set or is - empty \return A string containing the environment variable if it is set and is not empty, else - the default - */ - std::string GetEnvironmentVariableWithDefault(const char* variable, const char* default_value); - - //! Check if a file exists and is accessible - /*! - \param filename The name of the file - \return True if it exists and is accessible, false if not - */ - bool FileExists(const char* filename); - - //! Get a filename from the config file - /*! - Also checks that the file exists. There is a hard exit if not - \param variables The Store containing your Tools' config file options - \param config_param The name of the config file variable - \param default_filename A fallback - \return The filename - */ - std::string GetConfigFilename(Store& variables, - const char* config_param, - const char* default_filename); - } // namespace utils - } // namespace Ghost -} // namespace HK +namespace Ghost::Utils { + //! Get an environment variable, falling back to a default value + /*! + \param variable The name of the environment variable + \param default_value The default value, to use if the environment variable isn't set or is + empty \return A string containing the environment variable if it is set and is not empty, else + the default + */ + std::string GetEnvironmentVariableWithDefault(const char* variable, const char* default_value); + + //! Check if a file exists and is accessible + /*! + \param filename The name of the file + \return True if it exists and is accessible, false if not + */ + bool FileExists(const char* filename); + + //! Get a filename from the config file + /*! + Also checks that the file exists. There is a hard exit if not + \param variables The Store containing your Tools' config file options + \param config_param The name of the config file variable + \param default_filename A fallback + \return The filename + */ + std::string GetConfigFilename(Store& variables, + const char* config_param, + const char* default_filename); + + //! Open a filestream from a filename + std::fstream OpenFileStream(std::string fileName); + + //! Converts `std::string` to `double` + /*! + Wrapper to `std::atof` that accepts a `const char *` + */ + inline double atof(const std::string& str) {return std::atof( str.c_str() );} + //! Converts `std::string` to `int` + /*! + Wrapper to `std::atoi` that accepts a `const char *` + */ + inline int atoi(const std::string& str) {return std::atoi( str.c_str() );} + + //! Read in line break it up into tokens separated by whitespace + /*! + Any line starting with # is ignored (treated as a comment). + \param inFile The input file stream to read a line from + \param lineSize The size of the buffer (maximum length of the line in characters - 1) + \param inBuf A buffer to store each line temporarily. Should be size `lineSize` + \return A vector containing ntokens elements. Will be a vector of size 0 if no line can be found (e.g. end of file, all lines are comments) + */ + std::vector readInLine(std::fstream& inFile, int lineSize, char* inBuf); + + //! Split a string into tokens based on various separators + /*! + \param separators String containing the items to split on + \param input The string you want to tokenize + \return A vector containing ntokens elements. Will be a vector of size 0 if either input is invalid. If there are no separators found in input, will be a vector of size 1 containing the input string + */ + std::vector tokenize(std::string separators, std::string input); + +} // namespace Ghost::Utils diff --git a/template/MyTool.cpp b/template/MyTool.cpp index e589f62..742d1df 100644 --- a/template/MyTool.cpp +++ b/template/MyTool.cpp @@ -1,8 +1,8 @@ #include "MyTool.h" -MyTool::MyTool() : Tool() {} +GhostNAMESPACE::MyTool::MyTool() : Tool() {} -bool MyTool::Initialise(std::string configfile, DataModel& data) { +bool GhostNAMESPACE::MyTool::Initialise(std::string configfile, DataModel& data) { if(configfile != "") m_variables.Initialise(configfile); @@ -17,12 +17,12 @@ bool MyTool::Initialise(std::string configfile, DataModel& data) { return true; } -bool MyTool::Execute() { +bool GhostNAMESPACE::MyTool::Execute() { return true; } -bool MyTool::Finalise() { +bool GhostNAMESPACE::MyTool::Finalise() { return true; } diff --git a/template/MyTool.h b/template/MyTool.h index 8136867..a43be03 100644 --- a/template/MyTool.h +++ b/template/MyTool.h @@ -12,25 +12,32 @@ * * This is a blank template for a Tool used by the script to generate a new custom tool. Please fill out the * description and author information. - * - * $Author: B.Richards $ - * $Date: 2019/05/28 10:44:00 $ */ -class MyTool : public Tool { +namespace GhostNAMESPACE { + class MyTool : public Tool { public: - MyTool(); ///< Simple constructor + //! Simple constructor + MyTool(); + + //! Initialise Function for setting up Tool resources. + /** + * @param + * configfile The path and name of the dynamic configuration file + * to read in. @param data A reference to the transient data + * class used to pass information between Tools. + */ bool Initialise(std::string configfile, - DataModel& data); ///< Initialise Function for setting up Tool resources. @param - ///< configfile The path and name of the dynamic configuration file - ///< to read in. @param data A reference to the transient data - ///< class used to pass information between Tools. - bool Execute(); ///< Execute function used to perform Tool purpose. - bool Finalise(); ///< Finalise funciton used to clean up resources. + DataModel& data); + //! Execute function used to perform Tool purpose. + bool Execute(); + //! Finalise funciton used to clean up resources. + bool Finalise(); private: -}; + }; +} // namespace GhostNAMESPACE #endif