Automate photon position for a range of values using macro


I am trying to automate the z0 position of photons entering my detector. Normally, the positions for x0, y0, and z0 was specified in the file but I would like to overwrite only that of z0.

I have created a macro papis.mac with the code:

# specified 50keV gamma energies to the direction (0.,0.,zpos)
/gun/particle gamma
/gun/energy 50 keV
/gun/position 0 0 {zpos} mm
/run/beamOn 100000
#/control/shell Edep.dat output_{eKin}.dat

And I applied the papis.mac in my runz.mac macro:

# Macro file for example B1
/control/verbose 0
/control/macroPath $HOME/folde/papis.mac
/run/verbose 0
/event/verbose 0
/tracking/verbose 1

/control/foreach papis.mac zpos "-15., -14., -13., -12., -11., -10., -9., -8., -7., -6., -5., -4., -3., -2., -1., 0"

However this doesn’t overwrite the value for z0. How can I keep this fixed for each position of z0 from the macro while randomizing x0 and y0 from the main file? I’d appreciate any help please.

@mkelsey @weller @couet can you please take a look at this and share insights? any help will be appreciated. thanks in advance.

The arguments to foreach are space delimited, and should not be enclosed in quotes. Thus:

/control/foreach papis.mac zpos -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0

Thank you for the response @weller

The issue is that the values does not overwrite the z position. This is an excerpt from my file:

G4double envSizeXY = 0;
  G4double envSizeZ = 0;

  if (!fEnvelopeBox)
    G4LogicalVolume* envLV
      = G4LogicalVolumeStore::GetInstance()->GetVolume("Envelope");
    if ( envLV ) fEnvelopeBox = dynamic_cast<G4Box*>(envLV->GetSolid());

  if ( fEnvelopeBox ) {
    envSizeXY = fEnvelopeBox->GetXHalfLength()*2;
    envSizeZ = fEnvelopeBox->GetZHalfLength()*2;
  else  {
    G4ExceptionDescription msg;
    msg << "Envelope volume of box shape not found.\n"; 
    msg << "Perhaps you have changed geometry.\n";
    msg << "The gun will be place at the center.";

  //G4double size = 1.0; 
  G4double x0 = envSizeXY * (G4UniformRand()-0.5);
  G4double y0 = envSizeXY * (G4UniformRand()-0.5);
  G4double z0 = -envSizeZ;
  G4cout << "x0, y0, z0 = " << x0 << ",\t" << y0 << ",\t" << z0 << G4endl;


What I want to do is randomize the position of x0 and y0 but use the macro to control that of z0 using a loop. Is this achievable?

I think that the code you posted will be executed for every single event. That means, the changes/settings that you apply in the macro will later be overwritten - especially the z-component of the direction.

I would try something like this:

G4double x0 = envSizeXY * (G4UniformRand()-0.5);
G4double y0 = envSizeXY * (G4UniformRand()-0.5);
G4double z0 = fParticleGun->GetParticlePosition().z();


There might be better ways :slight_smile:

1 Like

Thank you so much! That did the trick!!!

I appreciate your time @mkelsey @weller