Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4GenericMessenger.cc
Go to the documentation of this file.
1// ********************************************************************
2// * License and Disclaimer *
3// * *
4// * The Geant4 software is copyright of the Copyright Holders of *
5// * the Geant4 Collaboration. It is provided under the terms and *
6// * conditions of the Geant4 Software License, included in the file *
7// * LICENSE and available at http://cern.ch/geant4/license . These *
8// * include a list of copyright holders. *
9// * *
10// * Neither the authors of this software system, nor their employing *
11// * institutes,nor the agencies providing financial support for this *
12// * work make any representation or warranty, express or implied, *
13// * regarding this software system or assume any liability for its *
14// * use. Please see the license in the file LICENSE and URL above *
15// * for the full disclaimer and the limitation of liability. *
16// * *
17// * This code implementation is the result of the scientific and *
18// * technical work of the GEANT4 collaboration. *
19// * By using, copying, modifying or distributing the software (or *
20// * any work based on the software) you agree to acknowledge its *
21// * use in resulting scientific publications, and indicate your *
22// * acceptance of all terms of the Geant4 Software license. *
23// ********************************************************************
24//
25// G4GenericMessenger
26//
27// Author:
28// P.Mato, CERN - 27 September 2012
29// Updates:
30// M.Asai, SLAC - 26 November 2013
31// Adding methods with unit declaration and making thread-safe for
32// version 10.
33// M.Asai, SLAC - 04 May 2014
34// Fix core dump when GetCurrentValue() method is invoked for
35// a command defined by DeclareMethod().
36// M.Asai, SLAC - 30 September 2020
37// Adding new parameter type 'L' for long int.
38// M.Asai, SLAC - 11 July 2021
39// Adding G4ThreeVector type without unit
40// M.Asai, JLab - 24 April 2024
41// Fix DeclareMethod() wrongly converts valid boolean parameters.
42// --------------------------------------------------------------------
43
44#include "G4GenericMessenger.hh"
45
46#include "G4Threading.hh"
47#include "G4Types.hh"
48#include "G4UIcmdWithABool.hh"
49#include "G4UIcmdWith3Vector.hh"
52#include "G4UIcommand.hh"
53#include "G4UIdirectory.hh"
54#include "G4UImessenger.hh"
55#include "G4Tokenizer.hh"
56
57#include <iostream>
58
59class G4InvalidUICommand : public std::bad_cast
60{
61 public:
62 G4InvalidUICommand() = default;
63 const char* what() const throw() override
64 {
65 return "G4InvalidUICommand: command does not exist or is of invalid type";
66 }
67};
68
70 : directory(dir), object(obj)
71{
72 dircmd = new G4UIdirectory(dir);
73 dircmd->SetGuidance(doc);
74}
75
77{
78 delete dircmd;
79 for (const auto& propertie : properties) {
80 delete propertie.second.command;
81 }
82 for (const auto& method : methods) {
83 delete method.second.command;
84 }
85}
86
89{
90 G4String fullpath = directory + name;
91 G4UIcommand* cmd = nullptr;
92 if (var.TypeInfo() == typeid(G4ThreeVector)) {
93 cmd = new G4UIcmdWith3Vector(fullpath.c_str(), this);
94 (static_cast<G4UIcmdWith3Vector*>(cmd))
95 ->SetParameterName("valueX", "valueY", "valueZ", false, false);
96 }
97 else {
98 cmd = new G4UIcommand(fullpath.c_str(), this);
99 char ptype;
100 if (var.TypeInfo() == typeid(int) || var.TypeInfo() == typeid(long)
101 || var.TypeInfo() == typeid(unsigned int) || var.TypeInfo() == typeid(unsigned long))
102 {
103 ptype = 'i';
104 }
105 else if (var.TypeInfo() == typeid(float) || var.TypeInfo() == typeid(double)) {
106 ptype = 'd';
107 }
108 else if (var.TypeInfo() == typeid(bool)) {
109 ptype = 'b';
110 }
111 else if (var.TypeInfo() == typeid(G4String)) {
112 ptype = 's';
113 }
114 else {
115 ptype = 's';
116 }
117 cmd->SetParameter(new G4UIparameter("value", ptype, false));
118 }
119 if (!doc.empty()) {
120 cmd->SetGuidance(doc);
121 }
122 return properties[name] = Property(var, cmd);
123}
124
127 const G4AnyType& var, const G4String& doc)
128{
129 if (var.TypeInfo() != typeid(float) && var.TypeInfo() != typeid(double)
130 && var.TypeInfo() != typeid(G4ThreeVector))
131 {
132 return DeclareProperty(name, var, doc);
133 }
134 G4String fullpath = directory + name;
135 G4UIcommand* cmd;
136 if (var.TypeInfo() == typeid(float) || var.TypeInfo() == typeid(double)) {
137 cmd = new G4UIcmdWithADoubleAndUnit(fullpath.c_str(), this);
138 (static_cast<G4UIcmdWithADoubleAndUnit*>(cmd))->SetParameterName("value", false, false);
139 (static_cast<G4UIcmdWithADoubleAndUnit*>(cmd))->SetDefaultUnit(defaultUnit);
140 }
141 else {
142 cmd = new G4UIcmdWith3VectorAndUnit(fullpath.c_str(), this);
143 (static_cast<G4UIcmdWith3VectorAndUnit*>(cmd))
144 ->SetParameterName("valueX", "valueY", "valueZ", false, false);
145 (static_cast<G4UIcmdWith3VectorAndUnit*>(cmd))->SetDefaultUnit(defaultUnit);
146 }
147
148 if (!doc.empty()) {
149 cmd->SetGuidance(doc);
150 }
151 return properties[name] = Property(var, cmd);
152}
153
156{
157 G4String fullpath = directory + name;
158 auto* cmd = new G4UIcommand(fullpath.c_str(), this);
159 if (!doc.empty()) {
160 cmd->SetGuidance(doc);
161 }
162 for (std::size_t i = 0; i < fun.NArg(); ++i) {
163 G4String argNam = "arg" + ItoS((G4int)i);
164 char ptype = 's';
165 auto& tInfo = fun.ArgType(i);
166 if (tInfo == typeid(int) || tInfo == typeid(long) || tInfo == typeid(unsigned int)
167 || tInfo == typeid(unsigned long))
168 {
169 ptype = 'i';
170 }
171 else if (tInfo == typeid(float) || tInfo == typeid(double)) {
172 ptype = 'd';
173 }
174 else if (tInfo == typeid(bool)) {
175 ptype = 'b';
176 }
177 else if (tInfo == typeid(G4String)) {
178 ptype = 's';
179 }
180 else {
181 ptype = 's';
182 }
183 cmd->SetParameter(new G4UIparameter(argNam, ptype, false));
184 }
185 return methods[name] = Method(fun, object, cmd);
186}
187
189 const G4String& defaultUnit,
190 const G4AnyMethod& fun,
191 const G4String& doc)
192{
193 G4String fullpath = directory + name;
194 if (fun.NArg() != 1) {
196 ed << "G4GenericMessenger::DeclareMethodWithUnit() does not support a "
197 "method that has more than\n"
198 << "one arguments (or no argument). Please use "
199 "G4GenericMessenger::DeclareMethod method for\n"
200 << "your command <" << fullpath << ">.";
201 G4Exception("G4GenericMessenger::DeclareMethodWithUnit()", "Intercom70002", FatalException, ed);
202 }
203 G4UIcommand* cmd = new G4UIcmdWithADoubleAndUnit(fullpath.c_str(), this);
204 (static_cast<G4UIcmdWithADoubleAndUnit*>(cmd))->SetParameterName("value", false, false);
205 (static_cast<G4UIcmdWithADoubleAndUnit*>(cmd))->SetDefaultUnit(defaultUnit);
206 if (!doc.empty()) {
207 cmd->SetGuidance(doc);
208 }
209 return methods[name] = Method(fun, object, cmd);
210}
211
213{
214 if (properties.find(command->GetCommandName()) != properties.cend()) {
215 Property& p = properties[command->GetCommandName()];
216 return p.variable.ToString();
217 }
218 if (methods.find(command->GetCommandName()) != methods.cend()) {
219 G4cout << " GetCurrentValue() is not available for a command defined by "
220 "G4GenericMessenger::DeclareMethod()."
221 << G4endl;
222 return G4String();
223 }
224
225 throw G4InvalidUICommand();
226}
227
229{
230 // Check if there are units on this commands
231 if (typeid(*command) == typeid(G4UIcmdWithADoubleAndUnit)) {
233 }
234 else if (typeid(*command) == typeid(G4UIcmdWith3VectorAndUnit)) {
236 }
237 else if (typeid(*command) == typeid(G4UIcmdWithABool)) {
238 if(StoB(newValue)) {
239 newValue = "1";
240 } else {
241 newValue = "0";
242 }
243 }
244
245 if (properties.find(command->GetCommandName()) != properties.cend()) {
246 Property& p = properties[command->GetCommandName()];
247 p.variable.FromString(newValue);
248 }
249 else if (methods.find(command->GetCommandName()) != methods.cend()) {
250 Method& m = methods[command->GetCommandName()];
251 if (m.method.NArg() == 0) {
252 m.method.operator()(m.object);
253 }
254 else if (m.method.NArg() > 0) {
255 G4Tokenizer tokens(newValue);
256 G4String paraValue;
257 for (std::size_t i = 0; i < m.method.NArg(); ++i) {
258 G4String aToken = tokens();
259 if(m.method.ArgType(i)==typeid(bool)) {
260 if(StoB(aToken)) {
261 aToken = "1";
262 } else {
263 aToken = "0";
264 }
265 }
266 paraValue += aToken + " ";
267 }
268 m.method.operator()(m.object, paraValue);
269 }
270 else {
271 throw G4InvalidUICommand();
272 }
273 }
274}
275
277{
278 dircmd->SetGuidance(s);
279}
280
282 UnitSpec spec)
283{
284 // Change the type of command (unfortunatelly this is done a posteriory)
285 // We need to delete the old command before creating the new one and therefore
286 // we need to recover the information before the deletetion
288 G4String cmdpath = command->GetCommandPath();
290 ed << "G4GenericMessenger::Command::SetUnit() is thread-unsafe and should "
291 "not be used\n"
292 << "in multi-threaded mode. For your command <" << cmdpath << ">, use\n"
293 << " DeclarePropertyWithUnit(const G4String& name, const G4String& "
294 "defaultUnit,\n"
295 << " const G4AnyType& variable, const G4String& "
296 "doc)\n"
297 << "or\n"
298 << " DeclareMethodWithUnit(const G4String& name, const G4String& "
299 "defaultUnit,\n"
300 << " const G4AnyType& variable, const G4String& "
301 "doc)\n"
302 << "to define a command with a unit <" << unit << ">.";
303 if (spec != UnitDefault) {
304 ed << "\nPlease use a default unit instead of unit category.";
305 }
306 G4Exception("G4GenericMessenger::Command::SetUnit()", "Intercom70001", FatalException, ed);
307 return *this;
308 }
309
310 G4String cmdpath = command->GetCommandPath();
311 G4UImessenger* messenger = command->GetMessenger();
312 G4String range = command->GetRange();
313 std::vector<G4String> guidance;
315 G4bool par_omitable = command->GetParameter(0)->IsOmittable();
316 for (G4int i = 0; i < (G4int)command->GetGuidanceEntries(); ++i) {
317 guidance.push_back(command->GetGuidanceLine(i));
318 }
319 // Before deleting the command we need to add a fake one to avoid deleting
320 // the directory entry and with its guidance
321 G4UIcommand tmp((cmdpath + "_tmp").c_str(), messenger);
322 delete command;
323
324 if (*type == typeid(float) || *type == typeid(double)) {
325 auto* cmd_t = new G4UIcmdWithADoubleAndUnit(cmdpath, messenger);
326 if (spec == UnitDefault) {
327 cmd_t->SetDefaultUnit(unit);
328 }
329 else if (spec == UnitCategory) {
330 cmd_t->SetUnitCategory(unit);
331 }
332 cmd_t->SetParameterName(par_name, par_omitable);
333 command = cmd_t;
334 }
335 else if (*type == typeid(G4ThreeVector)) {
336 auto* cmd_t = new G4UIcmdWith3VectorAndUnit(cmdpath, messenger);
337 if (spec == UnitDefault) {
338 cmd_t->SetDefaultUnit(unit);
339 }
340 else if (spec == UnitCategory) {
341 cmd_t->SetUnitCategory(unit);
342 }
343 command = cmd_t;
344 }
345 else {
346 G4cerr << "Only parameters of type <double> or <float> can be associated "
347 "with units"
348 << G4endl;
349 return *this;
350 }
351 for (auto& i : guidance) {
353 }
354 command->SetRange(range);
355 return *this;
356}
357
359 G4bool omittable,
360 G4bool currentAsDefault)
361{
362 return SetParameterName(0, name, omittable, currentAsDefault);
363}
364
366 const G4String& name,
367 G4bool omittable,
368 G4bool currentAsDefault)
369{
370 if (pIdx < 0 || pIdx >= (G4int)(command->GetParameterEntries())) {
371 G4cerr << "Invalid parameter index : " << pIdx << "\nMethod ignored." << G4endl;
372 return *this;
373 }
374 G4UIparameter* theParam = command->GetParameter(pIdx);
375 theParam->SetParameterName(name);
376 theParam->SetOmittable(omittable);
377 theParam->SetCurrentAsDefault(currentAsDefault);
378 return *this;
379}
380
382 const G4String& namey,
383 const G4String& namez,
384 G4bool omittable,
385 G4bool currentAsDefault)
386{
387 if (*type != typeid(G4ThreeVector)) {
388 G4cerr << "This SetParameterName method is for G4ThreeVector!! "
389 << "Method ignored." << G4endl;
390 return *this;
391 }
392 G4UIparameter* theParam = command->GetParameter(0);
393 theParam->SetParameterName(namex);
394 theParam->SetOmittable(omittable);
395 theParam->SetCurrentAsDefault(currentAsDefault);
396 theParam = command->GetParameter(1);
397 theParam->SetParameterName(namey);
398 theParam->SetOmittable(omittable);
399 theParam->SetCurrentAsDefault(currentAsDefault);
400 theParam = command->GetParameter(2);
401 theParam->SetParameterName(namez);
402 theParam->SetOmittable(omittable);
403 theParam->SetCurrentAsDefault(currentAsDefault);
404 return *this;
405}
406
408{
409 return SetCandidates(0, candList);
410}
411
413 const G4String& candList)
414{
415 if (pIdx < 0 || pIdx >= (G4int)(command->GetParameterEntries())) {
416 G4cerr << "Invalid parameter index : " << pIdx << "\nMethod ignored." << G4endl;
417 return *this;
418 }
419 G4UIparameter* theParam = command->GetParameter(pIdx);
420 theParam->SetParameterCandidates(candList);
421 return *this;
422}
423
425{
426 return SetDefaultValue(0, defVal);
427}
428
430 const G4String& defVal)
431{
432 if (pIdx < 0 || pIdx >= (G4int)(command->GetParameterEntries())) {
433 G4cerr << "Invalid parameter index : " << pIdx << "\nMethod ignored." << G4endl;
434 return *this;
435 }
436 G4UIparameter* theParam = command->GetParameter(pIdx);
437 theParam->SetDefaultValue(defVal);
438 return *this;
439}
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
std::size_t NArg() const
const std::type_info & ArgType(size_t n=0) const
void FromString(const std::string &val)
Definition G4AnyType.hh:126
const std::type_info & TypeInfo() const
Definition G4AnyType.hh:113
std::string ToString() const
Definition G4AnyType.hh:124
Command & DeclareMethod(const G4String &name, const G4AnyMethod &fun, const G4String &doc="")
void SetGuidance(const G4String &s)
Command & DeclareProperty(const G4String &name, const G4AnyType &variable, const G4String &doc="")
Command & DeclareMethodWithUnit(const G4String &name, const G4String &defaultUnit, const G4AnyMethod &fun, const G4String &doc="")
G4GenericMessenger(void *obj, const G4String &dir="", const G4String &doc="")
void SetNewValue(G4UIcommand *command, G4String newValue) override
G4String GetCurrentValue(G4UIcommand *command) override
Command & DeclarePropertyWithUnit(const G4String &name, const G4String &defaultUnit, const G4AnyType &variable, const G4String &doc="")
G4InvalidUICommand()=default
const char * what() const override
G4UImessenger * GetMessenger() const
const G4String & GetGuidanceLine(G4int i) const
G4UIparameter * GetParameter(G4int i) const
static G4String ConvertToString(G4bool boolVal)
const G4String & GetCommandPath() const
void SetParameter(G4UIparameter *const newParameter)
void SetGuidance(const char *aGuidance)
std::size_t GetGuidanceEntries() const
void SetRange(const char *rs)
static G4double ConvertToDimensionedDouble(const char *st)
const G4String & GetCommandName() const
const G4String & GetRange() const
static G4ThreeVector ConvertToDimensioned3Vector(const char *st)
G4String ItoS(G4int i)
G4bool StoB(G4String s)
void SetDefaultValue(const char *theDefaultValue)
void SetParameterName(const char *pName)
G4bool IsOmittable() const
void SetOmittable(G4bool om)
void SetParameterCandidates(const char *theString)
void SetCurrentAsDefault(G4bool val)
const G4String & GetParameterName() const
G4bool IsMultithreadedApplication()
Command & SetParameterName(const G4String &, G4bool, G4bool=false)
Command & SetCandidates(const G4String &)
Command & SetDefaultValue(const G4String &)
Command & SetUnit(const G4String &, UnitSpec=UnitDefault)