Calibrate the instrument with a standard#

Goal: measure your instrument’s contribution to the pattern once, on a standard, and reuse it for every sample measured the same way. That contribution is its peak shape and whichever corrections apply to your geometry. Holding the instrument fixed means the sample refinement refines only the sample’s parameters: its peak broadening, cell and structure.

You need:

  • A pattern of a standard (LaB6, Si, CeO2) measured at the same wavelength and geometry as your samples.

  • A recipe for your sample, written for the same engine you will use for the standard. With easydiffraction, it must also use the same calculator.

  • The engine’s environment (Install).

        flowchart LR
    A["Standard recipe<br/>instrument refined"] -->|run| B["output_recipe.json"]
    B -->|"copy payload.instrument<br/>set flags to false"| C["Sample recipe"]
    C -->|run| D[Sample results]
    

1. Refine the standard#

Start from the LaB6 example for your engine. Copy it into a folder of your own, for example my_lab6/.

examples/example_LaB6/input.json

examples/example_LaB6/topas/input.json

examples/example_LaB6/easydiffraction/input.json

This example refines the cell. For a calibration, set the flags of a, b and c to false.

Put your pattern into the recipe’s xrd_data block. Set the cell to your standard’s certified value, held (false).

Refine the scale, the background, the peak-shape parameters and the corrections that matter for your instrument. Which corrections those are depends on the geometry and the engine. See the instrument section of your engine’s page: GSAS-II, TOPAS or easydiffraction.

Then run it:

pixi run -e gsasii powderline my_lab6/input.json
pixi run powderline my_lab6/input.json --topas-version 6 --topas-dir C:/TOPAS6

TOPAS runs on Windows only. See Run TOPAS recipes.

pixi run -e easydiffraction powderline my_lab6/input.json

Check the fit before going on. Plot y_obs, y_calc and y_diff from my_lab6/output/fit_profile.txt and look at the difference curve, not just Rwp. A poor calibrant fit gives a wrong instrument for every sample. Good refinement practice has more on judging a fit.

2. Copy the refined instrument#

Open my_lab6/output/output_recipe.json. It is your recipe with the refined values written back. Copy its whole payload.instrument block into your sample recipe, replacing the one there.

Note

If the run reported output_recipe_valid: false, the engine returned a value the recipe format refuses. Read the output_recipe_not_valid warning and fix the standard’s refinement before you copy anything.

3. Hold the instrument#

Set every refine flag in the copied block to false. The sample refinement should refine only the sample’s parameters, not the instrument’s.

Change only the flags. For each parameter, the value stays and the flag becomes false:

"U": [49.11908, true]    becomes    "U": [49.11908, false]

Do this for every flag in payload.instrument:

radiation.wavelength, the three corrections (zero_shift, polarization, axial_divergence) and the six broadening terms U, V, W, X, Y, Z. Values are [value, flag].

Every parameter in radiation, corrections and broadening.parameters. Values are [value, flag, min, max]; leave the bounds as they are.

Every parameter in radiation, corrections and broadening.parameters. Values are [value, flag, min, max]; leave the bounds as they are. The peak types depend on the calculator, so the block validates only in a sample recipe with the same refinement_controls.calculator as the standard’s.

The hold() function under In Python does this for you.

Caution

Check that the refined values make sense before you hold them. A held value carries its problem into every sample refinement. See Good refinement practice.

Note

A negative profile term is common and is not an error in itself; what matters is the total peak width over your fit window. Each engine handles a width that would go below zero in its own way. The GSAS-II LaB6 example shows it: its refined Y is about −10, so its Lorentzian width would fall below zero above about 10.7° 2θ. GSAS-II floors the width at 0.001 centidegree there, without a message, so those peaks are computed as Gaussian. EB-93 shows what that means when the same data go to easydiffraction. TOPAS (EB-69) and easydiffraction (EB-87) behave differently, which is one more reason to refine the standard again in the engine you use.

4. Validate and run the sample#

pixi run powderline my_sample/input.json --validate-only

Then run it with your engine:

pixi run -e gsasii powderline my_sample/input.json
pixi run powderline my_sample/input.json --topas-version 6 --topas-dir C:/TOPAS6
pixi run -e easydiffraction powderline my_sample/input.json

Check: open my_sample/output/parameter_dispositions.csv. Every row whose path starts with payload.instrument reads held_by_user.

Warning

An instrument block belongs to one engine. GSAS-II’s U, V, W give the Gaussian variance σ² in centidegrees²; TOPAS’s and easydiffraction’s give the Gaussian FWHM² in degrees² (FWHM² = 8 ln 2 · σ² / 10⁴). X and Y swap roles. To use a GSAS-II calibration with TOPAS, refine the standard again with TOPAS.

In Python#

The same steps as a script. hold() sets every refine flag in a block to false and leaves everything else as it is.

from pathlib import Path
import powderline

cal = powderline.run(powderline.load_recipe_asset(Path("my_lab6/input.json")),
                     Path("my_lab6/output"))
if not cal["output_recipe_valid"]:
    raise SystemExit("the standard's output recipe is not valid: check its warnings")

def hold(block):
    """Return a copy of the block with every refine flag set to False."""
    if isinstance(block, dict):
        return {k: hold(v) for k, v in block.items()}
    if isinstance(block, list) and len(block) >= 2 and isinstance(block[1], bool):
        return [block[0], False, *block[2:]]
    return block

sample = powderline.load_recipe_asset(Path("my_sample/input.json"))
sample["payload"]["instrument"] = hold(cal["output_recipe"]["payload"]["instrument"])
result = powderline.run(sample, Path("my_sample/output"))
print(result["rwp"])

Run it in the engine’s environment, for example pixi run -e gsasii python calibrate.py.

Next: Refine a structure, or Run a series to refine one sample’s model against many patterns.