Simulate a pattern#
Goal: calculate the pattern a model gives, without fitting anything. Use it to predict a pattern, to check what an instrument profile or a structure change does to the peaks, or to make synthetic data for testing a pipeline.
You need:
A recipe for your engine with the model you want: structure, instrument, background (Refine a structure).
An
xrd_datablock. Itsttharray sets the 2θ grid of the calculated pattern.
A simulation is a run that refines nothing. It uses the same recipe
format as a refinement, with every refine flag false.
1. Set every flag to false and mark the run as a simulation#
Set every refine flag to false, including the polarization and any
background peak flags, and run one cycle:
"refinement_controls": {"refinement_cycles": 1}
refinement_cycles: 1 is a simulation. A refine flag left true is a
validation error.
Set every refine flag to false and calculate only:
"refinement_controls": {"iters": 0, "chi2_convergence_criteria": 0.001, "x_calculation_step": 0.001}
iters: 0 is a simulation. A refine flag left true is a validation error.
The other controls are still stated.
Set every refine flag to false. A recipe with no flag set is a
simulation: lmfit is not run. The controls stay as they are, all stated.
Background coefficients share one flag, background.chebyshev.refine_flag.
Set it to false too.
examples/example_LaB6_simulation/ and examples/example_DRX_33_simulation/
are GSAS-II simulations of the LaB6 and DRX_33 refinement examples.
2. Validate#
pixi run powderline my_sim/input.json --validate-only
Check: the report says Mode: Simulation (all parameters locked) and
Parameters requested: 0.
3. Run#
pixi run -e gsasii powderline my_sim/input.json
pixi run powderline my_sim/input.json --topas-version 6 --topas-dir C:/TOPAS6
A TOPAS simulation still needs tc.exe to calculate the pattern. Without
it, the run only writes TOPAS’s input (Run TOPAS recipes).
pixi run -e easydiffraction powderline my_sim/input.json
4. Read the simulated pattern#
The calculated pattern is the y_calc column of output/fit_profile.txt,
on the tth grid of your xrd_data. A simulation differs from a refinement
in these ways:
Value in a simulation |
|
|---|---|
|
|
|
|
|
PowderLine’s uniform statistics with no refined parameters. Against real data they show how good the starting values are. Against placeholder intensities they mean nothing. |
ESDs in |
|
|
not written by GSAS-II; written with no rows by TOPAS and easydiffraction |
|
the input’s values, since nothing was refined |
|
no row |
A statistic with no degrees of freedom is null, never NaN. GSAS-II’s own
Rwp, under engine_details, is capped at 100 %.
In Python#
This turns a refinement recipe into a simulation. hold_all() sets every
refine flag to false, including the background’s refine_flag.
from pathlib import Path
import powderline
def hold_all(node):
"""Return a copy of a recipe block with every refine flag set to False."""
if isinstance(node, dict):
return {k: (False if k == "refine_flag" else hold_all(v)) for k, v in node.items()}
if isinstance(node, list) and len(node) >= 2 and isinstance(node[1], bool):
return [node[0], False, *node[2:]]
if isinstance(node, list):
return [hold_all(v) for v in node]
return node
recipe = powderline.load_recipe_asset(Path("my_refinement/input.json"))
recipe["payload"] = hold_all(recipe["payload"])
controls = recipe["payload"]["refinement_controls"]
if recipe["schema_name"].startswith("gsasii."):
controls["refinement_cycles"] = 1
elif recipe["schema_name"].startswith("topas."):
controls["iters"] = 0
result = powderline.run(recipe, Path("my_sim/output"))
y_calc = result["fit_profile"]["y_calc"]