Structure Refinement: Co2SiO4, D20¶
This example demonstrates a Rietveld refinement of Co2SiO4 crystal structure using constant wavelength neutron powder diffraction data from D20 at ILL.
Import Library¶
In [2]:
Copied!
from easydiffraction import Experiment
from easydiffraction import Project
from easydiffraction import SampleModel
from easydiffraction import download_from_repository
from easydiffraction import Experiment
from easydiffraction import Project
from easydiffraction import SampleModel
from easydiffraction import download_from_repository
⚠️ 'pycrysfml' module not found. This calculation engine will not be available. ✅ 'cryspy' calculation engine is successfully imported. ✅ 'pdffit' calculation engine is successfully imported.
In [3]:
Copied!
model = SampleModel('cosio')
model = SampleModel('cosio')
Set Space Group¶
In [4]:
Copied!
model.space_group.name_h_m = 'P n m a'
model.space_group.it_coordinate_system_code = 'abc'
model.space_group.name_h_m = 'P n m a'
model.space_group.it_coordinate_system_code = 'abc'
Set Unit Cell¶
In [5]:
Copied!
model.cell.length_a = 10.3
model.cell.length_b = 6.0
model.cell.length_c = 4.8
model.cell.length_a = 10.3
model.cell.length_b = 6.0
model.cell.length_c = 4.8
Set Atom Sites¶
In [6]:
Copied!
model.atom_sites.add('Co1', 'Co', 0, 0, 0, wyckoff_letter='a', b_iso=0.5)
model.atom_sites.add('Co2', 'Co', 0.279, 0.25, 0.985, wyckoff_letter='c', b_iso=0.5)
model.atom_sites.add('Si', 'Si', 0.094, 0.25, 0.429, wyckoff_letter='c', b_iso=0.5)
model.atom_sites.add('O1', 'O', 0.091, 0.25, 0.771, wyckoff_letter='c', b_iso=0.5)
model.atom_sites.add('O2', 'O', 0.448, 0.25, 0.217, wyckoff_letter='c', b_iso=0.5)
model.atom_sites.add('O3', 'O', 0.164, 0.032, 0.28, wyckoff_letter='d', b_iso=0.5)
model.atom_sites.add('Co1', 'Co', 0, 0, 0, wyckoff_letter='a', b_iso=0.5)
model.atom_sites.add('Co2', 'Co', 0.279, 0.25, 0.985, wyckoff_letter='c', b_iso=0.5)
model.atom_sites.add('Si', 'Si', 0.094, 0.25, 0.429, wyckoff_letter='c', b_iso=0.5)
model.atom_sites.add('O1', 'O', 0.091, 0.25, 0.771, wyckoff_letter='c', b_iso=0.5)
model.atom_sites.add('O2', 'O', 0.448, 0.25, 0.217, wyckoff_letter='c', b_iso=0.5)
model.atom_sites.add('O3', 'O', 0.164, 0.032, 0.28, wyckoff_letter='d', b_iso=0.5)
Symmetry Constraints¶
Show CIF output before applying symmetry constraints.
In [7]:
Copied!
model.show_as_cif()
model.show_as_cif()
Sample model 🧩 'cosio' as cif
data_cosio |
_space_group.IT_coordinate_system_code abc |
_space_group.name_H-M_alt "P n m a" |
_cell.angle_alpha 90.0 |
_cell.angle_beta 90.0 |
_cell.angle_gamma 90.0 |
_cell.length_a 10.3 |
_cell.length_b 6.0 |
_cell.length_c 4.8 |
loop_ |
_atom_site.ADP_type |
_atom_site.B_iso_or_equiv |
_atom_site.fract_x |
_atom_site.fract_y |
_atom_site.fract_z |
_atom_site.label |
_atom_site.occupancy |
_atom_site.type_symbol |
_atom_site.Wyckoff_letter |
Biso 0.5 0 0 0 Co1 1.0 Co a |
Biso 0.5 0.279 0.25 0.985 Co2 1.0 Co c |
Biso 0.5 0.094 0.25 0.429 Si 1.0 Si c |
Biso 0.5 0.091 0.25 0.771 O1 1.0 O c |
Biso 0.5 0.448 0.25 0.217 O2 1.0 O c |
Biso 0.5 0.164 0.032 0.28 O3 1.0 O d |
Apply symmetry constraints.
In [8]:
Copied!
model.apply_symmetry_constraints()
model.apply_symmetry_constraints()
Show CIF output after applying symmetry constraints.
In [9]:
Copied!
model.show_as_cif()
model.show_as_cif()
Sample model 🧩 'cosio' as cif
data_cosio |
_space_group.IT_coordinate_system_code abc |
_space_group.name_H-M_alt "P n m a" |
_cell.angle_alpha 90 |
_cell.angle_beta 90 |
_cell.angle_gamma 90 |
_cell.length_a 10.3 |
_cell.length_b 6.0 |
_cell.length_c 4.8 |
loop_ |
_atom_site.ADP_type |
_atom_site.B_iso_or_equiv |
_atom_site.fract_x |
_atom_site.fract_y |
_atom_site.fract_z |
_atom_site.label |
_atom_site.occupancy |
_atom_site.type_symbol |
_atom_site.Wyckoff_letter |
Biso 0.5 0.0 0.0 0.0 Co1 1.0 Co a |
Biso 0.5 0.279 0.25 0.985 Co2 1.0 Co c |
Biso 0.5 0.094 0.25 0.429 Si 1.0 Si c |
Biso 0.5 0.091 0.25 0.771 O1 1.0 O c |
Biso 0.5 0.448 0.25 0.217 O2 1.0 O c |
Biso 0.5 0.164 0.032 0.28 O3 1.0 O d |
In [10]:
Copied!
download_from_repository('co2sio4_d20.xye', destination='data')
download_from_repository('co2sio4_d20.xye', destination='data')
⚠️ Warning
File 'data/co2sio4_d20.xye' already exists and will not be overwritten.
Create Experiment¶
In [11]:
Copied!
expt = Experiment('d20', data_path='data/co2sio4_d20.xye')
expt = Experiment('d20', data_path='data/co2sio4_d20.xye')
Data loaded successfully
Experiment 🔬 'd20'. Number of data points: 1418
Set Instrument¶
In [12]:
Copied!
expt.instrument.setup_wavelength = 1.87
expt.instrument.calib_twotheta_offset = 0.1
expt.instrument.setup_wavelength = 1.87
expt.instrument.calib_twotheta_offset = 0.1
Set Peak Profile¶
In [13]:
Copied!
expt.peak.broad_gauss_u = 0.3
expt.peak.broad_gauss_v = -0.5
expt.peak.broad_gauss_w = 0.4
expt.peak.broad_gauss_u = 0.3
expt.peak.broad_gauss_v = -0.5
expt.peak.broad_gauss_w = 0.4
Set Background¶
In [14]:
Copied!
expt.background.add(x=8, y=500)
expt.background.add(x=9, y=500)
expt.background.add(x=10, y=500)
expt.background.add(x=11, y=500)
expt.background.add(x=12, y=500)
expt.background.add(x=15, y=500)
expt.background.add(x=25, y=500)
expt.background.add(x=30, y=500)
expt.background.add(x=50, y=500)
expt.background.add(x=70, y=500)
expt.background.add(x=90, y=500)
expt.background.add(x=110, y=500)
expt.background.add(x=130, y=500)
expt.background.add(x=150, y=500)
expt.background.add(x=8, y=500)
expt.background.add(x=9, y=500)
expt.background.add(x=10, y=500)
expt.background.add(x=11, y=500)
expt.background.add(x=12, y=500)
expt.background.add(x=15, y=500)
expt.background.add(x=25, y=500)
expt.background.add(x=30, y=500)
expt.background.add(x=50, y=500)
expt.background.add(x=70, y=500)
expt.background.add(x=90, y=500)
expt.background.add(x=110, y=500)
expt.background.add(x=130, y=500)
expt.background.add(x=150, y=500)
Set Linked Phases¶
In [15]:
Copied!
expt.linked_phases.add('cosio', scale=1.0)
expt.linked_phases.add('cosio', scale=1.0)
In [16]:
Copied!
project = Project()
project = Project()
Set Plotting Engine¶
In [17]:
Copied!
project.plotter.engine = 'plotly'
project.plotter.engine = 'plotly'
Current plotter changed to
plotly
Add Sample Model¶
In [18]:
Copied!
project.sample_models.add(model)
project.sample_models.add(model)
Add Experiment¶
In [19]:
Copied!
project.experiments.add(expt)
project.experiments.add(expt)
In [20]:
Copied!
project.analysis.current_calculator = 'cryspy'
project.analysis.current_calculator = 'cryspy'
Current calculator changed to
cryspy
Set Minimizer¶
In [21]:
Copied!
project.analysis.current_minimizer = 'lmfit (leastsq)'
project.analysis.current_minimizer = 'lmfit (leastsq)'
Current minimizer changed to
lmfit (leastsq)
Plot Measured vs Calculated¶
In [22]:
Copied!
project.plot_meas_vs_calc(expt_name='d20', show_residual=True)
project.plot_meas_vs_calc(expt_name='d20', show_residual=True)
In [23]:
Copied!
project.plot_meas_vs_calc(expt_name='d20', x_min=41, x_max=54, show_residual=True)
project.plot_meas_vs_calc(expt_name='d20', x_min=41, x_max=54, show_residual=True)
Set Free Parameters¶
In [24]:
Copied!
model.cell.length_a.free = True
model.cell.length_b.free = True
model.cell.length_c.free = True
model.atom_sites['Co2'].fract_x.free = True
model.atom_sites['Co2'].fract_z.free = True
model.atom_sites['Si'].fract_x.free = True
model.atom_sites['Si'].fract_z.free = True
model.atom_sites['O1'].fract_x.free = True
model.atom_sites['O1'].fract_z.free = True
model.atom_sites['O2'].fract_x.free = True
model.atom_sites['O2'].fract_z.free = True
model.atom_sites['O3'].fract_x.free = True
model.atom_sites['O3'].fract_y.free = True
model.atom_sites['O3'].fract_z.free = True
model.atom_sites['Co1'].b_iso.free = True
model.atom_sites['Co2'].b_iso.free = True
model.atom_sites['Si'].b_iso.free = True
model.atom_sites['O1'].b_iso.free = True
model.atom_sites['O2'].b_iso.free = True
model.atom_sites['O3'].b_iso.free = True
model.cell.length_a.free = True
model.cell.length_b.free = True
model.cell.length_c.free = True
model.atom_sites['Co2'].fract_x.free = True
model.atom_sites['Co2'].fract_z.free = True
model.atom_sites['Si'].fract_x.free = True
model.atom_sites['Si'].fract_z.free = True
model.atom_sites['O1'].fract_x.free = True
model.atom_sites['O1'].fract_z.free = True
model.atom_sites['O2'].fract_x.free = True
model.atom_sites['O2'].fract_z.free = True
model.atom_sites['O3'].fract_x.free = True
model.atom_sites['O3'].fract_y.free = True
model.atom_sites['O3'].fract_z.free = True
model.atom_sites['Co1'].b_iso.free = True
model.atom_sites['Co2'].b_iso.free = True
model.atom_sites['Si'].b_iso.free = True
model.atom_sites['O1'].b_iso.free = True
model.atom_sites['O2'].b_iso.free = True
model.atom_sites['O3'].b_iso.free = True
In [25]:
Copied!
expt.linked_phases['cosio'].scale.free = True
expt.instrument.calib_twotheta_offset.free = True
expt.peak.broad_gauss_u.free = True
expt.peak.broad_gauss_v.free = True
expt.peak.broad_gauss_w.free = True
expt.peak.broad_lorentz_y.free = True
for point in expt.background:
point.y.free = True
expt.linked_phases['cosio'].scale.free = True
expt.instrument.calib_twotheta_offset.free = True
expt.peak.broad_gauss_u.free = True
expt.peak.broad_gauss_v.free = True
expt.peak.broad_gauss_w.free = True
expt.peak.broad_lorentz_y.free = True
for point in expt.background:
point.y.free = True
Set Constraints¶
Set aliases for parameters.
In [26]:
Copied!
project.analysis.aliases.add(
label='biso_Co1',
param_uid=project.sample_models['cosio'].atom_sites['Co1'].b_iso.uid,
)
project.analysis.aliases.add(
label='biso_Co2',
param_uid=project.sample_models['cosio'].atom_sites['Co2'].b_iso.uid,
)
project.analysis.aliases.add(
label='biso_Co1',
param_uid=project.sample_models['cosio'].atom_sites['Co1'].b_iso.uid,
)
project.analysis.aliases.add(
label='biso_Co2',
param_uid=project.sample_models['cosio'].atom_sites['Co2'].b_iso.uid,
)
Set constraints.
In [27]:
Copied!
project.analysis.constraints.add(
lhs_alias='biso_Co2',
rhs_expr='biso_Co1',
)
project.analysis.constraints.add(
lhs_alias='biso_Co2',
rhs_expr='biso_Co1',
)
Apply constraints.
In [28]:
Copied!
project.analysis.apply_constraints()
project.analysis.apply_constraints()
Run Fitting¶
In [29]:
Copied!
project.analysis.fit()
project.analysis.fit()
Using experiment 🔬 'd20' for 'single' fitting 🚀 Starting fit process with 'lmfit (leastsq)'... 📈 Goodness-of-fit (reduced χ²) change:
iteration | χ² | improvement [%] |
---|---|---|
1 |
423.20 |
|
43 |
71.71 |
83.1% ↓ |
83 |
40.43 |
43.6% ↓ |
123 |
17.05 |
57.8% ↓ |
163 |
10.78 |
36.8% ↓ |
203 |
9.26 |
14.1% ↓ |
243 |
8.08 |
12.7% ↓ |
283 |
5.66 |
30.0% ↓ |
323 |
4.67 |
17.4% ↓ |
363 |
4.57 |
2.3% ↓ |
564 |
4.56 |
🏆 Best goodness-of-fit (reduced χ²) is 4.56 at iteration 562
✅ Fitting complete.
Fit results
✅ Success: True
⏱️ Fitting time: 10.80 seconds
📏 Goodness-of-fit (reduced χ²): 4.56
📏 R-factor (Rf): 3.04%
📏 R-factor squared (Rf²): 4.54%
📏 Weighted R-factor (wR): 4.87%
📈 Fitted parameters:
datablock | category | entry | parameter | start | fitted | uncertainty | units | change | |
---|---|---|---|---|---|---|---|---|---|
1 | cosio |
atom_sites |
Co1 |
b_iso |
0.5000 |
0.2770 |
0.0802 |
Ų |
44.59 % ↓ |
2 | cosio |
atom_sites |
Co2 |
fract_x |
0.2790 |
0.2794 |
0.0007 |
0.14 % ↑ |
|
3 | cosio |
atom_sites |
Co2 |
fract_z |
0.9850 |
0.9847 |
0.0015 |
0.03 % ↓ |
|
4 | cosio |
atom_sites |
Si |
b_iso |
0.5000 |
0.3519 |
0.0625 |
Ų |
29.62 % ↓ |
5 | cosio |
atom_sites |
Si |
fract_x |
0.0940 |
0.0937 |
0.0004 |
0.31 % ↓ |
|
6 | cosio |
atom_sites |
Si |
fract_z |
0.4290 |
0.4290 |
0.0008 |
0.01 % ↑ |
|
7 | cosio |
atom_sites |
O1 |
b_iso |
0.5000 |
0.6457 |
0.0581 |
Ų |
29.14 % ↑ |
8 | cosio |
atom_sites |
O1 |
fract_x |
0.0910 |
0.0911 |
0.0003 |
0.08 % ↑ |
|
9 | cosio |
atom_sites |
O1 |
fract_z |
0.7710 |
0.7714 |
0.0006 |
0.05 % ↑ |
|
10 | cosio |
atom_sites |
O2 |
b_iso |
0.5000 |
0.5778 |
0.0582 |
Ų |
15.57 % ↑ |
11 | cosio |
atom_sites |
O2 |
fract_x |
0.4480 |
0.4482 |
0.0003 |
0.06 % ↑ |
|
12 | cosio |
atom_sites |
O2 |
fract_z |
0.2170 |
0.2167 |
0.0007 |
0.14 % ↓ |
|
13 | cosio |
atom_sites |
O3 |
b_iso |
0.5000 |
0.8389 |
0.0485 |
Ų |
67.79 % ↑ |
14 | cosio |
atom_sites |
O3 |
fract_x |
0.1640 |
0.1636 |
0.0002 |
0.26 % ↓ |
|
15 | cosio |
atom_sites |
O3 |
fract_y |
0.0320 |
0.0317 |
0.0003 |
1.08 % ↓ |
|
16 | cosio |
atom_sites |
O3 |
fract_z |
0.2800 |
0.2800 |
0.0005 |
0.02 % ↑ |
|
17 | cosio |
cell |
length_a |
10.3000 |
10.3090 |
0.0003 |
Å |
0.09 % ↑ |
|
18 | cosio |
cell |
length_b |
6.0000 |
6.0039 |
0.0002 |
Å |
0.07 % ↑ |
|
19 | cosio |
cell |
length_c |
4.8000 |
4.7868 |
0.0001 |
Å |
0.28 % ↓ |
|
20 | d20 |
background |
8 |
y |
500.0000 |
608.6305 |
14.5414 |
21.73 % ↑ |
|
21 | d20 |
background |
9 |
y |
500.0000 |
580.6214 |
9.7278 |
16.12 % ↑ |
|
22 | d20 |
background |
10 |
y |
500.0000 |
562.8991 |
9.2422 |
12.58 % ↑ |
|
23 | d20 |
background |
11 |
y |
500.0000 |
540.2882 |
8.7695 |
8.06 % ↑ |
|
24 | d20 |
background |
12 |
y |
500.0000 |
519.8428 |
6.0496 |
3.97 % ↑ |
|
25 | d20 |
background |
15 |
y |
500.0000 |
507.3838 |
3.4846 |
1.48 % ↑ |
|
26 | d20 |
background |
25 |
y |
500.0000 |
463.0794 |
3.1898 |
7.38 % ↓ |
|
27 | d20 |
background |
30 |
y |
500.0000 |
434.2455 |
2.3904 |
13.15 % ↓ |
|
28 | d20 |
background |
50 |
y |
500.0000 |
450.8166 |
2.2505 |
9.84 % ↓ |
|
29 | d20 |
background |
70 |
y |
500.0000 |
430.3828 |
2.0250 |
13.92 % ↓ |
|
30 | d20 |
background |
90 |
y |
500.0000 |
413.7132 |
2.2594 |
17.26 % ↓ |
|
31 | d20 |
background |
110 |
y |
500.0000 |
361.2599 |
2.0915 |
27.75 % ↓ |
|
32 | d20 |
background |
130 |
y |
500.0000 |
291.0612 |
1.9671 |
41.79 % ↓ |
|
33 | d20 |
background |
150 |
y |
500.0000 |
238.7749 |
2.9764 |
52.25 % ↓ |
|
34 | d20 |
instrument |
twotheta_offset |
0.1000 |
0.2884 |
0.0020 |
deg |
188.44 % ↑ |
|
35 | d20 |
linked_phases |
cosio |
scale |
1.0000 |
1.1957 |
0.0106 |
19.57 % ↑ |
|
36 | d20 |
peak |
broad_gauss_u |
0.3000 |
0.2423 |
0.0068 |
deg² |
19.22 % ↓ |
|
37 | d20 |
peak |
broad_gauss_v |
-0.5000 |
-0.5288 |
0.0145 |
deg² |
5.76 % ↑ |
|
38 | d20 |
peak |
broad_gauss_w |
0.4000 |
0.3840 |
0.0090 |
deg² |
4.01 % ↓ |
|
39 | d20 |
peak |
broad_lorentz_y |
0.0000 |
0.0159 |
0.0045 |
deg |
N/A |
Plot Measured vs Calculated¶
In [30]:
Copied!
project.plot_meas_vs_calc(expt_name='d20', show_residual=True)
project.plot_meas_vs_calc(expt_name='d20', show_residual=True)
In [31]:
Copied!
project.plot_meas_vs_calc(expt_name='d20', x_min=41, x_max=54, show_residual=True)
project.plot_meas_vs_calc(expt_name='d20', x_min=41, x_max=54, show_residual=True)
Summary¶
This final section shows how to review the results of the analysis.
Show Project Summary¶
In [32]:
Copied!
project.summary.show_report()
project.summary.show_report()
*** PROJECT INFO *** Title Untitled Project *** CRYSTALLOGRAPHIC DATA *** Phase datablock 🧩 cosio Space group P n m a Cell parameters
alpha |
90.00000 |
beta |
90.00000 |
gamma |
90.00000 |
a |
10.30896 |
b |
6.00391 |
c |
4.78675 |
Atom sites
Label | Type | fract_x | fract_y | fract_z | Occupancy | B_iso |
---|---|---|---|---|---|---|
Co1 |
Co |
0.00000 |
0.00000 |
0.00000 |
1.00000 |
0.27703 |
Co2 |
Co |
0.27938 |
0.25000 |
0.98470 |
1.00000 |
0.27703 |
Si |
Si |
0.09371 |
0.25000 |
0.42904 |
1.00000 |
0.35192 |
O1 |
O |
0.09107 |
0.25000 |
0.77140 |
1.00000 |
0.64570 |
O2 |
O |
0.44825 |
0.25000 |
0.21671 |
1.00000 |
0.57784 |
O3 |
O |
0.16358 |
0.03165 |
0.28005 |
1.00000 |
0.83894 |
*** EXPERIMENTS *** Experiment datablock 🔬 d20 Experiment type powder, neutron, constant wavelength Wavelength 1.87000 2θ offset 0.28844 Profile type pseudo-voigt Peak broadening (Gaussian)
U |
0.24233 |
V |
-0.52880 |
W |
0.38395 |
Peak broadening (Lorentzian)
X |
0.00000 |
Y |
0.01591 |
*** FITTING *** Calculation engine cryspy Minimization engine lmfit (leastsq) Fit quality
Goodness-of-fit (reduced χ²) |
4.56 |