diff --git a/include/RMGHardware.hh b/include/RMGHardware.hh index 3525a46..f7cf45d 100644 --- a/include/RMGHardware.hh +++ b/include/RMGHardware.hh @@ -26,6 +26,7 @@ #include "G4Region.hh" #include "G4VUserDetectorConstruction.hh" +#include "RMGHardwareMessenger.hh" #include "RMGNavigationTools.hh" class G4VPhysicalVolume; @@ -56,6 +57,7 @@ class RMGHardware : public G4VUserDetectorConstruction { }; void RegisterDetector(DetectorType type, const std::string& pv_name, int uid, int copy_nr = 0); + void RegisterDetectorCmd(const std::string& parameters); inline const auto& GetDetectorMetadataMap() { return fDetectorMetadata; } inline const auto& GetDetectorMetadata(std::pair det) { return fDetectorMetadata.at(det); @@ -80,8 +82,10 @@ class RMGHardware : public G4VUserDetectorConstruction { // one element for each sensitive detector physical volume std::map, DetectorMetadata> fDetectorMetadata; std::set fActiveDetectors; + bool fActiveDetectorsInitialized = false; std::unique_ptr fMessenger; + std::unique_ptr fHwMessenger; void DefineCommands(); /// The world volume diff --git a/include/RMGHardwareMessenger.hh b/include/RMGHardwareMessenger.hh new file mode 100644 index 0000000..cc0aa8c --- /dev/null +++ b/include/RMGHardwareMessenger.hh @@ -0,0 +1,39 @@ +// Copyright (C) 2022 Luigi Pertoldi +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . + +#ifndef _RMG_HARDWARE_MESSENGER_HH_ +#define _RMG_HARDWARE_MESSENGER_HH_ + +#include "G4UImessenger.hh" + +class RMGHardware; +class RMGHardwareMessenger : public G4UImessenger { + + public: + + RMGHardwareMessenger(RMGHardware* hw); + ~RMGHardwareMessenger(); + + void SetNewValue(G4UIcommand* command, G4String newValues); + + private: + + RMGHardware* fHardware; + G4UIcommand* fRegisterCmd; +}; + +#endif + +// vim: tabstop=2 shiftwidth=2 expandtab diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 78c768e..d05edbc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,6 +33,7 @@ set(PROJECT_PUBLIC_HEADERS set(PROJECT_SOURCES ${_root}/src/RMGHardware.cc + ${_root}/src/RMGHardwareMessenger.cc ${_root}/src/RMGEventAction.cc ${_root}/src/RMGGeneratorCosmicMuons.cc ${_root}/src/RMGGeneratorUtil.cc diff --git a/src/RMGHardware.cc b/src/RMGHardware.cc index 73faaa3..5b01289 100644 --- a/src/RMGHardware.cc +++ b/src/RMGHardware.cc @@ -23,10 +23,13 @@ namespace fs = std::filesystem; #include "G4LogicalVolume.hh" #include "G4PhysicalVolumeStore.hh" #include "G4SDManager.hh" +#include "G4Tokenizer.hh" +#include "G4UIparameter.hh" #include "G4UserLimits.hh" #include "G4VPhysicalVolume.hh" #include "RMGGermaniumDetector.hh" +#include "RMGHardwareMessenger.hh" #include "RMGLog.hh" #include "RMGNavigationTools.hh" #include "RMGOpticalDetector.hh" @@ -131,6 +134,7 @@ void RMGHardware::ConstructSDandField() { RMGLog::OutFormat(RMGLog::debug, "Registered new sensitive detector volume of type {}: {} (uid={}, lv={})", magic_enum::enum_name(v.type), pv->GetName().c_str(), v.uid, lv->GetName().c_str()); + fActiveDetectorsInitialized = true; } std::string vec_repr = ""; @@ -153,6 +157,11 @@ void RMGHardware::ConstructSDandField() { void RMGHardware::RegisterDetector(DetectorType type, const std::string& pv_name, int uid, int copy_nr) { + if (fActiveDetectorsInitialized) { + RMGLog::Out(RMGLog::error, + "Active detectors cannot be mutated after constructing the detector."); + return; + } // sanity check for (const auto& [k, v] : fDetectorMetadata) { @@ -178,6 +187,24 @@ void RMGHardware::RegisterDetector(DetectorType type, const std::string& pv_name } } +void RMGHardware::RegisterDetectorCmd(const std::string& parameters) { + G4Tokenizer next(parameters); + + auto type_str = next(); + auto type = magic_enum::enum_cast(type_str); + if (!type.has_value()) { + RMGLog::OutFormat(RMGLog::error, "Invalid detector type {} in command", type_str); + return; + } + auto pv_name = next(); + const int uid = std::stoi(next()); + int copy_nr = 0; + auto copy_nr_str = next(); + if (!copy_nr_str.empty()) copy_nr = std::stoi(copy_nr_str); + + this->RegisterDetector(type.value(), pv_name, uid, copy_nr); +} + void RMGHardware::DefineCommands() { fMessenger = std::make_unique(this, "/RMG/Geometry/", @@ -196,7 +223,8 @@ void RMGHardware::DefineCommands() { .SetGuidance("Print list of defined physical volumes") .SetStates(G4State_Idle); - // TODO: RegisterDetector() UI command interface + // RegisterDetector cannot be defined with the G4GenericMessenger (it has to many parameters). + fHwMessenger = std::make_unique(this); } // vim: tabstop=2 shiftwidth=2 expandtab diff --git a/src/RMGHardwareMessenger.cc b/src/RMGHardwareMessenger.cc new file mode 100644 index 0000000..70c9258 --- /dev/null +++ b/src/RMGHardwareMessenger.cc @@ -0,0 +1,52 @@ +// Copyright (C) 2022 Luigi Pertoldi +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . + +#include "RMGHardwareMessenger.hh" + +#include "RMGHardware.hh" + +#ifndef FMT_HEADER_ONLY +#define FMT_HEADER_ONLY +#endif +#include "fmt/core.h" +#include "magic_enum/magic_enum.hpp" + +RMGHardwareMessenger::RMGHardwareMessenger(RMGHardware* hw) : fHardware(hw) { + auto detector_types = magic_enum::enum_names(); + auto options = fmt::format("{}", fmt::join(detector_types, "|")); + + fRegisterCmd = new G4UIcommand("/RMG/Geometry/RegisterDetector", this); + fRegisterCmd->SetGuidance("register a sensitive detector"); + fRegisterCmd->SetGuidance("[usage] /RMG/Geometry/RegisterDetector T PV ID [C]"); + fRegisterCmd->SetGuidance(fmt::format(" T:(str) {}", options).c_str()); + fRegisterCmd->SetGuidance(" PV:(s) physvol"); + fRegisterCmd->SetGuidance(" ID:(int) unique detector id"); + fRegisterCmd->SetGuidance(" C:(int) copy nr (default 0)"); + + fRegisterCmd->SetParameter(new G4UIparameter("type", 's', false)); + fRegisterCmd->SetParameter(new G4UIparameter("pv_name", 's', false)); + fRegisterCmd->SetParameter(new G4UIparameter("uid", 'i', false)); + fRegisterCmd->SetParameter(new G4UIparameter("copy_nr", 'i', true)); + + fRegisterCmd->AvailableForStates(G4State_PreInit); +} + +RMGHardwareMessenger::~RMGHardwareMessenger() { delete fRegisterCmd; } + +void RMGHardwareMessenger::SetNewValue(G4UIcommand* command, G4String newValues) { + if (command == fRegisterCmd) fHardware->RegisterDetectorCmd(newValues); +} + +// vim: tabstop=2 shiftwidth=2 expandtab