Contents Previous Next Geant4 User's Guide
For Application Developers
Communication and Control


7.2 User Interface - Defining New Commands


7.2.1 G4UImessenger

G4UImessenger is a base class which represents a messenger that delivers command(s) to the destination class object. Your concrete messenger should have the following functionalities. These requirements mean that your messenger should keep all pointers to your command objects as its data members.

You can use G4UIcommand derived classes for the most frequent types of command. These derived classes have their own conversion methods according to their types, and they make implementation of the SetNewValue() and GetCurrentValue() methods of your messenger much easier and simpler.

For complicated commands which take various parameters, you can use the G4UIcommand base class, and construct G4UIparameter objects by yourself. You don't need to delete G4UIparameter object(s).

In the SetNewValue() and GetCurrentValue() methods of your messenger, you can compare the G4UIcommand pointer given in the argument of these methods with the pointer of your command, because your messenger keeps the pointers to the commands. Thus, you don't need to compare by command name. Please remember, in the cases where you use G4UIcommand derived classes, you should store the pointers with the types of these derived classes so that you can use methods defined in the derived classes according to their types without casting.

G4UImanager/G4UIcommand/G4UIparameter have very powerful type and range checking routines. You are strongly recommended to set the range of your parameters. For the case of a numerical value (int or double), the range can be given by a G4String using C++ notation, e.g., "X > 0 && X < 10". For the case of a string type parameter, you can set a candidate list. Please refer to the detailed descriptions below.

GetCurrentValue() will be invoked after the user's application of the corresponding command, and before the SetNewValue() invocation. This GetCurrentValue() method will be invoked only if

For the first two cases, you can re-set the range or the candidate list if you need to do so, but these ``re-set'' parameters are needed only for the case where the range or the candidate list varies dynamically.

A command can be ``state sensitive'', i.e., the command can be accepted only for a certain G4ApplicationState(s). For example, the /run/beamOn command should not be accepted when Geant4 is processing another event (``G4State_EventProc'' state). You can set the states available for the command with the AvailableForStates() method.


7.2.2 G4UIcommand and its derived classes

Methods available for all derived classes

These are methods defined in the G4UIcommand base class which should be used from the derived classes.

G4UIdirectory

This is a G4UIcommand derived class for defining a directory.

G4UIcmdWithoutParameter

This is a G4UIcommand derived class for a command which takes no parameter.

G4UIcmdWithABool

This is a G4UIcommand derived class which takes one boolean type parameter.

G4UIcmdWithAnInteger

This is a G4UIcommand derived class which takes one integer type parameter.

G4UIcmdWithADouble

This is a G4UIcommand derived class which takes one double type parameter.

G4UIcmdWithAString

This is a G4UIcommand derived class which takes one string type parameter.

G4UIcmdWith3Vector

This is a G4UIcommand derived class which takes one three vector parameter.

G4UIcmdWithADoubleAndUnit

This is a G4UIcommand derived class which takes one double type parameter and its unit.

G4UIcmdWith3VectorAndUnit

This is a G4UIcommand derived class which takes one three vector parameter and its unit.

Additional comments on the SetParameterName() method

You can add one additional argument of G4bool type for every SetParameterName() method mentioned above. This additional argument is named currentAsDefaultFlag and the default value of this argument is false. If you assign this extra argument as true, the default value of the parameter will be overriden by the current value of the target class.


7.2.3 An example messenger

This example is of G4ParticleGunMessenger, which is made by inheriting G4UIcommand.

#ifndef G4ParticleGunMessenger_h
#define G4ParticleGunMessenger_h 1

class G4ParticleGun;
class G4ParticleTable;
class G4UIcommand;
class G4UIdirectory;
class G4UIcmdWithoutParameter;
class G4UIcmdWithAString;
class G4UIcmdWithADoubleAndUnit;
class G4UIcmdWith3Vector;
class G4UIcmdWith3VectorAndUnit;

#include "G4UImessenger.hh"
#include "globals.hh"

class G4ParticleGunMessenger: public G4UImessenger
{
  public:
    G4ParticleGunMessenger(G4ParticleGun * fPtclGun);
    ~G4ParticleGunMessenger();
    
  public:
    void SetNewValue(G4UIcommand * command,G4String newValues);
    G4String GetCurrentValue(G4UIcommand * command);

  private:
    G4ParticleGun * fParticleGun;
    G4ParticleTable * particleTable;
    
  private: //commands
    G4UIdirectory *             gunDirectory;
    G4UIcmdWithoutParameter *   listCmd;
    G4UIcmdWithAString *        particleCmd;
    G4UIcmdWith3Vector *        directionCmd;
    G4UIcmdWithADoubleAndUnit * energyCmd;
    G4UIcmdWith3VectorAndUnit * positionCmd;
    G4UIcmdWithADoubleAndUnit * timeCmd;
    
};

#endif 
Source listing 7.2.1
An example of G4ParticleGunMessenger.hh.

#include "G4ParticleGunMessenger.hh"
#include "G4ParticleGun.hh"
#include "G4Geantino.hh"
#include "G4ThreeVector.hh"
#include "G4ParticleTable.hh"
#include "G4UIdirectory.hh"
#include "G4UIcmdWithoutParameter.hh"
#include "G4UIcmdWithAString.hh"
#include "G4UIcmdWithADoubleAndUnit.hh"
#include "G4UIcmdWith3Vector.hh"
#include "G4UIcmdWith3VectorAndUnit.hh"
#include <iostream.h>

G4ParticleGunMessenger::G4ParticleGunMessenger(G4ParticleGun * fPtclGun)
:fParticleGun(fPtclGun)
{
  particleTable = G4ParticleTable::GetParticleTable();

  gunDirectory = new G4UIdirectory("/gun/");
  gunDirectory->SetGuidance("Particle Gun control commands.");

  listCmd = new G4UIcmdWithoutParameter("/gun/list",this);
  listCmd->SetGuidance("List available particles.");
  listCmd->SetGuidance(" Invoke G4ParticleTable.");

  particleCmd = new G4UIcmdWithAString("/gun/particle",this);
  particleCmd->SetGuidance("Set particle to be generated.");
  particleCmd->SetGuidance(" (geantino is default)");
  particleCmd->SetParameterName("particleName",true);
  particleCmd->SetDefaultValue("geantino");
  G4String candidateList; 
  G4int nPtcl = particleTable->entries();
  for(G4int i=0;i<nPtcl;i++)
  {
    candidateList += particleTable->GetParticleName(i);
    candidateList += " ";
  }
  particleCmd->SetCandidates(candidateList);

  directionCmd = new G4UIcmdWith3Vector("/gun/direction",this);
  directionCmd->SetGuidance("Set momentum direction.");
  directionCmd->SetGuidance("Direction needs not to be a unit vector.");
  directionCmd->SetParameterName("Px","Py","Pz",true,true); 
  directionCmd->SetRange("Px != 0 || Py != 0 || Pz != 0");
  
  energyCmd = new G4UIcmdWithADoubleAndUnit("/gun/energy",this);
  energyCmd->SetGuidance("Set kinetic energy.");
  energyCmd->SetParameterName("Energy",true,true);
  energyCmd->SetDefaultUnit("GeV");
  energyCmd->SetUnitCandidates("eV keV MeV GeV TeV");

  positionCmd = new G4UIcmdWith3VectorAndUnit("/gun/position",this);
  positionCmd->SetGuidance("Set starting position of the particle.");
  positionCmd->SetParameterName("X","Y","Z",true,true);
  positionCmd->SetDefaultUnit("cm");
  positionCmd->SetUnitCandidates("micron mm cm m km");

  timeCmd = new G4UIcmdWithADoubleAndUnit("/gun/time",this);
  timeCmd->SetGuidance("Set initial time of the particle.");
  timeCmd->SetParameterName("t0",true,true);
  timeCmd->SetDefaultUnit("ns");
  timeCmd->SetUnitCandidates("ns ms s");
  
  // Set initial value to G4ParticleGun
  fParticleGun->SetParticleDefinition( G4Geantino::Geantino() );
  fParticleGun->SetParticleMomentumDirection( G4ThreeVector(1.0,0.0,0.0) );
  fParticleGun->SetParticleEnergy( 1.0*GeV );
  fParticleGun->SetParticlePosition(G4ThreeVector(0.0*cm, 0.0*cm, 0.0*cm));
  fParticleGun->SetParticleTime( 0.0*ns );
}

G4ParticleGunMessenger::~G4ParticleGunMessenger()
{
  delete listCmd;
  delete particleCmd;
  delete directionCmd;
  delete energyCmd;
  delete positionCmd;
  delete timeCmd;
  delete gunDirectory;
}

void G4ParticleGunMessenger::SetNewValue(
  G4UIcommand * command,G4String newValues)
{
  if( command==listCmd )
  { particleTable->dumpTable(); }
  else if( command==particleCmd )
  {
    G4ParticleDefinition* pd = particleTable->findParticle(newValues);
    if(pd != NULL)
    { fParticleGun->SetParticleDefinition( pd ); }
  }
  else if( command==directionCmd )
  { fParticleGun->SetParticleMomentumDirection(directionCmd->
     GetNew3VectorValue(newValues)); }
  else if( command==energyCmd )
  { fParticleGun->SetParticleEnergy(energyCmd->
     GetNewDoubleValue(newValues)); }
  else if( command==positionCmd )
  { fParticleGun->SetParticlePosition(
     directionCmd->GetNew3VectorValue(newValues)); }
  else if( command==timeCmd )
  { fParticleGun->SetParticleTime(timeCmd->
     GetNewDoubleValue(newValues)); }
}

G4String G4ParticleGunMessenger::GetCurrentValue(G4UIcommand * command)
{
  G4String cv;
  
  if( command==directionCmd )
  { cv = directionCmd->ConvertToString(
     fParticleGun->GetParticleMomentumDirection()); }
  else if( command==energyCmd )
  { cv = energyCmd->ConvertToString(
     fParticleGun->GetParticleEnergy(),"GeV"); }
  else if( command==positionCmd )
  { cv = positionCmd->ConvertToString(
     fParticleGun->GetParticlePosition(),"cm"); }
  else if( command==timeCmd )
  { cv = timeCmd->ConvertToString(
     fParticleGun->GetParticleTime(),"ns"); }
  else if( command==particleCmd )
  { // update candidate list
    G4String candidateList; 
    G4int nPtcl = particleTable->entries();
    for(G4int i=0;i<nPtcl;i++)
    {
      candidateList += particleTable->GetParticleName(i);
      candidateList += " ";
    }
    particleCmd->SetCandidates(candidateList);
  }
  return cv;
}
Source listing 7.2.2
An example of G4ParticleGunMessenger.cc.


7.2.4 How to control the output of G4cout/G4cerr

Instead of cout and cerr, Geant4 uses G4cout and G4cerr. Output streams from G4cout/G4cerr are handled by G4UImanager which allows the application programmer to control the flow of the stream. Output strings may therefore be displayed on another window or stored in a file. This is accomplished as follows:

  1. Derive a class from G4UIsession and implement the two methods:
          G4int ReceiveG4cout(G4String coutString);
          G4int ReceiveG4cerr(G4String cerrString);
     
    These methods receive the string stream of G4cout and G4cerr, respectively. The string can be handled to meet specific requirements. The following sample code shows how to make a log file of the output stream:
            ostream logFile;
            logFile.open("MyLogFile");
            G4int MySession::ReceiveG4cout(G4String coutString)
            {
              logFile << coutString << flush;
              return 0;
            }
     

  2. Set the destination of G4cout/G4cerr using G4UImanager::SetCoutDestination(session).

    Typically this method is invoked from the constructor of G4UIsession and its derived classes, such as G4UIGAG/G4UIteminal. This method sets the destination of G4cout/G4cerr to the session. For example, when the following code appears in the constructor of G4UIterminal, the method SetCoutDestination(this) tells UImanager that this instance of G4UIterminal receives the stream generated by G4cout.

    
    	G4UIterminal::G4UIterminal()
    	{
    	  UI = G4UImanager::GetUIpointer();
    	  UI->SetCoutDestination(this);
    	  //  ...
    	}
        
     
    Similarly, UI->SetCoutDestination(NULL) must be added to the destructor of the class.

  3. Write or modify the main program. To modify exampleN01 to produce a log file, derive a class as described in step 1 above, and add the following lines to the main program:
    	#include "MySession.hh"
    	main()
            {
    	  // get the pointer to the User Interface manager
    	  G4UImanager* UI = G4UImanager::GetUIpointer();
    	  // construct a session which receives G4cout/G4cerr
    	  MySession * LoggedSession = new MySession;
    	  UI->SetCoutDestination(LoggedSession);
    	  // session->SessionStart(); // not required in this case
              // .... do simulation here ...
    
    	  delete LoggedSession;
    	  return 0;
    	}
     
Note: G4cout/G4cerr should not be used in the constructor of a class if the instance of the class is intended to be used as static. This restriction comes from the language specification of C++. See the documents below for details.

M.A.Ellis, B.Stroustrup. ``Annotated C++ Reference Manual'', Section 3.4
P.J.Plauger, ``The Draft Standard C++ Library''




About the authors