Forcing Particle to a Boundary

Howdy,

I am attempting to optimize my simulation to require less run time per particle and it appears the charged particle interaction with an electric field is a major cost. I would like to check if the particle has reached constant velocity in the drift field then do a forced move to the boundary in ‘z’.
The most brute force approach would be to simply step the particle a long distance but this would depend on GEANT4 not allowing the boundary crossing without generating a step. Based on others wanting to avoid killing particles at small gaps and manually stepping the track over them, it doesn’t look like this is true.

The more elegant solution would be to find the boundary and then just step to 5µm short of it. Though this looks more challenging as my geometry is heavily nested including an assembly volume as I need to translate and rotate. Does the G4Track->GetPosition() return the ThreeVector in the same coordinate system to be compared to G4Track->GetNextVolume()->GetTranslation()?

Thanks and Respectfully

  • Will

Hi Will,

I believe that the method G4Track()->GetPosition() return in the World coordinate system whereas G4Track->GetNextVolume()->GetTranslation() would return a vector in the mother volume coordinate system of your NextVolume. Because the translation of your NextVolume is inside of your mother volume. If your mother volume is the World then yes it’s the same coordinate system.

Alexandre

Unfortunately not, the volume with the field is nested two layers down from the world while the next volume is either two or three layers down as it’s a division inside of a holder volume. The boundaries are coincident to the particle track along z but I think the GetNextVoume() would grab the division.
I’ll try just using the GetTranslation() on both current and next volumes and see if that provides enough information to make the jump.
Side question becomes, with GEANT4 calling some functions by default, how do I pass variables between them? If too tangential I’ll start a new topic.

Thanks

  • Will

You mean different functions in the same class/instance? Data members :slight_smile: If the functions that G4 calls have to be const, declare those internal data members as mutable.

An example would be taking a volume thickness GasGapZ from DetectorConstruction to Detector to be able to offset to the boundary from the center of the next volume from GetTranslation().

Thanks

  • Will

Are you wanting to pass a parameter from the volume construction to a sensitive detector instance? You could do that in ConstructSDandField() – put the volume dimensions into data members, then either pass the parameter to your SD class constructor, or give it a mutator (SetThickness()) member function and pass the dimension to it that way.

If you are dealing with a UserAction class (EventAction, SteppingAction, whatever), you have lots of different possibilities. The action class could query the RunManager to retrieve a pointer to your DetectorConstruction, downcast it with dynamic_cast<>, and call an accessor function (GetDetectorThickness() or something) to retrieve the parameter. Or you could put all of your geometry parameters into a static container (singleton), and all your code could reach out and grab what they need.

Going back to your original request:

First I would advise that in order to get the correct drift velocity you will need to have low thresholds for an electron’s processes.

Second it is unclear what your words “this would depend on GEANT4 not allowing the boundary crossing without generating a step” mean. Geant4 will in nearly all circumstances finish a step at the next volume boundary if that step was not stopped already by a physics process.

Aside from these, my suggestion would be either i) to create a parallel geometry in which includes only the volume of the surface you want to arrive, ii) to suspend a particle that has reached the drift velocity, taking it off the Geant4 particle stack, and iii) to restart it at the appropriate location.

I don’t have a perfect scenario how to undertake the last two, and the appropriate forum to discuss that would probably be the one for ‘Particles, Track, Event and Biasing’.

But the G4 documentation does explain how to create a parallel geometry, and it is relatively easy to register a copy of the key volumes in your geometry which you want to exist in it. Once you have the global location of a particle where you have extracted it from your detailed (“mass”) geometry, you could ask the navigator for that parallel geometry simply to move it along.

This would help particularly if your geometry is complex, as it should be a robust solution.
Best regards, John

… it is unclear what your words “this would depend on GEANT4 not allowing the boundary crossing without generating a step” mean. Geant4 will in nearly all circumstances finish a step at the next volume boundary if that step was not stopped already by a physics process.

Because I know the layer with the field is a given thickness, I was thinking using that thickness to force a step length after the drift velocity stabilizes and then have GEANT4 force the step shorter when it tried to cross the boundary from the drift gap to the anode. I might try it this way even if it’s only to test the idea.

Aside from these, my suggestion would be either i) to create a parallel geometry in which includes only the volume of the surface you want to arrive, ii) to suspend a particle that has reached the drift velocity, taking it off the Geant4 particle stack, and iii) to restart it at the appropriate location.

This would basically mimic the drift gap with no field and have the electron travel through this via normal stepping processes. Then when it reached the boundary get transferred back to the main geometry for interaction with the rest of the detector? I’ll take a read of the documentation to see how that’s done.

I have tried the forced step method but I don’t think it’s actually moving the particle

	G4int GG_inst = Vol.find("Gas Gap");
	if (GG_inst > 0)
	{
		if ((particle == "e-" || particle == "e+"))
		{
			if (abs((postStepPoint->GetKineticEnergy() - preStepPoint->GetKineticEnergy()) - track->GetKineticEnergy()) <= 1.*eV)
			{
				
				G4cout << "Initial Energy: " <<preStepPoint->GetKineticEnergy() << ", Final Energy: " <<
					postStepPoint->GetKineticEnergy() << G4endl;
				G4cout << "Total Energy: " << track->GetKineticEnergy() << G4endl;
				G4cout << "Energy Stabilized, Forcing 3.0mm Step" << G4endl;
				G4cout << "Velocity " << postStepPoint->GetVelocity()/(m/s) << G4endl;
				track->SetStepLength(3.*mm);
			}
		}
	}

The output is a near continuous triggering of the G4cout statements with the same energy and velocity. I don’t think track->SetStepLength(3.*mm); is actually changing the step length as the GasGapZ is only 5.45mm so there should never be more than two steps within a single G4ParticleGun::gamma event without triggering a new TrackID (/event/verbose 1).

Do I need to call another action to implement the step length? Thoughts?