Skip to content

X: Fluorescence upgrade, forward this PR and #3088 to FluoCrystal and FluoPowder - #3094

Merged
willend merged 8 commits into
mainfrom
2026-11-farhi-fluorescence-upgrade1
Nov 12, 2026
Merged

willend merged 8 commits into
mainfrom
2026-11-farhi-fluorescence-upgrade1

Conversation

@farhi

@farhi farhi commented Nov 11, 2026

Copy link
Copy Markdown
Contributor

Following #3088 "X: Fluorescence: fix cross-section normalization, sampling, SPLIT cache and file handling"

This is a large PR. It mostly forwards #3088 to FluoCrystal and FluoPowder

Fluorescence: New features

Area Change Behaviour change Effect on results
Attenuation Total cross section CSb_Total is used. The remainder after fluorescence, Rayleigh and Compton becomes a new non-radiative outcome, ABSORPTION=5 (Auger and similar). The photon is absorbed with no emission when that outcome is drawn. my_s now covers all photo-absorption. Large at low Z and below edges: stronger attenuation, and a lower fluorescence and transmitted yield (the sum of the three processes was below the true total). Higher Z at high energy is closer to before.
Polarisation DCSPb_Rayl and DCSPb_Compt are used when (Ex,Ey,Ez) ≠ 0, with the azimuth measured from the polarisation vector. The scattered polarisation is the projection of the incoming one. Azimuthal dependence is now modelled. Unpolarised photons behave as before. Large for synchrotron beams: scattering is suppressed along the polarisation direction, so detector position matters
Line widths Each line's FWHM is the sum of the initial and final level widths, found by matching edge-energy differences. It falls back to the K width. Per-line widths replace the K width for all lines Medium on line shape: L and M lines change, and K lines are slightly broader. Integrated intensity is unchanged.

FluoPowder: bug fixes and new features forwarded from Fluorescence

Area Change Behaviour change Effect on results
Parameters Add flag_low_z (new setting), align flag_kissel doc to Z≥50 New option: uniform element sampling with re-weighting instead of XS-weighted sampling Same mean results with flag_low_z=1; better statistics for trace elements, higher variance per ray
Doc header Add polarisation, line-width and Auger/absorption paragraphs; update type list to 0..5 (DIFFRACTION=3, TRANSMISSION=4, ABSORPTION=5) Documentation only None
DECLARE Add n_atoms, line_width, xs_fluo/Compton/Rayleigh, extended SPLIT cache (reuse_valid, reuse_x/y/z, reuse_kx/ky/kz, reuse_xs_*, reuse_xs_absorb) Per-unit atom counts and per-element XS cached; SPLIT cache keyed on full incoming state Fixes wrong SPLIT reuse after any position/direction change; removes systematic bias in split runs
INITIALIZE / density mat_density now from sum_w_over_rho (volumes add) instead of mass-weighted sum of densities Correct mixture density for compounds Slightly different default density/fluo_rho for multi-element materials; affects all absolute intensities
INITIALIZE / packing packing_factor only applied when explicitly given (else forced to 1) No implicit re-scaling from density/mat_density Removes double-counting when user gives density; fluo and diffraction use consistent rho
INITIALIZE / lines Compute line_width per element via fluo_line_widths (initial+final shell widths) Per-line natural widths instead of generic dE halving Realistic fluorescence line shapes/widths
TRACE / XS Per-element XS weighted by nat (atoms per unit) instead of mass fractions; compound totals from cum-sum last element Element selection now uses atom-count weighting Correct element mixture for compounds (esp. low-Z/high-Z mixes); small intensity shifts
TRACE / absorption Add xs[ABSORPTION] = CSb_Total minus processes (Auger, non-radiative); include in sigma_barn and process selection; drop old (sum)/sigma_barn p-correction Non-radiative photo-absorption is an explicit ABSORB outcome and contributes to attenuation Higher attenuation (total CS now includes Auger); fewer but correctly weighted scattered/transmitted rays
TRACE / transmit mc_scatt <= 0 now falls through to transmission branch instead of ABSORB Thin/transparent samples transmit with p *= p_trans instead of dying Fixes loss of photons in optically thin samples
TRACE / geometry Hollow intermediate lengths always computed (old p_interact >= 0 condition removed) p_interact<0 only disables forcing, hollow geometry still handled Hollow/concentric shells now attenuate correctly with p_interact=-1
TRACE / fluo XRMC_SelectFluorescenceEnergy now takes per-line line_dE; Ef<=0 → ABSORB; new Lorentzian dE/2*tan(π/2*randpm1()) and Gaussian dE/(2√(2ln2))*randnorm() sampling; emission isotropic and unpolarised (Ex=Ey=Ez=0), no θ polarisation factor Removes the old (1-s)²/(1+cos²θ)/2 angular factor on fluorescence Physically correct line shapes; removes spurious polarisation/angle bias on fluorescence intensity
TRACE / Rayleigh Use per-element sigma_Z=CSb_Rayl, DCSb_Rayl or polarised DCSPb_Rayl with azimuth from fluo_pol_azimuth; scattered polarisation via fluo_pol_scattered Polarised differential cross sections; weight 4π·dsigma/sigma_Z Correct angular distribution and polarisation transfer for polarised beams; unpolarised results unchanged in mean
TRACE / Compton Same per-element CSb_Compt/DCSPb_Compt treatment; ComptonEnergy(E,θ) sets final energy Polarised DCSP, correct Compton shift (was DCS_Compt mass-normalised variant) Correct energy shift and angular weights; fixes potential normalisation error
TRACE / diffraction Powder part kept; DIFFRACTION selected among processes via XRMC_SelectInteraction; alpha reset fix; polarisation weighting unchanged Diffraction now competes with fluo/Rayleigh/Compton/absorption in one total attenuation Diffraction intensities now also attenuated by the (larger, Auger-inclusive) total CS — slightly lower, more physical
TRACE / SPLIT Reuse test compares x,y,z,kx,ky,kz,ki and reuse_valid; reuse restores last cum-sum element (old code summed all cum entries — a bug) Correct cached totals in split rays Fixes biased intensities under SPLIT

FluoCrystal: bug fixes and new features forwarded from Fluorescence

Area Change Behaviour change Effect on results
Parameters Add flag_low_z; align flag_kissel doc to Z≥50 New option: uniform element sampling with re-weighting Same mean with flag_low_z=1; better statistics for trace elements
Doc header Add polarisation, line-width, Auger/absorption paragraphs; type list now 0..5 (DIFFRACTION=3, TRANSMISSION=4, ABSORPTION=5); replace "SPLIT is currently BROKEN" note Documentation only None
DECLARE Add n_atoms, line_width, xs_fluo/Compton/Rayleigh, extended SPLIT cache (reuse_valid, reuse_x/y/z, reuse_kx/ky/kz, reuse_xs_*, reuse_xs_absorb) Per-unit atom counts and per-element XS cached; SPLIT keyed on full incoming state Fixes wrong SPLIT reuse; removes bias in split runs (SPLIT now usable)
INITIALIZE / density mat_density from sum_w_over_rho (volumes add) instead of mass-weighted sum Correct mixture density for compounds Slightly different default density/fluo_rho for multi-element materials; affects absolute intensities
INITIALIZE / packing packing_factor only applied when explicitly given (else forced to 1) No implicit re-scaling from density/mat_density Removes double-counting when density is user-supplied
INITIALIZE / SX hkl_info.sigma_i = 0 set explicitly (Compton now handled by XRayLib, not sigma_inc) Incoherent background no longer taken from the .lau header Removes double-counting of Compton if a #sigma_inc header value was present
INITIALIZE / lines line_width per element via fluo_line_widths (initial+final shell widths) Per-line natural widths Realistic fluorescence line shapes/widths
TRACE / XS Per-element XS weighted by nat (atoms per unit) instead of mass fractions Element selection uses atom-count weighting Correct element mixture for compounds; small intensity shifts
TRACE / absorption Add xs[ABSORPTION] = CSb_Total minus processes (Auger); include in sigma_barn and process selection Non-radiative photo-absorption is an explicit ABSORB outcome contributing to attenuation Higher attenuation (total CS incl. Auger); fewer but correctly weighted rays
TRACE / transmit mc_scatt <= 0 falls through to transmission instead of ABSORB Thin samples transmit with p *= p_trans Fixes photon loss in optically thin crystals
TRACE / geometry Hollow intermediate lengths always computed (old p_interact >= 0 condition removed) p_interact<0 only disables forcing Hollow/concentric shells attenuate correctly with p_interact=-1
TRACE / fluo Per-line line_dE passed to XRMC_SelectFluorescenceEnergy; Ef<=0 → ABSORB; new Lorentzian/Gaussian sampling; emission isotropic and unpolarised (Ex=Ey=Ez=0), old θ polarisation factor removed Removes the (1-s)²/(1+cos²θ)/2 angular factor on fluorescence Correct line shapes; removes spurious polarisation/angle bias
TRACE / Rayleigh Per-element sigma_Z=CSb_Rayl, DCSb_Rayl or polarised DCSPb_Rayl via fluo_pol_azimuth; fluo_pol_scattered for outgoing polarisation Polarised differential cross sections; weight 4π·dsigma/sigma_Z (was /xs[RAYLEIGH] compound-sum) Correct angular distribution and polarisation transfer; unpolarised means unchanged
TRACE / Compton Same per-element CSb_Compt/DCSPb_Compt treatment; fixes use of the uninitialised Ef in DCS_Compt(Z, Ef, θ) and ComptonEnergy(Ef, θ) → now uses E Correct incoming energy in Compton DCS and energy shift Fixes a real bug: Compton angular weights and shifts were computed with garbage energy
TRACE / diffraction SX part kept (Ewald-sphere search, hkl_select, 2D-Gauss kf, pmul weight, polarisation weighting); DIFFRACTION competes in the process selection; alpha handling unchanged Diffraction now attenuated by the total (Auger-inclusive) CS Slightly lower, more physical diffraction intensities
TRACE / SPLIT reuse Reuse test compares x,y,z,kx,ky,kz,ki with reuse_valid; cached totals restored from the last cum-sum element (old code summed all cum entries — a bug); hkl_search results (coh_refl, coh_xsect, tau_count) reused via cache Correct cached values in split rays; reciprocal-space search skipped for identical incoming rays Fixes biased intensities under SPLIT; large speed-up with SPLIT
FINALLY / DISPLAY Unchanged; DISPLAY INHERIT Fluorescence kept None None
FINALLY / DISPLAY Unchanged (diffraction counter still reported); DISPLAY INHERIT Fluorescence kept None None

Tests values

  • SOLEIL_CRISTAL: 620370 -> 1390520 (~ x2)
  • SOLEIL_MARS: 134100000 -> 228635000
  • Test_PowderN: FluoPowder 6.29534e-12 -> 2.81248e-12 closer to other references (SX and PowderN)
  • Test_SX: 6.1e-14 -> 3.33118e-14 closer to other references (SX)
  • SOLEIL_ROCK: 119954000000 -> 2326220000
  • Test_Absorption: 9.36962e-10 -> 5.31547e-12 closer to other references

Declaration of use of AI-tools

  • Please add a checkmark here if you used AI-tools during the work for this contribution
  • Further, please describe how / where and for what the tools were used: Claude and Mistral. Add new features, propagate to other comps. Required additional fixes.

Development OS / boundary conditions

Please describe what OS you developed and tested your additions on, and if any special dependencies are required:

  • debian/arm64
  • McXtrace 3.10.2

PR Checklist for contributing to McStas/McXtrace

For a coherent and useful contribution to McStas/McXtrace, please fill in relevant parts of the checklist:

  • My contribution includes patches to an existing component file

    • I have used the mcdoc utility and rendered a reasonable documentation page for the component (please attach as screenshot in comments!)
    • I have ensured that basic use of the component is OK (e.g. an instrument using it compiles?)
    • I have used the mctest utility to test one or more instruments making use of the component (please attach mcviewtest report as screenshot in comments)
    • I have used the mccode-clangformat tool to apply the standard McCode component indentation scheme
    • I have used the mcrun --c-lint "linter" and followed advice to remove most / all warnings that are raised
  • My contribution includes patches to an existing instrument file

    • I have used the mcdoc utility and rendered a reasonable documentation page for the instrument (please attach as screenshot in comments!)
    • I have used the mctest utility to test the instrument (please attach mcviewtest report as screenshot in comments)
    • I have used the mcrun --c-lint "linter" and followed advice to remove most / all warnings that are raised
  • My contribution includes a new component file

    • I have ensured that naming of parameters are in the style of existing components. (Please check the McStas or McXtrace NOMENCLATURE docs.)
    • I have ensured that component parameters are in the usually units of McStas or McXtrace (SI + neutron/x-ray 'usual' units)
    • I have used the mcdoc utility and rendered a reasonable documentation page for the component (please attach as screenshot in comments!)
    • I have ensured that basic use of the component is OK (e.g. an instrument using it compiles?)
    • I have included a corresponding example instrument and will fill in the new instrument section below
    • I have used the mccode-clangformat tool to apply the standard McCode component indentation scheme
    • My new component is added within the contrib component category
  • My contribution includes a new instrument file

    • I have used the mcdoc utility and rendered a reasonable documentation page for the instrument (please attach as screenshot in comments!)
    • I have ensured that basic use of the instrument is OK (e.g. it compiles?)
    • ... and provided reasonable default parameters in that instrument that produce reasonable output
    • ... and maybe even added a %Test: line (or a %TestScan: line for a parameter scan) to describe expected behaviour
    • I have used the mcrun --c-lint "linter" and followed advice to remove most / all warnings that are raised
    • My new instrument is added within the examples hierarchy in a folder in the style of examples/ESS/New_stuff/New_stuff.instr
    • My new instrument has a new, unique filename, not clashing with existing example instruments
    • My new instrument requires a data/input file. If the datafile is specific for my instrument I have left it in the same example folder, but if general use I have placed it in the global data folder.
  • My work touches the code-generator in mccode/src

    • I have added reasoning and documentation for the change through an ADR record in our GRAMMAR section
    • I am attaching test output in the comments
  • My work touches / adds to the runtime lib code (.c,.h etc in multiple locations

    • I am have added reasoning and documentation for the change below
    • I am attaching test output in the comments
    • Unit test: every new or changed common/lib/share, mccode/nlib/share, mcstas-comps/share or mcxtrace-comps/share library and runtime file (.c, .h, .h.in) has a Test_lib_<name> instrument in examples/libtest/ (McStas and/or McXtrace), with a %Test: line where the result can be checked. If it cannot be standalone, say why in the free-form text (e.g. needs a component or external package)
  • My PR is meant to fix a specific, existing issue

    • I have indicated the issue number here:
    • I have added documentation for the fix and possible side effects
  • My contribution contains something else

    • Explanation is added in free form text above or below the checklist

@willend

willend commented Nov 11, 2026

Copy link
Copy Markdown
Contributor

Hmm there was a merge conflict and I probably took the wrong choice of %Test values. Will look for improved numbers for ROCK and MARS

willend and others added 2 commits November 11, 2026 21:17
MARS, CRISTAL: values for this branch, lost in the merge with main.
ROCK: test with ROCK_dE=0.01. With dE=1 keV the monochromator output is
undersampled at 1e6 rays and the monitor varies by orders of magnitude
between seeds. Reference: 7.3e9 +/- 7% at 1e8 rays, dE=1.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
With ROCK_dE=0.01 and 1e7 rays the monitor error is about 2%.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
@willend

willend commented Nov 11, 2026

Copy link
Copy Markdown
Contributor

@farhi two commits were pushed to this branch to get the McXtrace tests in line (419e2c4 and the one after), please check that you agree:

SOLEIL_MARS, SOLEIL_CRISTAL: when main was merged in, the conflict on the %Test lines was resolved in favour of the values from #3092 (which belong to the #3088 code). They are now back at the values for this branch: MARS 2.29e+08, CRISTAL 1.39e+06, i.e. your numbers from 3dfbba8, rounded.

SOLEIL_ROCK: the test value was not reproducible. With the default ROCK_dE=1 keV the source spread is far wider than the monochromator bandpass, so at 1e6 rays a few rays carry the weight. The intensity has 0.9 % error before the Bragg crystals and 62 % right after; the fluorescence sample is not the cause. ROCK_fluo_monitor_I, code of this branch, no MPI:

Setting Seeds tried ROCK_fluo_monitor_I Rel. error Time
default, 1e6 7 2.6e8 ... 3.3e10 38-95 % 1.5 s
-n1e7 3 5.3e9 ... 8.6e9 21-24 % 14 s
SPLIT 20 on ROCK_bragg_crystal, 1e6 4 6.1e9 ... 2.1e10 10-15 % (reported) 18 s
ROCK_dE=0.01, 1e6 3 7.4e9 ... 9.4e9 7 % 1.5 s
ROCK_dE=0.01 -n1e7 2 8.13e9, 8.24e9 2 % 14 s
default, 1e8 (reference) 1 7.3e9 7 % 130 s

The test line is now

* %Test: ROCK_E0=15.918 ROCK_dE=0.01 -n1e7 Detector: ROCK_fluo_monitor_I=8.2e+09

Only the test line changed, not the instrument defaults. With SPLIT alone the seed-to-seed spread is larger than the reported error, so it was not used.

Two things for you to judge:

  • The same undersampling exists on main (7.7e10 ... 2.6e11 over 4 seeds), which is why this value kept moving. Would a smaller default ROCK_dE make sense for the instrument itself?
  • With this branch the ROCK fluorescence signal is roughly a factor 10-15 lower than on main. Is that the intended effect of the non-radiative handling?

Runs were done on macOS with the three Fluo* components of this branch; other components from an installed 3.99.99 dev build.

🤖 Generated with Claude Code

@willend
willend merged commit d336ab5 into main Nov 12, 2026
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.

2 participants