{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "0",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-18T18:18:21.257731Z",
"iopub.status.busy": "2026-08-18T18:18:21.257549Z",
"iopub.status.idle": "2026-08-18T18:18:21.261805Z",
"shell.execute_reply": "2026-08-18T18:18:21.261060Z"
},
"tags": [
"hide-in-docs"
]
},
"outputs": [],
"source": [
"# Check whether easydiffraction is installed; install it if needed.\n",
"# Required for remote environments such as Google Colab.\n",
"import importlib.util\n",
"\n",
"if importlib.util.find_spec('easydiffraction') is None:\n",
" %pip install easydiffraction==0.20.1"
]
},
{
"cell_type": "markdown",
"id": "1",
"metadata": {},
"source": [
"# LaB6 - powder neutron CW - FCJ asymmetry\n",
"\n",
"Verifies the LaB6 baseline with only the Finger-Cox-Jephcoat\n",
"axial-divergence asymmetry enabled.\n",
"\n",
"**Refinement:** none. The cryspy CW profile has no Finger-Cox-Jephcoat\n",
"term, so it cannot reproduce the FullProf FCJ reference. The CrysFML\n",
"Thompson-Cox-Hastings profile supports the corresponding FCJ terms and\n",
"is compared directly with FullProf."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "2",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-18T18:18:21.263584Z",
"iopub.status.busy": "2026-08-18T18:18:21.263406Z",
"iopub.status.idle": "2026-08-18T18:18:24.177944Z",
"shell.execute_reply": "2026-08-18T18:18:24.177069Z"
}
},
"outputs": [],
"source": [
"import easydiffraction as edi\n",
"from easydiffraction import ExperimentFactory\n",
"from easydiffraction import StructureFactory\n",
"from easydiffraction.analysis import verification as verify"
]
},
{
"cell_type": "markdown",
"id": "3",
"metadata": {},
"source": [
"## Build the project"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "4",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-18T18:18:24.180042Z",
"iopub.status.busy": "2026-08-18T18:18:24.179725Z",
"iopub.status.idle": "2026-08-18T18:18:24.488932Z",
"shell.execute_reply": "2026-08-18T18:18:24.488033Z"
}
},
"outputs": [],
"source": [
"project = edi.Project()"
]
},
{
"cell_type": "markdown",
"id": "5",
"metadata": {},
"source": [
"## Define the structure"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "6",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-18T18:18:24.490673Z",
"iopub.status.busy": "2026-08-18T18:18:24.490476Z",
"iopub.status.idle": "2026-08-18T18:18:24.497648Z",
"shell.execute_reply": "2026-08-18T18:18:24.496959Z"
}
},
"outputs": [],
"source": [
"structure = StructureFactory.from_scratch(name='lab6')\n",
"structure.space_group.name_h_m = 'P m -3 m' # FullProf Space group symbol\n",
"structure.cell.length_a = 4.156885 # FullProf a\n",
"structure.atom_sites.create(\n",
" id='La', # FullProf Atom\n",
" type_symbol='La', # FullProf Typ\n",
" fract_x=0.0, # FullProf X\n",
" fract_y=0.0, # FullProf Y\n",
" fract_z=0.0, # FullProf Z\n",
" adp_type='Biso', # FullProf Biso\n",
" adp_iso=0.25812, # FullProf Biso\n",
")\n",
"structure.atom_sites.create(\n",
" id='B', # FullProf Atom\n",
" type_symbol='B', # FullProf Typ\n",
" fract_x=0.19972, # FullProf X\n",
" fract_y=0.5, # FullProf Y\n",
" fract_z=0.5, # FullProf Z\n",
" adp_type='Biso', # FullProf Biso\n",
" adp_iso=0.11925, # FullProf Biso\n",
")\n",
"\n",
"project.structures.add(structure)"
]
},
{
"cell_type": "markdown",
"id": "7",
"metadata": {},
"source": [
"## Load the FullProf reference"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "8",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-18T18:18:24.499491Z",
"iopub.status.busy": "2026-08-18T18:18:24.499285Z",
"iopub.status.idle": "2026-08-18T18:18:24.509978Z",
"shell.execute_reply": "2026-08-18T18:18:24.509357Z"
}
},
"outputs": [],
"source": [
"FULLPROF_PROJECT_DIR = 'pd-neut-cwl_lab6'\n",
"FULLPROF_PRF_FILE = 'ECH0030684_LaB6_1p622A_fcj.prf'\n",
"FULLPROF_SUM_FILE = 'ECH0030684_LaB6_1p622A_fcj.sum'\n",
"FULLPROF_BAC_FILE = 'ECH0030684_LaB6_1p622A_fcj.bac'\n",
"FULLPROF_LABEL = verify.fullprof_label(FULLPROF_PROJECT_DIR, FULLPROF_SUM_FILE)\n",
"\n",
"FULLPROF_ZERO = -0.45778 # FullProf Zero\n",
"FULLPROF_SCALE = 42.98374 # FullProf Scale\n",
"FULLPROF_WAVELENGTH = 1.623899 # FullProf Lambda\n",
"FULLPROF_U = 0.143431 # FullProf U\n",
"FULLPROF_V = -0.523140 # FullProf V\n",
"FULLPROF_W = 0.590412 # FullProf W\n",
"FULLPROF_X = 0.0 # FullProf X\n",
"FULLPROF_Y = 0.054515 # FullProf Y\n",
"FULLPROF_WDT = 12.0 # FullProf Wdt\n",
"FULLPROF_S_L = 0.08000 # FullProf S_L\n",
"FULLPROF_D_L = 0.08000 # FullProf D_L\n",
"\n",
"x, calc_fullprof = verify.load_fullprof_calc_profile(\n",
" FULLPROF_PROJECT_DIR,\n",
" FULLPROF_PRF_FILE,\n",
" FULLPROF_BAC_FILE,\n",
" FULLPROF_ZERO,\n",
")"
]
},
{
"cell_type": "markdown",
"id": "9",
"metadata": {},
"source": [
"## Create the experiment"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "10",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-18T18:18:24.511754Z",
"iopub.status.busy": "2026-08-18T18:18:24.511578Z",
"iopub.status.idle": "2026-08-18T18:18:25.015656Z",
"shell.execute_reply": "2026-08-18T18:18:25.014834Z"
}
},
"outputs": [],
"source": [
"experiment = ExperimentFactory.from_scratch(\n",
" name='lab6',\n",
" sample_form='powder',\n",
" beam_mode='constant wavelength',\n",
" radiation_probe='neutron',\n",
" scattering_type='bragg',\n",
")\n",
"verify.set_reference_as_measured(experiment, x, calc_fullprof)\n",
"\n",
"experiment.linked_structures.create(structure_id='lab6', scale=FULLPROF_SCALE)\n",
"\n",
"experiment.instrument.setup_wavelength = FULLPROF_WAVELENGTH\n",
"experiment.instrument.calib_twotheta_offset = FULLPROF_ZERO\n",
"\n",
"experiment.peak.broad_gauss_u = FULLPROF_U\n",
"experiment.peak.broad_gauss_v = FULLPROF_V\n",
"experiment.peak.broad_gauss_w = FULLPROF_W\n",
"experiment.peak.broad_lorentz_x = FULLPROF_X\n",
"experiment.peak.broad_lorentz_y = FULLPROF_Y\n",
"\n",
"experiment.peak.cutoff_fwhm = FULLPROF_WDT\n",
"\n",
"project.experiments.add(experiment)"
]
},
{
"cell_type": "markdown",
"id": "11",
"metadata": {},
"source": [
"## edi-cryspy VS FullProf"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "12",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-18T18:18:25.017718Z",
"iopub.status.busy": "2026-08-18T18:18:25.017556Z",
"iopub.status.idle": "2026-08-18T18:18:25.476770Z",
"shell.execute_reply": "2026-08-18T18:18:25.475966Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1;36mCalculator for experiment \u001b[0m\u001b[32m'lab6'\u001b[0m\u001b[1;36m already set to\u001b[0m\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"cryspy\n"
]
},
{
"data": {
"text/html": [
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"experiment.calculator.type = 'cryspy'\n",
"\n",
"project.analysis.calculate()\n",
"calc_ed_cryspy = experiment.data.intensity_calc\n",
"LABEL_ED_CRYSPY = verify.engine_label('cryspy')\n",
"\n",
"project.display.pattern_comparison(\n",
" 'lab6',\n",
" reference=calc_fullprof,\n",
" candidate=calc_ed_cryspy,\n",
" reference_label=FULLPROF_LABEL,\n",
" candidate_label=LABEL_ED_CRYSPY,\n",
")"
]
},
{
"cell_type": "markdown",
"id": "13",
"metadata": {},
"source": [
"## Agreement check (cryspy)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "14",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-18T18:18:25.480147Z",
"iopub.status.busy": "2026-08-18T18:18:25.479961Z",
"iopub.status.idle": "2026-08-18T18:18:25.488404Z",
"shell.execute_reply": "2026-08-18T18:18:25.487728Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" | Comparison | Metric | Expected | Actual | OK |
|---|
| 1 | edi 0.20.1 (cryspy 0.13.0) vs FullProf 8.40 | Profile diff (%) | < 2.5 | 21.05 | ❌ |
|---|
| 2 | | Max deviation (%) | < 6 | 16.34 | ❌ |
|---|
| 3 | | Area ratio | 0.99 to 1.01 | 0.9963 | ✅ |
|---|
| 4 | | Shape correlation | > 0.999 | 0.9774 | ❌ |
|---|
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
" • Known discrepancy = FCJ asymmetry is not implemented in cryspy.
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"verify.assert_patterns_agree(\n",
" [\n",
" (f'{LABEL_ED_CRYSPY} vs {FULLPROF_LABEL}', calc_fullprof, calc_ed_cryspy),\n",
" ],\n",
" known_discrepancy=True,\n",
" reason='FCJ asymmetry is not implemented in cryspy.',\n",
")"
]
},
{
"cell_type": "markdown",
"id": "15",
"metadata": {},
"source": [
"## edi-crysfml VS FullProf"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "16",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-18T18:18:25.490445Z",
"iopub.status.busy": "2026-08-18T18:18:25.490288Z",
"iopub.status.idle": "2026-08-18T18:18:25.757969Z",
"shell.execute_reply": "2026-08-18T18:18:25.757248Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1;36mCalculator for experiment \u001b[0m\u001b[32m'lab6'\u001b[0m\u001b[1;36m changed to\u001b[0m\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"crysfml\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"⚠️ Switching peak profile type adds these settings with defaults: \n",
" • asym_fcj_1=0.0 \n",
" • asym_fcj_2=0.0 \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"⚠️ Switching peak profile type resets these settings to defaults: \n",
" • broad_gauss_u: 0.143431 -> 0.01 \n",
" • broad_gauss_v: -0.52314 -> -0.01 \n",
" • broad_gauss_w: 0.590412 -> 0.02 \n",
" • broad_lorentz_y: 0.054515 -> 0.0 \n",
" • cutoff_fwhm: 12.0 -> 0.0 \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1;36mPeak profile type for experiment \u001b[0m\u001b[32m'lab6'\u001b[0m\u001b[1;36m changed to\u001b[0m\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"thompson-cox-hastings\n"
]
},
{
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"experiment.calculator.type = 'crysfml'\n",
"\n",
"# Switching profile types resets shared profile parameters to defaults,\n",
"# so restore the FullProf values after selecting TCH with FCJ asymmetry.\n",
"experiment.peak.type = 'thompson-cox-hastings'\n",
"\n",
"experiment.peak.broad_gauss_u = FULLPROF_U\n",
"experiment.peak.broad_gauss_v = FULLPROF_V\n",
"experiment.peak.broad_gauss_w = FULLPROF_W\n",
"experiment.peak.broad_lorentz_x = FULLPROF_X\n",
"experiment.peak.broad_lorentz_y = FULLPROF_Y\n",
"experiment.peak.asym_fcj_1 = FULLPROF_S_L\n",
"experiment.peak.asym_fcj_2 = FULLPROF_D_L\n",
"\n",
"project.analysis.calculate()\n",
"calc_ed_crysfml = experiment.data.intensity_calc\n",
"LABEL_ED_CRYSFML = verify.engine_label('crysfml')\n",
"\n",
"project.display.pattern_comparison(\n",
" 'lab6',\n",
" reference=calc_fullprof,\n",
" candidate=calc_ed_crysfml,\n",
" reference_label=FULLPROF_LABEL,\n",
" candidate_label=LABEL_ED_CRYSFML,\n",
")"
]
},
{
"cell_type": "markdown",
"id": "17",
"metadata": {},
"source": [
"## Agreement check (crysfml)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "18",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-18T18:18:25.760490Z",
"iopub.status.busy": "2026-08-18T18:18:25.760305Z",
"iopub.status.idle": "2026-08-18T18:18:25.767285Z",
"shell.execute_reply": "2026-08-18T18:18:25.766733Z"
}
},
"outputs": [
{
"data": {
"text/html": [
" | Comparison | Metric | Expected | Actual | OK |
|---|
| 1 | edi 0.20.1 (crysfml 0.8.0) vs FullProf 8.40 | Profile diff (%) | < 2.5 | 0.44 | ✅ |
|---|
| 2 | | Max deviation (%) | < 6 | 0.37 | ✅ |
|---|
| 3 | | Area ratio | 0.99 to 1.01 | 1.0039 | ✅ |
|---|
| 4 | | Shape correlation | > 0.999 | 1.0000 | ✅ |
|---|
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"verify.assert_patterns_agree(\n",
" [\n",
" (f'{LABEL_ED_CRYSFML} vs {FULLPROF_LABEL}', calc_fullprof, calc_ed_crysfml),\n",
" ],\n",
")"
]
}
],
"metadata": {
"jupytext": {
"cell_metadata_filter": "-all",
"main_language": "python",
"notebook_metadata_filter": "-all"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.14.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}