Skip to content

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

Merged
willend merged 6 commits into
mainfrom
2026-11-farhi-fluorescence-fix1
Nov 11, 2026
Merged

willend merged 6 commits into
mainfrom
2026-11-farhi-fluorescence-fix1

Conversation

@farhi

@farhi farhi commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

X: Fluorescence.comp: fix cross-section normalisation, sampling, SPLIT cache and file handling

This is a rather large bug fix for the McXtrace Fluorescence component. Affected files:

  • Fluorescence
  • SOLEIL_ROCK
  • Test_FluoPowder

Here is a synthetic table with changes:

Area Fix Behaviour change Effect on results
Cross-section weighting Elements weighted by atoms per unit, not by mass fraction rho is now the density of units (formula units or unit cells) Large: absolute intensities change for multi-element materials
Density / packing_factor Additive volumes for the default density. packing_factor is applied only when given. Error if no density can be found. A user-supplied density is no longer scaled a second time Medium: attenuation is corrected, mostly for compounds and dense samples
Fluorescence emission Isotropic and unpolarised. The ad-hoc angular weights are removed and E is zeroed after emission. Fluorescence no longer depends on incident polarisation or angle Medium: angular and polarisation dependence of the fluorescence signal disappears
Line shape Gaussian σ = FWHM/2.355 (was FWHM/2). Photon absorbed if Ef ≤ 0 or no line can be excited. Narrower Gaussian peaks Small: peaks are about 15% narrower, with no intensity change
Line selection Index off-by-one fixed, so the last line is now reachable Rare lines are now sampled Negligible
Rayleigh and Compton Normalised per element (CSb_Rayl(Z), CSb_Compt(Z)). Compton uses DCSb_Compt (barn) instead of DCS_Compt (cm²/g). cos θ is clamped. Correct units and normalisation. No NaN in the angle. Large for Compton (unit mismatch). Rayleigh changes for compounds.
flag_low_z Weight includes the missing factor nElements. Index clamped and zero cross sections guarded. Previously biased low Medium: results change only with flag_low_z=1
SPLIT cache Cache keyed on position, direction and |k|. Per-process totals are taken from the last cumulated element. Cache initialised. Stale reuse is gone Medium with SPLIT (SPLIT and non-SPLIT runs now agree). None otherwise.
Geometry (p_interact<0) Intermediate lengths are always computed Hollow samples work with forcing off Medium for hollow samples with p_interact=-1 (was broken)
Transmission Transmitted photons propagate dl0+dl1+dl2 (through the hole). mc_scatt<=0 now transmits instead of absorbing. Photons exit correctly. Weak-interaction photons are no longer lost. Small to medium: the transmitted beam is no longer lost for weak or thin samples
Disabled processes flag_rayleigh=0, flag_compton=0 and unknown types are rejected up front Same outcome, handled earlier None
File parsing material is not overwritten. Title offset is Line+5. Parentheses and . are kept in formulas. CIF/LAZ names and formulas are parsed correctly Case-dependent: formulas are no longer truncated or garbled
Display and docs else if bug fixed. Duplicate drawing removed. Docs updated (flag_kissel Z ≥ 50, type order). Cosmetic None

Net effect: reference results have been updated in SOLEIL_ROCK and Test_FluoPowder. The largest changes are for compounds, Compton, and SPLIT or hollow geometries.


Here are more details on the changes:

Physics and normalisation

  • Cross sections per unit, not per mass fraction. Elemental cross sections (barn/atom) were weighted by mass fraction. They are now weighted by atoms per unit, n_atoms[i] = nAtoms[i]*weight/molarMass.
    • rho is now the density of units: formula units, or unit cells when weight is a cell weight.
    • Docs for weight, density, rho and packing_factor are updated accordingly.
  • Material density. It is now computed from additive volumes (1/ρ = Σ wᵢ/ρᵢ) instead of a mass-weighted sum of elemental densities. The component exits with an error if neither density nor rho can be determined.
  • packing_factor. It is applied only when given explicitly, in the range 0 to 1. Previously a default density/mat_density was always derived and applied, which double-counted a user-supplied density.
  • Fluorescence emission. It is now isotropic and unpolarised.
    • The ad-hoc (1-s)² and (1+cos²θ)/2 weights are removed.
    • Ex, Ey and Ez are zeroed after emission.
  • Line shapes. The Gaussian now uses σ = FWHM/(2√(2 ln 2)) instead of FWHM/2. The Lorentzian keeps HWHM = FWHM/2. A photon is absorbed if the emitted energy is ≤ 0 or no line can be excited.
  • Rayleigh and Compton weights.
    • They are normalised by the per-element CSb_Rayl(Z) and CSb_Compt(Z) instead of the compound total.
    • Compton now uses DCSb_Compt (barn/at/sr) instead of DCS_Compt (cm²/g/sr).
    • θ is computed once, with cos θ clamped to [-1, 1] to avoid NaN.
  • flag_low_z. The weight now includes the missing factor nElements, because elements are sampled uniformly with probability 1/nElements. The element index is clamped, and zero cross sections are guarded.
  • Disabled processes. flag_rayleigh=0, flag_compton=0 and unknown types are now rejected up front with ABSORB.
  • Unit comment. The my_s comment is corrected: barn·Å⁻³ → m⁻¹ via the factor 100.

Sampling and library functions

  • Off-by-one in XRMC_SelectFromDistribution callers. The cumulated arrays have a leading 0, so N must be nb_items + 1.
    • Fluorescence line selection used XRAYLIB_LINES_MAX instead of +1, so the last line was unreachable.
    • It now passes XRAYLIB_LINES_MAX+1 and clamps the index.
    • Documented in the function header.
  • XRMC_SelectFluorescenceEnergy.
    • *dE is initialised to 0.
    • It returns 0 when sum_xs <= 0 (no line excited).
  • XRMC_SelectInteraction. It uses a fixed cum_xs[8] stack array, with nb_processes <= 7 checked, instead of malloc/free.

SPLIT caching

  • Cache validity. The cache is now keyed on the full incoming state (position, direction and |k|), guarded by a reuse_valid flag. Before, it matched on |k| only, so unrelated photons with the same energy could reuse stale geometry.
  • Per-process totals on reuse. They were being accumulated by summing the cumulated arrays, which is wrong. They are now taken from the last element of each cumulated sum.
  • Cache initialisation. reuse_intersect and the new cache fields are initialised.

Geometry and transport

  • p_interact < 0. Intermediate lengths (l1, l2) are now always computed. Previously a hollow geometry broke when forcing was disabled, which is documented as "-1 inactivate".
  • No scattering possible. When mc_scatt <= 0 the photon is transmitted instead of absorbed.
  • Transmission path. The photon propagates to the exit point, dl0+dl1+dl2, including any hole, instead of only d_path (dl0+dl2).

Material file parsing

  • material parameter. It is no longer overwritten with the guessed formula. A local mat_name is used throughout (parser, error and info messages).
  • Title token offset. It is Line+5. It was Line+7, which dropped the first formula characters.
  • removeSpacesFromStr. It now keeps (, ) and ., so formulas like Ca(OH)2 or fractional stoichiometry survive. It casts to unsigned char.
  • Include. <ctype.h> is now included explicitly.

Display and docs

  • DISPLAY. Fixed the } if (shape == 2) bug, which should be else if. Removed the duplicated box-drawing block.
  • Docs.
    • The flag_kissel doc now says Z ≥ 50, matching the code. It said "Z>=52 Te".
    • The type doc lists TRANSMISSION=3 / DIFFRACTION=4 in the order of the actual #defines? Please check: the #defines are DIFFRACTION 3 and TRANSMISSION 4, so the fixed doc order matches the code.
  • Cleanup. Removed the unused flag variable.

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 used to analyse bugs and find solutions.

Development OS / boundary conditions

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

  • debian 13/amd64
  • McXtrace 3.10.2 as initial basis for tests

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

    • Updates to %Test: target values

@willend

willend commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

@farhi looks OK to me, with one remark:
The DISPLAY section has some line() instructions removed, i guess originally intended to connect two x5 multiline 'end-pieces'. I guess a box() might be both simpler and nicer with --trace=2?

@farhi

farhi commented Nov 10, 2026

Copy link
Copy Markdown
Contributor Author

@farhi looks OK to me, with one remark: The DISPLAY section has some line() instructions removed, i guess originally intended to connect two x5 multiline 'end-pieces'. I guess a box() might be both simpler and nicer with --trace=2?

Yes, I've ported the display section from SX. Wait for completion of tests, and merge OK

@willend
willend merged commit f0d68e9 into main Nov 11, 2026
20 checks passed
willend added a commit to willend/McCode that referenced this pull request Nov 11, 2026
… fix

Both use FluoPowder, which inherits the Fluorescence code changed in mccode-dev#3088.
Refs mccode-dev#3091

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
khurrumsaleem pushed a commit to khurrumsaleem/McCode that referenced this pull request Nov 12, 2026
khurrumsaleem pushed a commit to khurrumsaleem/McCode that referenced this pull request 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