Bayesian Analysis (MCMC) – LBCO and Si¶
This notebook continues the powder diffraction refinement tutorial. In that tutorial, you built a two-phase model containing La₀.₅Ba₀.₅CoO₃ (LBCO) and a small Si impurity, refined the model against simulated time-of-flight neutron data, and saved the project.
A conventional least-squares refinement gives a best-fit point and uncertainty estimates based on the local shape of the objective function. Bayesian analysis instead uses Markov chain Monte Carlo (MCMC) sampling to explore the joint posterior distribution of the free parameters. This allows us to investigate questions such as:
- Where is each posterior distribution centered, and how does that compare with the deterministic best-fit value?
- How broad are their credible intervals?
- Do the local parameter correlations from the deterministic fit persist across the posterior, and are any relationships nonlinear or asymmetric?
- How does parameter uncertainty propagate into the calculated diffraction pattern?
The deterministic fit already provides a correlation matrix derived from the local covariance estimate near the best-fit point. Bayesian sampling extends this view by exploring how parameters vary together throughout the joint posterior. It can therefore reveal curved, asymmetric, bounded, or multimodal relationships that one local correlation coefficient cannot describe.
This notebook follows the same teaching structure as the refinement tutorial:
- Introduction: a complete, guided MCMC analysis of the refined LBCO+Si model.
- Exercise: repeat the analysis after fixing one member of a strongly correlated peak-profile pair, then compare the results.
We will use the DREAM sampler provided by the bumps (dream)
minimizer. The short chains used here keep the tutorial practical. A
scientific analysis requires longer chains and careful convergence
checks.
🛠️ Import Library¶
import easydiffraction as edi
📘 Introduction: MCMC Analysis of LBCO+Si¶
We will first work through the complete Bayesian workflow without exercises. This reference analysis samples the same seven scientific parameters that remained free at the end of the refinement tutorial:
- the LBCO lattice parameter,
- the LBCO and Si scale factors, and
- four peak-profile parameters.
The resulting project will be called project_1, following the
convention used for the introductory Si fit in the previous tutorial.
📂 Load the Refined Project¶
Rather than rebuilding the experiment and structures, download the project saved at the end of the refinement tutorial. This restores the measured data, both structures, the refined values, and the free-parameter settings.
The following cell downloads our pre-generated refined project from
the EasyDiffraction repository. This lets you continue even if you did
not complete the refinement tutorial or your saved project is missing.
The download_data function will not overwrite an existing project
unless you set overwrite=True, so it is safe to run even if the
project is already present.
📖 See documentation for more details about loading a saved project.
refinement_project_dir = edi.download_data(
'proj-fitting-exercise-si-lbco-main',
destination='projects',
)
project_1 = edi.Project.load(refinement_project_dir)
Getting data...
Data 'proj-fitting-exercise-si-lbco-main': La0.5Ba0.5CoO3 + Si, fitted DMSC exercise project
✅ Data 'proj-fitting-exercise-si-lbco-main' downloaded and extracted to '../../../projects/proj-fitting-exercise-si-lbco-main-62547397a81c'
Save a copy under a new name before changing the analysis. This keeps the deterministic refinement unchanged and gives the sampler its own location for posterior summaries and chain data.
project_1.metadata.title = 'Reference Bayesian Analysis of LBCO with Si Impurity'
project_1.metadata.description = (
'Reference MCMC analysis of a two-phase LBCO and Si powder diffraction model.'
)
project_1.save_as(dir_path='projects/exercise-bayesian-si-lbco-reference')
Saving project 📦 'main' to '../../../projects/exercise-bayesian-si-lbco-reference'
├── 📄 project.edi
├── 📁 structures/
│ └── 📄 lbco.edi
│ └── 📄 si.edi
├── 📁 experiments/
│ └── 📄 sim_lbco.edi
├── 📁 analysis/
│ └── 📄 analysis.edi
└── 📁 reports/
└── 📄 main.html
Confirm that the restored project contains the LBCO and Si structures
and the sim_lbco experiment.
project_1.structures.show_names()
project_1.experiments.show_names()
Defined structures 🧩
['lbco', 'si']
Defined experiments 🔬
['sim_lbco']
project_1.display.structure(struct_name='lbco')
project_1.display.structure(struct_name='si')
Structure 🧩 'lbco' (Atom view type: 'covalent')
wheel = zoom
right-drag = pan
Structure 🧩 'si' (Atom view type: 'covalent')
wheel = zoom
right-drag = pan
project_1.display.pattern(expt_name='sim_lbco')
🎯 Choose the Sampled Parameters¶
MCMC varies every free parameter simultaneously. Before sampling, it is worth asking which parameters are needed to answer the scientific question.
First, display all free parameters in the refined project.
project_1.display.parameters.free()
Free parameters for both structures (🧩 data blocks) and experiments (🔬 data blocks)
| datablock | category | entry | parameter | value | uncertainty | min | max | units | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | lbco | cell | length_a | 3.89147 | 0.00015 | -inf | inf | Å | |
| 2 | sim_lbco | linked_structure | lbco | scale | 42.36000 | 0.24000 | -inf | inf | |
| 3 | sim_lbco | linked_structure | si | scale | 0.32700 | 0.01200 | -inf | inf | |
| 4 | sim_lbco | peak | rise_alpha_1 | 0.01655 | 0.00014 | -inf | inf | μs/Å | |
| 5 | sim_lbco | peak | decay_beta_1 | 0.01857 | 0.00042 | -inf | inf | μs/Å | |
| 6 | sim_lbco | peak | broad_gauss_sigma_1 | -68200.00000 | 1500.00000 | -inf | inf | μs/Å | |
| 7 | sim_lbco | peak | broad_gauss_sigma_2 | 16130.00000 | 780.00000 | -inf | inf | μs²/Ų | |
| 8 | sim_lbco | background | 1 | intensity | 0.27700 | 0.02900 | -inf | inf | |
| 9 | sim_lbco | background | 2 | intensity | 0.25110 | 0.00590 | -inf | inf | |
| 10 | sim_lbco | background | 3 | intensity | 0.25200 | 0.00380 | -inf | inf | |
| 11 | sim_lbco | background | 4 | intensity | 0.24150 | 0.00300 | -inf | inf | |
| 12 | sim_lbco | background | 5 | intensity | 0.24280 | 0.00210 | -inf | inf | |
| 13 | sim_lbco | background | 6 | intensity | 0.22150 | 0.00250 | -inf | inf | |
| 14 | sim_lbco | background | 7 | intensity | 0.23840 | 0.00880 | -inf | inf |
The seven line-segment background intensities were refined in the previous tutorial. If we left them free, this analysis would sample 14 parameters instead of 7. The larger space would require more model evaluations, take longer to explore, and generally need a longer chain to mix well. Background parameters can also correlate with phase scales and broad peaks, making the posterior harder to interpret.
We therefore fix the background at its refined values. This is a practical simplification for a short teaching example, not a universal rule. Fixing the background means that its uncertainty is not propagated into the final credible intervals. In a complete scientific analysis, you should sample relevant background parameters or otherwise account for their uncertainty when it can affect the result.
experiment_1 = project_1.experiments['sim_lbco']
for line_segment in experiment_1.background:
line_segment.intensity.free = False
Display the remaining free parameters to verify the sampling problem.
project_1.display.parameters.free()
Free parameters for both structures (🧩 data blocks) and experiments (🔬 data blocks)
| datablock | category | entry | parameter | value | uncertainty | min | max | units | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | lbco | cell | length_a | 3.89147 | 0.00015 | -inf | inf | Å | |
| 2 | sim_lbco | linked_structure | lbco | scale | 42.36000 | 0.24000 | -inf | inf | |
| 3 | sim_lbco | linked_structure | si | scale | 0.32700 | 0.01200 | -inf | inf | |
| 4 | sim_lbco | peak | rise_alpha_1 | 0.01655 | 0.00014 | -inf | inf | μs/Å | |
| 5 | sim_lbco | peak | decay_beta_1 | 0.01857 | 0.00042 | -inf | inf | μs/Å | |
| 6 | sim_lbco | peak | broad_gauss_sigma_1 | -68200.00000 | 1500.00000 | -inf | inf | μs/Å | |
| 7 | sim_lbco | peak | broad_gauss_sigma_2 | 16130.00000 | 780.00000 | -inf | inf | μs²/Ų |
🚀 Run a Local Refinement¶
Fixing the background changes the optimization problem slightly. We first run a fast local least-squares refinement to update the best-fit values and their uncertainty estimates. These values will provide the starting point and finite bounds for MCMC.
We use the BUMPS Levenberg-Marquardt minimizer, bumps (lm), so the
local and Bayesian stages use the same minimizer library.
📖 See documentation for more details about the available minimizers.
project_1.analysis.minimizer.show_supported()
Minimizer 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 (dream) | BUMPS library with DREAM Bayesian sampling | |
| 5 | bumps (lm) | BUMPS library with Levenberg-Marquardt method | |
| 6 | dfols | DFO-LS library for derivative-free least-squares optimization | |
| 7 | emcee | emcee affine-invariant ensemble Bayesian sampling | |
| 8 | lmfit | LMFIT library using the default Levenberg-Marquardt method | |
| 9 | lmfit (least_squares) | LMFIT library with SciPy's trust region reflective algorithm | |
| 10 | * | lmfit (leastsq) | LMFIT library with Levenberg-Marquardt least squares method |
project_1.analysis.minimizer.type = 'bumps (lm)'
Current minimizer changed to
bumps (lm)
project_1.analysis.fit()
project_1.display.fit.results()
Standard fitting
📋 Using experiment 🔬 'sim_lbco' for 'single' fitting
🚀 Starting fit process with 'bumps (lm)'...
📈 Goodness-of-fit progress:
| iteration | time (s) | χ² | change / status | |
|---|---|---|---|---|
| 1 | 1 | 0.02 | 1.58 | |
| 2 | 27 | 1.12 | 1.58 |
🏆 Best goodness-of-fit (reduced χ²) is 1.58 at iteration 17
✅ Fitting complete.
Saving project 📦 'main' to '../../../projects/exercise-bayesian-si-lbco-reference'
├── 📄 project.edi
├── 📁 structures/
│ └── 📄 lbco.edi
│ └── 📄 si.edi
├── 📁 experiments/
│ └── 📄 sim_lbco.edi
├── 📁 analysis/
│ └── 📄 analysis.edi
└── 📁 reports/
└── 📄 main.html
⚙️ 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) | 1.12 |
| 4 | 📏 Goodness-of-fit (reduced χ²) | 1.58 |
| 5 | 📏 R-factor (Rf, %) | 5.06 |
| 6 | 📏 R-factor squared (Rf², %) | 4.61 |
| 7 | 📏 Weighted R-factor (wR, %) | 4.05 |
📈 Refined parameters:
| datablock | category | entry | parameter | units | start | value | s.u. | change | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | lbco | cell | length_a | Å | 3.8915 | 3.8915 | 0.0002 | 0.00 % ↑ | |
| 2 | sim_lbco | linked_structure | lbco | scale | 42.3600 | 42.3607 | 0.2296 | 0.00 % ↑ | |
| 3 | sim_lbco | linked_structure | si | scale | 0.3270 | 0.3266 | 0.0112 | 0.14 % ↓ | |
| 4 | sim_lbco | peak | rise_alpha_1 | μs/Å | 0.0165 | 0.0166 | 0.0001 | 0.02 % ↑ | |
| 5 | sim_lbco | peak | decay_beta_1 | μs/Å | 0.0186 | 0.0186 | 0.0004 | 0.03 % ↑ | |
| 6 | sim_lbco | peak | broad_gauss_sigma_1 | μs/Å | -68200.0000 | -68198.9042 | 1460.1673 | 0.00 % ↓ | |
| 7 | sim_lbco | peak | broad_gauss_sigma_2 | μs²/Ų | 16130.0000 | 16127.9516 | 772.9224 | 0.01 % ↓ |
• 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
🔗 Understand the Local Correlation Chart¶
The correlation chart summarizes how pairs of refined parameters can change together near the least-squares optimum. Each off-diagonal value is a correlation coefficient between -1 and +1:
- a value near +1 means that the two parameters tend to increase together;
- a value near -1 means that one tends to decrease when the other increases; and
- a value near 0 means that there is little linear relationship.
Correlation does not mean that one parameter physically causes the other. It means that the measured pattern cannot distinguish their effects independently within this model.
project_1.display.fit.correlations(max_parameters=5)
The matrix shows only one triangular half because the other half would
contain the same values in reverse order. With max_parameters=5,
EasyDiffraction filters the chart to keep the strongest relationships
readable. In an interactive Jupyter display, hover over a colored cell
to see the two full parameter names and the numerical correlation
coefficient.
The strongest relationship is typically the negative correlation
between broad_gauss_sigma_1 and broad_gauss_sigma_2, close to
-0.94. Both parameters contribute to the d-spacing dependence of the
Gaussian TOF peak width. An increase in one can be partly compensated
by a decrease in the other while producing a similar calculated peak
shape.
This chart comes from the local covariance estimate, so it describes only the neighborhood around the best-fit point. MCMC will show whether the relationship remains linear and approximately elliptical across a wider region of parameter space.
🎲 Define the Sampling Region¶
DREAM requires finite lower and upper bounds for every sampled
parameter. Here, we derive them from the uncertainty estimated by the
local fit. set_fit_bounds_from_uncertainty() places each bound four
estimated standard uncertainties from the current value by default,
while respecting any physical parameter limits.
These bounds act as bounded prior support in this example. They must be inspected rather than accepted blindly: narrow bounds can truncate the posterior, while unnecessarily wide bounds can make sampling less efficient.
📖 See documentation for more details about parameter values, uncertainties, and fit bounds.
for param in project_1.free_parameters:
param.set_fit_bounds_from_uncertainty()
project_1.display.parameters.free()
Free parameters for both structures (🧩 data blocks) and experiments (🔬 data blocks)
| datablock | category | entry | parameter | value | uncertainty | min | max | units | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | lbco | cell | length_a | 3.89148 | 0.00015 | 3.89086 | 3.89209 | Å | |
| 2 | sim_lbco | linked_structure | lbco | scale | 42.36069 | 0.22958 | 41.44235 | 43.27902 | |
| 3 | sim_lbco | linked_structure | si | scale | 0.32656 | 0.01119 | 0.28179 | 0.37132 | |
| 4 | sim_lbco | peak | rise_alpha_1 | 0.01655 | 0.00013 | 0.01602 | 0.01708 | μs/Å | |
| 5 | sim_lbco | peak | decay_beta_1 | 0.01858 | 0.00041 | 0.01694 | 0.02021 | μs/Å | |
| 6 | sim_lbco | peak | broad_gauss_sigma_1 | -68198.90416 | 1460.16730 | -74039.57337 | -62358.23495 | μs/Å | |
| 7 | sim_lbco | peak | broad_gauss_sigma_2 | 16127.95164 | 772.92242 | 13036.26194 | 19219.64133 | μs²/Ų |
🎲 Run DREAM Sampling¶
In Bayesian analysis, the posterior combines the likelihood of the measured data with prior assumptions. MCMC constructs chains of correlated samples whose long-run distribution approximates that posterior.
DREAM uses multiple chains and differential-evolution proposals to explore correlated parameter spaces. This makes it useful for the strong peak-profile correlation observed above.
📖 See documentation for more details about Bayesian minimizers and posterior displays.
project_1.analysis.minimizer.type = 'bumps (dream)'
project_1.analysis.minimizer.sampling_steps = 300 # lower than the default 3000
project_1.analysis.minimizer.burn_in_steps = 60 # lower than the default 600
project_1.analysis.minimizer.random_seed = 42
⚠️ Switching minimizer type removes these settings: • max_iterations
⚠️ Switching minimizer type adds these settings with defaults: • burn_in_steps=600 • initialization_method='latin_hypercube' • parallel_workers=0 • population_size=4 • random_seed=None • sampling_steps=3000 • thinning_interval=1
Current minimizer changed to
bumps (dream)
Burn-in samples allow the chains to move away from their initial positions before the retained posterior is summarized. The fixed seed makes the tutorial output reproducible.
project_1.analysis.fit()
Standard fitting
📋 Using experiment 🔬 'sim_lbco' for 'single' fitting
🚀 Starting fit process with 'bumps (dream)'...
📈 Bayesian sampling progress:
| step | progress | time (s) | log posterior | phase | |
|---|---|---|---|---|---|
| 1 | 0.40 | -628.67 | pre-processing | ||
| 2 | 21/360 | 5.8% | 8.17 | -352.40 | burn-in |
| 3 | 40/360 | 11.1% | 14.91 | -345.10 | burn-in |
| 4 | 60/360 | 16.7% | 26.19 | -342.11 | burn-in |
| 5 | 61/360 | 16.9% | 26.68 | -341.96 | sampling |
| 6 | 76/360 | 21.1% | 34.32 | -340.55 | sampling |
| 7 | 91/360 | 25.3% | 42.61 | -339.56 | sampling |
| 8 | 106/360 | 29.4% | 50.07 | -338.54 | sampling |
| 9 | 121/360 | 33.6% | 58.99 | -338.50 | sampling |
| 10 | 136/360 | 37.8% | 65.32 | -338.42 | sampling |
| 11 | 151/360 | 41.9% | 71.41 | -338.37 | sampling |
| 12 | 166/360 | 46.1% | 76.62 | -337.43 | sampling |
| 13 | 181/360 | 50.3% | 82.34 | -337.80 | sampling |
| 14 | 196/360 | 54.4% | 87.44 | -337.47 | sampling |
| 15 | 211/360 | 58.6% | 93.24 | -338.31 | sampling |
| 16 | 226/360 | 62.8% | 98.43 | -338.08 | sampling |
| 17 | 241/360 | 66.9% | 104.15 | -338.21 | sampling |
| 18 | 256/360 | 71.1% | 109.32 | -337.89 | sampling |
| 19 | 271/360 | 75.3% | 114.77 | -337.34 | sampling |
| 20 | 286/360 | 79.4% | 119.95 | -336.96 | sampling |
| 21 | 301/360 | 83.6% | 125.32 | -337.48 | sampling |
| 22 | 316/360 | 87.8% | 130.44 | -338.37 | sampling |
| 23 | 331/360 | 91.9% | 136.04 | -338.27 | sampling |
| 24 | 346/360 | 96.1% | 141.15 | -337.94 | sampling |
| 25 | 360/360 | 100.0% | 146.71 | -337.66 | sampling |
| 26 | 187.39 | post-processing |
✅ Bayesian sampling complete.
⚠️ Convergence diagnostics indicate the posterior may be poorly mixed.
Saving project 📦 'main' to '../../../projects/exercise-bayesian-si-lbco-reference'
├── 📄 project.edi
├── 📁 structures/
│ └── 📄 lbco.edi
│ └── 📄 si.edi
├── 📁 experiments/
│ └── 📄 sim_lbco.edi
├── 📁 analysis/
│ ├── 📄 analysis.edi
│ └── 📄 mcmc.h5
└── 📁 reports/
└── 📄 main.html
📋 Understand the Bayesian Fit Summary¶
The result table now reports posterior medians and 95% credible intervals in addition to fit-quality metrics. A 95% credible interval is the interval containing 95% of the retained marginal posterior samples under this model and bounded sampling setup.
The table also reports convergence diagnostics:
- r-hat compares variation within and between chains. Values close
to 1 are desirable; EasyDiffraction uses
r-hat <= 1.01as its displayed convergence criterion. - ess bulk is the effective sample size after accounting for autocorrelation. A larger value means that the chain contains more independent information; the display recommends at least 400.
project_1.display.fit.results()
⚙️ Settings used:
| Name | Value | Description | |
|---|---|---|---|
| 1 | sampling_steps | 300 | Total sampler iterations per chain. |
| 2 | burn_in_steps | 60 | Sampler iterations discarded as warm-up. |
| 3 | thinning_interval | 1 | Sampler thinning interval. |
| 4 | population_size | 4 | Number of chains or walkers. |
| 5 | parallel_workers | 0 | Worker count; 0 uses all available CPUs. |
| 6 | initialization_method | latin_hypercube | Sampler initialization method. |
| 7 | random_seed | 42 | Random seed; None uses a system-derived seed. |
📋 Bayesian fit results:
| Metric | Value | |
|---|---|---|
| 1 | 🧪 Sampler | bumps (dream) |
| 2 | ❌ Overall status | failed |
| 3 | 💬 Engine message | DREAM sampling completed |
| 4 | ⏱️ Fitting time (seconds) | 187.39 |
| 5 | 📏 Goodness-of-fit (reduced χ²) | 1.58 |
| 6 | 📏 R-factor (Rf, %) | 5.06 |
| 7 | 📏 R-factor squared (Rf², %) | 4.61 |
| 8 | 📏 Weighted R-factor (wR, %) | 4.05 |
| 9 | 📉 Best log-posterior | -333.99 |
| 10 | 📊 Convergence status | failed |
| 11 | 📊 Max r-hat | 1.162 |
| 12 | 📊 Min ess bulk | 280.912 |
| 13 | 📊 Draws per chain | 300 |
| 14 | 📊 Chains | 28 |
📈 Committed parameters:
| datablock | category | entry | parameter | units | start | value | s.u. | change | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | lbco | cell | length_a | Å | 3.8915 | 3.8915 | 0.0001 | 0.00 % ↓ | |
| 2 | sim_lbco | linked_structure | lbco | scale | 42.3607 | 42.3607 | 0.2068 | 0.00 % ↓ | |
| 3 | sim_lbco | linked_structure | si | scale | 0.3266 | 0.3266 | 0.0096 | 0.00 % ↓ | |
| 4 | sim_lbco | peak | rise_alpha_1 | μs/Å | 0.0166 | 0.0166 | 0.0001 | 0.00 % ↓ | |
| 5 | sim_lbco | peak | decay_beta_1 | μs/Å | 0.0186 | 0.0186 | 0.0004 | 0.00 % ↓ | |
| 6 | sim_lbco | peak | broad_gauss_sigma_1 | μs/Å | -68198.9042 | -68198.9042 | 1320.4183 | 0.00 % ↓ | |
| 7 | sim_lbco | peak | broad_gauss_sigma_2 | μs²/Ų | 16127.9516 | 16127.9516 | 716.8792 | 0.00 % ↓ |
• value = estimate written back to the project (best posterior sample)
• s.u. = standard uncertainty (one sigma), posterior standard deviation
• change = relative change from start, in %; ↑ = increase, ↓ = decrease
📊 Posterior distribution:
| datablock | category | entry | parameter | units | median | 95% CI | r-hat | ess bulk | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | lbco | cell | length_a | Å | 3.8915 | [3.8912, 3.8917] | 1.162 | 307.7 | |
| 2 | sim_lbco | linked_structure | lbco | scale | 42.3521 | [41.9423, 42.7509] | 1.124 | 333.6 | |
| 3 | sim_lbco | linked_structure | si | scale | 0.3269 | [0.3083, 0.3458] | 1.154 | 346.3 | |
| 4 | sim_lbco | peak | rise_alpha_1 | μs/Å | 0.0166 | [0.0163, 0.0168] | 1.160 | 280.9 | |
| 5 | sim_lbco | peak | decay_beta_1 | μs/Å | 0.0186 | [0.0179, 0.0193] | 1.133 | 308.0 | |
| 6 | sim_lbco | peak | broad_gauss_sigma_1 | μs/Å | -68217.1483 | [-71110.3724, -65728.8313] | 1.149 | 310.6 | |
| 7 | sim_lbco | peak | broad_gauss_sigma_2 | μs²/Ų | 16147.0046 | [14865.4694, 17725.2796] | 1.150 | 299.3 |
• 95% CI = 95% credible interval (2.5%-97.5%, asymmetric)
• r-hat = Gelman-Rubin diagnostic (good convergence: r-hat <= 1.01)
• ess bulk = bulk effective sample size (typically >= 400)
⚠️ ess bulk < 400: Consider longer sampling or reparameterization.
A short teaching run may fail these convergence criteria even when it finishes normally. That means the numerical posterior summaries are provisional. Increase the number of sampling steps and inspect the diagnostics again before drawing scientific conclusions.
🔗 Understand Posterior Correlations¶
Calling the same method after MCMC now builds the matrix from posterior samples rather than from the local least-squares covariance estimate. It answers: across the sampled posterior, which parameter pairs vary together, and how strongly?
project_1.display.fit.correlations(max_parameters=5)
Compare this chart with the local chart above. Similar coefficients suggest that the local approximation captured the main linear relationship. A substantial difference can indicate curvature, asymmetry, bounds, or another feature that a local covariance matrix cannot represent.
🗺️ Understand the Posterior Pair Plot¶
The pair plot shows more information than a matrix of single coefficients:
- Diagonal panels show each parameter's one-dimensional marginal posterior density. A narrow peak indicates greater precision; a wide, skewed, truncated, or multimodal shape indicates more uncertainty or a more complicated posterior.
- Lower-triangle panels show joint posterior samples for pairs of parameters. The contours summarize where the sampled density is concentrated.
- A compact, nearly round cloud suggests weak correlation. An elongated upward cloud suggests positive correlation, and an elongated downward cloud suggests negative correlation. Curved or split contours cannot be summarized well by one correlation coefficient.
- The upper triangle is intentionally blank because it would duplicate the lower triangle.
project_1.display.posterior.pairs(max_parameters=5)
In Jupyter, the default plotting engine resolves to interactive Plotly. Hover over a diagonal density curve to see the full parameter name, parameter value, and probability density. Hover over a visible sample point in a lower-triangle panel to see the exact values of both parameters for that posterior draw. The shaded contour itself has no hover tooltip; it is a smoothed two-dimensional density guide. Use the Plotly toolbar to zoom, pan, and reset the view, and click legend items to hide or show samples, contours, or marginal densities.
The broad_gauss_sigma_1–broad_gauss_sigma_2 panel should form a
long downward band. This reveals the range of compensating parameter
combinations, whereas the correlation chart reduces the relationship
to one number.
📈 Understand Marginal Posterior Distributions¶
A separate distribution plot gives a more detailed view of each diagonal panel. It includes a histogram, a smoothed marginal density, the median, the best posterior sample, and the 95% credible interval. Hover over the traces and interval markers to read their values.
project_1.display.posterior.distribution()
A density pressed against a fit bound warns that the allowed region may be too narrow or that the parameter is poorly identified. A best sample far from the median can occur for a skewed or irregular posterior and is another reason not to summarize MCMC with only one point estimate.
📊 Understand the Posterior-Predictive Plot¶
Posterior prediction propagates an evenly spaced subset of retained parameter combinations through the diffraction calculation. The best-posterior-sample curve shows one calculated pattern, while the 95% band shows parameter uncertainty propagated into the pattern.
project_1.display.posterior.predictive(expt_name='sim_lbco')
project_1.display.posterior.predictive(
expt_name='sim_lbco',
x_min=80000,
x_max=81500,
)
Compare the width of the band with the experimental uncertainty and remaining residuals. A narrow band does not prove that the model is correct: systematic deviations can indicate model inadequacy, underestimated experimental uncertainty, or effects not included in the refinement. In the interactive view, hover over the measured and best-sample curves to inspect individual x and intensity values. The shaded 95% band is read from its upper and lower boundaries and does not itself show a hover tooltip.
Save the completed reference Bayesian project. Its MCMC chain and posterior data are stored with the project and remain available for comparison with the exercise below.
project_1.save()
Saving project 📦 'main' to '../../../projects/exercise-bayesian-si-lbco-reference'
├── 📄 project.edi
├── 📁 structures/
│ └── 📄 lbco.edi
│ └── 📄 si.edi
├── 📁 experiments/
│ └── 📄 sim_lbco.edi
├── 📁 analysis/
│ ├── 📄 analysis.edi
│ └── 📄 mcmc.h5
└── 📁 reports/
└── 📄 main.html
💪 Exercise: Fix One Correlated Parameter¶
The reference analysis showed that broad_gauss_sigma_1 and
broad_gauss_sigma_2 are strongly negatively correlated. In this
exercise, you will fix broad_gauss_sigma_2 at its refined value and
repeat the Bayesian workflow.
Removing one member of the pair reduces the sampling dimension and
removes that pair from the correlation and pair plots. This can improve
sampling efficiency, but it changes the scientific question: the new
posterior is conditional on the chosen fixed value of
broad_gauss_sigma_2. Its uncertainty is no longer propagated. The
exercise demonstrates the computational and visual effect of fixing a
parameter; it does not establish that fixing it is always the correct
scientific choice.
📂 Exercise 1: Create a Fresh Project¶
Load the original deterministic refinement again as project_2 and
save it under a new name. Starting from the deterministic project
ensures that the second MCMC run does not reuse the first posterior
state or its uncertainty estimates.
Hint:
Use edi.Project.load() with refinement_project_dir, which was
downloaded in the introduction.
Solution:
project_2 = edi.Project.load(refinement_project_dir)
project_2.metadata.title = 'Bayesian Analysis with Fixed broad_gauss_sigma_2'
project_2.metadata.description = (
'MCMC analysis of LBCO and Si with one peak-profile parameter fixed.'
)
project_2.save_as(dir_path='projects/exercise-bayesian-si-lbco-main')
Saving project 📦 'main' to '../../../projects/exercise-bayesian-si-lbco-main'
├── 📄 project.edi
├── 📁 structures/
│ └── 📄 lbco.edi
│ └── 📄 si.edi
├── 📁 experiments/
│ └── 📄 sim_lbco.edi
├── 📁 analysis/
│ └── 📄 analysis.edi
└── 📁 reports/
└── 📄 main.html
Hint:
Iterate over project_2.experiments['sim_lbco'].background and set
each point's intensity.free attribute to False.
Solution:
experiment_2 = project_2.experiments['sim_lbco']
for line_segment in experiment_2.background:
line_segment.intensity.free = False
Exercise 2.2: Fix broad_gauss_sigma_2¶
Remove broad_gauss_sigma_2 from the refined and sampled parameter
set, then display the remaining free parameters. How many remain?
Hint:
Set the parameter's free attribute to False, then call
project_2.display.parameters.free().
Solution:
experiment_2.peak.broad_gauss_sigma_2.free = False
project_2.display.parameters.free()
Free parameters for both structures (🧩 data blocks) and experiments (🔬 data blocks)
| datablock | category | entry | parameter | value | uncertainty | min | max | units | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | lbco | cell | length_a | 3.89147 | 0.00015 | -inf | inf | Å | |
| 2 | sim_lbco | linked_structure | lbco | scale | 42.36000 | 0.24000 | -inf | inf | |
| 3 | sim_lbco | linked_structure | si | scale | 0.32700 | 0.01200 | -inf | inf | |
| 4 | sim_lbco | peak | rise_alpha_1 | 0.01655 | 0.00014 | -inf | inf | μs/Å | |
| 5 | sim_lbco | peak | decay_beta_1 | 0.01857 | 0.00042 | -inf | inf | μs/Å | |
| 6 | sim_lbco | peak | broad_gauss_sigma_1 | -68200.00000 | 1500.00000 | -inf | inf | μs/Å |
Six parameters remain. The background intensities and
broad_gauss_sigma_2 will stay at their refined values throughout the
following local fit and MCMC run.
🚀 Exercise 3: Repeat the Local Refinement¶
Select bumps (lm), run the fit, display the result table, and inspect
the local correlation chart. Is the original strongly correlated pair
still present?
Hint:
Repeat the local-refinement sequence from the introduction with
project_2.
Solution:
project_2.analysis.minimizer.type = 'bumps (lm)'
project_2.analysis.fit()
project_2.display.fit.results()
Current minimizer changed to
bumps (lm)
Standard fitting
📋 Using experiment 🔬 'sim_lbco' for 'single' fitting
🚀 Starting fit process with 'bumps (lm)'...
📈 Goodness-of-fit progress:
| iteration | time (s) | χ² | change / status | |
|---|---|---|---|---|
| 1 | 1 | 0.02 | 1.58 | |
| 2 | 24 | 1.24 | 1.58 |
🏆 Best goodness-of-fit (reduced χ²) is 1.58 at iteration 15
✅ Fitting complete.
Saving project 📦 'main' to '../../../projects/exercise-bayesian-si-lbco-main'
├── 📄 project.edi
├── 📁 structures/
│ └── 📄 lbco.edi
│ └── 📄 si.edi
├── 📁 experiments/
│ └── 📄 sim_lbco.edi
├── 📁 analysis/
│ └── 📄 analysis.edi
└── 📁 reports/
└── 📄 main.html
⚙️ 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) | 1.24 |
| 4 | 📏 Goodness-of-fit (reduced χ²) | 1.58 |
| 5 | 📏 R-factor (Rf, %) | 5.06 |
| 6 | 📏 R-factor squared (Rf², %) | 4.61 |
| 7 | 📏 Weighted R-factor (wR, %) | 4.04 |
📈 Refined parameters:
| datablock | category | entry | parameter | units | start | value | s.u. | change | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | lbco | cell | length_a | Å | 3.8915 | 3.8915 | 0.0002 | 0.00 % ↑ | |
| 2 | sim_lbco | linked_structure | lbco | scale | 42.3600 | 42.3607 | 0.2289 | 0.00 % ↑ | |
| 3 | sim_lbco | linked_structure | si | scale | 0.3270 | 0.3266 | 0.0111 | 0.14 % ↓ | |
| 4 | sim_lbco | peak | rise_alpha_1 | μs/Å | 0.0165 | 0.0166 | 0.0001 | 0.02 % ↑ | |
| 5 | sim_lbco | peak | decay_beta_1 | μs/Å | 0.0186 | 0.0186 | 0.0004 | 0.03 % ↑ | |
| 6 | sim_lbco | peak | broad_gauss_sigma_1 | μs/Å | -68200.0000 | -68202.5586 | 509.2645 | 0.00 % ↑ |
• 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
project_2.display.fit.correlations(max_parameters=5)
The broad_gauss_sigma_1–broad_gauss_sigma_2 pair is absent because
broad_gauss_sigma_2 was not varied. This does not show that the
physical ambiguity disappeared; it shows that the fixed parameter is
no longer part of the estimated covariance or posterior.
🎲 Exercise 4: Set New Sampling Bounds¶
Derive finite bounds from the new local-fit uncertainties and verify
them. Why is it better to recalculate the bounds than to copy them from
project_1?
Hint:
Iterate over project_2.free_parameters and call
set_fit_bounds_from_uncertainty().
Solution:
for param in project_2.free_parameters:
param.set_fit_bounds_from_uncertainty()
project_2.display.parameters.free()
Free parameters for both structures (🧩 data blocks) and experiments (🔬 data blocks)
| datablock | category | entry | parameter | value | uncertainty | min | max | units | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | lbco | cell | length_a | 3.89148 | 0.00015 | 3.89086 | 3.89209 | Å | |
| 2 | sim_lbco | linked_structure | lbco | scale | 42.36072 | 0.22886 | 41.44527 | 43.27618 | |
| 3 | sim_lbco | linked_structure | si | scale | 0.32656 | 0.01115 | 0.28197 | 0.37115 | |
| 4 | sim_lbco | peak | rise_alpha_1 | 0.01655 | 0.00013 | 0.01603 | 0.01708 | μs/Å | |
| 5 | sim_lbco | peak | decay_beta_1 | 0.01858 | 0.00040 | 0.01696 | 0.02019 | μs/Å | |
| 6 | sim_lbco | peak | broad_gauss_sigma_1 | -68202.55856 | 509.26448 | -70239.61649 | -66165.50064 | μs/Å |
Fixing one correlated parameter changes the local covariance matrix and therefore the uncertainty estimates of the remaining parameters. The new bounds should be based on this new local problem.
🎲 Exercise 5: Repeat DREAM Sampling¶
Configure DREAM with the same short-chain settings used for
project_1, then sample the six-parameter posterior.
Hint:
Use 300 sampling steps, 60 burn-in steps, and random seed 42 so the two runs use comparable settings.
Solution:
project_2.analysis.minimizer.type = 'bumps (dream)'
project_2.analysis.minimizer.sampling_steps = 300
project_2.analysis.minimizer.burn_in_steps = 60
project_2.analysis.minimizer.random_seed = 42
⚠️ Switching minimizer type removes these settings: • max_iterations
⚠️ Switching minimizer type adds these settings with defaults: • burn_in_steps=600 • initialization_method='latin_hypercube' • parallel_workers=0 • population_size=4 • random_seed=None • sampling_steps=3000 • thinning_interval=1
Current minimizer changed to
bumps (dream)
project_2.analysis.fit()
Standard fitting
📋 Using experiment 🔬 'sim_lbco' for 'single' fitting
🚀 Starting fit process with 'bumps (dream)'...
📈 Bayesian sampling progress:
| step | progress | time (s) | log posterior | phase | |
|---|---|---|---|---|---|
| 1 | 0.32 | -416.89 | pre-processing | ||
| 2 | 21/360 | 5.8% | 7.35 | -344.12 | burn-in |
| 3 | 40/360 | 11.1% | 12.98 | -339.61 | burn-in |
| 4 | 60/360 | 16.7% | 19.76 | -337.61 | burn-in |
| 5 | 61/360 | 16.9% | 20.06 | -337.54 | sampling |
| 6 | 76/360 | 21.1% | 24.53 | -337.57 | sampling |
| 7 | 91/360 | 25.3% | 29.55 | -337.44 | sampling |
| 8 | 106/360 | 29.4% | 33.96 | -337.81 | sampling |
| 9 | 121/360 | 33.6% | 38.30 | -337.40 | sampling |
| 10 | 136/360 | 37.8% | 43.67 | -337.05 | sampling |
| 11 | 151/360 | 41.9% | 47.97 | -336.71 | sampling |
| 12 | 166/360 | 46.1% | 52.51 | -336.64 | sampling |
| 13 | 181/360 | 50.3% | 57.40 | -336.74 | sampling |
| 14 | 196/360 | 54.4% | 61.85 | -336.34 | sampling |
| 15 | 211/360 | 58.6% | 66.53 | -337.28 | sampling |
| 16 | 226/360 | 62.8% | 71.46 | -336.99 | sampling |
| 17 | 241/360 | 66.9% | 75.78 | -337.34 | sampling |
| 18 | 256/360 | 71.1% | 80.72 | -336.46 | sampling |
| 19 | 271/360 | 75.3% | 85.34 | -336.20 | sampling |
| 20 | 286/360 | 79.4% | 89.83 | -336.28 | sampling |
| 21 | 301/360 | 83.6% | 94.91 | -336.98 | sampling |
| 22 | 316/360 | 87.8% | 99.22 | -336.51 | sampling |
| 23 | 331/360 | 91.9% | 103.92 | -337.36 | sampling |
| 24 | 346/360 | 96.1% | 109.01 | -337.14 | sampling |
| 25 | 360/360 | 100.0% | 113.37 | -337.66 | sampling |
| 26 | 158.45 | post-processing |
✅ Bayesian sampling complete.
⚠️ Convergence diagnostics indicate the posterior may be poorly mixed.
Saving project 📦 'main' to '../../../projects/exercise-bayesian-si-lbco-main'
├── 📄 project.edi
├── 📁 structures/
│ └── 📄 lbco.edi
│ └── 📄 si.edi
├── 📁 experiments/
│ └── 📄 sim_lbco.edi
├── 📁 analysis/
│ ├── 📄 analysis.edi
│ └── 📄 mcmc.h5
└── 📁 reports/
└── 📄 main.html
Hint:
Use project_2.display.fit.results(), then compare the diagnostics
with those displayed for project_1 in the introduction.
Solution:
project_2.display.fit.results()
⚙️ Settings used:
| Name | Value | Description | |
|---|---|---|---|
| 1 | sampling_steps | 300 | Total sampler iterations per chain. |
| 2 | burn_in_steps | 60 | Sampler iterations discarded as warm-up. |
| 3 | thinning_interval | 1 | Sampler thinning interval. |
| 4 | population_size | 4 | Number of chains or walkers. |
| 5 | parallel_workers | 0 | Worker count; 0 uses all available CPUs. |
| 6 | initialization_method | latin_hypercube | Sampler initialization method. |
| 7 | random_seed | 42 | Random seed; None uses a system-derived seed. |
📋 Bayesian fit results:
| Metric | Value | |
|---|---|---|
| 1 | 🧪 Sampler | bumps (dream) |
| 2 | ❌ Overall status | failed |
| 3 | 💬 Engine message | DREAM sampling completed |
| 4 | ⏱️ Fitting time (seconds) | 158.45 |
| 5 | 📏 Goodness-of-fit (reduced χ²) | 1.58 |
| 6 | 📏 R-factor (Rf, %) | 5.06 |
| 7 | 📏 R-factor squared (Rf², %) | 4.61 |
| 8 | 📏 Weighted R-factor (wR, %) | 4.04 |
| 9 | 📉 Best log-posterior | -334.00 |
| 10 | 📊 Convergence status | failed |
| 11 | 📊 Max r-hat | 1.112 |
| 12 | 📊 Min ess bulk | 307.085 |
| 13 | 📊 Draws per chain | 300 |
| 14 | 📊 Chains | 24 |
📈 Committed parameters:
| datablock | category | entry | parameter | units | start | value | s.u. | change | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | lbco | cell | length_a | Å | 3.8915 | 3.8915 | 0.0001 | 0.00 % ↓ | |
| 2 | sim_lbco | linked_structure | lbco | scale | 42.3607 | 42.3607 | 0.1860 | 0.00 % ↓ | |
| 3 | sim_lbco | linked_structure | si | scale | 0.3266 | 0.3266 | 0.0091 | 0.00 % ↓ | |
| 4 | sim_lbco | peak | rise_alpha_1 | μs/Å | 0.0166 | 0.0166 | 0.0001 | 0.00 % ↓ | |
| 5 | sim_lbco | peak | decay_beta_1 | μs/Å | 0.0186 | 0.0186 | 0.0003 | 0.00 % ↓ | |
| 6 | sim_lbco | peak | broad_gauss_sigma_1 | μs/Å | -68202.5586 | -68202.5586 | 412.5731 | 0.00 % ↓ |
• value = estimate written back to the project (best posterior sample)
• s.u. = standard uncertainty (one sigma), posterior standard deviation
• change = relative change from start, in %; ↑ = increase, ↓ = decrease
📊 Posterior distribution:
| datablock | category | entry | parameter | units | median | 95% CI | r-hat | ess bulk | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | lbco | cell | length_a | Å | 3.8915 | [3.8912, 3.8917] | 1.107 | 307.1 | |
| 2 | sim_lbco | linked_structure | lbco | scale | 42.3328 | [41.9703, 42.6813] | 1.088 | 419.3 | |
| 3 | sim_lbco | linked_structure | si | scale | 0.3269 | [0.3084, 0.3454] | 1.094 | 406.7 | |
| 4 | sim_lbco | peak | rise_alpha_1 | μs/Å | 0.0166 | [0.0164, 0.0168] | 1.091 | 415.1 | |
| 5 | sim_lbco | peak | decay_beta_1 | μs/Å | 0.0186 | [0.0179, 0.0194] | 1.112 | 313.1 | |
| 6 | sim_lbco | peak | broad_gauss_sigma_1 | μs/Å | -68155.3315 | [-68965.5420, -67306.6883] | 1.108 | 381.2 |
• 95% CI = 95% credible interval (2.5%-97.5%, asymmetric)
• r-hat = Gelman-Rubin diagnostic (good convergence: r-hat <= 1.01)
• ess bulk = bulk effective sample size (typically >= 400)
⚠️ ess bulk < 400: Consider longer sampling or reparameterization.
Reducing the dimension can make sampling easier, but a 300-step chain is still short. Convergence must be judged from the diagnostics, not assumed from the number of free parameters.
Exercise 6.2: Inspect Correlations and Pair Relationships¶
Display the posterior correlation matrix and pair plot. Confirm that
broad_gauss_sigma_2 is absent, then inspect whether
broad_gauss_sigma_1 is correlated with any remaining parameter.
Hint:
Use the same display.fit.correlations(max_parameters=5) and
display.posterior.pairs(max_parameters=5) calls as in the
introduction. Hover over cells and sample points to identify the
parameter pairs and values.
Solution:
project_2.display.fit.correlations(max_parameters=5)
project_2.display.posterior.pairs(max_parameters=5)
The original pair is gone because only sampled parameters appear in posterior charts. Look for any remaining elongated contours rather than concluding that all correlations have disappeared. Fixing one parameter can expose or strengthen relationships among the parameters that remain free.
Exercise 6.3: Compare broad_gauss_sigma_1¶
Plot the marginal posterior for broad_gauss_sigma_1 from both runs.
Compare the medians, shapes, and 95% credible intervals. Why might the
second interval be narrower?
Hint:
Call display.posterior.distribution() for each project and pass the
corresponding broad_gauss_sigma_1 parameter using param.
Solution:
project_1.display.posterior.distribution(
param=experiment_1.peak.broad_gauss_sigma_1,
)
project_2.display.posterior.distribution(
param=experiment_2.peak.broad_gauss_sigma_1,
)
The conditional posterior can be narrower because
broad_gauss_sigma_1 no longer shares uncertainty with
broad_gauss_sigma_2. That apparent precision comes from assuming the
fixed value is exact. It may underestimate the true uncertainty if
broad_gauss_sigma_2 is not independently known.
Exercise 6.4: Compare Posterior Predictions¶
Plot the same zoomed posterior-predictive region for both analyses.
Does fixing broad_gauss_sigma_2 noticeably change the best curve or
uncertainty band?
Hint:
Call display.posterior.predictive() for both projects with the same
experiment name and the same x_min and x_max values.
Solution:
project_1.display.posterior.predictive(
expt_name='sim_lbco',
x_min=80000,
x_max=81500,
)
project_2.display.posterior.predictive(
expt_name='sim_lbco',
x_min=80000,
x_max=81500,
)
Two parameterizations can produce similarly good calculated patterns while assigning different uncertainties to individual parameters. This is why parameter correlations, marginal posteriors, and posterior predictions should be interpreted together.
💾 Exercise 7: Save the Project¶
Save the second posterior and its MCMC chain.
Hint:
The project directory was set in Exercise 1, so use project_2.save()
to update the existing saved project.
Solution:
project_2.save()
Saving project 📦 'main' to '../../../projects/exercise-bayesian-si-lbco-main'
├── 📄 project.edi
├── 📁 structures/
│ └── 📄 lbco.edi
│ └── 📄 si.edi
├── 📁 experiments/
│ └── 📄 sim_lbco.edi
├── 📁 analysis/
│ ├── 📄 analysis.edi
│ └── 📄 mcmc.h5
└── 📁 reports/
└── 📄 main.html
Final Remarks¶
In this part of the notebook, you learned how to:
- prepare a refined EasyDiffraction project for MCMC;
- reduce runtime by fixing nuisance parameters while recognizing the uncertainty tradeoff;
- use a local fit to obtain starting values and finite bounds;
- sample a correlated posterior with DREAM;
- distinguish a local covariance correlation from a posterior-sample correlation;
- read correlation matrices, pair plots, marginal distributions, and posterior-predictive plots; and
- understand how fixing one member of a correlated pair changes the statistical question and the reported uncertainty.
For a scientific analysis, run longer chains, verify convergence, examine sensitivity to bounds and fixed values, and reconsider the diffraction model when systematic residuals remain.
🎁 Bonus¶
Congratulations — you've now completed Part 2 of the diffraction data analysis exercises for the DMSC Summer School!
If you'd like to keep exploring, the EasyDiffraction library offers many additional tutorials and examples on the official documentation site: 👉 https://docs.easydiffraction.org/lib/latest/tutorials
Besides the Python package, EasyDiffraction also comes with a graphical user interface (GUI) for deterministic diffraction refinement workflows. Bayesian analysis is not yet available in the GUI, so MCMC workflows currently require the Python library.
If you prefer a point-and-click interface over coding, the GUI provides a user-friendly way to perform deterministic refinements. You can download it as a standalone application here: 👉 https://easydiffraction.org
We'd love to hear your feedback on EasyDiffraction — both the library and the GUI! 💬