diff --git a/EasyReflectometryApp/Backends/Py/logic/structure.py b/EasyReflectometryApp/Backends/Py/logic/structure.py index 6645011b..2c0d6f64 100644 --- a/EasyReflectometryApp/Backends/Py/logic/structure.py +++ b/EasyReflectometryApp/Backends/Py/logic/structure.py @@ -9,7 +9,16 @@ def flatten(project_lib: ProjectLib) -> tuple[list[dict], list[dict], float]: """Flatten the current model's sample into drawable boxes for the Structure view. Returns (structure, legend, total_thickness): - - structure: one dict per drawn box, top to bottom (contract in MD/VISUAL_LAYERS_PLAN.md §3.2) + - structure: one dict per drawn box, top to bottom, with the keys + label layer name, or assembly name for a gradient + material material name, or 'front -> back' for a gradient + color box color; color_end is the second color of a gradient, else '' + sld, isld real/imaginary SLD of the material, preformatted to 2 decimals + thickness layer thickness in Angstrom, as a float + roughness upper roughness in Angstrom, preformatted to 1 decimal + assembly assembly name, and assembly_index/layer_index to address the layer + kind 'layer' | 'gradient' | 'superphase' | 'subphase' + repetitions n for a collapsed repeating multilayer, else 1 - legend: distinct {label, color} pairs in stack order - total_thickness: physical total in Angstrom (collapsed repeats counted n times, caps excluded) """ diff --git a/INSTALLATION.md b/INSTALLATION.md index a8bfca08..2c3854c7 100644 --- a/INSTALLATION.md +++ b/INSTALLATION.md @@ -5,7 +5,7 @@ To make the installation of EasyReflectometry as easy as possible, we prepare pa - [Windows](https://github.com/EasyScience/EasyReflectometryApp/releases/download/v1.4.0/EasyReflectometryApp_v1.4.0_windows-2022.exe) - [MacOS](https://github.com/EasyScience/EasyReflectometryApp/releases/download/v1.4.0/EasyReflectometryApp_v1.4.0_macos-14-AppleSilicon.zip) (ARM) - [Linux](https://github.com/EasyScience/EasyReflectometryApp/releases/download/v1.4.0/EasyReflectometryApp_v1.4.0_ubuntu-22.04) (built on Ubuntu-22.04) -- [Linux](https://github.com/EasyScience/EasyReflectometryApp/releases/download/v1.4.0/EasyReflectometryApp_v1.4.0_ubuntu-24.04) (built on Ubuntu-22.04) +- [Linux](https://github.com/EasyScience/EasyReflectometryApp/releases/download/v1.4.0/EasyReflectometryApp_v1.4.0_ubuntu-24.04) (built on Ubuntu-24.04) If the relevant EasyReflectometry installation does not work on your system, then please try installation from source. diff --git a/README.md b/README.md index 1c03b34a..67e51885 100644 --- a/README.md +++ b/README.md @@ -31,13 +31,14 @@ Current main features of **EasyReflectometry**: - Growing support for flexible _item_ types, including chemically consistent models. - Ability to corefine multiple contrasts of reflectometry data. - Multiple minimization engines: [lmfit](https://lmfit.github.io/lmfit-py), [bumps](https://github.com/bumps/bumps) and [DFO-LS](https://github.com/numericalalgorithmsgroup/dfols) (including the differential evolution method). +- Support for magnetic structures: a magnetic scattering length density and in-plane moment angle per layer, refined with [refl1d](https://refl1d.readthedocs.io/en/latest/). +- Support for polarised reflectometry measurements: import of one file per spin channel, spin-asymmetry views, and simultaneous refinement of all measured spin channels against a single model. - Interactive HTML and standard PDF report generation. - Undo/redo for both parameter changes and fitting. - Saving and loading of projects. Planned improvements / new functionality for **EasyReflectometry**: -- Support for magnetic structures and polarised reflectometry measurements. - Support for mixed model reflectometry datasets. - Reading of q-dependent resolution from a file. diff --git a/ROADMAP.md b/ROADMAP.md index f128fd24..88b3eb44 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -28,8 +28,8 @@ gantt ESS Start of User Operation :milestone, m3, 2026-11, 2min section Hard Condensed Matter - Magnetism support :c1, after m1, 40w - Spin asymmetry and polarisation analysis :c2, after m2, 30w + Magnetism support :done, c1, after m1, 40w + Spin asymmetry and polarisation analysis :done, c2, after m2, 30w section Item Library # Bilayer item :d1, 2024-01, 8w @@ -121,7 +121,10 @@ This would involve significant EasyCore work, in addition to the development of ### Magnetism support -This will begin with enabling the magnetism functionality available in `refl1d`, concurrent to which the graphical user interface will be designed with input from the relevant user communities. +**Delivered.** Magnetic layers can be defined on the Model page and refined with `refl1d`; +see the [magnetism tutorial](./docs/src/tutorials/magnetism.md). + +This began with enabling the magnetism functionality available in `refl1d`, concurrent to which the graphical user interface will be designed with input from the relevant user communities. - [Discuss with user community and document requirements for magnetism](https://github.com/easyScience/EasyReflectometryApp/issues/113) - [Expose magnetisation in EasyReflectometryLib](https://github.com/easyScience/EasyReflectometryLib/issues/21) @@ -130,6 +133,10 @@ This will begin with enabling the magnetism functionality available in `refl1d`, ### Spin asymmetry and polarisation analysis +**Delivered.** Polarised experiments are imported one file per spin channel, displayed per channel, +fitted together and shown as spin asymmetry; see the +[polarised data tutorial](./docs/src/tutorials/polarized_data.md). + Enabling the analysis of difference between different spin flipper state - [Discuss with user community and document requirements for polarisation analysis](https://github.com/easyScience/EasyReflectometryApp/issues/115) diff --git a/docs/src/index.md b/docs/src/index.md index b60a735a..1a2522b5 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -13,6 +13,10 @@ tutorial.md tutorials/model_def.md tutorials/load_data.md tutorials/simple_fitting.md +tutorials/magnetism.md +tutorials/polarized_data.md +tutorials/bayesian.md tutorials/summary.md +tutorials/datasets.md tutorials/settings.md ``` \ No newline at end of file diff --git a/docs/src/installation.md b/docs/src/installation.md index ae16701d..edb9069a 100644 --- a/docs/src/installation.md +++ b/docs/src/installation.md @@ -1,10 +1,10 @@ # Installation To make the installation of EasyReflectometry as easy as possible, we prepare packaged releases for three major operating systems: -- [Windows](https://github.com/EasyScience/EasyReflectometryApp/releases/download/v1.1.1/EasyReflectometryApp_v1.1.1_windows-2022.exe) -- [MacOS (Silicon)](https://github.com/EasyScience/EasyReflectometryApp/releases/download/v1.1.1/EasyReflectometryApp_v1.1.1_macos-14-AppleSilicon.zip) -- [Linux (built on Ubuntu-24.04)](https://github.com/EasyScience/EasyReflectometryApp/releases/download/v1.1.1/EasyReflectometryApp_v1.1.1_ubuntu-22.04) -- [Linux (built on Ubuntu-22.04)](https://github.com/EasyScience/EasyReflectometryApp/releases/download/v1.1.1/EasyReflectometryApp_v1.1.1_ubuntu-24.04) +- [Windows](https://github.com/EasyScience/EasyReflectometryApp/releases/download/v1.4.0/EasyReflectometryApp_v1.4.0_windows-2022.exe) +- [MacOS (Silicon)](https://github.com/EasyScience/EasyReflectometryApp/releases/download/v1.4.0/EasyReflectometryApp_v1.4.0_macos-14-AppleSilicon.zip) +- [Linux (built on Ubuntu-22.04)](https://github.com/EasyScience/EasyReflectometryApp/releases/download/v1.4.0/EasyReflectometryApp_v1.4.0_ubuntu-22.04) +- [Linux (built on Ubuntu-24.04)](https://github.com/EasyScience/EasyReflectometryApp/releases/download/v1.4.0/EasyReflectometryApp_v1.4.0_ubuntu-24.04) If the relevant EasyReflectometry installation does not work on your system, then please try installation from source. diff --git a/docs/src/tutorials/bayesian.md b/docs/src/tutorials/bayesian.md new file mode 100644 index 00000000..92c16fde --- /dev/null +++ b/docs/src/tutorials/bayesian.md @@ -0,0 +1,94 @@ +# Bayesian analysis + +Next to the classical minimisers the app can sample the posterior distribution of the fitted +parameters with the BUMPS DREAM sampler. Instead of a single best value per parameter you +get a distribution: a median, a credible interval, and the correlations between parameters. + +## Starting a sampling run + +Bayesian sampling is selected like a minimiser. In `Analysis` › `Advanced` › +**Minimization method**, pick **BUMPS-DREAM (Bayesian)** - the first entry of the +**Minimizer** drop-down. + + + +The settings below the drop-down change with the choice. Instead of the classical +**Tolerance** and **Max evaluations**, the sampler shows: + +| Setting | Meaning | +|---|---| +| **Samples** | Total number of samples to draw. | +| **Burn-in steps** | Initial steps discarded before the chains are recorded. | +| **Population** | Number of chains walking the parameter space. | +| **Thinning** | Keep every n-th draw, to reduce autocorrelation. | +| **Initializer** | How the starting population is spread over the parameter ranges. | + +The parameters that are sampled, and the ranges they are sampled in, are the ones ticked +for fitting in the `Basic controls`, exactly as for a classical fit. + +With the Bayesian minimiser selected, the fit button in `Basic controls` reads +**Start sampling** instead of **Start fitting**. It becomes **Cancel fitting** while a run +is in progress; cancelling keeps the interface locked until the worker has actually +stopped, so a superseded run can never write into the parameters of the next one. + +## Reading the results + +### On the reflectivity chart + +When a run finishes, the `Reflectivity` tab of the `Analysis` page gains two extra items, +with their own legend entries: + +- **Posterior median** - the median calculated curve over the retained draws. +- **95% credible interval** - the band containing 95 % of the posterior predictive curves. + +### The Bayesian Posterior tab + +The `Analysis` page has a second main tab, **Bayesian Posterior**, holding five views. +Until a run has finished, it shows *"No Bayesian results available. Run a BUMPS-DREAM +sampling to see posterior distributions."* + + + +| View | Shows | +|---|---| +| **Marginals** | Marginal posterior distribution of each sampled parameter. | +| **Corner Plot** | Pairwise parameter correlations together with the marginals. | +| **Traces** | The MCMC chain traces, for eyeballing mixing and burn-in. | +| **2D Heatmap** | Joint posterior density of any two chosen parameters - pick them with the **X-axis** and **Y-axis** selectors. | +| **Diagnostics** | Convergence diagnostics, see below. | + +Each view has a **Save** button that writes the plot to disk. + +```{note} +The **Marginals**, **Corner Plot** and **Traces** views are rendered with `plotly`. If it is +not installed the view says so and gives the install command; the rest of the app is +unaffected. +``` + +### Diagnostics + +The **Diagnostics** view reports whether the run can be trusted: + +- **Sampling Configuration** - requested samples, burn-in steps, thinning, population + (chains), retained draws and number of parameters, as actually used by the run. +- **Acceptance Rate** of the sampler. +- **Gelman-Rubin R̂** per parameter. Values close to 1 indicate that the chains have + converged on the same distribution. + +## When results are discarded + +Posterior results describe one specific run of one specific model, so the app clears them - +the overlays, the plots and the results dialog - as soon as they would become stale: + +- when a project is created, loaded or reset, +- when a classical fit is started, +- when a new sampling run is started. + +## Limitations + +- **Polarised experiments cannot be sampled yet.** Fitting them classically is supported, + see [polarised data](./polarized_data.md), but a Bayesian run over a polarised experiment + is not available. +- Data files without an uncertainty column are sampled with zero variances, which the + sampler reports with a message. The fit is still performed, but the resulting credible + intervals should not be read as measurement uncertainties. diff --git a/docs/src/tutorials/datasets.md b/docs/src/tutorials/datasets.md new file mode 100644 index 00000000..e33983f4 --- /dev/null +++ b/docs/src/tutorials/datasets.md @@ -0,0 +1,33 @@ +# Demo datasets + +The repository ships four simulated neutron reflectometry datasets for trying out the +constraint features described in [material and model setup](./model_def.md). They live in +[`examples/datasets`](https://github.com/easyScience/EasyReflectometryApp/tree/master/examples/datasets), +together with a +[full write-up](https://github.com/easyScience/EasyReflectometryApp/blob/master/examples/datasets/README.md) +of each demo and the script that regenerates them. + +All four are ORSO `.ort` files simulated from a **known structure** with 4 % noise and 5 % +`dQ/Q` resolution, so every demo has a right answer to compare the fit against. The ground +truth is recorded in each file's header, and each header also carries the sample structure +in the ORSO model language, so the files can be opened in two ways: + +- **Model** › `Load a sample` › **Load sample from file** builds the layer stack for you, + with the true thicknesses, roughnesses and SLDs as starting values. Change those starting + values before fitting, so there is something to find. +- **Experiment** › **Load experiment(s) from file(s)** loads the reflectivity curve, which + also works with a hand-built sample. + +| Dataset | Demonstrates | +|---|---| +| `two_layer_film.ort` | A two-layer film whose total thickness is known (exactly 90 Å) - the thickness budget and the derived total film thickness. | +| `swapped_layers.ort` | A layer-ordering inequality: started from the swapped guess, the fit only recovers the truth with a `≤` constraint between the two thicknesses. | +| `ni_ti_multilayer.ort` | A `[Ti / Ni] × 8` repeating multilayer with a Bragg peak that pins the period - the **Constant period Λ** and **Conformal roughness** recipes. | +| `dppc_monolayer.ort` | A DPPC monolayer at the air/D2O interface - the surfactant recipes (equal head/tail area per molecule, solvent roughness). | + +```{note} +For `ni_ti_multilayer.ort` the loaded stack arrives flattened (8 × [Ti | Ni] becomes 16 +layers in one assembly); rebuild it as a `Repeating Multi-layer` by hand for the +constant-period demo. For `dppc_monolayer.ort` the loaded stack is the slab equivalent of +the surfactant; replace it with a `Surfactant layer` assembly for the surfactant recipes. +``` diff --git a/docs/src/tutorials/load_data.md b/docs/src/tutorials/load_data.md index dfef8b39..aea40f5c 100644 --- a/docs/src/tutorials/load_data.md +++ b/docs/src/tutorials/load_data.md @@ -15,3 +15,8 @@ When data is loaded, it is possible to change instrumental parameters that affec - **A**: Scale the data by the given value. - **B**: Set the level where data merges into the experimental background. - **C**: Instrumental resolution that percentage varies as a function of Q. + +## Polarised data +A measurement that recorded several spin channels is loaded with the second button, +`Load polarized experiment (file per channel)`, which takes one file per channel and asks +how to assign them. See [polarised data](./polarized_data.md). diff --git a/docs/src/tutorials/magnetism.md b/docs/src/tutorials/magnetism.md new file mode 100644 index 00000000..ddfb3a4b --- /dev/null +++ b/docs/src/tutorials/magnetism.md @@ -0,0 +1,88 @@ +# Magnetic layers + +A layer can be given a magnetisation, so that the two neutron spin states see different +scattering length densities. This page covers the **Model** page controls; loading and +fitting measured spin channels is described in +[polarised data](./polarized_data.md). + +```{note} +Magnetic layers can only be calculated by `refl1d`. `refnx` has no magnetism, so the app +asks to switch the project's calculation engine the first time a layer is made magnetic. +``` + +## The Magnetism group + +The **Magnetism** group is in the basic controls of the **Model** page, below the layer +editor. It is titled after the assembly currently selected in the `Layer editor`, for +example `Magnetism: Multi-layer`, and shows one row per layer of that assembly. + + + +| Column | Meaning | +|---|---| +| **No.** | Position of the layer in the assembly. | +| **Layer** | Layer name, as in the `Layer editor`. | +| **ρM/10⁻⁶Å⁻²** | Magnetic scattering length density of the layer. | +| **θM/°** | In-plane angle of the magnetic moment. | +| **Magn.** | Makes the layer magnetic. Unticking it removes the magnetisation. | + +`ρM` and `θM` are only editable once **Magn.** is ticked. + +```{note} +`θM = 270°` aligns the moment with the guide field, which produces no spin-flip +scattering. This is the value to start from for a simple saturated film. +``` + +### Switching the calculation engine + +Ticking **Magn.** while the project uses an engine that cannot model magnetism opens the +**Switch calculation engine?** dialog. Accepting it makes the layer magnetic *and* switches +the project to `refl1d` in one step - the page does not change under you. + +Switching recalculates the reflectivity and makes any existing fit result stale; the sample +and the loaded data are untouched. The engine can be switched back once no layer is +magnetic any more. + +The engine itself lives in the **Calculation engine** group of the advanced controls on the +**Model** page (and in `Analysis` › `Advanced`, see +[simple fitting](./simple_fitting.md)). Selecting an engine that cannot model magnetism +while the sample still has magnetic layers is refused, with a message on both pages. + +## Fitting ρM and θM + +`ρM` and `θM` appear in the `Analysis` parameter table like any other layer parameter, +named after their assembly and model - for example `Model Fe rho_m`. They come with default +limits, a fit checkbox and can be used in constraints. The parameter name filter accepts +`magnetic` as a keyword to show only the magnetic parameters. + +## Magnetic depth profiles + +Once at least one layer is magnetic, the **Magnetic profile** group appears in the basic +controls, below **Magnetism**. The same switches are repeated in `Analysis` › +`Advanced` › `Plot control`, and the two share one selection. + + + +- **Show ρ↑ and ρ↓** - adds the spin-up and spin-down potentials + `ρ ± ρM·cos(θM − A)` for each magnetic model to the SLD chart, dashed in the model's + colour. For non-magnetic layers the two curves collapse onto the nuclear SLD. +- **Show ρM** - the magnetic SLD profile on its own. +- **Show θM** - the in-plane moment angle, on its own right-hand axis. `θM` is only defined + where there is a moment, so the curve is drawn in pieces rather than joined across the + gaps. +- **Show R↑↑ and R↓↓** - splits each magnetic model's reflectivity into its two + non-spin-flip cross-sections on the **Model** page reflectivity chart, dashed in the + model's colour with their own legend rows. Off by default. + +The y-range of the SLD chart covers every visible curve and grows when a curve is switched +on, so `ρ + ρM` is never clipped. If no model is magnetic, the chart, its legend and the +sidebar are unchanged. + +```{note} +For a magnetic sample the plain model curve is **not** an unpolarised average - the +calculator returns the ↑↑ cross-section - so `R↑↑` is drawn on top of it. The sidebar says +so as well. +``` + +The `Analysis` reflectivity chart is unaffected by this switch: it already draws one +calculated curve per measured spin channel when the experiment is polarised. diff --git a/docs/src/tutorials/model_def.md b/docs/src/tutorials/model_def.md index 23c8effb..61d8495d 100644 --- a/docs/src/tutorials/model_def.md +++ b/docs/src/tutorials/model_def.md @@ -43,17 +43,105 @@ By clicking an assembly, the `Layer editor` is specified and changes can be made - **1**: Choose a material from materials in the `Material Editor`. - **2**+**3**: Setting the Thickness and Upper Roughness of the material in Angstrom, Å. +### Magnetism +A layer can also be given a magnetisation, in the `Magnetism` group below the layer editor. +This needs the `refl1d` calculation engine and is described in +[magnetic layers](./magnetism.md). + +## Structure view +The main window has a **Structure** tab next to **Reflectivity** showing a schematic of +the current model's layer stack: one colored box per layer, ambient medium on top, substrate +at the bottom. Boxes share a color per material (see the legend), box heights follow layer +thickness, and repeated multilayers with many repetitions are drawn once with a "× N" badge. + + + +Hover a box for its material, SLD, thickness and roughness; click it to select that layer in +the sidebar editor. The view updates immediately when the model changes, including after a fit. + +Note the view is a schematic, not a to-scale cross-section: heights are clamped so very thin +layers stay visible and very thick ones do not crowd out the rest. + ## Advanced controls -In the advanced controls, it is possible to apply a specific Q-range of interest and sample constraints on the model. +In the advanced controls, it is possible to apply a specific Q-range of interest, to choose +the calculation engine, and to constrain the parameters of the model. ![Advanced controls](./_images/sample_adv.png) - **A**: Setting min. Q value of interest. - **B**: Setting max. Q value of interest. -- **C**: Setting Q-resolution.

-- **D**: Set 1. dependent parameter. -- **E**: Set 2. dependent parameter. -- **F**: Set the mathematical operator (+,-,*,/) for **G** to apply to **E**. -- **G**: Numeric value to apply to **F**. -- **H**: Set the comparison operators (=,<,>) between **D** and **E**. -- **I**: Apply the sample constraint to the model. +- **C**: Setting Q-resolution. + +The **Calculation engine** group selects between `refnx` and `refl1d` for this project. The +same selector is available on the `Analysis` page. Only `refl1d` can model magnetic layers, +so selecting `refnx` while the sample has magnetic layers is refused - see +[magnetic layers](./magnetism.md). + +Below these sit three constraint groups, from the most specific to the most general. + +### Physics constraints +The `Physics constraints` group applies physically motivated constraints to an assembly with +one click. The list is per assembly of the current model, and only shows the recipes that +make sense for that assembly type; a recipe that cannot be applied right now is marked +`n/a` with the reason, and one that is always in force is marked `always on`. + + + +| Recipe | Effect | +|---|---| +| **Conformal roughness** | Every interface of the assembly shares the roughness of its first layer. | +| **Conformal thickness** | Every layer of the assembly shares the thickness of its first layer. | +| **Constant period Λ** | The summed thickness of the layers stays constant: the last layer absorbs whatever the others change by. | +| **Equal head/tail area per molecule** | The head layer takes the area per molecule of the tail layer (surfactant layers). | +| **Symmetric head groups** | The back head layer follows the front head layer thickness and area per molecule (bilayers). | +| **Solvent roughness follows the surfactant** | The roughness of the first layer below the surfactant follows the tail roughness. Needs **Conformal roughness**. | +| **Mixture fractions sum to 1** | Material mixtures and solvated materials keep their fractions normalised. Always on, not toggleable. | + +Each active recipe appears as a single row in the `Active Constraints` table of the +`Single constraints` group, of type `physics`, counting the parameters it ties together. + +### Single constraints +The `Single constraints` group creates numeric or symbolic relationships between individual +parameters. + + + +1. Pick the **dependent parameter** from the drop-down. +2. Pick the relation: `=`, `≤` or `≥`. +3. Type the **expression**, for example `np.sqrt(1 / sld_ni) + 4`. Use + **Insert parameter alias…** to paste the alias of another parameter rather than typing + it, and **Insert total film thickness** to use the read-only sum of all layer thicknesses + between superphase and subphase. +4. Check the **Preview** line, which shows how the constraint will read - and, for an + inequality, that numeric literals are interpreted in the dependent parameter's unit. +5. Press **Add constraint**. + +`=` ties the parameter to the expression, so it is no longer free. `≤` and `≥` against other +parameters become **inequality constraints**, which are enforced as penalties during +fitting. + +```{warning} +Inequality constraints need a BUMPS minimizer (`Analysis` › `Minimization method`). With +`lmfit` or `DFO-LS` selected the group shows a warning and fits are refused until the +minimizer is changed or the inequality is removed. A warning also appears when the current +parameter values violate an inequality, and again fits will not start until they hold. +``` + +Existing constraints are listed in the `Active Constraints` table, with columns `No.`, +`Type`, `Parameter` and `Expression`. The `Type` column tells the kinds apart - `expr` for a +plain equality, `≤ ≥` for an inequality, `physics` for a recipe from the group above, +`bound` for an upper bound and `value` for a fixed value - and each row can be removed +individually. + +### Model constraints +The `Model constraints` group ties whole models together rather than single parameters: +select two or more models and press **Constrain models parameters** to constrain all of +their matching parameters at once. This is the tool for co-refining several contrasts that +share a structure. The resulting constraints are listed in the `Model Constraints` table +below the selector and can be removed there. + + + +### Trying the constraints out +Four simulated datasets with a known ground truth are provided for exercising these +features - see [demo datasets](./datasets.md). diff --git a/docs/src/tutorials/polarized_data.md b/docs/src/tutorials/polarized_data.md new file mode 100644 index 00000000..dd67bdfc --- /dev/null +++ b/docs/src/tutorials/polarized_data.md @@ -0,0 +1,98 @@ +# Polarised data + +A polarised measurement records up to four spin channels of the same sample. The app loads +them as a single experiment, draws them separately, and fits them together against one +model. + +| Channel | Meaning | +|---|---| +| `pp` ↑↑ | non-spin-flip, both incoming and outgoing spin up | +| `mm` ↓↓ | non-spin-flip, both incoming and outgoing spin down | +| `pm` ↑↓ | spin-flip | +| `mp` ↓↑ | spin-flip | + +## Loading one file per channel + +The **Experimental data** group on the `Experiment` page has a second button, +**Load polarized experiment (file per channel)**, below the ordinary +**Load experiment(s) from file(s)**. Select one file per spin channel - the file picker +allows multiple selection - and the **Assign spin channels** dialog opens. + + + +Each file gets a channel drop-down, pre-assigned from the ORSO `polarization` header or, +failing that, from the file name. Adjust anything that came out wrong. Any number of +channels may be assigned, a single one included, and a file that should be ignored is set +to **not used**. + +The dialog refuses to continue and explains why if a channel is assigned to more than one +file, if a file is missing, or if nothing at all is assigned. + +```{note} +One resolution function is used for the whole polarised experiment, taken from the first +assigned channel. Differing per-channel resolution metadata in the other files is ignored; +the dialog says so. +``` + +If the project's calculation engine cannot model magnetism, the dialog also notes that the +channels will be loaded and displayed but not modelled until the sample has magnetic layers +and the engine is switched - see [magnetic layers](./magnetism.md). + +## Seeing the channels + +- The experiment chart draws one measured series, with its error bounds, per **visible** + channel, in a fixed palette (↑↑ `pp`, ↑↓ `pm`, ↓↑ `mp`, ↓↓ `mm`), with a per-channel + legend. +- The **Polarization channels** group in the advanced controls of the `Experiment` page + toggles which channels are drawn. At least one measured channel always stays visible. +- Experiment lists mark a polarised experiment with a `⇅N` badge, `N` being the number of + measured spin channels. +- With several experiments selected, each polarised experiment contributes one series per + visible channel, using the experiment colour as the hue base. + +## Spin asymmetry + +The spin asymmetry + +``` +SA(q) = (R↑↑ − R↓↓) / (R↑↑ + R↓↓) +``` + +is available as a **Spin asymmetry** tab next to **Reflectivity** on the `Experiment` page +(measured data only) and as a third tab of the lower panel on the `Analysis` page (measured +data plus the model). Neither tab is shown unless the experiment measured **both** +non-spin-flip channels; without one, the `Experiment` page has no tab strip at all. + + + +Error bars are propagated from the channel uncertainties. Two kinds of point are dropped, +with a note of how many: + +- points where `R↑↑ + R↓↓` is not significantly above zero - the background-dominated tail, + which would otherwise wreck the axis; +- points where the two channels do not share the same `q`. + +The axis shows the full `[−1, 1]` window and expands only if background-subtracted data go +outside it. + +## Fitting a polarised experiment + +Fitting a polarised experiment fits **all** its measured spin channels at once against the +shared model. Thickness, roughness, nuclear SLD, scale and background are common to every +channel; `ρM` and `θM` are constrained by all of them. Polarised and ordinary experiments +can be fitted together in the same refinement. + +The analysis and residual charts draw one measured/calculated pair per visible channel, +each with that channel's cross-section. A channel the model cannot calculate - a spin-flip +channel on a non-magnetic sample - shows its measured points only and contributes no +residuals. + +In the `Summary` report a polarised experiment contributes one row per measured spin +channel, named after the channel, and the report figures plot each channel in its channel +colour. + +## Limitations + +- One resolution function per polarised experiment, taken from the first assigned channel. +- Bayesian sampling of polarised experiments is not supported yet; see + [Bayesian analysis](./bayesian.md). diff --git a/docs/src/tutorials/simple_fitting.md b/docs/src/tutorials/simple_fitting.md index 63cec0c1..67fa0b49 100644 --- a/docs/src/tutorials/simple_fitting.md +++ b/docs/src/tutorials/simple_fitting.md @@ -32,3 +32,27 @@ The advanced control is then for changing the calculation engine and setting the - **B**: Setting the minimisation method for minimising variables. - **C**: Specifying the tolerance of the set minimiser. - **D**: Setting the maximum number of iterations(evaluations) for the minimiser to run. + +The calculation engine (**A**) is also available on the `Model` page, in its advanced +controls; both selectors change the same project setting. Note that only `refl1d` can model +magnetic layers, so a sample with magnetism cannot be calculated with `refnx` - see +[magnetic layers](./magnetism.md). + +The first entry of the minimiser list (**B**), `BUMPS-DREAM (Bayesian)`, does not minimise +but samples the posterior distribution of the fitted parameters; it replaces **C** and **D** +with its own sampling settings. See [Bayesian analysis](./bayesian.md). + +## Residuals +The lower panel of the `Analysis` page has three tabs: `SLD`, `Residuals` and, for a +polarised experiment that measured both non-spin-flip channels, `Spin asymmetry`. + +The `Residuals` tab plots the weighted residual `(M-E)/σ` against `q` - the difference +between the model and the experiment, in units of the measured uncertainty. A good fit +scatters evenly around zero with no structure left in it; a systematic wave or a drift means +the model is missing something. The tab has the same legend, hover, zoom, pan and reset +controls as the other charts, and its q-axis follows the logarithmic setting of the +reflectivity chart. + +With several experiments, or with a polarised experiment, the tab draws one residual curve +per visible measured series. A spin channel the model cannot calculate contributes no +residuals.