Skip to content

Tutorial: a transport material for NCrystal

This tutorial writes IRMA's graphite mode-2 physics into an NCrystal material and then checks the material through NCrystal's own interface. The export takes 75 seconds; the verification takes seconds. Two installations are involved: IRMA with the phonopy extra for the export itself, and an NCrystal installation with the in-repo ncrystal_plugin_IRMA built against it for the verification (the build commands are in the NCrystal plugins section of the installation page).

The export configuration

The exporter reads a YAML configuration naming the phonon calculation and the export settings. Save this as graphite_export.yaml in the repository root; the material section is the same graphite the ENDF tutorial evaluated, and the export section is the production sampling:

material:
  phonopy_yaml: tests/mode2_euphonic_n1_validation/graphite/phonopy.yaml
  mesh: [40, 40, 40]
  temperature_K: 296.0
  scatterers:
    - {symbol: C, sigma_bound_b: 5.551, awr: 11.898, b_coh_fm: 6.646,
       sigma_inc_b: 0.001}
export:
  material_id: graphite
  inelastic_mode: 2
  num_directions: 10000
  multiphonon_num_directions: 1000
  multiphonon_max_order: auto
  jobs: 8
  gain_side: scaled_sym   # store the energy-loss half; NCrystal rebuilds the gain side
  elastic: true

No grid appears here because the automatic grid is the default: IRMA builds the same converged alpha and beta grids the ENDF evaluator uses, from the same shared code, so the exported physics and a tape from the same calculation never drift apart. The NCrystal data exporter page documents every field.

Run the export

python -m irma.ncrystal graphite_export.yaml -o out/

Seventy-five seconds later, out/ holds two files:

graphite__C.irmapack    4.3 MB   the exported physics
graphite.ncmat          438 B    the loadable material

The data file carries the mode-2 \(S(\alpha,\beta)\) half-table (the energy-loss half; NCrystal reconstructs the gain side by detailed balance at run time) and the anisotropic Debye-Waller elastic tensors for 296 K, with the meta.* record of the IRMA version and run settings. The NCMAT file is small because it delegates: the crystal cell comes from the phonopy calculation, the @DYNINFO block is a placeholder, and the @CUSTOM_IRMA section points NCrystal's plugin at the data file:

NCMAT v5
@CELL
  lengths 2.4606 2.46060000039 6.705
  angles 90 90 119.999999995
@ATOMPOSITIONS
  C 0 0 0
  C 0 0 0.5
  C 0.333333333333 0.666666666667 0
  C 0.666666666667 0.333333333333 0.5
@DYNINFO
  element C
  fraction 1
  type vdosdebye
  debye_temp 1037.8
@CUSTOM_IRMA
  pack <absolute path to>/out/graphite__C.irmapack

(The cell here comes from the phonopy calculation, so its constants differ in the last digits from the rounded values of the ENDF tutorial's input file; that is expected. The @CUSTOM_IRMA section records the data file by the absolute path the exporter wrote, so keep the pair where the export put them, or re-run the export at the new location.)

Verify it inside NCrystal

In the Python environment where you built the plugin (pip install --no-build-isolation ./ncrystal_plugin_IRMA), NCrystal's own plugin test comes first:

ncrystal-pluginmanager --test IRMA
NCrystal: End of plugin test function "test_IRMA".
All ok

Then load the material and ask for cross sections, from out/:

import NCrystal as NC
mat = NC.load("graphite.ncmat;temp=296K")
for e_meV in (5.0, 25.3, 100.0):
    xs = mat.scatter.crossSectionIsotropic(e_meV * 1e-3)
    print(f"E = {e_meV:6.1f} meV   sigma_scatter = {xs:8.3f} barn/atom")
E =    5.0 meV   sigma_scatter =    4.983 barn/atom
E =   25.3 meV   sigma_scatter =    5.125 barn/atom
E =  100.0 meV   sigma_scatter =    4.801 barn/atom

That is IRMA's coherent one-phonon plus anisotropic-Debye-Waller physics answering through NCrystal's standard interface. The values are deterministic for a given export: yours should match to the printed digits, and a larger deviation means a version or input mismatch. The ;temp=296K in the load string must name a temperature the export actually wrote: the data files are strictly per-temperature, and the plugin treats a mismatch as a hard error rather than a silent interpolation (the exporter page has the details). To cover several temperatures, run the exporter once per temperature; each run writes its own data file.

Use it in a transport code

Any NCrystal-aware code takes the same material string. In McStas, the NCrystal_sample component's cfg parameter accepts "graphite.ncmat;temp=296K"; in OpenMC, openmc.Material.from_ncrystal does the same. From there an entire beamline simulation samples IRMA's physics; the graphite validation record shows this route carried all the way to a McStas model of the ARCS spectrometer compared against measurement.

The same export in the GUI

The NCrystal plugin tab is this tutorial as a form: the material and export sections mirror the YAML, the scatterer row fills itself from the phonopy calculation, and the Log column streams the same export log.

The NCrystal plugin tab staged with this tutorial's export