diff --git a/docs/src/tutorials/fitting/plot_reflectivity.ipynb b/notebooks/ess_hercules_2026.ipynb similarity index 79% rename from docs/src/tutorials/fitting/plot_reflectivity.ipynb rename to notebooks/ess_hercules_2026.ipynb index 029a29f6..09ccabae 100644 --- a/docs/src/tutorials/fitting/plot_reflectivity.ipynb +++ b/notebooks/ess_hercules_2026.ipynb @@ -5,11 +5,16 @@ "id": "72470023", "metadata": {}, "source": [ - "# Multi-Dataset Reflectometry Fitting\n", + "# Multi-Dataset Reflectometry Fitting - Teaching Notebook\n", "\n", - "This notebook demonstrates **simultaneous fitting** of multiple reflectivity datasets using a single Ni-on-Si model with [EasyReflectometry](https://github.com/easyscience/EasyReflectometryLib).\n", + "This notebook is structured as guided teaching material for **simultaneous fitting** of multiple reflectivity datasets using [EasyReflectometry](https://github.com/easyscience/EasyReflectometryLib).\n", "\n", - "The input file `reflectivity_geomgrid.ort` contains **4 datasets** (data_set: 0–3) from an ESS Estia instrument simulation. All datasets share the same structural model but each covers its own Q-range. The `MultiFitter` fits them simultaneously — just like the ERA GUI does." + "The input file `reflectivity_geomgrid.ort` contains **4 datasets** (data_set: 0-3) from an ESS Estia instrument simulation. All datasets share one structural model but each covers its own Q-range.\n", + "\n", + "Learning goals:\n", + "- Build and fit a baseline layer model from physical reasoning.\n", + "- Critically evaluate fit quality and propose improvements.\n", + "- Compare a simple model against a more realistic interlayer model." ] }, { @@ -34,8 +39,12 @@ "from easyreflectometry.calculators import CalculatorFactory\n", "from easyreflectometry.data import load\n", "from easyreflectometry.fitting import MultiFitter\n", - "from easyreflectometry.model import Model, PercentageFwhm\n", - "from easyreflectometry.sample import Layer, Material, Multilayer, Sample\n", + "from easyreflectometry.model import Model\n", + "from easyreflectometry.model import PercentageFwhm\n", + "from easyreflectometry.sample import Layer\n", + "from easyreflectometry.sample import Material\n", + "from easyreflectometry.sample import Multilayer\n", + "from easyreflectometry.sample import Sample\n", "\n", "%matplotlib inline" ] @@ -76,9 +85,21 @@ "id": "ae052acf", "metadata": {}, "source": [ - "## 3. Define Materials\n", + "## 3. Materials and Layer-Order Hypothesis\n", + "\n", + "Before looking at any model-building code, answer this:\n", + "\n", + "- Given materials **Air**, **Ni**, **Si**, what is the physical stack order?\n", + "- Which one is the **superphase**?\n", + "- Which one is the **thin film**?\n", + "- Which one is the **substrate**?\n", + "\n", + "Expected baseline interpretation:\n", + "- Air = superphase\n", + "- Ni = thin film\n", + "- Si = substrate\n", "\n", - "We define three materials for our Ni-on-Si model:\n", + "We define these three materials for the baseline model:\n", "\n", "| Material | SLD (10⁻⁶ Å⁻²) | Description |\n", "|----------|-----------------|-------------|\n", @@ -104,9 +125,12 @@ "id": "eedaf83b", "metadata": {}, "source": [ - "## 4. Define Layers\n", + "## 4. Define Layers (Try First, Then Expand)\n", "\n", - "Each material is wrapped in a `Layer` with initial guesses for **thickness** and **roughness**. The air and Si layers are semi-infinite (thickness = 0)." + "Task:\n", + "- Create layer objects for Air, Ni, and Si.\n", + "- Choose initial guesses for thickness and roughness.\n", + "- Keep Air and Si semi-infinite (`thickness = 0`).\n" ] }, { @@ -126,14 +150,19 @@ "id": "4ad2248a", "metadata": {}, "source": [ - "## 5. Build the Model\n", + "## 5. Build the Model (Try First, Then Expand)\n", "\n", - "Assemble layers into a `Sample` and wrap it in a `Model` with:\n", + "Task:\n", + "- Assemble a `Sample` using the stack Air | Ni | Si.\n", + "- Wrap it in a `Model` with scale, background, and resolution.\n", + "- Connect the calculator interface.\n", + "\n", + "Hints for physical meaning:\n", "- **Scale factor** — overall intensity scaling \n", "- **Background** — incoherent/instrumental background \n", "- **Resolution** — Gaussian smearing (3% FWHM) \n", "\n", - "A single model instance is shared across all datasets." + "A single model instance is shared across all datasets.\n" ] }, { @@ -161,9 +190,13 @@ "id": "21f2a006", "metadata": {}, "source": [ - "## 6. Set Free Parameters\n", + "## 6. Set Free Parameters (Try First, Then Expand)\n", + "\n", + "Task:\n", + "- Decide which parameters should vary in the baseline model.\n", + "- Propose physically sensible bounds.\n", "\n", - "Select which parameters to refine and set physically reasonable bounds." + "Start with: Ni thickness, Ni roughness, Si roughness, scale, and background.\n" ] }, { @@ -248,7 +281,12 @@ "source": [ "## 8. Fit Results\n", "\n", - "Print the goodness-of-fit metric and the refined parameter values." + "Print the goodness-of-fit metric and the refined parameter values.\n", + "\n", + "Discussion prompts:\n", + "- Does the fit capture all features across the full Q-range?\n", + "- Which parts of the curve show the largest mismatch?\n", + "- What missing physics might explain residual structure?" ] }, { @@ -345,14 +383,19 @@ "source": [ "---\n", "\n", - "# Part 2: Interlayer Model — Si | NiSi | Ni | NiO | Air\n", + "# Part 2: Guided Improvement Challenge\n", "\n", - "The simple **Si | Ni | air** model above assumes atomically sharp interfaces. In reality, interdiffusion and oxidation can form thin interlayers at:\n", + "The simple **Si | Ni | Air** model assumes ideal, sharp interfaces.\n", "\n", - "- The **Ni–air** interface → a **NiO** oxide layer \n", - "- The **Si–Ni** interface → a **NiSi** silicide intermixing layer\n", + "Before revealing a refined model, propose improvements:\n", + "- What could form between **Ni and Air** after exposure/processing?\n", + "- What could form between **Si and Ni** due to intermixing or reaction?\n", "\n", - "We now extend the model with these two additional layers and check whether the fit improves (lower reduced χ²)." + "Possible hypothesis:\n", + "- A nickel oxide-like layer (**NiOx**) near the top interface\n", + "- A nickel silicide-like intermixed layer (**NiSi**) near the substrate interface\n", + "\n", + "We now extend the model and check whether reduced chi-squared improves." ] }, { @@ -362,6 +405,10 @@ "source": [ "## 10. Define Interlayer Materials\n", "\n", + "One concrete implementation uses:\n", + "- **NiOx** represented here with a NiO-like SLD\n", + "- **NiSi** as an intermixed silicide layer\n", + "\n", "| Material | SLD (10⁻⁶ Å⁻²) | Description |\n", "|----------|-----------------|-------------|\n", "| NiO | 6.7 | Nickel oxide at the Ni–air interface |\n", @@ -384,11 +431,15 @@ "id": "b4cab8e9", "metadata": {}, "source": [ - "## 11. Define Interlayer Layers & Rebuild the Sample\n", + "## 11. Define Interlayer Layers and Rebuild the Sample (Try First, Then Expand)\n", "\n", - "We create NiO and NiSi layers with initial thickness and roughness guesses, along with fresh copies of the Ni, Si, and air layers. The full layer stack from substrate to superphase is:\n", + "Task:\n", + "- Add interlayers at the two interfaces motivated above.\n", + "- Rebuild the sample with a physically consistent order.\n", "\n", - "**Si → NiSi → Ni → NiO → Air**" + "The full stack from substrate to superphase is:\n", + "\n", + "**Si -> NiSi -> Ni -> NiO -> Air**\n" ] }, { @@ -432,14 +483,18 @@ "id": "9b7baae1", "metadata": {}, "source": [ - "## 12. Set Free Parameters for Interlayer Model\n", + "## 12. Set Free Parameters for Interlayer Model (Try First, Then Expand)\n", + "\n", + "Task:\n", + "- Decide which new interlayer parameters should be free.\n", + "- Set realistic bounds to avoid unphysical solutions.\n", "\n", - "We vary more parameters than in Part 1. In addition to Ni thickness/roughness, Si roughness, scale, and background, we now also refine:\n", + "Compared with Part 1, we now also refine:\n", "\n", "- **NiO**: SLD, thickness, roughness \n", "- **NiSi**: SLD, thickness, roughness\n", "\n", - "This adds 6 extra degrees of freedom (11 total vs. 5 before)." + "This adds 6 extra degrees of freedom (11 total vs. 5 before).\n" ] }, { @@ -500,7 +555,8 @@ "\n", "model2.background.max = 1e-4\n", "\n", - "# Scale & backgroundmodel2.background.min = 1e-10\n", + "# Scale and background\n", + "model2.background.min = 1e-10\n", "\n", "model2.scale.fixed = False\n", "model2.background.fixed = False\n", @@ -540,7 +596,12 @@ "source": [ "## 14. Interlayer Fit Results & χ² Comparison\n", "\n", - "Print the refined parameters and compare the reduced χ² of the two models to see whether the interlayers improve the fit." + "Print the refined parameters and compare reduced chi-squared for the two models.\n", + "\n", + "Discussion prompts:\n", + "- Did the interlayer model improve the fit significantly?\n", + "- Is the improvement large enough to justify the added complexity?\n", + "- Which parameters are physically interpretable, and which may be compensating each other?" ] }, { @@ -584,7 +645,14 @@ "id": "ccdb8df5", "metadata": {}, "source": [ - "## 15. Visualisation — Interlayer Model" + "## 15. Final Comparison and Reflection\n", + "\n", + "Use the plots and metrics to evaluate model quality.\n", + "\n", + "Final teaching questions:\n", + "- What specific improvements do you observe in reflectivity and SLD behaviour?\n", + "- What additional complexity could be added next (e.g., graded interfaces, multiple oxides, hydration, lateral inhomogeneity)?\n", + "- What data or constraints would be needed to justify more complex structures?" ] }, { @@ -637,7 +705,7 @@ ], "metadata": { "kernelspec": { - "display_name": "era", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -651,7 +719,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.12" + "version": "3.12.11" } }, "nbformat": 4, diff --git a/docs/src/tutorials/fitting/reflectivity_geomgrid.ort b/notebooks/reflectivity_geomgrid.ort similarity index 100% rename from docs/src/tutorials/fitting/reflectivity_geomgrid.ort rename to notebooks/reflectivity_geomgrid.ort