Experiment
An Experiment in EasyDiffraction includes the measured diffraction data along with all relevant parameters that describe the experimental setup and associated conditions. This can include information about the instrumental resolution, peak shape, background, etc.
Defining an Experiment
EasyDiffraction allows you to:
- Load an existing experiment from a file (CIF format). Both the metadata and measured data are expected to be in CIF format.
- Manually define a new experiment by specifying its type, other
necessary experimental parameters, as well as load measured data. This
is useful when you want to create an experiment from scratch or when
you have a measured data file in a non-CIF format (e.g.,
.xye,.xy).
Below, you will find instructions on how to define and manage
experiments in EasyDiffraction. It is assumed that you have already
created a project object, as described in the Project
section as well as defined its structures, as described in the
Structure section.
Adding from CIF
This is the most straightforward way to define an experiment in
EasyDiffraction. If you have a crystallographic information file (CIF)
for your experiment, that contains both the necessary information
(metadata) about the experiment as well as the measured data, you can
add it to your project.experiments collection using the
add_from_cif_path method. In this case, the name of the experiment
will be taken from CIF.
# Load an experiment from a CIF file
project.experiments.add_from_cif_path('data/hrpt_300K.cif')
You can also pass the content of the CIF file as a string using the
add_from_cif_str method:
# Add an experiment from a CIF string
cif_string = """
... content of the CIF file ...
"""
project.experiments.add_from_cif_str(cif_string)
Accessing the experiment after adding it will also be done through the
experiments object of the project instance. The name of the
experiment will be the same as the data block id in the CIF file. For
example, if the CIF file contains a data block with the id hrpt,
data_hrpt _experiment_type.beam_mode "constant wavelength" ...
you can access it in the code as follows:
# Access the experiment by its name
project.experiments['hrpt']
Defining Manually
If you do not have a CIF file or prefer to define the experiment
manually, you can use the add_from_data_path method of the
experiments object of the project instance. In this case, you will
need to specify the name of the experiment, which will be used to
reference it later, as well as data_path to the measured data file
(e.g., .xye, .xy). Supported formats are described in the
Measured Data Category section.
Optionally, you can also specify the additional parameters that define the type of experiment you want to create. If you do not specify any of these parameters, the default values will be used, which are the first in the list of supported options for each parameter:
- sample_form: The form of the sample (powder, single crystal).
- beam_mode: The mode of the beam (constant wavelength, time-of-flight).
- radiation_probe: The type of radiation used (neutron, X-ray).
- scattering_type: The type of scattering (bragg, total).
Important
It is important to mention that once an experiment is added, you cannot change these parameters. If you need to change them, you must create a new experiment or redefine the existing one.
Here is an example of how to add an experiment with all relevant components explicitly defined:
# Add an experiment with default parameters, based on the specified type.
project.experiments.add_from_data_path(
name='hrpt',
data_path='data/hrpt_lbco.xye',
sample_form='powder',
beam_mode='constant wavelength',
radiation_probe='neutron',
scattering_type='bragg',
)
To add an experiment of default type, you can simply do:
# Add an experiment of default type
project.experiments.add_from_data_path(
name='hrpt',
data_path='data/hrpt_lbco.xye',
)
If you do not have measured data for fitting and only want to view the
simulated pattern, you can define an experiment without measured data
using the create method:
# Add an experiment without measured data
project.experiments.create(
name='hrpt',
sample_form='powder',
beam_mode='constant wavelength',
radiation_probe='x-ray',
)
The calculated pattern needs a range to compute over. With no measured
data loaded, this comes from the data_range category, which defaults
to a sensible window derived from the instrument so the experiment is
calculable straight away. To choose the range yourself, set its bounds
and step (in 2ΞΈ for constant-wavelength, or time-of-flight for TOF):
# Set the calculation range explicitly (constant wavelength)
data_range = project.experiments['hrpt'].data_range
data_range.two_theta_min = 10.0
data_range.two_theta_max = 160.0
data_range.two_theta_inc = 0.05
Once a measured scan is present the range is read from the data instead,
so data_range becomes read-only.
Finally, you can also add an experiment by passing the experiment object
directly using the add method:
# Add an experiment by passing the experiment object directly
from easydiffraction import ExperimentFactory
experiment = ExperimentFactory.create(
name='hrpt',
data_path='data/hrpt_lbco.xye',
sample_form='powder',
beam_mode='constant wavelength',
radiation_probe='neutron',
scattering_type='bragg',
)
project.experiments.add(experiment)
Modifying Parameters
When an experiment is added, it is created with a set of default parameters that you can modify to match your specific experimental setup. All parameters are grouped into categories based on their function, making it easier to manage and understand the different aspects of the experiment:
- Instrument Category: Defines the instrument configuration, including wavelength, two-theta offset, and resolution parameters.
- Peak Category: Specifies the peak profile type and its parameters, such as broadening and asymmetry.
- Background Category: Defines the background type and allows you to add background points.
- Linked Structures Category: Links the structure defined in the previous step to the experiment, allowing you to specify the scale factor for the linked structure.
- Measured Data Category: Contains the measured data. The expected format depends on the experiment type, but generally includes columns for 2ΞΈ angle or TOF and intensity.
1. Instrument Category
# Modify the default instrument parameters
project.experiments['hrpt'].instrument.setup_wavelength = 1.494
project.experiments['hrpt'].instrument.calib_twotheta_offset = 0.6
2. Excluded Regions Category
# Add excluded regions to the experiment
project.experiments['hrpt'].excluded_regions.create(start=0, end=10)
project.experiments['hrpt'].excluded_regions.create(start=160, end=180)
3. Peak Category
# Select the desired peak profile type
project.experiments['hrpt'].peak.type = 'pseudo-voigt'
# Modify default peak profile parameters
project.experiments['hrpt'].peak.broad_gauss_u = 0.1
project.experiments['hrpt'].peak.broad_gauss_v = -0.1
project.experiments['hrpt'].peak.broad_gauss_w = 0.1
project.experiments['hrpt'].peak.broad_lorentz_x = 0
project.experiments['hrpt'].peak.broad_lorentz_y = 0.1
For time-of-flight data, the peak profiles by source type and relative performance (fastest to slowest):
| TOF profile | TOF source | Performance |
|---|---|---|
| Pseudo-Voigt (non-convoluted) | Symmetric profile; simplest TOF case | Fastest |
| Jorgensen (back-to-back exponentials β Gaussian) | Simpler TOF profile, including reactor-source TOF implementations | Fast |
| Ikeda-Carpenter β pseudo-Voigt |
Spallation-source TOF; moderator pulse shape model | Moderate |
| Jorgensen-Von Dreele (back-to-back exponentials β pseudo-Voigt) | Spallation-source TOF | Slower |
| Double back-to-back exponentials β pseudo-Voigt (Z-Rietveld type0m) | Spallation-source TOF; more elaborate asymmetric profile | Slowest |
= work in progress (not yet available for selection).
4. Background Category
# Select the desired background type
project.experiments['hrpt'].background.type = 'line-segment'
# Add background points
project.experiments['hrpt'].background.create(position=10, intensity=170)
project.experiments['hrpt'].background.create(position=30, intensity=170)
project.experiments['hrpt'].background.create(position=50, intensity=170)
project.experiments['hrpt'].background.create(position=110, intensity=170)
project.experiments['hrpt'].background.create(position=165, intensity=170)
Instead of placing every point by hand, you can let EasyDiffraction
detect a sensible set of background points directly from the measured
pattern with the auto_estimate method. Called with no arguments, it
builds a peak-insensitive background curve, places points between the
peaks, and reads their heights from that curve so they do not eat into
peak intensities:
# Automatically estimate background points from the measured pattern
project.experiments['hrpt'].background.auto_estimate()
The generated points are ordinary, editable control points. They are created fixed (not refined); you can review them, keep them, or free any of them for refinement (see Analysis). Each call overwrites the existing points (when there are active data to estimate from), so you always start from a clean, reproducible background; if no active data remain β for example every point is excluded, or data are not yet loaded β it warns and leaves your existing points unchanged. It works for both constant-wavelength and time-of-flight data, neutron and X-ray.
You can also guide the estimate with optional arguments, for example to cap the number of points or choose a specific method:
# Estimate with at most 10 background points
project.experiments['hrpt'].background.auto_estimate(n_points=10)
5. Linked Structures Category
# Link the structure defined in the previous step to the experiment
project.experiments['hrpt'].linked_structures.create(structure_id='lbco', scale=10.0)
6. Preferred Orientation Category
For textured powders, add a MarchβDollase preferred-orientation
correction per phase. Set the March coefficient march_r (1 = no
texture, <1 platy/disk, >1 needle), the texture direction
(index_h, index_k, index_l), and optionally the random untextured
fraction march_random_fract:
# Add a MarchβDollase preferred-orientation correction for a phase
project.experiments['hrpt'].preferred_orientation.create(
structure_id='lbco', march_r=1.2, index_h=0, index_k=0, index_l=1
)
This is a constant-wavelength Bragg powder correction, available on the
cryspy engine. The defaults (march_r=1, march_random_fract=0)
apply no texture, so it has no effect until you set them. See the
preferred-orientation parameters
for details.
7. Measured Data Category
If you do not have a CIF file for your experiment, you can load measured data from a file in a supported format. The measured data is added to the experiment and saved with the project as Edi. The expected format depends on the experiment type.
Supported data file formats:
.xyeor.xys(3 columns, including standard deviations)- _data.two_theta
- _data.intensity_meas
- _data.intensity_meas_su
.xy(2 columns, no standard deviations):- _data.two_theta
- _data.intensity_meas
If no standard deviations are provided, they are automatically calculated as the square root of measured intensities.
Optional comments with # are possible in data file headers.
Here are some examples:
example1.xye
# 2theta intensity su
10.00 167 12.6
10.05 157 12.5
10.10 187 13.3
10.15 197 14.0
10.20 164 12.5
...
164.65 173 30.1
164.70 187 27.9
164.75 175 38.2
164.80 168 30.9
164.85 109 41.2
example2.xy
# 2theta intensity
10.00 167
10.05 157
10.10 187
10.15 197
10.20 164
...
164.65 173
164.70 187
164.75 175
164.80 168
164.85 109
example3.xy
10 167.3 10.05 157.4 10.1 187.1 10.15 197.8 10.2 164.9 ... 164.65 173.3 164.7 187.5 164.75 175.8 164.8 168.1 164.85 109
Listing Defined Experiments
To check which experiments have been added to the project, use:
# Show defined experiments
project.experiments.show_names()
Expected output:
Defined experiments π¬
['hrpt']
Viewing an Experiment as Text
To inspect an experiment's serialized text (the same content the project persists into its Edi files), use:
# Show experiment as text
project.experiments['hrpt'].show_as_text()
Long loops (measured data, reflections) are truncated with ... for
display. Example output:
Experiment π¬ 'hrpt' as text
ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CIF β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 1 data_hrpt β
β 2 β
β 3 _experiment_type.sample_form powder β
β 4 _experiment_type.beam_mode "constant wavelength" β
β 5 _experiment_type.radiation_probe neutron β
β 6 _experiment_type.scattering_type bragg β
β 7 β
β 8 _calculator.type cryspy β
β 9 β
β 10 _peak.broad_gauss_u 0.0816(31) β
β 11 _peak.broad_gauss_v -0.1159(66) β
β 12 _peak.broad_gauss_w 0.1204(32) β
β 13 _peak.broad_lorentz_x 0. β
β 14 _peak.broad_lorentz_y 0.0844(21) β
β 15 _peak.type cwl-pseudo-voigt β
β 16 β
β 17 _instrument.setup_wavelength 1.494 β
β 18 _instrument.calib_twotheta_offset 0.6226(10) β
β 19 β
β 20 loop_ β
β 21 _linked_structure.structure_id β
β 22 _linked_structure.scale β
β 23 lbco 9.135(54) β
β 24 β
β 25 _background.type line-segment β
β 26 β
β 27 loop_ β
β 28 _background.id β
β 29 _background.position β
β 30 _background.intensity β
β 31 1 10. 168.4(1.4) β
β 32 ... β
β 33 β
β 34 loop_ β
β 35 _data.two_theta β
β 36 _data.id β
β 37 _data.intensity_meas β
β 38 _data.intensity_meas_su β
β 39 10. 1 167. 12.6 β
β 40 ... β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Saving an Experiment
Saving the project, as described in the Project section, will
also save the experiment. Each experiment is saved as a separate
.edi file in the experiments subdirectory of the project
directory. The project file contains references to these files.
EasyDiffraction supports different types of experiments, and each experiment is saved in a dedicated Edi file with experiment-specific parameters.
Below are examples of how different experiments are saved in Edi format.
pd-neut-cwl
This example represents a constant-wavelength neutron powder diffraction experiment:
data_hrpt _experiment_type.beam_mode "constant wavelength" _experiment_type.radiation_probe neutron _experiment_type.sample_form powder _experiment_type.scattering_type bragg _instrument.setup_wavelength 1.494 _instrument.calib_twotheta_offset 0.6225(4) _peak.broad_gauss_u 0.0834 _peak.broad_gauss_v -0.1168 _peak.broad_gauss_w 0.123 _peak.broad_lorentz_x 0 _peak.broad_lorentz_y 0.0797 loop_ _linked_structure.structure_id _linked_structure.scale lbco 9.0976(3) loop_ _background.id _background.position _background.intensity 1 10 174.3 2 20 159.8 3 30 167.9 4 50 166.1 5 70 172.3 6 90 171.1 7 110 172.4 8 130 182.5 9 150 173.0 10 165 171.1 loop_ _data.id _data.two_theta _data.intensity_meas _data.intensity_meas_su 1 10.00 167 12.6 2 10.05 157 12.5 3 10.10 187 13.3 4 10.15 197 14.0 5 10.20 164 12.5 6 10.25 171 13.0 ... 164.60 153 20.7 164.65 173 30.1 164.70 187 27.9 164.75 175 38.2 164.80 168 30.9 164.85 109 41.2
pd-neut-tof
This example demonstrates a time-of-flight neutron powder diffraction experiment:
data_wish _experiment_type.beam_mode "time-of-flight" _experiment_type.radiation_probe neutron _experiment_type.sample_form powder _experiment_type.scattering_type bragg _instrument.setup_twotheta_bank 152.827 _instrument.calib_d_to_tof_linear 20773.1(3) _instrument.calib_d_to_tof_quadratic -1.08308 _instrument.calib_d_to_tof_offset -13.7(5) _peak.rise_alpha_0 -0.009(1) _peak.rise_alpha_1 0.109(2) _peak.decay_beta_0 0.00670(3) _peak.decay_beta_1 0.0100(3) _peak.broad_gauss_sigma_0 0 _peak.broad_gauss_sigma_1 0 _peak.broad_gauss_sigma_2 15.7(8) loop_ _linked_structure.structure_id _linked_structure.scale ncaf 1.093(5) loop_ _background.id _background.position _background.intensity 1 9162.3 465(38) 2 11136.8 593(30) 3 14906.5 546(18) 4 17352.2 496(14) 5 20179.5 452(10) 6 22176.0 468(12) 7 24644.7 380(6) 8 28257.2 378(4) 9 34034.4 328(4) 10 41214.6 323(3) 11 49830.9 273(3) 12 58204.9 260(4) 13 70186.9 262(5) 14 82103.2 268(5) 15 102712.0 262(15) loop_ _data.id _data.time_of_flight _data.intensity_meas _data.intensity_meas_su 1 9001.0 616.523 124.564 2 9006.8 578.769 123.141 3 9012.6 574.184 120.507 4 9018.5 507.739 111.300 5 9024.3 404.672 101.616 6 9030.1 469.244 107.991 ... 103085.0 275.072 60.978 103151.4 214.187 55.675 103217.9 256.211 62.825 103284.4 323.872 73.082 103351.0 242.382 65.736 103417.6 277.666 73.837
sc-neut-cwl
This example represents a single-crystal neutron diffraction experiment:
data_heidi _experiment_type.beam_mode "constant wavelength" _experiment_type.radiation_probe neutron _experiment_type.sample_form "single crystal" _experiment_type.scattering_type bragg _instrument.setup_wavelength 0.793 loop_ _linked_structure.structure_id _linked_structure.scale tbti 2.92(6) loop_ _refln.index_h _refln.index_k _refln.index_l _refln.intensity_meas _refln.intensity_meas_su 1 1 1 194.5677 2.3253 2 2 0 22.6319 1.1233 3 1 1 99.2917 2.5620 2 2 2 219.2877 3.2522 ... 16 8 8 29.3063 12.6552 17 7 7 1601.5154 628.8915 13 13 7 1176.0896 414.6018 19 5 1 0.8334 20.4207 15 9 9 10.9864 8.0650 12 12 10 14.4074 11.3800
Now that the experiment has been defined, you can proceed to the next step: Analysis.