Structure Refinement: NCAF, WISH¶
This example demonstrates a Rietveld refinement of Na2Ca3Al2F14 crystal structure using time-of-flight neutron powder diffraction data from WISH at ISIS.
Two datasets from detector banks 5+6 and 4+7 are used for joint fitting.
Import Library¶
In [2]:
Copied!
from easydiffraction import ExperimentFactory
from easydiffraction import Project
from easydiffraction import SampleModelFactory
from easydiffraction import download_from_repository
from easydiffraction import ExperimentFactory
from easydiffraction import Project
from easydiffraction import SampleModelFactory
from easydiffraction import download_from_repository
In [3]:
Copied!
model = SampleModelFactory.create(name='ncaf')
model = SampleModelFactory.create(name='ncaf')
Set Space Group¶
In [4]:
Copied!
model.space_group.name_h_m = 'I 21 3'
model.space_group.it_coordinate_system_code = '1'
model.space_group.name_h_m = 'I 21 3'
model.space_group.it_coordinate_system_code = '1'
Set Unit Cell¶
In [5]:
Copied!
model.cell.length_a = 10.250256
model.cell.length_a = 10.250256
Set Atom Sites¶
In [6]:
Copied!
model.atom_sites.add_from_args(
    label='Ca',
    type_symbol='Ca',
    fract_x=0.4663,
    fract_y=0.0,
    fract_z=0.25,
    wyckoff_letter='b',
    b_iso=0.92,
)
model.atom_sites.add_from_args(
    label='Al',
    type_symbol='Al',
    fract_x=0.2521,
    fract_y=0.2521,
    fract_z=0.2521,
    wyckoff_letter='a',
    b_iso=0.73,
)
model.atom_sites.add_from_args(
    label='Na',
    type_symbol='Na',
    fract_x=0.0851,
    fract_y=0.0851,
    fract_z=0.0851,
    wyckoff_letter='a',
    b_iso=2.08,
)
model.atom_sites.add_from_args(
    label='F1',
    type_symbol='F',
    fract_x=0.1377,
    fract_y=0.3054,
    fract_z=0.1195,
    wyckoff_letter='c',
    b_iso=0.90,
)
model.atom_sites.add_from_args(
    label='F2',
    type_symbol='F',
    fract_x=0.3625,
    fract_y=0.3633,
    fract_z=0.1867,
    wyckoff_letter='c',
    b_iso=1.37,
)
model.atom_sites.add_from_args(
    label='F3',
    type_symbol='F',
    fract_x=0.4612,
    fract_y=0.4612,
    fract_z=0.4612,
    wyckoff_letter='a',
    b_iso=0.88,
)
model.atom_sites.add_from_args(
    label='Ca',
    type_symbol='Ca',
    fract_x=0.4663,
    fract_y=0.0,
    fract_z=0.25,
    wyckoff_letter='b',
    b_iso=0.92,
)
model.atom_sites.add_from_args(
    label='Al',
    type_symbol='Al',
    fract_x=0.2521,
    fract_y=0.2521,
    fract_z=0.2521,
    wyckoff_letter='a',
    b_iso=0.73,
)
model.atom_sites.add_from_args(
    label='Na',
    type_symbol='Na',
    fract_x=0.0851,
    fract_y=0.0851,
    fract_z=0.0851,
    wyckoff_letter='a',
    b_iso=2.08,
)
model.atom_sites.add_from_args(
    label='F1',
    type_symbol='F',
    fract_x=0.1377,
    fract_y=0.3054,
    fract_z=0.1195,
    wyckoff_letter='c',
    b_iso=0.90,
)
model.atom_sites.add_from_args(
    label='F2',
    type_symbol='F',
    fract_x=0.3625,
    fract_y=0.3633,
    fract_z=0.1867,
    wyckoff_letter='c',
    b_iso=1.37,
)
model.atom_sites.add_from_args(
    label='F3',
    type_symbol='F',
    fract_x=0.4612,
    fract_y=0.4612,
    fract_z=0.4612,
    wyckoff_letter='a',
    b_iso=0.88,
)
In [7]:
Copied!
download_from_repository(
    'wish_ncaf_5_6.xys',
    destination='data',
)
download_from_repository(
    'wish_ncaf_5_6.xys',
    destination='data',
)
Downloading...
File 'wish_ncaf_5_6.xys' from 'easyscience/diffraction-lib'
In [8]:
Copied!
download_from_repository(
    'wish_ncaf_4_7.xys',
    destination='data',
)
download_from_repository(
    'wish_ncaf_4_7.xys',
    destination='data',
)
Downloading...
File 'wish_ncaf_4_7.xys' from 'easyscience/diffraction-lib'
Create Experiment¶
In [9]:
Copied!
expt56 = ExperimentFactory.create(
    name='wish_5_6',
    data_path='data/wish_ncaf_5_6.xys',
    beam_mode='time-of-flight',
)
expt56 = ExperimentFactory.create(
    name='wish_5_6',
    data_path='data/wish_ncaf_5_6.xys',
    beam_mode='time-of-flight',
)
Data loaded successfully
Experiment 🔬 'wish_5_6'. Number of data points: 4121
In [10]:
Copied!
expt47 = ExperimentFactory.create(
    name='wish_4_7',
    data_path='data/wish_ncaf_4_7.xys',
    beam_mode='time-of-flight',
)
expt47 = ExperimentFactory.create(
    name='wish_4_7',
    data_path='data/wish_ncaf_4_7.xys',
    beam_mode='time-of-flight',
)
Data loaded successfully
Experiment 🔬 'wish_4_7'. Number of data points: 4043
Set Instrument¶
In [11]:
Copied!
expt56.instrument.setup_twotheta_bank = 152.827
expt56.instrument.calib_d_to_tof_offset = -13.5
expt56.instrument.calib_d_to_tof_linear = 20773.0
expt56.instrument.calib_d_to_tof_quad = -1.08308
expt56.instrument.setup_twotheta_bank = 152.827
expt56.instrument.calib_d_to_tof_offset = -13.5
expt56.instrument.calib_d_to_tof_linear = 20773.0
expt56.instrument.calib_d_to_tof_quad = -1.08308
In [12]:
Copied!
expt47.instrument.setup_twotheta_bank = 121.660
expt47.instrument.calib_d_to_tof_offset = -15.0
expt47.instrument.calib_d_to_tof_linear = 18660.0
expt47.instrument.calib_d_to_tof_quad = -0.47488
expt47.instrument.setup_twotheta_bank = 121.660
expt47.instrument.calib_d_to_tof_offset = -15.0
expt47.instrument.calib_d_to_tof_linear = 18660.0
expt47.instrument.calib_d_to_tof_quad = -0.47488
Set Peak Profile¶
In [13]:
Copied!
expt56.peak.broad_gauss_sigma_0 = 0.0
expt56.peak.broad_gauss_sigma_1 = 0.0
expt56.peak.broad_gauss_sigma_2 = 15.5
expt56.peak.broad_mix_beta_0 = 0.007
expt56.peak.broad_mix_beta_1 = 0.01
expt56.peak.asym_alpha_0 = -0.0094
expt56.peak.asym_alpha_1 = 0.1
expt56.peak.broad_gauss_sigma_0 = 0.0
expt56.peak.broad_gauss_sigma_1 = 0.0
expt56.peak.broad_gauss_sigma_2 = 15.5
expt56.peak.broad_mix_beta_0 = 0.007
expt56.peak.broad_mix_beta_1 = 0.01
expt56.peak.asym_alpha_0 = -0.0094
expt56.peak.asym_alpha_1 = 0.1
In [14]:
Copied!
expt47.peak.broad_gauss_sigma_0 = 0.0
expt47.peak.broad_gauss_sigma_1 = 29.8
expt47.peak.broad_gauss_sigma_2 = 18.0
expt47.peak.broad_mix_beta_0 = 0.006
expt47.peak.broad_mix_beta_1 = 0.015
expt47.peak.asym_alpha_0 = -0.0115
expt47.peak.asym_alpha_1 = 0.1
expt47.peak.broad_gauss_sigma_0 = 0.0
expt47.peak.broad_gauss_sigma_1 = 29.8
expt47.peak.broad_gauss_sigma_2 = 18.0
expt47.peak.broad_mix_beta_0 = 0.006
expt47.peak.broad_mix_beta_1 = 0.015
expt47.peak.asym_alpha_0 = -0.0115
expt47.peak.asym_alpha_1 = 0.1
Set Background¶
In [15]:
Copied!
expt56.background_type = 'line-segment'
for x, y in [
    (9162, 465),
    (11136, 593),
    (13313, 497),
    (14906, 546),
    (16454, 533),
    (17352, 496),
    (18743, 428),
    (20179, 452),
    (21368, 397),
    (22176, 468),
    (22827, 477),
    (24644, 380),
    (26439, 381),
    (28257, 378),
    (31196, 343),
    (34034, 328),
    (37265, 310),
    (41214, 323),
    (44827, 283),
    (49830, 273),
    (52905, 257),
    (58204, 260),
    (62916, 261),
    (70186, 262),
    (74204, 262),
    (82103, 268),
    (91958, 268),
    (102712, 262),
]:
    expt56.background.add_from_args(x=x, y=y)
expt56.background_type = 'line-segment'
for x, y in [
    (9162, 465),
    (11136, 593),
    (13313, 497),
    (14906, 546),
    (16454, 533),
    (17352, 496),
    (18743, 428),
    (20179, 452),
    (21368, 397),
    (22176, 468),
    (22827, 477),
    (24644, 380),
    (26439, 381),
    (28257, 378),
    (31196, 343),
    (34034, 328),
    (37265, 310),
    (41214, 323),
    (44827, 283),
    (49830, 273),
    (52905, 257),
    (58204, 260),
    (62916, 261),
    (70186, 262),
    (74204, 262),
    (82103, 268),
    (91958, 268),
    (102712, 262),
]:
    expt56.background.add_from_args(x=x, y=y)
Background type for experiment 'wish_5_6' changed to
line-segment
In [16]:
Copied!
expt47.background_type = 'line-segment'
for x, y in [
    (9090, 488),
    (10672, 566),
    (12287, 494),
    (14037, 559),
    (15451, 529),
    (16764, 445),
    (18076, 460),
    (19456, 413),
    (20466, 511),
    (21880, 396),
    (23798, 391),
    (25447, 385),
    (28073, 349),
    (30058, 332),
    (32583, 309),
    (34804, 355),
    (37160, 318),
    (40324, 290),
    (46895, 260),
    (50631, 256),
    (54602, 246),
    (58439, 264),
    (66520, 250),
    (75002, 258),
    (83649, 257),
    (92770, 255),
    (101524, 260),
]:
    expt47.background.add_from_args(x=x, y=y)
expt47.background_type = 'line-segment'
for x, y in [
    (9090, 488),
    (10672, 566),
    (12287, 494),
    (14037, 559),
    (15451, 529),
    (16764, 445),
    (18076, 460),
    (19456, 413),
    (20466, 511),
    (21880, 396),
    (23798, 391),
    (25447, 385),
    (28073, 349),
    (30058, 332),
    (32583, 309),
    (34804, 355),
    (37160, 318),
    (40324, 290),
    (46895, 260),
    (50631, 256),
    (54602, 246),
    (58439, 264),
    (66520, 250),
    (75002, 258),
    (83649, 257),
    (92770, 255),
    (101524, 260),
]:
    expt47.background.add_from_args(x=x, y=y)
Background type for experiment 'wish_4_7' changed to
line-segment
Set Linked Phases¶
In [17]:
Copied!
expt56.linked_phases.add_from_args(id='ncaf', scale=1.0)
expt56.linked_phases.add_from_args(id='ncaf', scale=1.0)
In [18]:
Copied!
expt47.linked_phases.add_from_args(id='ncaf', scale=2.0)
expt47.linked_phases.add_from_args(id='ncaf', scale=2.0)
Set Excluded Regions¶
In [19]:
Copied!
expt56.excluded_regions.add_from_args(start=0, end=10010)
expt56.excluded_regions.add_from_args(start=100010, end=200000)
expt56.excluded_regions.add_from_args(start=0, end=10010)
expt56.excluded_regions.add_from_args(start=100010, end=200000)
In [20]:
Copied!
expt47.excluded_regions.add_from_args(start=0, end=10006)
expt47.excluded_regions.add_from_args(start=100004, end=200000)
expt47.excluded_regions.add_from_args(start=0, end=10006)
expt47.excluded_regions.add_from_args(start=100004, end=200000)
In [21]:
Copied!
project = Project()
project = Project()
Set Plotting Engine¶
In [22]:
Copied!
project.plotter.engine = 'plotly'
project.plotter.engine = 'plotly'
Add Sample Model¶
In [23]:
Copied!
project.sample_models.add(model)
project.sample_models.add(model)
Add Experiment¶
In [24]:
Copied!
project.experiments.add(expt56)
project.experiments.add(expt47)
project.experiments.add(expt56)
project.experiments.add(expt47)
In [25]:
Copied!
project.analysis.current_calculator = 'cryspy'
project.analysis.current_calculator = 'cryspy'
Current calculator changed to
cryspy
Set Minimizer¶
In [26]:
Copied!
project.analysis.current_minimizer = 'lmfit (leastsq)'
project.analysis.current_minimizer = 'lmfit (leastsq)'
Current minimizer changed to
lmfit (leastsq)
Set Fit Mode¶
In [27]:
Copied!
project.analysis.fit_mode = 'joint'
project.analysis.fit_mode = 'joint'
Current fit mode changed to
joint
Set Free Parameters¶
In [28]:
Copied!
model.atom_sites['Ca'].b_iso.free = True
model.atom_sites['Al'].b_iso.free = True
model.atom_sites['Na'].b_iso.free = True
model.atom_sites['F1'].b_iso.free = True
model.atom_sites['F2'].b_iso.free = True
model.atom_sites['F3'].b_iso.free = True
model.atom_sites['Ca'].b_iso.free = True
model.atom_sites['Al'].b_iso.free = True
model.atom_sites['Na'].b_iso.free = True
model.atom_sites['F1'].b_iso.free = True
model.atom_sites['F2'].b_iso.free = True
model.atom_sites['F3'].b_iso.free = True
In [29]:
Copied!
expt56.linked_phases['ncaf'].scale.free = True
expt56.instrument.calib_d_to_tof_offset.free = True
expt56.instrument.calib_d_to_tof_linear.free = True
expt56.peak.broad_gauss_sigma_2.free = True
expt56.peak.broad_mix_beta_0.free = True
expt56.peak.broad_mix_beta_1.free = True
expt56.peak.asym_alpha_1.free = True
expt47.linked_phases['ncaf'].scale.free = True
expt47.instrument.calib_d_to_tof_linear.free = True
expt47.instrument.calib_d_to_tof_offset.free = True
expt47.peak.broad_gauss_sigma_2.free = True
expt47.peak.broad_mix_beta_0.free = True
expt47.peak.broad_mix_beta_1.free = True
expt47.peak.asym_alpha_1.free = True
expt56.linked_phases['ncaf'].scale.free = True
expt56.instrument.calib_d_to_tof_offset.free = True
expt56.instrument.calib_d_to_tof_linear.free = True
expt56.peak.broad_gauss_sigma_2.free = True
expt56.peak.broad_mix_beta_0.free = True
expt56.peak.broad_mix_beta_1.free = True
expt56.peak.asym_alpha_1.free = True
expt47.linked_phases['ncaf'].scale.free = True
expt47.instrument.calib_d_to_tof_linear.free = True
expt47.instrument.calib_d_to_tof_offset.free = True
expt47.peak.broad_gauss_sigma_2.free = True
expt47.peak.broad_mix_beta_0.free = True
expt47.peak.broad_mix_beta_1.free = True
expt47.peak.asym_alpha_1.free = True
Plot Measured vs Calculated¶
In [30]:
Copied!
project.plot_meas_vs_calc(expt_name='wish_5_6', show_residual=True)
project.plot_meas_vs_calc(expt_name='wish_5_6', show_residual=True)
In [31]:
Copied!
project.plot_meas_vs_calc(expt_name='wish_4_7', show_residual=True)
project.plot_meas_vs_calc(expt_name='wish_4_7', show_residual=True)
Run Fitting¶
In [32]:
Copied!
project.analysis.fit()
project.analysis.fit()
Using all experiments 🔬 ['wish_5_6', 'wish_4_7'] for 'joint' fitting
🚀 Starting fit process with 'lmfit (leastsq)'...
📈 Goodness-of-fit (reduced χ²) change:
| iteration | χ² | improvement [%] | |
|---|---|---|---|
| 1 | 1 | 47.53 | |
| 2 | 24 | 15.57 | 67.2% ↓ | 
| 3 | 109 | 15.49 | 
🏆 Best goodness-of-fit (reduced χ²) is 15.49 at iteration 94
✅ Fitting complete.
Fit results
✅ Success: True
⏱️ Fitting time: 79.70 seconds
📏 Goodness-of-fit (reduced χ²): 15.49
📏 R-factor (Rf): 6.98%
📏 R-factor squared (Rf²): 8.05%
📏 Weighted R-factor (wR): 9.15%
📈 Fitted parameters:
| datablock | category | entry | parameter | start | fitted | uncertainty | units | change | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | ncaf | atom_site | Ca | b_iso | 0.9200 | 0.9340 | 0.0448 | Ų | 1.52 % ↑ | 
| 2 | ncaf | atom_site | Al | b_iso | 0.7300 | 0.7330 | 0.0569 | Ų | 0.41 % ↑ | 
| 3 | ncaf | atom_site | Na | b_iso | 2.0800 | 2.0474 | 0.1082 | Ų | 1.57 % ↓ | 
| 4 | ncaf | atom_site | F1 | b_iso | 0.9000 | 0.9389 | 0.0373 | Ų | 4.32 % ↑ | 
| 5 | ncaf | atom_site | F2 | b_iso | 1.3700 | 1.3442 | 0.0408 | Ų | 1.88 % ↓ | 
| 6 | ncaf | atom_site | F3 | b_iso | 0.8800 | 0.8481 | 0.0551 | Ų | 3.62 % ↓ | 
| 7 | wish_5_6 | peak | None | gauss_sigma_2 | 15.5000 | 15.6543 | 0.7398 | µs²/Ų | 1.00 % ↑ | 
| 8 | wish_5_6 | peak | None | mix_beta_0 | 0.0070 | 0.0067 | 0.0000 | deg | 4.54 % ↓ | 
| 9 | wish_5_6 | peak | None | mix_beta_1 | 0.0100 | 0.0101 | 0.0002 | deg | 1.46 % ↑ | 
| 10 | wish_5_6 | peak | None | asym_alpha_1 | 0.1000 | 0.1094 | 0.0012 | 9.43 % ↑ | |
| 11 | wish_5_6 | linked_phases | ncaf | scale | 1.0000 | 1.1029 | 0.0035 | 10.29 % ↑ | |
| 12 | wish_5_6 | instrument | None | d_to_tof_offset | -13.5000 | -13.6260 | 0.4257 | µs | 0.93 % ↑ | 
| 13 | wish_5_6 | instrument | None | d_to_tof_linear | 20773.0000 | 20773.0394 | 0.3051 | µs/Å | 0.00 % ↑ | 
| 14 | wish_4_7 | peak | None | gauss_sigma_2 | 18.0000 | 18.2604 | 0.8685 | µs²/Ų | 1.45 % ↑ | 
| 15 | wish_4_7 | peak | None | mix_beta_0 | 0.0060 | 0.0065 | 0.0000 | deg | 7.52 % ↑ | 
| 16 | wish_4_7 | peak | None | mix_beta_1 | 0.0150 | 0.0148 | 0.0003 | deg | 1.38 % ↓ | 
| 17 | wish_4_7 | peak | None | asym_alpha_1 | 0.1000 | 0.1222 | 0.0018 | 22.15 % ↑ | |
| 18 | wish_4_7 | linked_phases | ncaf | scale | 2.0000 | 2.5216 | 0.0077 | 26.08 % ↑ | |
| 19 | wish_4_7 | instrument | None | d_to_tof_offset | -15.0000 | -14.9768 | 0.5084 | µs | 0.15 % ↓ | 
| 20 | wish_4_7 | instrument | None | d_to_tof_linear | 18660.0000 | 18660.1028 | 0.3625 | µs/Å | 0.00 % ↑ | 
Plot Measured vs Calculated¶
In [33]:
Copied!
project.plot_meas_vs_calc(expt_name='wish_5_6', show_residual=True)
project.plot_meas_vs_calc(expt_name='wish_5_6', show_residual=True)
In [34]:
Copied!
project.plot_meas_vs_calc(expt_name='wish_4_7', show_residual=True)
project.plot_meas_vs_calc(expt_name='wish_4_7', show_residual=True)
Summary¶
This final section shows how to review the results of the analysis.
Show Project Summary¶
In [35]:
Copied!
project.summary.show_report()
project.summary.show_report()
PROJECT INFO ━━━━━━━━━━━━
Title
Untitled Project
CRYSTALLOGRAPHIC DATA ━━━━━━━━━━━━━━━━━━━━━
Phase datablock
🧩 ncaf
Space group
I 21 3
Cell parameters
| Parameter | Value | |
|---|---|---|
| 1 | a | 10.25026 | 
| 2 | b | 10.25026 | 
| 3 | c | 10.25026 | 
| 4 | alpha | 90.00000 | 
| 5 | beta | 90.00000 | 
| 6 | gamma | 90.00000 | 
Atom sites
| label | type | x | y | z | occ | Biso | |
|---|---|---|---|---|---|---|---|
| 1 | Ca | Ca | 0.46630 | 0.00000 | 0.25000 | 1.00000 | 0.93400 | 
| 2 | Al | Al | 0.25210 | 0.25210 | 0.25210 | 1.00000 | 0.73301 | 
| 3 | Na | Na | 0.08510 | 0.08510 | 0.08510 | 1.00000 | 2.04740 | 
| 4 | F1 | F | 0.13770 | 0.30540 | 0.11950 | 1.00000 | 0.93890 | 
| 5 | F2 | F | 0.36250 | 0.36330 | 0.18670 | 1.00000 | 1.34424 | 
| 6 | F3 | F | 0.46120 | 0.46120 | 0.46120 | 1.00000 | 0.84814 | 
EXPERIMENTS ━━━━━━━━━━━
Experiment datablock
🔬 wish_5_6
Experiment type
SampleFormEnum.POWDER, RadiationProbeEnum.NEUTRON, time-of-flight
Profile type
PeakProfileTypeEnum.PSEUDO_VOIGT_IKEDA_CARPENTER
Experiment datablock
🔬 wish_4_7
Experiment type
SampleFormEnum.POWDER, RadiationProbeEnum.NEUTRON, time-of-flight
Profile type
PeakProfileTypeEnum.PSEUDO_VOIGT_IKEDA_CARPENTER
FITTING ━━━━━━━
Calculation engine
cryspy
Minimization engine
lmfit (leastsq)
Fit quality
| metric | value | |
|---|---|---|
| 1 | Goodness-of-fit (reduced χ²) | 15.49 |