Structure Refinement: LBCO, HRPT¶
This minimalistic example is designed to show how Rietveld refinement can be performed when both the crystal structure and experiment are defined directly in code. Only the experimentally measured data is loaded from an external file.
For this example, constant-wavelength neutron powder diffraction data for La0.5Ba0.5CoO3 from HRPT at PSI is used.
It does not contain any advanced features or options, and includes no comments or explanations — these can be found in the other tutorials. Default values are used for all parameters if not specified. Only essential and self-explanatory code is provided.
The example is intended for users who are already familiar with the EasyDiffraction library and want to quickly get started with a simple refinement. It is also useful for those who want to see what a refinement might look like in code. For a more detailed explanation of the code, please refer to the other tutorials.
Import Library¶
import easydiffraction as ed
Step 1: Define Project¶
project = ed.Project()
Step 2: Define Structure¶
project.structures.create(name='lbco')
structure = project.structures['lbco']
structure.space_group.name_h_m = 'P m -3 m'
structure.space_group.it_coordinate_system_code = '1'
structure.cell.length_a = 3.88
structure.atom_sites.create(
label='La',
type_symbol='La',
fract_x=0,
fract_y=0,
fract_z=0,
wyckoff_letter='a',
adp_iso=0.5,
occupancy=0.5,
)
structure.atom_sites.create(
label='Ba',
type_symbol='Ba',
fract_x=0,
fract_y=0,
fract_z=0,
wyckoff_letter='a',
adp_iso=0.5,
occupancy=0.5,
)
structure.atom_sites.create(
label='Co',
type_symbol='Co',
fract_x=0.5,
fract_y=0.5,
fract_z=0.5,
wyckoff_letter='b',
adp_iso=0.5,
)
structure.atom_sites.create(
label='O',
type_symbol='O',
fract_x=0,
fract_y=0.5,
fract_z=0.5,
wyckoff_letter='c',
adp_iso=0.5,
)
Step 3: Define Experiment¶
data_path = ed.download_data(id=3, destination='data')
Getting data...
Data #3: La0.5Ba0.5CoO3, HRPT (PSI), 300 K
✅ Data #3 already present at 'data/ed-3.xye'. Keeping existing file.
project.experiments.add_from_data_path(
name='hrpt',
data_path=data_path,
sample_form='powder',
beam_mode='constant wavelength',
radiation_probe='neutron',
)
Data loaded successfully
Experiment 🔬 'hrpt'. Number of data points: 3098.
experiment = project.experiments['hrpt']
experiment.instrument.setup_wavelength = 1.494
experiment.instrument.calib_twotheta_offset = 0.6
experiment.peak.broad_gauss_u = 0.1
experiment.peak.broad_gauss_v = -0.1
experiment.peak.broad_gauss_w = 0.1
experiment.peak.broad_lorentz_y = 0.1
experiment.background.create(id='1', x=10, y=170)
experiment.background.create(id='2', x=30, y=170)
experiment.background.create(id='3', x=50, y=170)
experiment.background.create(id='4', x=110, y=170)
experiment.background.create(id='5', x=165, y=170)
experiment.excluded_regions.create(id='1', start=0, end=5)
experiment.excluded_regions.create(id='2', start=165, end=180)
experiment.linked_phases.create(id='lbco', scale=10.0)
Step 4: Perform Analysis (no constraints)¶
structure.cell.length_a.free = True
structure.atom_sites['La'].adp_iso.free = True
structure.atom_sites['Ba'].adp_iso.free = True
structure.atom_sites['Co'].adp_iso.free = True
structure.atom_sites['O'].adp_iso.free = True
experiment.instrument.calib_twotheta_offset.free = True
experiment.peak.broad_gauss_u.free = True
experiment.peak.broad_gauss_v.free = True
experiment.peak.broad_gauss_w.free = True
experiment.peak.broad_lorentz_y.free = True
experiment.background['1'].y.free = True
experiment.background['2'].y.free = True
experiment.background['3'].y.free = True
experiment.background['4'].y.free = True
experiment.background['5'].y.free = True
experiment.linked_phases['lbco'].scale.free = True
project.analysis.fit()
Standard fitting
📋 Using experiment 🔬 'hrpt' for 'single' fitting
🚀 Starting fit process with 'lmfit (leastsq)'...
📈 Goodness-of-fit (reduced χ²) change:
| iteration | χ² | improvement [%] | |
|---|---|---|---|
| 1 | 1 | 165.02 | |
| 2 | 28 | 33.58 | 79.7% ↓ |
| 3 | 45 | 10.82 | 67.8% ↓ |
| 4 | 63 | 6.49 | 40.0% ↓ |
| 5 | 81 | 3.35 | 48.4% ↓ |
| 6 | 98 | 2.24 | 33.1% ↓ |
| 7 | 116 | 1.91 | 14.7% ↓ |
| 8 | 133 | 1.50 | 21.3% ↓ |
| 9 | 150 | 1.45 | 3.6% ↓ |
| 10 | 167 | 1.34 | 7.8% ↓ |
| 11 | 185 | 1.29 | 3.4% ↓ |
| 12 | 276 | 1.29 |
🏆 Best goodness-of-fit (reduced χ²) is 1.29 at iteration 275
✅ Fitting complete.
project.analysis.display.fit_results()
Fit results
✅ Success: True
⏱️ Fitting time: 13.87 seconds
📏 Goodness-of-fit (reduced χ²): 1.29
📏 R-factor (Rf): 5.63%
📏 R-factor squared (Rf²): 5.27%
📏 Weighted R-factor (wR): 4.41%
📈 Fitted parameters:
| datablock | category | entry | parameter | start | fitted | uncertainty | units | change | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | lbco | cell | length_a | 3.8800 | 3.8909 | 0.0000 | Å | 0.28 % ↑ | |
| 2 | lbco | atom_site | La | adp_iso | 0.5000 | 0.5052 | 3231.7297 | Ų | 1.04 % ↑ |
| 3 | lbco | atom_site | Ba | adp_iso | 0.5000 | 0.5049 | 5252.5594 | Ų | 0.97 % ↑ |
| 4 | lbco | atom_site | Co | adp_iso | 0.5000 | 0.2370 | 0.0611 | Ų | 52.60 % ↓ |
| 5 | lbco | atom_site | O | adp_iso | 0.5000 | 1.3935 | 0.0167 | Ų | 178.71 % ↑ |
| 6 | hrpt | linked_phases | lbco | scale | 10.0000 | 9.1351 | 0.0642 | 8.65 % ↓ | |
| 7 | hrpt | peak | broad_gauss_u | 0.1000 | 0.0816 | 0.0031 | deg² | 18.43 % ↓ | |
| 8 | hrpt | peak | broad_gauss_v | -0.1000 | -0.1159 | 0.0067 | deg² | 15.93 % ↑ | |
| 9 | hrpt | peak | broad_gauss_w | 0.1000 | 0.1204 | 0.0033 | deg² | 20.45 % ↑ | |
| 10 | hrpt | peak | broad_lorentz_y | 0.1000 | 0.0844 | 0.0021 | deg | 15.55 % ↓ | |
| 11 | hrpt | instrument | twotheta_offset | 0.6000 | 0.6226 | 0.0010 | deg | 3.76 % ↑ | |
| 12 | hrpt | background | 1 | y | 170.0000 | 168.5585 | 1.3671 | 0.85 % ↓ | |
| 13 | hrpt | background | 2 | y | 170.0000 | 164.3357 | 0.9992 | 3.33 % ↓ | |
| 14 | hrpt | background | 3 | y | 170.0000 | 166.8881 | 0.7388 | 1.83 % ↓ | |
| 15 | hrpt | background | 4 | y | 170.0000 | 175.4006 | 0.6578 | 3.18 % ↑ | |
| 16 | hrpt | background | 5 | y | 170.0000 | 174.2813 | 0.9105 | 2.52 % ↑ |
⚠️ Red uncertainty: exceeds the fitted value (consider adding constraints)
project.plotter.plot_param_correlations()
project.plotter.plot_meas_vs_calc(expt_name='hrpt', show_residual=True)
Step 5: Perform Analysis (with constraints)¶
# As can be seen from the parameter-correlation plot, the isotropic
# displacement parameters of La and Ba are highly correlated. Because
# La and Ba share the same mixed-occupancy site, their contributions to
# the neutron diffraction pattern are difficult to separate, especially
# since their coherent scattering lengths are not very different.
# Therefore, it is necessary to constrain them to be equal. First we
# define aliases and then use them to create a constraint.
project.analysis.aliases.create(
label='biso_La',
param=project.structures['lbco'].atom_sites['La'].adp_iso,
)
project.analysis.aliases.create(
label='biso_Ba',
param=project.structures['lbco'].atom_sites['Ba'].adp_iso,
)
project.analysis.constraints.create(expression='biso_Ba = biso_La')
project.analysis.show_available_minimizers()
project.analysis.show_current_minimizer()
project.analysis.current_minimizer = 'lmfit'
Supported types
| Type | Description | |
|---|---|---|
| 1 | bumps | Bumps library using the default Levenberg-Marquardt method |
| 2 | bumps (amoeba) | Bumps library with Nelder-Mead simplex method |
| 3 | bumps (de) | Bumps library with differential evolution method |
| 4 | bumps (lm) | Bumps library with Levenberg-Marquardt method |
| 5 | dfols | DFO-LS library for derivative-free least-squares optimization |
| 6 | lmfit | LMFIT library using the default Levenberg-Marquardt least squares method |
| 7 | lmfit (least_squares) | LMFIT library with SciPy's trust region reflective algorithm |
| 8 | lmfit (leastsq) | LMFIT library with Levenberg-Marquardt least squares method |
Current minimizer
lmfit (leastsq)
Current minimizer changed to
lmfit
project.analysis.fit()
Standard fitting
📋 Using experiment 🔬 'hrpt' for 'single' fitting
🚀 Starting fit process with 'lmfit (leastsq)'...
📈 Goodness-of-fit (reduced χ²) change:
| iteration | χ² | improvement [%] | |
|---|---|---|---|
| 1 | 1 | 1.29 | |
| 2 | 36 | 1.29 |
🏆 Best goodness-of-fit (reduced χ²) is 1.29 at iteration 35
✅ Fitting complete.
project.analysis.display.fit_results()
Fit results
✅ Success: True
⏱️ Fitting time: 1.66 seconds
📏 Goodness-of-fit (reduced χ²): 1.29
📏 R-factor (Rf): 5.63%
📏 R-factor squared (Rf²): 5.27%
📏 Weighted R-factor (wR): 4.41%
📈 Fitted parameters:
| datablock | category | entry | parameter | start | fitted | uncertainty | units | change | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | lbco | cell | length_a | 3.8909 | 3.8909 | 0.0000 | Å | 0.00 % ↑ | |
| 2 | lbco | atom_site | La | adp_iso | 0.5052 | 0.5051 | 0.0278 | Ų | 0.03 % ↓ |
| 3 | lbco | atom_site | Co | adp_iso | 0.2370 | 0.2370 | 0.0564 | Ų | 0.00 % ↑ |
| 4 | lbco | atom_site | O | adp_iso | 1.3935 | 1.3935 | 0.0160 | Ų | 0.00 % ↓ |
| 5 | hrpt | linked_phases | lbco | scale | 9.1351 | 9.1351 | 0.0538 | 0.00 % ↓ | |
| 6 | hrpt | peak | broad_gauss_u | 0.0816 | 0.0816 | 0.0031 | deg² | 0.00 % ↑ | |
| 7 | hrpt | peak | broad_gauss_v | -0.1159 | -0.1159 | 0.0066 | deg² | 0.00 % ↑ | |
| 8 | hrpt | peak | broad_gauss_w | 0.1204 | 0.1204 | 0.0032 | deg² | 0.00 % ↑ | |
| 9 | hrpt | peak | broad_lorentz_y | 0.0844 | 0.0844 | 0.0021 | deg | 0.00 % ↓ | |
| 10 | hrpt | instrument | twotheta_offset | 0.6226 | 0.6226 | 0.0010 | deg | 0.00 % ↑ | |
| 11 | hrpt | background | 1 | y | 168.5585 | 168.5585 | 1.3669 | 0.00 % ↓ | |
| 12 | hrpt | background | 2 | y | 164.3357 | 164.3357 | 0.9990 | 0.00 % ↑ | |
| 13 | hrpt | background | 3 | y | 166.8881 | 166.8881 | 0.7386 | 0.00 % ↑ | |
| 14 | hrpt | background | 4 | y | 175.4006 | 175.4006 | 0.6488 | 0.00 % ↑ | |
| 15 | hrpt | background | 5 | y | 174.2813 | 174.2813 | 0.8944 | 0.00 % ↓ |
project.plotter.plot_param_correlations()
project.plotter.plot_meas_vs_calc(expt_name='hrpt', show_residual=True)