// // ******************************************************************** // * License and Disclaimer * // * * // * The Geant4 software is copyright of the Copyright Holders of * // * the Geant4 Collaboration. It is provided under the terms and * // * conditions of the Geant4 Software License, included in the file * // * LICENSE and available at http://cern.ch/geant4/license . These * // * include a list of copyright holders. * // * * // * Neither the authors of this software system, nor their employing * // * institutes,nor the agencies providing financial support for this * // * work make any representation or warranty, express or implied, * // * regarding this software system or assume any liability for its * // * use. Please see the license in the file LICENSE and URL above * // * for the full disclaimer and the limitation of liability. * // * * // * This code implementation is the result of the scientific and * // * technical work of the GEANT4 collaboration. * // * By using, copying, modifying or distributing the software (or * // * any work based on the software) you agree to acknowledge its * // * use in resulting scientific publications, and indicate your * // * acceptance of all terms of the Geant4 Software license. * // ******************************************************************** // // Author: Ivana Hrivnacova, 26/08/2022 (ivana@ipno.in2p3.fr) #include "G4AnalysisUtilities.hh" #include "G4UIdirectory.hh" #include "G4UIcommand.hh" #include "G4UIparameter.hh" #include "G4Tokenizer.hh" #include using namespace G4Analysis; //_____________________________________________________________________________ template G4THnMessenger::G4THnMessenger(G4THnToolsManager* manager) : fManager(manager) { CreateDirectory(); CreateCmd(); SetCmd(); for (unsigned int idim = 0; idim < DIM; ++idim) { fSetDimensionCmd[idim] = CreateSetBinsCommand(idim); } DeleteCmd(); CreateSetTitleCommand(); auto maxDim = (DIM < kMaxDim) ? DIM + 1 : kMaxDim; for (unsigned int idim = 0; idim < maxDim; ++idim) { fSetAxisCmd[idim] = CreateSetAxisCommand(idim); } CreateListCommand(); CreateGetCommand(); CreateGetVectorCommand(); // Initialize data for (unsigned int idim = 0; idim < DIM; ++idim) { fTmpId[idim] = G4Analysis::kInvalidId; fTmpBins[idim] = G4HnDimension(); fTmpInfo[idim] = G4HnDimensionInformation(); } } // // private functions // //_____________________________________________________________________________ template G4String G4THnMessenger::GetObjectType() const { return (G4Analysis::IsProfile()) ? std::to_string(DIM - 1) + "D profile " : std::to_string(DIM) + "D histogram"; } //_____________________________________________________________________________ template G4bool G4THnMessenger::IsProfileLastDimension(unsigned int idim) const { return (idim == DIM - 1) && (G4Analysis::IsProfile()); } //_____________________________________________________________________________ template std::unique_ptr G4THnMessenger::CreateCommand( G4String name, G4String guidance) { G4String fullName = "/analysis/" + G4Analysis::GetHnType() + "/" + name; G4String fullGuidance = guidance + GetObjectType(); auto command = std::make_unique(fullName, this); command->SetGuidance(fullGuidance); return command; } //_____________________________________________________________________________ template void G4THnMessenger::CreateDimensionParameters( unsigned int idim, std::vector& parameters) const { // Create [nbins], valMin, valMax, valUnit, valFcn, [valBinScheme] parameters. // The parameters in [] are omitted for the last dimension for profiles std::string xyz{"xyz"}; std::string axis = xyz.substr(idim, 1); if (! IsProfileLastDimension(idim)) { auto parName = axis + "nBins"; auto guidance = std::string("Number of ") + axis + "-bins (default = 100)\n" "Can be reset with /analysis/hn/set command"; auto param = new G4UIparameter(parName.c_str(), 'i', false); param->SetGuidance(guidance.c_str()); param->SetDefaultValue(100); parameters.push_back(param); } auto parName = axis + "valMin"; auto guidance = std::string("Minimum ") + axis + "-value, expressed in unit (default = 0.)\n" "Can be reset with /analysis/hn/set command"; auto param = new G4UIparameter(parName.c_str(), 'd', false); param->SetGuidance(guidance.c_str()); param->SetDefaultValue(0.); parameters.push_back(param); parName = axis + "valMax"; guidance = std::string("Maximum ") + axis + "-value, expressed in unit (default = 1.)\n" "Can be reset with /analysis/hn/set command"; param = new G4UIparameter(parName.c_str(), 'd', false); param->SetGuidance(guidance.c_str()); param->SetDefaultValue(1.); parameters.push_back(param); parName = axis + "valUnit"; guidance = std::string("The unit applied to filled ") + axis + "-values and \n" "Can be reset with /analysis/hn/set command"; param = new G4UIparameter(parName.c_str(), 's', true); param->SetGuidance(guidance.c_str()); param->SetDefaultValue("none"); parameters.push_back(param); parName = axis + "valFcn"; guidance = std::string("The function applied to filled ") + axis + "-values (log, log10, exp, none).\n" "Note that the unit parameter cannot be omitted in this case,\n" "but none value should be used instead."; param = new G4UIparameter(parName.c_str(), 's', true); param->SetGuidance(guidance.c_str()); param->SetParameterCandidates("log log10 exp none"); param->SetDefaultValue("none"); parameters.push_back(param); if (! IsProfileLastDimension(idim)) { parName = axis + "valBinScheme"; guidance = std::string("The binning scheme (linear, log).\n" "Note that the unit and fcn parameters cannot be omitted in this case,\n" "but none value should be used instead."); param = new G4UIparameter(parName.c_str(), 's', true); param->SetGuidance(guidance.c_str()); param->SetParameterCandidates("linear log"); param->SetDefaultValue("linear"); parameters.push_back(param); } } //_____________________________________________________________________________ template void G4THnMessenger::AddIdParameter(G4UIcommand& command) { // add parameter auto htId = new G4UIparameter("id", 'i', false); htId->SetGuidance("Histogram id"); htId->SetParameterRange("id>=0"); command.SetParameter(htId); } //_____________________________________________________________________________ template G4String G4THnMessenger::GetTAddress(G4int id) const { auto ht = fManager->GetT(id); if ( ht != nullptr ) { std::ostringstream os; os << static_cast(ht); return os.str(); } return {}; } //_____________________________________________________________________________ template G4String G4THnMessenger::GetTVectorAddress() const { auto htVector = fManager->GetTVector(); if ( htVector != nullptr ) { std::ostringstream os; os << static_cast(htVector); return os.str(); } return {}; } //_____________________________________________________________________________ template void G4THnMessenger::CreateDirectory() { G4String dirName = "/analysis/" + G4Analysis::GetHnType() + "/"; G4String guidance = GetObjectType() + " control"; fHnDir = std::make_unique(dirName); fHnDir->SetGuidance(guidance.c_str()); } //_____________________________________________________________________________ template void G4THnMessenger::CreateCmd() { fCreateCmd = CreateCommand("create", "Create "); fCreateCmd->AvailableForStates(G4State_PreInit, G4State_Idle); auto htName = new G4UIparameter("name", 's', false); htName->SetGuidance("Histogram name (label)"); fCreateCmd->SetParameter(htName); auto htTitle = new G4UIparameter("title", 's', false); htTitle->SetGuidance("Histogram title"); fCreateCmd->SetParameter(htTitle); std::vector parameters; for (unsigned int idim = 0; idim < DIM; ++idim) { CreateDimensionParameters(idim, parameters); for (size_t ipar = 0; ipar < parameters.size(); ++ipar) { // the first three parameters can be omittes in create command if (ipar < 3) parameters[ipar]->SetOmittable(true); fCreateCmd->SetParameter(parameters[ipar]); } parameters.clear(); } } //_____________________________________________________________________________ template void G4THnMessenger::SetCmd() { fSetCmd = CreateCommand("set", "Set "); fSetCmd->AvailableForStates(G4State_PreInit, G4State_Idle); // Add Id parameter AddIdParameter(*fSetCmd); // Update guidance fSetCmd->SetGuidance("\n nbins; valMin; valMax; unit; function; binScheme"); std::vector parameters; for (unsigned int idim = 0; idim < DIM; ++idim) { CreateDimensionParameters(idim, parameters); for (auto parameter: parameters) { fSetCmd->SetParameter(parameter); } parameters.clear(); } } //_____________________________________________________________________________ template void G4THnMessenger::DeleteCmd() { fDeleteCmd = CreateCommand("delete", "Delete "); fDeleteCmd->AvailableForStates(G4State_PreInit, G4State_Idle); // Add Id parameter AddIdParameter(*fDeleteCmd); auto parKeepSetting = new G4UIparameter("keepSetting", 'b', true); G4String guidance = "If set true, activation, plotting, etc. options will be kept\n" "and applied when a new object with the same id is created."; parKeepSetting->SetGuidance(guidance.c_str()); parKeepSetting->SetDefaultValue("false"); fDeleteCmd->SetParameter(parKeepSetting); } //_____________________________________________________________________________ template std::unique_ptr G4THnMessenger::CreateSetBinsCommand(unsigned int idim) { G4String xyz{"XYZ"}; auto axis = xyz.substr(idim, 1); auto command = CreateCommand("set" + axis, "Set " + axis + " parameters for the "); command->AvailableForStates(G4State_PreInit, G4State_Idle); // Add Id parameter AddIdParameter(*command); // Update guidance G4String guidance = "\n nAXISbins; AXISvalMin; AXISvalMax; AXISunit; AXISfunction; AXISbinScheme"; // update AXIS with xyz std::string::size_type n = 0; std::string ts{"AXIS"}; while ( ( n = guidance.find(ts, n)) != std::string::npos ) { guidance.replace(n, ts.size(), axis); n += ts.size(); } command->SetGuidance(guidance); std::vector parameters; CreateDimensionParameters(idim, parameters); for (auto parameter: parameters) { command->SetParameter(parameter); } return command; } //_____________________________________________________________________________ template void G4THnMessenger::CreateSetTitleCommand() { fSetTitleCmd = CreateCommand("setTitle", "Set title for the "); fSetTitleCmd->AvailableForStates(G4State_PreInit, G4State_Idle); // Add Id parameter AddIdParameter(*fSetTitleCmd); auto parTitle = new G4UIparameter("title", 's', true); auto guidance = GetObjectType() + " title"; parTitle->SetGuidance(guidance.c_str()); parTitle->SetDefaultValue("none"); fSetTitleCmd->SetParameter(parTitle); } //_____________________________________________________________________________ template std::unique_ptr G4THnMessenger::CreateSetAxisCommand(unsigned int idim) { G4String xyz{"XYZ"}; auto axis = xyz.substr(idim, 1); G4String commandName = "set" + axis + "axis"; G4String guidance = "Set " + axis + "-axis title for the ";; auto command = CreateCommand(std::move(commandName), guidance); command->AvailableForStates(G4State_PreInit, G4State_Idle); // Add Id parameter AddIdParameter(*command); auto parAxis = new G4UIparameter("axis", 's', false); guidance = GetObjectType() + " " + std::move(axis) + "-axis title"; parAxis->SetGuidance(guidance.c_str()); command->SetParameter(parAxis); return command; } //_____________________________________________________________________________ template void G4THnMessenger::CreateListCommand() { fListCmd = CreateCommand("list", "List all/activate "); fListCmd->AvailableForStates(G4State_Idle, G4State_GeomClosed, G4State_EventProc); auto parOnlyIfActive = new G4UIparameter("onlyIfActive", 'b', true); parOnlyIfActive->SetGuidance("Option whether to list only active objects"); parOnlyIfActive->SetDefaultValue("true"); fListCmd->SetParameter(parOnlyIfActive); } //_____________________________________________________________________________ template void G4THnMessenger::CreateGetCommand() { fGetTCmd = CreateCommand("get", "Get the address of the "); fGetTCmd->SetGuidance( "This command is only for Geant4 internal use."); fGetTCmd->AvailableForStates(G4State_Idle, G4State_GeomClosed, G4State_EventProc); // Add Id parameter AddIdParameter(*fGetTCmd); } //_____________________________________________________________________________ template void G4THnMessenger::CreateGetVectorCommand() { fGetTVectorCmd = CreateCommand("getVector", "Get the address of the vector of the "); fGetTVectorCmd->SetGuidance( "This command is only for Geant4 internal use."); fGetTVectorCmd->AvailableForStates(G4State_Idle, G4State_GeomClosed, G4State_EventProc); } //_____________________________________________________________________________ template void G4THnMessenger::GetBinData( unsigned int idim, G4int& counter, const std::vector& parameters, G4HnDimension& bins) const { G4int nbins = (! IsProfileLastDimension(idim)) ? G4UIcommand::ConvertToInt(parameters[counter++]) : 0; bins = {nbins, G4UIcommand::ConvertToDouble(parameters[counter]), G4UIcommand::ConvertToDouble(parameters[counter + 1])}; counter += 2; } //_____________________________________________________________________________ template void G4THnMessenger::GetBinInfoData( unsigned int idim, G4int& counter, const std::vector& parameters, G4HnDimension& bins, G4HnDimensionInformation& info) const { // get bin data (this will shift the counter for hnInfo data) GetBinData(idim, counter, parameters, bins); // get dimension information data if (! IsProfileLastDimension(idim)) { info = {parameters[counter], parameters[counter + 1], parameters[counter + 2]}; counter += 3; } else { info = {parameters[counter], parameters[counter + 1]}; counter += 2; } // apply unit to minValue and maxValue bins.fMinValue *= info.fUnit; bins.fMaxValue *= info.fUnit; } //_____________________________________________________________________________ template void G4THnMessenger::GetData( G4int& counter, const std::vector& parameters, std::array& bins, std::array& info) const { for (unsigned int idim = 0; idim < DIM; ++idim) { // get bin data (this will shift the counter for hnInfo data) GetBinInfoData(idim, counter, parameters, bins[idim], info[idim]); } } // // public functions // //_____________________________________________________________________________ template G4String G4THnMessenger::GetCurrentValue (G4UIcommand* command) { if ( command == fGetTCmd.get() ) return fTValue; if ( command == fGetTVectorCmd.get() ) return fTVectorValue; return ""; } //_____________________________________________________________________________ template void G4THnMessenger::SetNewValue(G4UIcommand* command, G4String newValues) { // tokenize parameters in a vector std::vector parameters; G4Analysis::Tokenize(newValues, parameters); // check consistency if ( parameters.size() != command->GetParameterEntries() ) { // Should never happen but let's check anyway for consistency G4Analysis::Warn( "Got wrong number of \"" + command->GetCommandName() + "\" parameters: " + to_string(parameters.size()) + " instead of " + to_string(command->GetParameterEntries()) + " expected", fkClass, "WarnAboutParameters"); return; } std::array bins; std::array info; if ( command == fCreateCmd.get() ) { auto counter = 0; const auto& name = parameters[counter++]; const auto& title = parameters[counter++]; GetData(counter, parameters, bins, info); fManager->Create(name, title, bins, info); return; } if ( command == fSetCmd.get() ) { auto counter = 0; const auto& id = G4UIcommand::ConvertToInt(parameters[counter++]); GetData(counter, parameters, bins, info); fManager->Set(id, bins, info); return; } if ( command == fDeleteCmd.get() ) { auto counter = 0; const auto& id = G4UIcommand::ConvertToInt(parameters[counter++]); const auto& keepSetting = G4UIcommand::ConvertToBool(parameters[counter++]); fManager->Delete(id, keepSetting); return; } if ( command == fSetTitleCmd.get() ) { auto counter = 0; const auto& id = G4UIcommand::ConvertToInt(parameters[counter++]); const auto& title = parameters[counter++]; fManager->SetTitle(id, title); return; } for (unsigned int idim = 0; idim < DIM; ++idim) { if ( command == fSetDimensionCmd[idim].get() ) { auto counter = 0; fTmpId[idim] = G4UIcommand::ConvertToInt(parameters[counter++]); GetBinInfoData(idim, counter, parameters, fTmpBins[idim], fTmpInfo[idim]); if ( DIM > 1 && idim > 0) { // the setX, setY, setZ must be apply consequently if (fTmpId[idim - 1] != fTmpId[idim]) { G4Analysis::Warn( "Command setX, setY, setZ must be called successively in this order.\n" "Command was ignored.", fkClass, "SetNewValue"); return; } } if ( idim == DIM - 1) { // Apply parameters when all dimensions are set fManager->Set(fTmpId[idim], fTmpBins, fTmpInfo); return; } } } if ( command == fSetTitleCmd.get() ) { auto counter = 0; const auto& id = G4UIcommand::ConvertToInt(parameters[counter++]); const auto& title = parameters[counter++]; fManager->SetTitle(id, title); return; } auto maxDim = (DIM < kMaxDim) ? DIM + 1 : kMaxDim; for (unsigned int idim = 0; idim < maxDim; ++idim) { if ( command == fSetAxisCmd[idim].get() ) { auto counter = 0; const auto& id = G4UIcommand::ConvertToInt(parameters[counter++]); const auto& axisTitle = parameters[counter++]; fManager->SetAxisTitle(idim, id, axisTitle); return; } } if ( command == fListCmd.get() ) { auto onlyIfActive = G4UIcommand::ConvertToBool(parameters[0]); fManager->List(G4cout, onlyIfActive); return; } if ( command == fGetTCmd.get() ) { const auto& id = G4UIcommand::ConvertToInt(newValues); fTValue = GetTAddress(id); return; } if ( command == fGetTVectorCmd.get() ) { fTVectorValue = GetTVectorAddress(); return; } }