Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/intercoms/src/G4GenericMessenger.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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"
 50 #include "G4UIcmdWith3VectorAndUnit.hh"
 51 #include "G4UIcmdWithADoubleAndUnit.hh"
 52 #include "G4UIcommand.hh"
 53 #include "G4UIdirectory.hh"
 54 #include "G4UImessenger.hh"
 55 #include "G4Tokenizer.hh"
 56 
 57 #include <iostream>
 58 
 59 class 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 
 69 G4GenericMessenger::G4GenericMessenger(void* obj, const G4String& dir, const G4String& doc)
 70   : directory(dir), object(obj)
 71 {
 72   dircmd = new G4UIdirectory(dir);
 73   dircmd->SetGuidance(doc);
 74 }
 75 
 76 G4GenericMessenger::~G4GenericMessenger()
 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 
 87 G4GenericMessenger::Command&
 88 G4GenericMessenger::DeclareProperty(const G4String& name, const G4AnyType& var, const G4String& doc)
 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 
125 G4GenericMessenger::Command&
126 G4GenericMessenger::DeclarePropertyWithUnit(const G4String& name, const G4String& defaultUnit,
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 
154 G4GenericMessenger::Command&
155 G4GenericMessenger::DeclareMethod(const G4String& name, const G4AnyMethod& fun, const G4String& doc)
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 
188 G4GenericMessenger::Command& G4GenericMessenger::DeclareMethodWithUnit(const G4String& name,
189                                                                        const G4String& defaultUnit,
190                                                                        const G4AnyMethod& fun,
191                                                                        const G4String& doc)
192 {
193   G4String fullpath = directory + name;
194   if (fun.NArg() != 1) {
195     G4ExceptionDescription ed;
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 
212 G4String G4GenericMessenger::GetCurrentValue(G4UIcommand* command)
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 
228 void G4GenericMessenger::SetNewValue(G4UIcommand* command, G4String newValue)
229 {
230   // Check if there are units on this commands
231   if (typeid(*command) == typeid(G4UIcmdWithADoubleAndUnit)) {
232     newValue = G4UIcommand::ConvertToString(G4UIcommand::ConvertToDimensionedDouble(newValue));
233   }
234   else if (typeid(*command) == typeid(G4UIcmdWith3VectorAndUnit)) {
235     newValue = G4UIcommand::ConvertToString(G4UIcommand::ConvertToDimensioned3Vector(newValue));
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 
276 void G4GenericMessenger::SetGuidance(const G4String& s)
277 {
278   dircmd->SetGuidance(s);
279 }
280 
281 G4GenericMessenger::Command& G4GenericMessenger::Command::SetUnit(const G4String& unit,
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
287   if (G4Threading::IsMultithreadedApplication()) {
288     G4String cmdpath = command->GetCommandPath();
289     G4ExceptionDescription ed;
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;
314   G4String par_name = command->GetParameter(0)->GetParameterName();
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) {
352     command->SetGuidance(i);
353   }
354   command->SetRange(range);
355   return *this;
356 }
357 
358 G4GenericMessenger::Command& G4GenericMessenger::Command::SetParameterName(const G4String& name,
359                                                                            G4bool omittable,
360                                                                            G4bool currentAsDefault)
361 {
362   return SetParameterName(0, name, omittable, currentAsDefault);
363 }
364 
365 G4GenericMessenger::Command& G4GenericMessenger::Command::SetParameterName(G4int pIdx,
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 
381 G4GenericMessenger::Command& G4GenericMessenger::Command::SetParameterName(const G4String& namex,
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 
407 G4GenericMessenger::Command& G4GenericMessenger::Command::SetCandidates(const G4String& candList)
408 {
409   return SetCandidates(0, candList);
410 }
411 
412 G4GenericMessenger::Command& G4GenericMessenger::Command::SetCandidates(G4int pIdx,
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 
424 G4GenericMessenger::Command& G4GenericMessenger::Command::SetDefaultValue(const G4String& defVal)
425 {
426   return SetDefaultValue(0, defVal);
427 }
428 
429 G4GenericMessenger::Command& G4GenericMessenger::Command::SetDefaultValue(G4int pIdx,
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 }
440