What is the StepTooSmall boundary process status, and can photons destroyed under this status be recovered?

I am simulating a simple gamma camera geometry with two materials and am detecting much fewer counts than expected.

Analysis of the boundary processes showed that the last photon status, just before the photon was killed, was set to “StepTooSmall” about 1/2 of the time, instead of OpAbsorption or Detection.

So what is this StepTooSmall status, and can I recover the photons killed with that status?

Below is a boundary interaction breakdown by status:

  • note that Detection are the photons entering my detector, so we get the SameMaterial status as expected)

  • The killed statuses are FresnelRefraction and StepTooSmall, neither of which make sense to me.

  • This simulation has every surface set to 100% reflectivity, so there should be no photons absorbed at all, as per my understanding.

  • The “Reflected” processes are boundary interactions that do not kill the photon (not necessarily reflection - can be reflection, refraction, or transmission)

  • The total # of photons are (1993+542+1893) + Volume_absorbed photons = 4428 + Volume_absorbed photons.
    Note that my simulation has a high opt. photon attenuation length, so the amount of Volume_absorbed is about 10 photons.

image

Interestingly, some boundary interactions with the StepTooSmall status are not killed, and I cannot find any calls from the StepTooSmall portion of the Geant4 source code to fStopAndKill!

(If this post is in an incorrect category, please let me know.)

I would really appreciate any insight you might have. Thank you!

Akhil

This is a complicated question so we’ll need to break it down.

The optical boundary process isn’t expected to kill these photons. It will kill photons if:

  1. The photon is detected. The material property EFFICIENCY must be set > 0 and the status will be ‘Detect’.
  2. There is no RINDEX defined for one material or surface. Status will be NoRINDEX.
    These don’t appear to apply in your case.

Do you have something else that kills photons? How do you know they’re killed? Can you see it with /tracking/verbose 2 ?

What do you mean be ‘Detection’? As noted above, detected photons should have status Detected.

Are you able to reproduce this with example OpNovice2?

Thank you, Mr. Sawkey.

  1. I have EFFICIENCY set to 1, but as REFLECTIVITY is set to 1 for all materials (debugging purposes), at present there are never any detections; if I lower REFLECTIVITY, as expected, there are some detected photons with status Detected.

  2. I have double checked this - cannot be the case.

The only other process that kills photons (as far as I know) would be the one corresponding to volumetric absorption. The list of statuses above corresponds to only boundary effects, so that cannot be the case.

I have not tried /tracking/verbose 2. I will do so and let you know.

‘Detection’: I have a special edit in my SteppingAction - if any photon enters the detectors (not the camera itself, but the silicon photomultipliers), then I manually set the track status to fStopAndKill, so as to not double count the photons. This is why I get a ‘SameMaterial’ status instead of a ‘Detected’ status.
It may be more appropriate to just change REFLECTIVITY and EFFICIENCY for the silicon photomultipliers, but my setup ought not affect anything else.

As far as reproducing this with OpNovice2, this behavior is not unique to my simulation:
I found a paper from the Universidade de Santiago de Compostela that has several photons killed with status set to ‘StepTooSmall’. I have attached images from their paper for reference.
image


The link to the paper: http://igfae.usc.es/~genp/academic/dea/DEA_Paloma.pdf

Running tracking/verbose 1 listed the processes as one of [Transportation, OpRayleigh, OpAbsorption], as expected. (Somehow, for my simulation, tracking/verbose 1 and tracking/verbose 2 gave identical results.)
Very rarely is OpAbsorption listed (that would be volumetric or surface absorption)
Note that we expect no surface absorption, and only a few percent volumetric absorption.

The last few processes of an optical photon track are listed below:

  • Note the volumes with EJ208 are scintillator strips, while the Vikuiti volumes wrap the EJ208 scintillators (metallic foil for photon reflection).

As far as I can tell, the last few moments of the track consist of the photon bouncing in between the Vikuiti wrapper and the EJ208 scintillator.
So I would expect an ‘OpAbsorption’ process hidden in the ‘Transportation’ process here.

Running with tracking/verbose 3:

I have attached the last step of a photon:
laststeps.txt (3.2 KB)
Why is there an OpAbsorption where there should be none?

I really appreciate your help. Thank you.

Sincerely,
Akhil

Try adding

/process/optical/boundary/verbose 2

to your macro. What you should see (example below) is that when a photon interacts at the boundary, there will often be two navigator steps at the same position. The first is what is really going on (status of e.g. FresnelReflection) and the second is internal workings of the boundary process (status StepTooSmall). Thus, if you are counting boundary interactions, don’t count the StepTooSmall or else you will double count. This is what happens in steps 374/375 of your tracking output. (look for step length = 0).

You’ll also see Transportation given as the process that limits the step. This means the photon reached another volume. All relevant processes still occur during the step, including OpBoundary if applicable.

In step 386 of your printout, the photon loses all its kinetic energy at the boundary. The printout doesn’t say why, but the verbose command above should help. Likely the photon is detected, in the optical boundary process sense of the word.

If a photon is absorbed by the G4OpBoundaryProcess, it is G4OpBoundaryProcess that does it, not G4OpAbsorption.

REFLECTIVITY is really 1-ABSORPTION at the boundary. And, EFFICIENCY is the fraction of fraction of absorbed photons that are detected. So, it’s not logical to set both REFLECTIVITY and EFFICIENCY to 1. No photons will be absorbed or detected.

Example output (edited for brevity):

G4WT0 > Step#    X(mm)    Y(mm)    Z(mm) KinE(MeV)  dE(MeV) StepLeng TrackLeng  NextVolume ProcName
G4WT0 >  Photon at Boundary!
G4WT0 >  thePrePV:  Tank
G4WT0 >  thePostPV: World
G4WT0 >  *** FresnelReflection ***
G4WT0 >     1    1e+03      489        0     3e-06        0 1.11e+03  1.11e+03       World Transportation
G4WT0 >  Photon at Boundary!
G4WT0 >  thePrePV:  World
G4WT0 >  thePostPV: Tank
G4WT0 >  *** StepTooSmall ***
G4WT0 >     2    1e+03      489        0     3e-06        0        0  1.11e+03        Tank Transportation

Unfortunately, this command did not change anything - I will probably need to read the verbosity section in the documentation more carefully.

Thank you for this insight; it is quite likely that I am double counting.
I will try it and get back to you. Thank you.

This is exactly what I am trying to do (for the scintillator material, there should only be volumetric absorption and absolutely no boundary absorption - efficiency is irrelevant)! Boundary absorption would only occur if we have dust/other material on the surface or skin effects, which I am ignoring at present.

So I am using an if statement as follows (after confirming that the primary particle is an optical photon) in SteppingAction:
image

My new results are:
image
with total # of photons: 4477, (9 Volume-absorbed, the rest (4468) either boundary-absorbed or SiPM detected).

Clearly my “Reflected” category is no longer double counting the StepTooSmall status (we now have 21 instead of 1106143), but I am still getting several processes with a StepTooSmall status and a non-zero step length that kill photons.

I know that there is no double counting in terms of “Killed & Detection” categories, as these are unique boundary interactions that sum to the total # of photons:

  • 2034 detections + 522 killed by refraction + 1912 killed by StepTooSmall = 4468 photons stopped at some boundary. (Note that there is very little volumetric attenuation, so this should be close to the total # of photons.)

The total # of photons is 4477, which is as expected:

  • EJ208 produces 9200 photons/MeV, so at 511MeV gammas, it would produce around 4700 photons in an event.

If I were to remove the StepTooSmall category entirely, then there would be undercounting, as 2034+522 = 2556, much less than 4477.

How would I find the process that generates the StepTooSmall status? It seems that the step prior to the StepTooSmall may have been misclassified as a “Reflection/Refraction” by my code, since the photon is not killed in that step.

Do you know of a way to count these boundary processes only once, without this misclassification?

Thank you.

Yes–it’s why I suggested example OpNovice2 at the start!

1 Like

I think I have a somehow related problem. Optical photons seem to be absorbed at the boundary between a scintillator and a reflector. Similarly as @akhilsadam I did set Reflectivity of the reflector to 1.0, but around 1% of photons are absorbed at the boundary with the reflector and lost from detection. I followed the above instruction and used /process/optical/boundary/verbose 2 to see more details. Clearly, a photon got absorbed at the boundary despite Reflectivity settings:

G4WT0 > *********************************************************************************************************
G4WT0 > * G4Track Information:   Particle = opticalphoton,   Track ID = 1,   Parent ID = 0
G4WT0 > *********************************************************************************************************
G4WT0 > 
G4WT0 > Step#    X(mm)    Y(mm)    Z(mm) KinE(MeV)  dE(MeV) StepLeng TrackLeng  NextVolume ProcName
G4WT0 >     0        0        0        0   2.5e-06        0        0         0 singlepixel_scint_phys initStep
G4WT0 > G4VDiscreteProcess::PostStepGetPhysicalInteractionLength() - [ OpBoundary]
G4WT0 >  Particle type - opticalphoton
G4WT0 >    mass:        0[GeV]
G4WT0 >    charge:      0[e]
G4WT0 >    Direction x: 0, y: 0, z: -1
G4WT0 >    Total Momentum = 2.5e-09[GeV]
G4WT0 >    Momentum: 0[GeV], y: 0[GeV], z: -2.5e-09[GeV]
G4WT0 >    Total Energy   = 2.5e-09[GeV]
G4WT0 >    Kinetic Energy = 2.5e-09[GeV]
G4WT0 >  MagneticMoment  [MeV/T]: 0
G4WT0 >    ProperTime     = 0[ns]
G4WT0 >  in Material  MPND_gagg
G4WT0 > InteractionLength= 1.797693134862316e+307[cm] 
G4WT0 >  Photon at Boundary! 
G4WT0 >  thePrePV:  singlepixel_scint_phys
G4WT0 >  thePostPV: singlepixel_refl_phy
G4WT0 >  Old Momentum Direction: (0,0,-1)
G4WT0 >  Old Polarization:       (0.9910420793306229,-0.1335499793936159,0)
G4WT0 >  New Momentum Direction: (0.3580643026832863,0.04749786964020635,0.9324880200429247)
G4WT0 >  New Polarization:       (-0.726204458224364,-0.6135640599208351,0.3101068029381492)
G4WT0 >  *** FresnelRefraction ***
G4WT0 >     1        0        0      -10   2.5e-06        0       10        10 singlepixel_refl_phy Transportation
G4WT0 > G4VDiscreteProcess::PostStepGetPhysicalInteractionLength() - [ OpBoundary]
G4WT0 >  Particle type - opticalphoton
G4WT0 >    mass:        0[GeV]
G4WT0 >    charge:      0[e]
G4WT0 >    Direction x: 0.3580643026832863, y: 0.04749786964020635, z: 0.9324880200429247
G4WT0 >    Total Momentum = 2.5e-09[GeV]
G4WT0 >    Momentum: 8.951607567082157e-10[GeV], y: 1.187446741005159e-10[GeV], z: 2.331220050107312e-09[GeV]
G4WT0 >    Total Energy   = 2.5e-09[GeV]
G4WT0 >    Kinetic Energy = 2.5e-09[GeV]
G4WT0 >  MagneticMoment  [MeV/T]: 0
G4WT0 >    ProperTime     = 0[ns]
G4WT0 >  in Material  G4_AIR
G4WT0 > InteractionLength= 1.797693134862316e+307[cm] 
G4WT0 >  Photon at Boundary! 
G4WT0 >  thePrePV:  singlepixel_refl_phy
G4WT0 >  thePostPV: singlepixel_scint_phys
G4WT0 >  *** StepTooSmall ***
G4WT0 >     2        0        0      -10   2.5e-06        0        0        10 singlepixel_scint_phys Transportation
G4WT0 > G4VDiscreteProcess::PostStepGetPhysicalInteractionLength() - [ OpBoundary]
G4WT0 >  Particle type - opticalphoton
G4WT0 >    mass:        0[GeV]
G4WT0 >    charge:      0[e]
G4WT0 >    Direction x: 0.3580643026832863, y: 0.04749786964020635, z: 0.9324880200429247
G4WT0 >    Total Momentum = 2.5e-09[GeV]
G4WT0 >    Momentum: 8.951607567082157e-10[GeV], y: 1.187446741005159e-10[GeV], z: 2.331220050107312e-09[GeV]
G4WT0 >    Total Energy   = 2.5e-09[GeV]
G4WT0 >    Kinetic Energy = 2.5e-09[GeV]
G4WT0 >  MagneticMoment  [MeV/T]: 0
G4WT0 >    ProperTime     = 0[ns]
G4WT0 >  in Material  MPND_gagg
G4WT0 > InteractionLength= 1.797693134862316e+307[cm] 
G4WT0 >  Photon at Boundary! 
G4WT0 >  thePrePV:  singlepixel_scint_phys
G4WT0 >  thePostPV: singlepixel_refl_phy
G4WT0 >  Old Momentum Direction: (0.3580643026832863,0.04749786964020635,0.9324880200429247)
G4WT0 >  Old Polarization:       (-0.726204458224364,-0.6135640599208351,0.3101068029381492)
G4WT0 >  New Momentum Direction: (-0.3483424556083636,0.02523961606095498,0.9370274784667901)
G4WT0 >  New Polarization:       (-0.7673112789465003,0.5665046970079638,-0.3005092834995303)
G4WT0 >  *** LobeReflection ***
G4WT0 >     3        5    0.663     3.02   2.5e-06        0       14        24 singlepixel_refl_phy Transportation
G4WT0 > G4VDiscreteProcess::PostStepGetPhysicalInteractionLength() - [ OpBoundary]
G4WT0 >  Particle type - opticalphoton
G4WT0 >    mass:        0[GeV]
G4WT0 >    charge:      0[e]
G4WT0 >    Direction x: -0.3483424556083636, y: 0.02523961606095498, z: 0.9370274784667901
G4WT0 >    Total Momentum = 2.5e-09[GeV]
G4WT0 >    Momentum: -8.708561390209091e-10[GeV], y: 6.309904015238746e-11[GeV], z: 2.342568696166975e-09[GeV]
G4WT0 >    Total Energy   = 2.5e-09[GeV]
G4WT0 >    Kinetic Energy = 2.5e-09[GeV]
G4WT0 >  MagneticMoment  [MeV/T]: 0
G4WT0 >    ProperTime     = 0[ns]
G4WT0 >  in Material  G4_AIR
G4WT0 > InteractionLength= 1.797693134862316e+307[cm] 
G4WT0 >  Photon at Boundary! 
G4WT0 >  thePrePV:  singlepixel_refl_phy
G4WT0 >  thePostPV: singlepixel_scint_phys
G4WT0 >  *** StepTooSmall ***
G4WT0 >     4        5    0.663     3.02   2.5e-06        0        0        24 singlepixel_scint_phys Transportation
G4WT0 > G4VDiscreteProcess::PostStepGetPhysicalInteractionLength() - [ OpBoundary]
G4WT0 >  Particle type - opticalphoton
G4WT0 >    mass:        0[GeV]
G4WT0 >    charge:      0[e]
G4WT0 >    Direction x: -0.3483424556083636, y: 0.02523961606095498, z: 0.9370274784667901
G4WT0 >    Total Momentum = 2.5e-09[GeV]
G4WT0 >    Momentum: -8.708561390209091e-10[GeV], y: 6.309904015238746e-11[GeV], z: 2.342568696166975e-09[GeV]
G4WT0 >    Total Energy   = 2.5e-09[GeV]
G4WT0 >    Kinetic Energy = 2.5e-09[GeV]
G4WT0 >  MagneticMoment  [MeV/T]: 0
G4WT0 >    ProperTime     = 0[ns]
G4WT0 >  in Material  MPND_gagg
G4WT0 > InteractionLength= 1.797693134862316e+307[cm] 
G4WT0 >  Photon at Boundary! 
G4WT0 >  thePrePV:  singlepixel_scint_phys
G4WT0 >  thePostPV: singlepixel_pmt_phys
G4WT0 >  Old Momentum Direction: (-0.3483424556083636,0.02523961606095498,0.9370274784667901)
G4WT0 >  Old Polarization:       (-0.7673112789465003,0.5665046970079638,-0.3005092834995303)
G4WT0 >  New Momentum Direction: (-0.3483424556083636,0.02523961606095498,-0.9370274784667901)
G4WT0 >  New Polarization:       (-0.8183637310103038,-0.4956518298805093,0.2908780969805015)
G4WT0 >  *** FresnelReflection ***
G4WT0 >     5     2.41    0.851       10   2.5e-06        0     7.45      31.4 singlepixel_pmt_phys Transportation
G4WT0 > G4VDiscreteProcess::PostStepGetPhysicalInteractionLength() - [ OpBoundary]
G4WT0 >  Particle type - opticalphoton
G4WT0 >    mass:        0[GeV]
G4WT0 >    charge:      0[e]
G4WT0 >    Direction x: -0.3483424556083636, y: 0.02523961606095498, z: -0.9370274784667901
G4WT0 >    Total Momentum = 2.5e-09[GeV]
G4WT0 >    Momentum: -8.708561390209091e-10[GeV], y: 6.309904015238746e-11[GeV], z: -2.342568696166975e-09[GeV]
G4WT0 >    Total Energy   = 2.5e-09[GeV]
G4WT0 >    Kinetic Energy = 2.5e-09[GeV]
G4WT0 >  MagneticMoment  [MeV/T]: 0
G4WT0 >    ProperTime     = 0[ns]
G4WT0 >  in Material  G4_Si
G4WT0 > InteractionLength= 1.797693134862316e+307[cm] 
G4WT0 >  Photon at Boundary! 
G4WT0 >  thePrePV:  singlepixel_pmt_phys
G4WT0 >  thePostPV: singlepixel_scint_phys
G4WT0 >  *** StepTooSmall ***
G4WT0 >     6     2.41    0.851       10   2.5e-06        0        0      31.4 singlepixel_scint_phys Transportation
G4WT0 > G4VDiscreteProcess::PostStepGetPhysicalInteractionLength() - [ OpBoundary]
G4WT0 >  Particle type - opticalphoton
G4WT0 >    mass:        0[GeV]
G4WT0 >    charge:      0[e]
G4WT0 >    Direction x: -0.3483424556083636, y: 0.02523961606095498, z: -0.9370274784667901
G4WT0 >    Total Momentum = 2.5e-09[GeV]
G4WT0 >    Momentum: -8.708561390209091e-10[GeV], y: 6.309904015238746e-11[GeV], z: -2.342568696166975e-09[GeV]
G4WT0 >    Total Energy   = 2.5e-09[GeV]
G4WT0 >    Kinetic Energy = 2.5e-09[GeV]
G4WT0 >  MagneticMoment  [MeV/T]: 0
G4WT0 >    ProperTime     = 0[ns]
G4WT0 >  in Material  MPND_gagg
G4WT0 > InteractionLength= 1.797693134862316e+307[cm] 
G4WT0 >  Photon at Boundary! 
G4WT0 >  thePrePV:  singlepixel_scint_phys
G4WT0 >  thePostPV: singlepixel_refl_phy
G4WT0 >  Old Momentum Direction: (-0.3483424556083636,0.02523961606095498,-0.9370274784667901)
G4WT0 >  Old Polarization:       (-0.8183637310103038,-0.4956518298805093,0.2908780969805015)
G4WT0 >  New Momentum Direction: (0.2814837006225525,0.03157577099009305,-0.959046347665333)
G4WT0 >  New Polarization:       (-0.8464714571198213,0.4789033135175184,-0.2326750708249342)
G4WT0 >  *** LobeReflection ***
G4WT0 >     7       -5     1.39    -9.92   2.5e-06        0     21.3      52.7 singlepixel_refl_phy Transportation
G4WT0 > G4VDiscreteProcess::PostStepGetPhysicalInteractionLength() - [ OpBoundary]
G4WT0 >  Particle type - opticalphoton
G4WT0 >    mass:        0[GeV]
G4WT0 >    charge:      0[e]
G4WT0 >    Direction x: 0.2814837006225525, y: 0.03157577099009305, z: -0.959046347665333
G4WT0 >    Total Momentum = 2.5e-09[GeV]
G4WT0 >    Momentum: 7.037092515563814e-10[GeV], y: 7.893942747523265e-11[GeV], z: -2.397615869163333e-09[GeV]
G4WT0 >    Total Energy   = 2.5e-09[GeV]
G4WT0 >    Kinetic Energy = 2.5e-09[GeV]
G4WT0 >  MagneticMoment  [MeV/T]: 0
G4WT0 >    ProperTime     = 0[ns]
G4WT0 >  in Material  G4_AIR
G4WT0 > InteractionLength= 1.797693134862316e+307[cm] 
G4WT0 >  Photon at Boundary! 
G4WT0 >  thePrePV:  singlepixel_refl_phy
G4WT0 >  thePostPV: singlepixel_scint_phys
G4WT0 >  *** StepTooSmall ***
G4WT0 >     8       -5     1.39    -9.92   2.5e-06        0        0      52.7 singlepixel_scint_phys Transportation
G4WT0 > G4VDiscreteProcess::PostStepGetPhysicalInteractionLength() - [ OpBoundary]
G4WT0 >  Particle type - opticalphoton
G4WT0 >    mass:        0[GeV]
G4WT0 >    charge:      0[e]
G4WT0 >    Direction x: 0.2814837006225525, y: 0.03157577099009305, z: -0.959046347665333
G4WT0 >    Total Momentum = 2.5e-09[GeV]
G4WT0 >    Momentum: 7.037092515563814e-10[GeV], y: 7.893942747523265e-11[GeV], z: -2.397615869163333e-09[GeV]
G4WT0 >    Total Energy   = 2.5e-09[GeV]
G4WT0 >    Kinetic Energy = 2.5e-09[GeV]
G4WT0 >  MagneticMoment  [MeV/T]: 0
G4WT0 >    ProperTime     = 0[ns]
G4WT0 >  in Material  MPND_gagg
G4WT0 > InteractionLength= 1.797693134862316e+307[cm] 
G4WT0 >  Photon at Boundary! 
G4WT0 >  thePrePV:  singlepixel_scint_phys
G4WT0 >  thePostPV: singlepixel_refl_phy
G4WT0 >  Old Momentum Direction: (0.2814837006225525,0.03157577099009305,-0.959046347665333)
G4WT0 >  Old Polarization:       (-0.8464714571198213,0.4789033135175184,-0.2326750708249342)
G4WT0 >  New Momentum Direction: (0.4040918759733085,0.04884714297335606,-0.9134132210537095)
G4WT0 >  New Polarization:       (-0.8116962453950581,0.479543364443296,-0.3334476972929483)
G4WT0 >  *** Absorption ***
G4WT0 >     9    -4.98     1.39      -10   2.5e-06        0   0.0825      52.8 singlepixel_refl_phy Transportation

The scintillator is wrapped in an ideal reflector material:

//ideal reflector
    auto idealReflector = new G4OpticalSurface("idealReflector");
    idealReflector->SetType(dielectric_dielectric);
    idealReflector->SetModel(unified);
    idealReflector->SetFinish(groundbackpainted); //Lambertian reflection
    idealReflector->SetSigmaAlpha(1.3*degree); // 

    G4MaterialPropertiesTable *idealReflector_MPT = new G4MaterialPropertiesTable();
    G4double pp[NUM] = {1 * eV, 7 * eV};
    G4double specularlobe[NUM] = {0.0, 0.0};
    G4double specularspike[NUM] = {0.0, 0.0};
    G4double backscatter[NUM] = {0.0, 0.0};
    G4double lambertian[NUM] = {1, 1}; //redundant
    G4double idealReflector_rindex[NUM] = {1.35, 1.35};
    G4double idealReflector_refl[NUM] = {1.0, 1.0}; //reflect everything
    G4double idealReflector_eff[NUM] = {0.0, 0.0}; //don't' detect anything
    idealReflector_MPT->AddProperty("RINDEX", pp, idealReflector_rindex, NUM);
    idealReflector_MPT->AddProperty("REFLECTIVITY", pp, idealReflector_refl, NUM);
    idealReflector_MPT->AddProperty("EFFICIENCY", pp, idealReflector_eff, NUM);
    idealReflector_MPT->AddProperty("SPECULARLOBECONSTANT", pp, specularlobe, NUM);
    idealReflector_MPT->AddProperty("SPECULARSPIKECONSTANT", pp, specularspike, NUM);
    idealReflector_MPT->AddProperty("BACKSCATTERCONSTANT", pp, backscatter, NUM);
    idealReflector->SetMaterialPropertiesTable(idealReflector_MPT);
    new G4LogicalBorderSurface("scintillator_reflector_border", scint_phy, refl_phy, idealReflector);

Despite 100% reflectivity, the photon was killed in the last Transportation step. This shouldn’t happen. What’s wrong here?

I don’t know. I suggest stepping through it with a debugger, and/or trying to reproduce with OpNovice2 example.

It seems that the problem is with “groundbackpainted” surface finish.

I used OpNovice2 with a modified OpNovice2.mac macro to make the cube surface a perfect Lambertian reflector:

/control/verbose 2
/tracking/verbose 2
/run/verbose 1
/process/optical/verbose 1
/control/cout/ignoreThreadsExcept 0

/opnovice2/boxProperty RINDEX 0.000002 1.3 0.000008 1.4
/opnovice2/boxProperty ABSLENGTH 0.000002 1000000 0.000005 2000000 0.000008 3000000

/opnovice2/worldProperty RINDEX 0.000002 1.01 0.000008 1.01
/opnovice2/worldProperty ABSLENGTH 0.000002 1000000 0.000005 2000000 0.000008 3000000

/opnovice2/surfaceModel unified
/opnovice2/surfaceType dielectric_dielectric
/opnovice2/surfaceFinish ground #groundbackpainted
/opnovice2/surfaceSigmaAlpha 1.1
/opnovice2/surfaceProperty SPECULARLOBECONSTANT 0.000002 .0 0.000008 .0
/opnovice2/surfaceProperty SPECULARSPIKECONSTANT 0.000002 .0 0.000008 .0
/opnovice2/surfaceProperty BACKSCATTERCONSTANT 0.000002 .0 0.000008 .0
/opnovice2/surfaceProperty REFLECTIVITY 0.000002 1.0 0.000008 1.0

/run/initialize
#
/gun/particle opticalphoton
/gun/energy 3 eV
/gun/position 0 0 0 cm
/gun/direction 1 0 0 
/opnovice2/gun/optPhotonPolar

When using /opnovice2/surfaceFinish ground it runs as expected:

Surface events (on +X surface, maximum one per photon) this run:
# of primary particles:         1e+02
OpAbsorption before surface:        0
Total # of surface events:        100
Unaccounted for:                    0

Surface events by process:
  Fresnel refraction:              46
  Lambertian reflection:           54
 Sum:                             100
 Unaccounted for:                   0
---------------------------------

When I change a single line in this script and set /opnovice2/surfaceFinish groundbackpainted it suddenly doesn’t know the refractive index anymore and the surface absorbs all photons:

Surface events (on +X surface, maximum one per photon) this run:
# of primary particles:         1e+02
OpAbsorption before surface:        0
Total # of surface events:        100
Unaccounted for:                    0

Surface events by process:
  No RINDEX:                      100
 Sum:                             100
 Unaccounted for:                   0
---------------------------------

Do you specify a RINDEX for the surface when using groundbackpainted? There needs to be one for the dielectric part of the material. It looks like RINDEX was specified for the surface in your first post, but not with OpNovice2 test.

Yes, you are right. It requires surface coating refractive index.

/control/verbose 2
#/tracking/verbose 2
/run/verbose 1
/process/optical/verbose 1
/control/cout/ignoreThreadsExcept 0

/opnovice2/boxProperty RINDEX 0.000002 1.91 0.000008 1.91
/opnovice2/boxProperty ABSLENGTH 0.000002 1000000 0.000005 2000000 0.000008 3000000

/opnovice2/worldProperty RINDEX 0.000002 1.0 0.000008 1.0
/opnovice2/worldProperty ABSLENGTH 0.000002 1000000 0.000005 2000000 0.000008 3000000

/opnovice2/surfaceModel unified
/opnovice2/surfaceType dielectric_dielectric
/opnovice2/surfaceFinish groundbackpainted
/opnovice2/surfaceSigmaAlpha 1.1
/opnovice2/surfaceProperty SPECULARLOBECONSTANT 0.000002 .0 0.000008 .0
/opnovice2/surfaceProperty SPECULARSPIKECONSTANT 0.000002 .0 0.000008 .0
/opnovice2/surfaceProperty BACKSCATTERCONSTANT 0.000002 .0 0.000008 .0
/opnovice2/surfaceProperty REFLECTIVITY 0.000002 1.0 0.000008 1.0
/opnovice2/surfaceProperty RINDEX        0.000002 1.35 0.000008 1.35

/run/initialize
#
/gun/particle opticalphoton
/gun/energy 3 eV
/gun/position 0 0 0 cm
/gun/direction 1 0 0 
/opnovice2/gun/optPhotonPolar
#

/analysis/setFileName opnovice
#/analysis/h1/set 3  40 -1 39
#/analysis/h1/set 4  100 -1.1 1.1
#/analysis/h1/set 5  100 -1.1 1.1
#/analysis/h1/set 6  100 -1.1 1.1
#/analysis/h1/set 7  100 -1.1 1.1
#/analysis/h1/set 8  100 -1.1 1.1
#/analysis/h1/set 9  100 -1.1 1.1
#/analysis/h1/set 10 100 -1.1 1.1
/analysis/h1/set 24 100 0 100
/analysis/h1/set 25 100 0 100

/run/beamOn 100

It runs now, but it produces different results then my code and than I expected.

Surface events (on +X surface, maximum one per photon) this run:
# of primary particles:         1e+02
OpAbsorption before surface:        0
Total # of surface events:        100
Unaccounted for:                    0

Surface events by process:
  Fresnel refraction:              33
  Lambertian reflection:           67
 Sum:                             100
 Unaccounted for:                   0
---------------------------------

There are 33 Fresnel refractions which means that photons are transmitted through the surface. I wanted to create a perfect reflector which reflects 100% photons, and the description of “GroundBackPainted” surface says that there are only Lambertian reflections available for this surface, so I don’t understand how refraction happens.

I don’t know how the process is determined for groundbackpainted. Each surface interaction may be three or more scatterings. (volume to surface dielectric, dielectric-paint, dielectric back to volume). Check with visualization or verbose output where the photons are actually going.

On visual inspection I don’t see any photons transmitted. Now, I’m very confused what is this code doing. The description says “Lambertian only”, while OpNovice says that there are refractions, but when running visualization there are no transmitted photons.

The reflection from the paint is Lambertian. I think the the status FresnelRefraction is being set at the boundary between the volume and the surface dielectric. I would have to step through the code with a debugger to give a more detailed answer. If you try it and are still not convinced, let me know.