Joint Refinement: Si, Bragg + PDF¶
This example demonstrates a joint refinement of the Si crystal structure combining Bragg diffraction and pair distribution function (PDF) analysis. The Bragg experiment uses time-of-flight neutron powder diffraction data from SEPD at Argonne, while the PDF experiment uses data from NOMAD at SNS. A single shared Si structure is refined simultaneously against both datasets.
🛠️ Import Library¶
In [2]:
Copied!
from easydiffraction import ExperimentFactory
from easydiffraction import Project
from easydiffraction import StructureFactory
from easydiffraction import download_data
from easydiffraction import ExperimentFactory
from easydiffraction import Project
from easydiffraction import StructureFactory
from easydiffraction import download_data
In [3]:
Copied!
structure = StructureFactory.from_scratch(name='si')
structure = StructureFactory.from_scratch(name='si')
Set Space Group¶
In [4]:
Copied!
structure.space_group.name_h_m = 'F d -3 m'
structure.space_group.coord_system_code = '1'
structure.space_group.name_h_m = 'F d -3 m'
structure.space_group.coord_system_code = '1'
Set Unit Cell¶
In [5]:
Copied!
structure.cell.length_a = 5.42
structure.cell.length_a = 5.42
Set Atom Sites¶
In [6]:
Copied!
structure.atom_sites.create(
id='Si',
type_symbol='Si',
fract_x=0,
fract_y=0,
fract_z=0,
adp_iso=0.5223,
)
structure.atom_sites.create(
id='Si',
type_symbol='Si',
fract_x=0,
fract_y=0,
fract_z=0,
adp_iso=0.5223,
)
In [7]:
Copied!
bragg_data_path = download_data('meas-si-sepd', destination='data')
bragg_data_path = download_data('meas-si-sepd', destination='data')
Getting data...
Data 'meas-si-sepd': Si, SEPD (Argonne)
✅ Data 'meas-si-sepd' downloaded to '../../../data/meas-si-sepd.xye'
Create Experiment¶
In [8]:
Copied!
bragg_expt = ExperimentFactory.from_data_path(
name='sepd', data_path=bragg_data_path, beam_mode='time-of-flight'
)
bragg_expt = ExperimentFactory.from_data_path(
name='sepd', data_path=bragg_data_path, beam_mode='time-of-flight'
)
Set Instrument¶
In [9]:
Copied!
bragg_expt.instrument.setup_twotheta_bank = 144.845
bragg_expt.instrument.calib_d_to_tof_offset = -8.4
bragg_expt.instrument.calib_d_to_tof_linear = 7476.91
bragg_expt.instrument.calib_d_to_tof_quadratic = -1.54
bragg_expt.instrument.setup_twotheta_bank = 144.845
bragg_expt.instrument.calib_d_to_tof_offset = -8.4
bragg_expt.instrument.calib_d_to_tof_linear = 7476.91
bragg_expt.instrument.calib_d_to_tof_quadratic = -1.54
Set Peak Profile¶
In [10]:
Copied!
bragg_expt.peak.type = 'jorgensen-von-dreele'
bragg_expt.peak.broad_gauss_sigma_0 = 5.61
bragg_expt.peak.broad_gauss_sigma_1 = 33.19
bragg_expt.peak.broad_lorentz_gamma_1 = 2.21
bragg_expt.peak.decay_beta_0 = 0.0406
bragg_expt.peak.decay_beta_1 = 0.0124
bragg_expt.peak.rise_alpha_1 = 0.5971
bragg_expt.peak.cutoff_fwhm = 8.2
bragg_expt.peak.type = 'jorgensen-von-dreele'
bragg_expt.peak.broad_gauss_sigma_0 = 5.61
bragg_expt.peak.broad_gauss_sigma_1 = 33.19
bragg_expt.peak.broad_lorentz_gamma_1 = 2.21
bragg_expt.peak.decay_beta_0 = 0.0406
bragg_expt.peak.decay_beta_1 = 0.0124
bragg_expt.peak.rise_alpha_1 = 0.5971
bragg_expt.peak.cutoff_fwhm = 8.2
⚠️ Switching peak profile type adds these settings with defaults: • broad_lorentz_gamma_0=0.0 • broad_lorentz_gamma_1=0.0 • broad_lorentz_gamma_2=0.0 • broad_lorentz_size_l=0.0 • broad_lorentz_strain_l=0.0
Peak profile type for experiment 'sepd' changed to
jorgensen-von-dreele
Set Background¶
In [11]:
Copied!
for idx, (x, y) in enumerate(
[
(2000.0, 203.79),
(9035.0, 103.74),
(9335.0, 125.12),
(11915.0, 119.81),
(12315.0, 127.52),
(12695.0, 123.16),
(13745.0, 121.72),
(14410.0, 140.39),
(14875.0, 135.11),
(15660.0, 129.95),
(23075.0, 143.23),
(23515.0, 175.48),
(28100.0, 166.48),
(29995.0, 203.98),
],
start=1,
):
bragg_expt.background.create(id=str(idx), position=x, intensity=y)
for idx, (x, y) in enumerate(
[
(2000.0, 203.79),
(9035.0, 103.74),
(9335.0, 125.12),
(11915.0, 119.81),
(12315.0, 127.52),
(12695.0, 123.16),
(13745.0, 121.72),
(14410.0, 140.39),
(14875.0, 135.11),
(15660.0, 129.95),
(23075.0, 143.23),
(23515.0, 175.48),
(28100.0, 166.48),
(29995.0, 203.98),
],
start=1,
):
bragg_expt.background.create(id=str(idx), position=x, intensity=y)
Set Linked Structures¶
In [12]:
Copied!
bragg_expt.linked_structures.create(structure_id='si', scale=634.3132)
bragg_expt.linked_structures.create(structure_id='si', scale=634.3132)
In [13]:
Copied!
pdf_data_path = download_data('meas-si-pdf-nomad', destination='data')
pdf_data_path = download_data('meas-si-pdf-nomad', destination='data')
Getting data...
Data 'meas-si-pdf-nomad': Si, NOMAD (SNS), PDF
✅ Data 'meas-si-pdf-nomad' downloaded to '../../../data/meas-si-pdf-nomad.gr'
Create Experiment¶
In [14]:
Copied!
pdf_expt = ExperimentFactory.from_data_path(
name='nomad',
data_path=pdf_data_path,
beam_mode='time-of-flight',
scattering_type='total',
)
pdf_expt = ExperimentFactory.from_data_path(
name='nomad',
data_path=pdf_data_path,
beam_mode='time-of-flight',
scattering_type='total',
)
⚠️ No uncertainty (sy) column provided. Defaulting to 0.03.
Set Peak Profile (PDF Parameters)¶
In [15]:
Copied!
pdf_expt.peak.damp_q = 0.02
pdf_expt.peak.broad_q = 0.03
pdf_expt.peak.cutoff_q = 35.0
pdf_expt.peak.sharp_delta_1 = 0.4
pdf_expt.peak.sharp_delta_2 = 3.0
pdf_expt.peak.damp_particle_diameter = 0
pdf_expt.peak.damp_q = 0.02
pdf_expt.peak.broad_q = 0.03
pdf_expt.peak.cutoff_q = 35.0
pdf_expt.peak.sharp_delta_1 = 0.4
pdf_expt.peak.sharp_delta_2 = 3.0
pdf_expt.peak.damp_particle_diameter = 0
Set Linked Structures¶
In [16]:
Copied!
pdf_expt.linked_structures.create(structure_id='si', scale=1.6)
pdf_expt.linked_structures.create(structure_id='si', scale=1.6)
In [17]:
Copied!
project = Project(name='si_bragg_pdf')
project = Project(name='si_bragg_pdf')
Add Structure¶
In [18]:
Copied!
project.structures.add(structure)
project.structures.add(structure)
Add Experiments¶
In [19]:
Copied!
project.experiments.add(bragg_expt)
project.experiments.add(pdf_expt)
project.experiments.add(bragg_expt)
project.experiments.add(pdf_expt)
In [20]:
Copied!
project.analysis.fitting_mode.type = 'joint'
project.analysis.joint_fit.create(experiment_id='sepd', weight=0.75)
project.analysis.joint_fit.create(experiment_id='nomad', weight=0.25)
project.analysis.fitting_mode.type = 'joint'
project.analysis.joint_fit.create(experiment_id='sepd', weight=0.75)
project.analysis.joint_fit.create(experiment_id='nomad', weight=0.25)
Fitting mode changed to
joint
Display Structure¶
In [21]:
Copied!
project.display.structure(struct_name='si')
project.display.structure(struct_name='si')
Structure 🧩 'si' (Atom view type: 'covalent')
Loading plot…
drag = rotate
wheel = zoom
right-drag = pan
wheel = zoom
right-drag = pan
Display Pattern (Before Fit)¶
In [22]:
Copied!
project.display.pattern(expt_name='sepd')
project.display.pattern(expt_name='sepd')
Loading plot…
In [23]:
Copied!
project.display.pattern(expt_name='nomad')
project.display.pattern(expt_name='nomad')
Loading plot…
Set Free Parameters¶
Shared structural parameters are refined against both datasets simultaneously.
In [24]:
Copied!
structure.cell.length_a.free = True
structure.cell.length_a.free = True
Bragg experiment parameters.
In [25]:
Copied!
bragg_expt.linked_structures['si'].scale.free = True
bragg_expt.instrument.calib_d_to_tof_offset.free = True
bragg_expt.peak.broad_gauss_sigma_1.free = True
bragg_expt.peak.broad_lorentz_gamma_1.free = True
bragg_expt.linked_structures['si'].scale.free = True
bragg_expt.instrument.calib_d_to_tof_offset.free = True
bragg_expt.peak.broad_gauss_sigma_1.free = True
bragg_expt.peak.broad_lorentz_gamma_1.free = True
PDF experiment parameters.
In [26]:
Copied!
pdf_expt.linked_structures['si'].scale.free = True
pdf_expt.peak.damp_q.free = True
pdf_expt.peak.broad_q.free = True
pdf_expt.peak.sharp_delta_1.free = True
pdf_expt.peak.sharp_delta_2.free = True
pdf_expt.linked_structures['si'].scale.free = True
pdf_expt.peak.damp_q.free = True
pdf_expt.peak.broad_q.free = True
pdf_expt.peak.sharp_delta_1.free = True
pdf_expt.peak.sharp_delta_2.free = True
Display Free Parameters¶
In [27]:
Copied!
project.display.parameters.free()
project.display.parameters.free()
Free parameters for both structures (🧩 data blocks) and experiments (🔬 data blocks)
| datablock | category | entry | parameter | value | uncertainty | min | max | units | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | si | cell | length_a | 5.42000 | -inf | inf | Å | ||
| 2 | sepd | linked_structure | si | scale | 634.31320 | -inf | inf | ||
| 3 | sepd | peak | broad_lorentz_gamma_1 | 2.21000 | -inf | inf | μs/Å | ||
| 4 | sepd | peak | broad_gauss_sigma_1 | 33.19000 | -inf | inf | μs/Å | ||
| 5 | sepd | instrument | d_to_tof_offset | -8.40000 | -inf | inf | μs | ||
| 6 | nomad | linked_structure | si | scale | 1.60000 | -inf | inf | ||
| 7 | nomad | peak | damp_q | 0.02000 | -inf | inf | Å⁻¹ | ||
| 8 | nomad | peak | broad_q | 0.03000 | -inf | inf | Å⁻² | ||
| 9 | nomad | peak | sharp_delta_1 | 0.40000 | -inf | inf | Å | ||
| 10 | nomad | peak | sharp_delta_2 | 3.00000 | -inf | inf | Ų |
Run Fitting¶
In [28]:
Copied!
project.analysis.minimizer.type = 'bumps (lm)'
project.analysis.minimizer.type = 'bumps (lm)'
Current minimizer changed to
bumps (lm)
In [29]:
Copied!
project.analysis.fit()
project.display.fit.results()
project.display.fit.correlations()
project.analysis.fit()
project.display.fit.results()
project.display.fit.correlations()
Using all experiments 🔬 ['sepd', 'nomad'] for 'joint' fitting
🚀 Starting fit process with 'bumps (lm)'...
📈 Goodness-of-fit progress:
| iteration | time (s) | χ² | change / status | |
|---|---|---|---|---|
| 1 | 1 | 0.55 | 988.58 | |
| 2 | 12 | 7.03 | 135.11 | 86.3% ↓ |
| 3 | 23 | 13.61 | 59.07 | 56.3% ↓ |
| 4 | 34 | 20.08 | 54.00 | 8.6% ↓ |
| 5 | 45 | 26.59 | 53.03 | 1.8% ↓ |
| 6 | 56 | 32.90 | 53.00 | |
| 7 | 69 | 40.46 | 53.00 | |
| 8 | 82 | 54.92 | 53.00 |
🏆 Best goodness-of-fit (reduced χ²) is 53.00 at iteration 82
✅ Fitting complete.
⚙️ Settings used:
| Name | Value | Description | |
|---|---|---|---|
| 1 | max_iterations | 1000 | Maximum solver iterations. |
📋 Least-squares fit results:
| Metric | Value | |
|---|---|---|
| 1 | 🧪 Minimizer | bumps (lm) |
| 2 | ✅ Overall status | success |
| 3 | ⏱️ Fitting time (seconds) | 54.92 |
| 4 | 📏 Goodness-of-fit (reduced χ²) | 53.00 |
| 5 | 📏 R-factor (Rf, %) | 8.64 |
| 6 | 📏 R-factor squared (Rf², %) | 5.05 |
| 7 | 📏 Weighted R-factor (wR, %) | 4.16 |
📈 Refined parameters:
| datablock | category | entry | parameter | units | start | value | s.u. | change | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | si | cell | length_a | Å | 5.4200 | 5.4306 | 0.0001 | 0.20 % ↑ | |
| 2 | sepd | linked_structure | si | scale | 634.3132 | 634.2327 | 3.9384 | 0.01 % ↓ | |
| 3 | sepd | peak | broad_lorentz_gamma_1 | μs/Å | 2.2100 | 2.2337 | 0.2271 | 1.07 % ↑ | |
| 4 | sepd | peak | broad_gauss_sigma_1 | μs/Å | 33.1900 | 32.6348 | 1.8571 | 1.67 % ↓ | |
| 5 | sepd | instrument | d_to_tof_offset | μs | -8.4000 | -8.0616 | 0.1768 | 4.03 % ↓ | |
| 6 | nomad | linked_structure | si | scale | 1.6000 | 1.5668 | 0.0026 | 2.08 % ↓ | |
| 7 | nomad | peak | damp_q | Å⁻¹ | 0.0200 | 0.0235 | 0.0001 | 17.67 % ↑ | |
| 8 | nomad | peak | broad_q | Å⁻² | 0.0300 | 0.0276 | 0.0001 | 8.14 % ↓ | |
| 9 | nomad | peak | sharp_delta_1 | Å | 0.4000 | 0.3848 | 0.0340 | 3.80 % ↓ | |
| 10 | nomad | peak | sharp_delta_2 | Ų | 3.0000 | 3.0514 | 0.0849 | 1.71 % ↑ |
• start = parameter value before refinement
• value = refined value from least-squares minimization
• s.u. = standard uncertainty (one sigma), from the covariance matrix
• change = relative change from start, in %; ↑ = increase, ↓ = decrease
• value = refined value from least-squares minimization
• s.u. = standard uncertainty (one sigma), from the covariance matrix
• change = relative change from start, in %; ↑ = increase, ↓ = decrease
Loading plot…
Display Pattern (After Fit)¶
In [30]:
Copied!
project.display.pattern(expt_name='sepd')
project.display.pattern(expt_name='sepd')
Loading plot…
In [31]:
Copied!
project.display.pattern(expt_name='nomad')
project.display.pattern(expt_name='nomad')
Loading plot…
💾 Save Project¶
In [32]:
Copied!
project.save_as(dir_path='projects/joint-si-bragg-pdf')
project.save_as(dir_path='projects/joint-si-bragg-pdf')
Saving project 📦 'si_bragg_pdf' to '../../../projects/joint-si-bragg-pdf'
├── 📄 project.edi
├── 📁 structures/
│ └── 📄 si.edi
├── 📁 experiments/
│ └── 📄 sepd.edi
│ └── 📄 nomad.edi
├── 📁 analysis/
│ └── 📄 analysis.edi
└── 📁 reports/
└── 📄 si_bragg_pdf.html