Skip to content

Add dbs to radiative splitting#974

Draft
blakewalters wants to merge 63 commits intonrc-cnrc:developfrom
blakewalters:add-dbs_to_radiative_splitting
Draft

Add dbs to radiative splitting#974
blakewalters wants to merge 63 commits intonrc-cnrc:developfrom
blakewalters:add-dbs_to_radiative_splitting

Conversation

@blakewalters
Copy link
Copy Markdown
Contributor

@blakewalters blakewalters commented Mar 11, 2023

This is a draft PR for the DBS option in the EgsRadiativeSplitting ausgab object and will be migrated to a regular PR once testing is complete, some of the more obvious bugs are ironed out, and it's been rebased on the current develop branch.

EGS developers are encouraged to download and try out the branch and provide comments and corrections as needed. Note also that posting of test results in the comment feed below is encouraged.

@blakewalters
Copy link
Copy Markdown
Contributor Author

Plots showing results of some initial tests in which I compared spectra using DBS in egs++, BEAMnrc and beampp in 2 different applications:

  1. EX16MVp

EX16MVp_DBS_comparison_spectra

  1. A 450 kVp X-ray tube (spectra scored in vacuum)

i) With bound Compton (i.e. not using SmartCompton in DBS):

450kV_rad_splitting_test_in_vac

ii) Without bound Compton (i.e. using SmartCompton in DBS):

450kV_rad_splitting_test_in_vac_smart_compt

From 2.ii, it's clear that using SmartCompton in the egs++ DBS algorithm has introduced some bias. Currently, the algorithm uses the same SmartCompton implementation as beampp. I plan to replace this implementation with the one found in BEAMnrc and see if the difference persists.

@ftessier
Copy link
Copy Markdown
Member

This is awesome @blakewalters. I move to merge this in develop soon, so that we have a lead testing time in the field before the next release! Let's review this on the short term!

@blakewalters blakewalters force-pushed the add-dbs_to_radiative_splitting branch from 9480277 to 20c8ac7 Compare May 12, 2023 23:56
@blakewalters
Copy link
Copy Markdown
Contributor Author

blakewalters commented May 13, 2023

Update 13/05/2023: After implementing BEAMnrc's SmartCompton algorithm (translated into C++) in the egs_radiative_splitting DBS routine, agreement between BEAMnrc and egs++ in the 450 kVp tube case shown above is inching ever closer:

450kV_rad_splitting_test_in_vac_smart_compt_12052023

In fact, at this point we might say there's no significant difference.

Continued testing is needed, though, given that, during one of these 450 kVp validation runs, I noted a phat photon crossing the scoring plane with r < DBS splitting radius.

@blakewalters
Copy link
Copy Markdown
Contributor Author

blakewalters commented Jul 7, 2023

Update 07/07/2023:

After finding/fixing the bug in the SmartCompton method which was causing the odd high weight photon to be scored inside the splitting field (see update from 13/05/2023 above), 450 kVp X-ray photon spectra calculated using the DBS routine implemented in egs_radiative_splitting both with and without SmartCompton (i.e. using the standard EGSnrc Compton routine) look to be in good agreement as shown in the figure below.

450kV_rad_splitting_test_in_vac_smart_compt_2

This is borne out in a plot of the fractional difference between egs++ and BEAMnrc spectra. However, this plot also highlights significant differences (>5% at the extreme ends of the spectrum) between BEAMnrc and egs++ results (Note: In a previous edit of this comment, I'd erroneously labeled the vertical axis (BEAMnrc-egs++)/egs++ when, in fact, fractional differences are given relative to BEAMnrc results).

450kV_rad_splitting_test_in_vac_smart_compt_2_diff

At this point, I can't say much about the source of these differences except that they're most likely not coming from egs++ DBS's handling of Compton events!

I think it might be worth repeating the egs++ simulations with UBS just to confirm that the difference isn't due to any slight differences in geometry between BEAMnrc and egs++.

@ftessier
Copy link
Copy Markdown
Member

ftessier commented Jul 7, 2023

Wonderful @blakewalters!

@blakewalters
Copy link
Copy Markdown
Contributor Author

blakewalters commented Sep 15, 2023

Update 09/22/2023:

Implementation of beampp's SmartCompton algorithm in egs++ (as opposed to the BEAMnrc SmartCompton algorithm from the previous update) results in similar differences with BEAMnrc:

450kV_rad_splitting_test_in_vac_smart_compt_6_diff_bpp_sc

Erratum: The first edit of this post from 09/15/2023 showed agreement between BEAMnrc and egs++ with the regular Compton routine used in place of Smart Compton. This was incorrect and, moreover, contradicts the results above from 07/07/2023.

A comparison of photon fluence vs radial position for BEAMnrc (SmartCompton) vs egs++ with both SmartCompton and regular Compton shows fairly close agreement:

dbs_test_pflu

While photon energy fluence is visibly significantly lower for the egs++ cases:

dbs_test_penflu

Indicating that, perhaps, the issue is actually "upstream" of Compton interactions and may be in the energy distribution of brems photons...

@mainegra
Copy link
Copy Markdown
Contributor

@blakewalters great job! Is the above the current status?

@blakewalters
Copy link
Copy Markdown
Contributor Author

That's where it's at, @mainegra. My next debugging step will be to see if there's something going on with the energies of the split brem photons. These energies are determined in a separate function after the interaction has been split and the photons generated.

link to egs_advanced_appliction.o when
compiling shared lib.
Note: Currently does not work.  This commit
is just to save recent changes.
Overrides key macros from egs_c_interface2.macros.
required EGSnrc calls in egs_advanced_application.

Also correcting some of the functions erroneously
coded with np->np+1!
1. Add calls to EGSnrc subroutines to egs_advanced_application
2. Fix major bugs in DBS algorithm
3. Introduce initializeData ausgab_object function.
@blakewalters
Copy link
Copy Markdown
Contributor Author

Thanks, @rtownson! I'll start there.

@blakewalters
Copy link
Copy Markdown
Contributor Author

blakewalters commented Oct 9, 2024

Update Oct 9, 2024

Using the egs_fluence ausgab object together with egs_beam_source, I've been able to use egs++ to calculate BEAMnrc photon spectra down to ~0.05% uncertainty. As a result, we can more precisely compare BEAMnrc and egs++ results.

The plot below shows the fractional difference between 225 kVp reflection spectra with relaxation effects on and eii on where now egs++ spectra with DBS (egs++_DBS) and UBS (egs++_UBS) are compared against the BEAMnrc spectrum with DBS (ssd=10 cm, r=10 cm, nsplit=10000).

225kVp_refl_split_test_pspect_diff_2

The plot clearly shows the ~1% difference between egs++ and BEAMnrc consistent with the previous update and which we surmise is due to slight differences in anode geometry.

Note, however, that egs++_UBS is ~0.2% higher than BEAMnrc at the peak at ~62 keV (this shows up as a ~0.2% dip in fractional difference relative to BEAMnrc). This is similar to the fractional difference between egs++_UBS and egs++_DBS at this energy, and we may cautiously advance that the treatment of fluorescent photons resulting from eii events in egs++_DBS is consistent with that in BEAMnrc with DBS (or BEAMnrc_DBS, if that's easier). This makes sense, given that egs++_DBS is heavily based on the DBS implementation in BEAMnrc.

The plot below shows a comparison of 225 kVp spectra using a transmission target, where no differences between BEAMnrc and egs++ geometries are expected:

225kVp_trans_split_test_pspect_diff_2

In this case, egs++_DBS and BEAMnrc_DBS show agreement to < 0.05% with the exception of the lowest energy bins, where uncertainties are > 1%. The spectrum calculated using egs++_UBS, however, is ~0.15% higher at the ~62 keV peak (showing up as a ~0.15% dip in the above plot). This is consistent with the ~0.2% higher peak seen in the egs++_UBS spectrum from the reflection anode (first plot). We also note a ~0.05% difference between egs++_UBS and BEAMnrc at ~190 keV, although this difference is likely within statistical uncertainty.

We can hesitatingly conclude, then, that treatment of fluorescent photons resulting from eii is the same in egs++_DBS and BEAMnrc_DBS. The question now is: Why are they both ~0.2% low at the K-shell peak(s)?

@blakewalters
Copy link
Copy Markdown
Contributor Author

@mainegra, @ftessier, @rtownson:

Continuing on with testing of the DBS implementation in EGSRadiativeSplitting, I've been mulling over a couple of questions:

  1. How do we implement DBS so that it will work with transformed sources? Right now, the implementation assumes the source is at Z=0, with the SSD and splitting radius defined relative to this. It would be easy to add more inputs to the AO to allow the user to translate/rotate the splitting field, but would it be more convenient and useful to somehow be able to "attach" a DBS splitting field to a particular source? That way, when a source is transformed, the relevant DBS splitting parameters are automatically transformed along with it. I guess an option would be to implement an "egs++_simulation_source" (something we might want to do anyway), in which case the DBS AO would just be part of the source simulation that can then be transformed in any way the user wishes in the second-stage simulation. Come to think of it, that might be the best way to accomplish this. Thoughts?

  2. What about BCSE? I'm assuming we ultimately want to implement BCSE along with DBS, but this will require hooking into MORTRAN macros inside of EGSnrc. It's currently fairly straightforward to access subroutines inside EGSnrc, but I don't know if macros can be modified, short of making changes to interface coding (e.g., egs_c_interface2.macros). Let me know if any of you know another way!

@mainegra
Copy link
Copy Markdown
Contributor

  • Adding enough info during input to allow for arbitrary splitting field definition would be my choice
  • BCSE is implemented in egs_brachy, perhaps a good place to start?

@rtownson
Copy link
Copy Markdown
Collaborator

rtownson commented Nov 26, 2024

The DBS should not be tied to the source or the way it is transformed, it should be completely independent IMO.

Ideally, it should let you set filter where it takes place by geometry, include regions and include media like in egs_isotropic_source. Then use a generic shape (not just a circle?) with a transform to denote the field, like the target shape for egs_collimated_source. This might be tricky to check, so if a circular cone is easier that's fine with me!

@ftessier
Copy link
Copy Markdown
Member

I agree with @mainegra and @rtownson, except that I feel there should be an option to transform the target shape with the source. That is, when dealing with an egs_transformed_source, one could opt to apply the transformation to the target shape as well. Seems simple enough to implement, a flag and corresponding conditional to multiply by T, the transformation. Perhaps this ought to be a generic source option, useful for egs_collimated_source as well, for example.

@rtownson
Copy link
Copy Markdown
Collaborator

I agree with @mainegra and @rtownson, except that I feel there should be an option to transform the target shape with the source. That is, when dealing with an egs_transformed_source, one could opt to apply the transformation to the target shape as well. Seems simple enough to implement, a flag and corresponding conditional to multiply by T, the transformation. Perhaps this ought to be a generic source option, useful for egs_collimated_source as well, for example.

I thought this was already essentially the case. Since egs_transformed_source transforms whatever particle you get out of the original source, which already had its direction towards the target. Thus its direction toward the target gets transformed to point toward a new target, as per the rotation in the transformation. Or are you imagining something else?

@ftessier
Copy link
Copy Markdown
Member

Yes, of course you are right! What I had in mind is that the DBS target shape would be defined within the source, not within the ausgab object. Or perhaps one could define a completely decoupled DBS field in the ausgab object? I can think of scenarios where either makes sense.

@rtownson
Copy link
Copy Markdown
Collaborator

Ah I see. I was certainly imagining a completely decoupled ausgab object. It feels unintuitive to place inputs for an ausgab object inside of a source. What if you had a collection of sources? You'd have to just have one target, in the source collection, but a user might put it in each of their sub sources, etc..

I can also imagine wanting several DBS ausgab objects. What if you have a simulation of multiple x-ray tubes?

@blakewalters
Copy link
Copy Markdown
Contributor Author

blakewalters commented Nov 27, 2024

@ftessier and @rtownson, this is why I was thinking that a shared library source might be the best way to take care of this: DBS is defined as an ausgab object in the source simulation and then that source can be duplicated/transformed in the 2nd stage simulation without having to worry about defining multiple DBS AO's. Kind of like what already happens when we use BEAMnrc to simulate an X-ray tube and then use this as a source in egs++. Of course, there may be issues with optimizing DBS parameters across multiple transformed sources.

@ftessier
Copy link
Copy Markdown
Member

ftessier commented Dec 2, 2024

Now that I think about it, would it makes sense to implement DBS as a source feature with a target shape, instead of an ausgab object? I know that DBS is implemented as a region-based VRT, so to speak, and does not fit in the source... But perhaps there is a way to adjust our thinking and make it a source feature? 🤔

@blakewalters
Copy link
Copy Markdown
Contributor Author

blakewalters commented Dec 2, 2024

@ftessier: After today's chat with @mainegra and @rtownson, we've arrived at the following steps for egs++ DBS implementation:

  1. Within the AO, implement the option to transform (rotate/translate) the DBS splitting cone.

  2. Also implement an option to read in the (active) source transform so that the the DBS splitting cone can also either: a) move with a dynamic source or b) be applied to the current source in a source collection. This transform would be applied on top of any transform input in the AO itself (i.e., step 1).

Priority, of course, is benchmarking the DBS routine for accuracy, and the hope is that all of us can undertake more extensive testing of the routine at some point between implementing step 1 and step 2.

There is also an issue with the UBS implementation in egs++ resulting in a ~0.15% discrepancy in the photon spectrum at the K-shell peak when electron impact ionization (EII) is on (see above). Although peripherally related to DBS, we would like to solve this as well.

@mainegra and @rtownson, please let me know if I'm missing anything essential from our discussion here.

@blakewalters
Copy link
Copy Markdown
Contributor Author

blakewalters commented Dec 3, 2024

Update 12/03/2024:

Testing with IBRDST=1

Continuing testing of the egs++ DBS implementation, I was interested in seeing its accuracy when the full Koch-Motz (KM) distribution is used for bremsstrahlung angular sampling (IBRDST=1). This is done by setting "brems angular sampling=KM" in the transport parameter input block. Note that comparisons above only the leading term of the KM distribution (IBRDST=0), or "brems angular sampling=simple" in the transport parameter inputs.

The plot below shows the fractional difference in the 225 kVp transmission photon spectra between the baseline case using the "simple" brems angular distribution and when the full KM expression is used. BEAMnrc was used to generate both spectra. Worth noting here is that in current egs++ DBS implementation (as in BEAMnrc DBS) smartBrems is not used when IBRDST=1. This differs from Iwan's beampp implementation of DBS, in which smartBrems does have conditions for handling IBRDST=1.

225kVp_trans_split_test_relaxon_simple_km_diff

Use of the full KM distribution results in differences in the energy spectrum ranging from -0.2% at 120 keV to 0.8% at 225 keV. Given that egs++ with DBS agrees with BEAMnrc with DBS to within <~0.05%, then, potential issues arising when IBRDST=1 is used with the egs++ DBS routine should be visible in a comparison with BEAMnrc (also using IBRDS=1).

The plot below shows the fractional difference in transmission photon spectra generated using egs++ with DBS and BEAMnrc with DBS where the full KM distribution is used for brems angular sampling in both simulations (black). The plot also shows the fractional difference when egs++ with UBS is used (red line).

225kVp_trans_split_test_pspect_diff_ibrdst1

This shows that, even using the full KM distribution, egs++ with DBS agrees with BEAMnrc with DBS to within ~0.05%. We also note that the ~0.2% difference at the K-shell peak (~60 keV) between BEAMnrc and egs++ with UBS when electron impact ionization (EII) is on persists with IBRDST=1.

A side issue: Comparison of egs++ with UBS and BEAMnrc with UBS against BEAMnrc_DBS:

In making these IBRDST=1 comparisons and attempting to locate the source of the discrepancy between egs++_UBS and BEAMnrc_DBS (and egs++_DBS) at ~60 keV, I also introduced into the comparison runs with BEAMnrc using UBS (nsplit=100) and found some "interesting" results overall.

Both figures below show the same plot of fractional difference between the photon spectra generated with egs++_UBS and BEAMnrc_UBS and our baseline BEAMnrc_DBS case at two different scales. Simulations with UBS were run with charged particle Russian Roulette on and off. In all cases, I reverted to the simple brems angular distribution (IBRDST=0).

225kVp_trans_split_test_pspect_diff_ubs_beamnrcdbs_fullscale

225kVp_trans_split_test_pspect_diff_ubs_beamnrcdbs

The full-scale plot (upper figure) shows significant differences between BEAMnrc with UBS and Russian Roulette on (green line) and BEAMnrc with DBS at energies < 50 keV, with differences of ~40% at energies <= 20 MeV. These large differences disappear when Russian Roulette is turned off (magenta line). The close-up (lower figure) shows that the ~0.2% difference between egs++ with UBS and BEAMnrc with DBS at the K-shell persists when Russian Roulette is turned off (red and black lines). Moreover, we don't see this difference with BEAMnrc_UBS when Russian Roulette is off (magenta line), a further indication of an issue with the UBS implementation in egs++ (with EII on).

Therefore, while not distracting ourselves too much from the original egs++ DBS implementation, these tests have given rise to a couple of UBS-related questions that need to be addressed:

  1. What is the source of the large discrepancy at low energies with BEAMnrc UBS when Russian Roulette is on? How does the implementation of Russian Roulette in BEAMnrc differ from that in egs++ (and EGSnrc)? Is this somehow an artifact of how I'm using BEAMnrc as a simulation source in an egs++ simulation when generating BEAMnrc spectra?
  2. What is causing the discrepancy at ~60 keV in the egs++ implementation of UBS (with EII on)?

@ftessier
Copy link
Copy Markdown
Member

ftessier commented Dec 4, 2024

  1. Within the AO, implement the option to transform (rotate/translate) the DBS splitting cone.

  2. Also implement an option to read in the (active) source transform so that the the DBS splitting cone can also either: a) move with a dynamic source or b) be applied to the current source in a source collection. This transform would be applied on top of any transform input in the AO itself (i.e., step 1).

Why are we considering a cone, instead of a general target shape for DBS?

@blakewalters
Copy link
Copy Markdown
Contributor Author

@ftessier, only because the smartBrems and smartCompton routines in DBS pre-calculate the number of split particles to generate based on the photon angular distributions for the respective interactions and a splitting field with a circular base (i.e. a cone). I guess we could use a rejection technique to make the shape of the field more general, and ultimately we may want to try this, but it doesn't seem like a priority at this point in the implementation.

@ikawrakow
Copy link
Copy Markdown

I guess we could use a rejection technique to make the shape of the field more general, and ultimately we may want to try this, but it doesn't seem like a priority at this point in the implementation.

It is obvious, right? And so elegant - just do UBS and Russian Roulette away the photons not going towards the FOI. What was Kawrakow thinking?

It was 20 years ago, but if IIRC, the speed gain from estimating the probability to emit bremsstrahlung or Compton-scatter into the FOI was very significant. The probability estimate used in the BEAMnrc implementation is just that - an estimate. It overestimates, and the overestimation can be quite significant in some cases. When I was implementing the treatment head simulation code for ViewRay I was able to derive a better estimate (compared to what is in BEAMnrc) and that sped it up by a factor of 2, IIRC. If you want to give the user the ability to define arbitrary FOIs, that will come at very significant efficiency cost.

@blakewalters
Copy link
Copy Markdown
Contributor Author

blakewalters commented Dec 4, 2024

@ikawrakow, you really are at large (but hopefully not at loose ends)! Yes, I suspected it would be a nontrivial matter to give the user the option to define an arbitrarily-shaped splitting field. Thanks for confirming this! And that offering the flexibility of defining a sawtooth splitting field or one that says "Bernie 2028" is really not worth the hit to efficiency.

Add option to apply affine transform to the DBS splitting cone.
@blakewalters
Copy link
Copy Markdown
Contributor Author

blakewalters commented Jan 9, 2025

Update 01/08/2025

Recently, the ability to apply an affine transform to the DBS splitting cone (defined by the splitting ssd and radius, fs, of the splitting field) has been implemented. This allows the user to user to orient the splitting geometry to match that of the e- beam and bremsstrahlung target.

To put this functionality through its paces, I evaluated the difference between the 225 kVp photon transmission spectra generated with the transforms illustrated in the figure below (T1-T3) and that with no transform applied to the splitting geometry (T0). In each transformed case, the transform applied to the DBS splitting cone matches an equivalent transform of the incident e- beam/target geometry. In all cases, DBS splitting parameters are: nsplit=1000, ssd=10 cm, fs=10 cm.

In T1, the target geometry/splitting cone has been translated +10 cm in both X- and Y-directions; in T2, the geometry has been rotated 45-degrees counterclockwise about the Y-axis; and in T3, the geometry has first been rotated 180-degrees about the Y-axis then translated -10cm in the Z-direction.

Fractional differences between the spectrum with no transform and spectra with transforms T1-T3 are shown in the figure below:

dbs_transform_pspect_diff

Note that I've exaggerated the -ve portion of the vertical axis to show that differences in low energy (<20 keV) components of the spectra are within uncertainty, although the photon fluence in this energy range is a factor of 2-3 lower than elsewhere in the spectra.

With the exception of low energy photons, this plot shows agreement to within ~0.05% between results with transforms applied to the splitting cone and the untransformed case, thus giving us confidence that transforming the splitting cone does not alter the results. Even so, some questions remain:

  1. In order to obtain approximately the same uncertainty with T2 (45-degree rotation of the geometry about the Y-axis) as in the untransformed case, I had to increase the no. of incident histories by a factor of 4. Why?
  2. Despite the fact that spectra < 20 keV agree within uncertainty, why are the differences so large, and why are they consistently -ve (i.e. higher than in the untransformed case)?

I make no claim that these cases represent an exhaustive test of the effects of transforming the splitting geometry, and suggests for further testing are welcome!

@blakewalters
Copy link
Copy Markdown
Contributor Author

blakewalters commented Feb 27, 2025

Update 02/26/2025

In the 3 most recent commits to this PR, I've implemented a charged particle splitting option in egs++ DBS. Inputs for this option existed prior to this, but were not enabled.

Charged particle splitting can be used when one is interested in recovering some of the contaminant electrons which are otherwise subject to Russian Roulette when DBS is used in simulating photon beams. This then allows the user to examine quantities such as the spectrum and fluence of these electrons, contaminant dose, etc.

In BEAMnrc DBS, e-/e+ splitting is done at a horizontal region boundary, the "splitting plane", within a component module (CM--always FLATFILT). Charged particles crossing this region boundary are split nsplit (i.e. the bremsstrahlung splitting no.) times with their weight reduced by a factor of 1/nsplit, with an option to redistribute split particles evenly about a circle of radius sqrt(x^2+y^2), where x and y are the X- and Y-positions of the particle at the splitting plane prior to splitting. This latter option is known as "radial redistribution" of split particles, and can improve spatial sampling of charged particles for beams with radial symmetry. In addition, the user is also asked to input the Z-position of a Russian Roulette plane (zrr) below which Russian Roulette is no longer played with charged particles and Russian Roulette IS played with photons about to undergo photoelectric, pair production or Compton events. These events are then split to generate nsplit (or nsplit*2 in the case of pair production) low-weight charged particles. In general, zrr is < the Z-position of the splitting plane. For more information on e-/e+ splitting, see the BEAMnrc Manual.

The implementation of charged particle splitting in egs++ DBS is similar to that in BEAMnrc DBS. Inputs are also similar, with the difference that the splitting plane is not restricted to a region boundary within a CM but can be any region or group of regions in the geometry. On entering this(these) region(s), phat charged particles are immediately split and possibly radially redistributed about the Z-axis. This offers greater flexibility, but may also prove a pitfall, in that it is difficult to imagine a situation where the splitting plane should not be perpendicular to the beam axis and encompass the entire beam field (at that plane).

Also, in egs++ the charged particle splitting plane is subject to any transform applied to the DBS splitting cone (see above). Thus, radial redistribution of split particles about the transformed plane would actually place particles outside their original (untransformed) region. To avoid this possibility, if the radial redistribution option is used, we always redistribute split particles evenly about the Z-axis in the original (untransformed) geometry. This means that split particles may not end up being evenly distributed about the beam axis (which, presumably, is the same as the transformed axis of the splitting cone), and so we advise against radial redistribution of split charged particles in cases where you are also applying a transform to the DBS splitting cone.

Onward, then, to testing of the e-/e+ splitting option, in which I repeat many of the tests above for the 225 kVp transmission beam but now examine both photon and electron spectra at the splitting ssd. In the case of electron spectra, I've increased the field radius considered to 20 cm (splitting radius=10 cm) in an attempt to improve the statistics of the e- spectrum (and recognizing that the fluence of contaminant e- is not restricted to the DBS splitting field).

More to come, stay tuned!

@blakewalters
Copy link
Copy Markdown
Contributor Author

blakewalters commented Feb 28, 2025

Update 02/27/2025

...continued from previous update.

As mentioned above, tests of e-/e+ splitting use the same 225 kVp photon transmission setup used in earlier tests, with a point source of e- incident on an infinite W slab (target) of thickness 0.01 cm. Below the target is vacuum.

The first comparisons between BEAMnrc and egs++ DBS with the e-/e+ splitting option involved placing the splitting plane at the bottom of the W target (at Z=0.01 cm) and the Russian Roulette plane (zrr) at 1 cm (i.e. in vacuum below the target). Since interactions resulting in charged particles (pair production, photoelectric, Compton) are only split below zrr, this ensures that all charged particles reaching the splitting plane are phat and, thus, serves as a test of splitting (and radial redistribution) at this plane.

The figure below shows the e- spectra 10 cm below the target (i.e. at the DBS ssd) in a circle of radius 20 cm:

225kVp_trans_split_test_esplit_zrr1cm_electron

In BEAMnrc and egs++, charged particle splitting at the splitting plane has resulted in improved statistics in the e- spectra, and superficial agreement between BEAMnrc and egs++ e- spectra can be seen. A plot of particle weights (not shown) indicates that all e- reaching the scoring plane have weight=1/1000, as expected.

The plot below shows the fractional difference between the BEAMnrc and egs++ e- spectra in this case:

225kVp_trans_split_test_esplit_zrr1cm_electron_diff

This shows agreement between BEAMnrc and egs++ e- spectra within an uncertainty of 2-10%.

The figure below shows the fractional difference between BEAMnrc and egs++ photon spectra (scored in a field with r=10 cm at the ssd) for this e-/e+ splitting case:

225kVp_trans_split_test_esplit_zrr1cm_photon_diff

Similar to earlier comparisons without e-/e+ splitting, BEAMnrc and egs++ photon spectra agree to within ~0.05%

In order to make a more definitive statement about the agreement between BEAMnrc and egs++ e-spectra, I wanted to generate e- spectra with uncertainties < 0.1%. I found that with zrr=1 cm, however, this required > 100x10^9 histories, which presented a challenge given the computing resources available. With this in mind, I varied the value of zrr in an attempt to optimize e- statistics, ultimately arriving at zrr=0.005 cm (i.e., halfway through the target), which allowed me to generate spectra having < 0.1% uncertainty at their peak (kinetic energy=40 keV) using 40x10^9 histories.

The plot below shows the fractional difference between BEAMnrc and egs++ e- spectra with this new value of zrr:

225kVp_trans_split_test_esplit_zrr005cm_electron_diff_2

From this plot, we can infer that BEAMnrc and egs++ e- spectra agree to within < 0.5% over most of the energy range, certainly a stronger statement regarding agreement than we were able to make above.

Comparing the photon spectra with this value of zrr (and no. of histories), though, we obtain the following:

225kVp_trans_split_test_esplit_zrr005cm_photon_diff_2

Which shows that, while agreeing within the uncertainty of the calculation, the egs++ photon spectrum is consistently higher than the BEAMnrc spectrum by ~0.01%. For reference, the plot also shows the comparison between photon spectra using identical simulation parameters but without e-/e+ splitting. This latter comparison exhibits something closer to the expected variations around zero, leading us to conclude that use of e-/e+ splitting introduces a systematic positive bias in the photon spectrum.

The plot below shows the fractional difference between photon spectra with e-/e+ splitting on and off for both BEAMnrc and egs++:

225kVp_trans_split_test_esplit_on_off_beamnrc_egs++_photon_diff_2

The plot clearly indicates that e-/e+ splitting introduces a systematic increase at the ~0.01% level in the egs++ photon results, while this is not the case for BEAMnrc.

Although this is a very small-scale (higher-order?) issue, it may end up having a larger effect at different energies and/or source configurations, and so it seems that some further debugging of the e-/e+ splitting algorithm in egs++ DBS is warranted. Stay tuned...again!

@blakewalters
Copy link
Copy Markdown
Contributor Author

Update 03/27/2025

By a process of systematically omitting photon interactions that may be split when e-/e+ splitting is on--pair production, photoelectric, Compton, and Rayleigh scattering--from the simulations (luckily, this is fairly straightforward in the egs++ implementation of DBS!), it appeared that Rayleigh interactions could be the source of the difference between photon spectra with e-/e+ splitting on and off. Indeed, the fractional differences between the egs++ photon spectra with e-/e+ splitting on and off both with and without Rayleigh scattering included in the simulations seem to bear this out. Below is a plot showing these fractional differences, where the resolution of the photon spectra has been halved (i.e. 10 energy bins over the range 0-225 keV) in an attempt to reduce the simulation time required to obtain the uncertainties required to resolve these differences:

225kVp_trans_split_test_esplitonoff_raylonoff_diff

Here we see that, when Rayleigh splitting is on, the photon spectrum with e-/e+ splitting is systematically ~0.02% higher than that without e-/e+ splitting (consistent with our result from 02/27/2025). With Rayleigh splitting off, however, the systematic aspect of the difference largely disappears, perhaps with an exception at higher energies, where significant differences are more difficult to resolve because of the higher uncertainties.

After my initial observation that the Rayleigh scattering implementation in egs++ DBS--which is essentially a copy of that in BEAMnrc DBS--may be the cause of the discrepancy between photon spectra with and without e-/e+ splitting, I did a fairly extensive debugging operation on this Rayleigh scattering implementation. Detailed output of the various angular sampling routines (Rayleigh angular sampling followed by "adjustment" of scattering angles by a random azimuthal angles using the routine UPHI(2,1)), however, revealed no obvious reasons why the photon spectrum with e-/e+ splitting on and when Rayleigh scattering is simulated would systematically include more photons than that with e-/e+ splitting on. I was, thus, left with the possibility that Rayleigh scattering is simply magnifying some other discrepancy resulting from e-/e+ splitting.

Still pursuing the idea of a bug in the egs++ DBS implementation of Rayleigh scattering, however, I plotted the fractional differences between BEAMnrc and egs++ photon spectra with no e+/e- splitting, comparing the differences with Rayleigh scattering on and off. Results are shown in the plot below:

225kVp_trans_split_test_raylonoff_diff

Within uncertainty, this shows no significant systematic "difference between the differences" whether Rayleigh is included in the simulation or not, lending further credence to the possibility that Rayleigh is simply amplifying a discrepancy introduced by e-/e+ splitting. To see if this also might be the case in BEAMnrc DBS, I plotted the fractional difference between BEAMnrc photon spectra with and without e-/e+ splitting when Rayleigh scattering is off and on. Results are shown in the graph below:

225kVp_trans_split_test_esplitonoff_raylonoff_beamnrc_diff

This appears to show that the photon spectrum is systematically greater (i.e. more particles across all energies) with e-/e+ splitting when Rayleigh scattering is off, which is the opposite of the behaviour with egs++ DBS! Uncertainties in these BEAMnrc results, however, are larger than those with egs++, making it difficult to draw definitive conclusions.

At this point, we cautiously surmise that e-/e+ splitting may be introducing a very small bias in the photon spectrum, the presence of which is rendered noticeable to within 0.01-0.02% when Rayleigh scattering is on. More accurate simulations, however, will be required to: 1) confirm with certainty that this bias exists and 2) determine whether or not it also exists in BEAMnrc DBS.

I have already started rerunning the above egs++ simulations with 4x the original number of histories (40x10^9 histories in all) to answer questions 1) and 2) above. These results will be posted here when available.

Adventurous souls are also invited to look through the DBS e-/e+ splitting implementation in egs_radiative_splitting to see where there may be a bug that would introduce a 0.01-0.02% discrepancy in photon spectra.

In the meantime, testing of the e-/e+ splitting implementation on other fronts--such as confirming that transforming the DBS splitting cone does not change the e- and photon spectra collected in a plane perpendicular to the beam--continues...

@blakewalters
Copy link
Copy Markdown
Contributor Author

blakewalters commented Mar 27, 2025

Update 03/27/2025 PM

Leaving behind the observed 0.01-0.02 % discrepancy between photon spectra with and without e-/e+ splitting (when Rayleigh scattering is on) for the moment, let us continue with testing of the e-/e+ splitting implementation under conditions of a transformed DBS splitting cone. The 3 transforms tested were the same as those used to ensure agreement between photon spectra with transformed splitting cones without e-/e+ splitting and are shown in the update of 01/08/2025.

Note that in all transformed cases, we have opted to not radially redistribute split charged particles about the Z-axis. This is because, for reasons given above, radial redistribution is always done about the untransformed Z-axis which will violate radial symmetry about the beam axis (which the transformed DBS cone presumably tracks) in most cases.

Also note that spectra are always collected at a plane perpendicular to the axis of the transformed splitting cone (i.e., the scoring plane is transformed as well).

The figure below shows the fractional differences in e- spectra between the untransformed (T0) and transformed cases for the 3 transforms considered.

225kVp_trans_split_test_esplit_zrr005cm_electron_transformations_diff

The plot shows agreement to within 0.2-0.5% over most of the energy range. Greater precision, though desirable, will be time consuming owing to the few contaminant e- generated per incident particle in this setup.

Tne plot below shows fractional differences between photon spectra in the untransformed (T0) and transformed cases:

225kVp_trans_split_test_esplit_zrr005cm_photon_transform_diff

which shows agreement to within ~0.01% for transforms T1 and T2 and agreement to within ~0.02% for T3. Note that the reason for the slightly greater difference in the case of T3 is not known, however, it is still within uncertainty of the T0 case.

@blakewalters
Copy link
Copy Markdown
Contributor Author

Update 03/28/2025

This update revisits yesterday's comparison between photon spectra obtained using egs++ DBS with and without e-/e+ splitting with Rayleigh scattering on and off. Recall that, with Rayleigh scattering on, e-/e+ appeared to introduce a ~0.01-0.02% increase in the photon spectrum. A detailed look at the egs++ DBS Rayleigh scattering routine did not reveal any obvious bugs, leading me to conclude that Rayleigh scattering may, in fact, "amplify" a systematic difference introduced by e-/e+ splitting.

Redoing the comparison using 4x the number of histories (i.e. uncertainties on photon spectra halved), we obtain the following plot of fractional difference:

225kVp_trans_split_test_esplitonoff_raylonoff_highres_diff

from which it is possible to conclude that any systematic difference introduced by e-/e+ with Rayleigh scattering on is at most ~0.01% and, moreover, is within uncertainty of any differences with Rayleigh scattering off.

My recommendations at this point are:

  1. Continue/expand egs++/DBS testing to run comparisons with BEAMnrc/DBS over a number of energies in the keV - MeV range and try higher splitting numbers. The current tests at 225 kVp with nsplit=1000 have proven valuable for debugging the DBS algorithm's handling of brems, photelectric, fluorescent, and, to a certain extent Compton and Rayleigh events, but have not tested annihilation or pair production. Comparisons against BEAMnrc/DBS at different energies will change the subset of interactions tested and, indeed, at least one comparison in the MeV range is essential. Also, simulations of kVp beams are optimized with splitting numbers on the order of 10,000-100,000. These higher splitting numbers may amplify any bugs in the code that I've missed in the current tests.
  2. Clean up the code. There are many instances in the current egs++/DBS implementation of repeating code that could be put into functions, code that could be rationalized, variable names that could be made more explicit, etc. Cleaning up the code in this way would make it easier to find potential bugs.
  3. Test egs++/DBS in actual applications. I'm currently using egs++/DBS to simulate a prototype kV irradiator and obtaining agreement with prior simulations where BEAMnrc/DBS was used to simulate the X-ray source. Admittedly, I'm only running simulations to ~2% uncertainty, so the test isn't very exacting, and the more conditions under which this egs++/DBS implementation can be benchmarked the better.
  4. Documentation. I've left fairly extensive comments in the code, but comprehensive documentation that can then be extracted by doxygen is required!

@ftessier ftessier force-pushed the develop branch 2 times, most recently from c14f2dd to b25605d Compare March 24, 2026 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants