diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index dae109fd6..c73390a81 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -44,6 +44,10 @@ - Type-annotate all public function signatures. - Docstrings on all public classes and methods (numpy style). These must include sections Parameters, Returns and Raises, where applicable. +- Docstring summary must be a single line no longer than 72 characters + (the `max-doc-length` setting in `pyproject.toml`). If the summary + does not fit, shorten the wording rather than wrapping to a second + line. - Prefer flat over nested, explicit over clever. - Write straightforward code; do not add defensive checks for unlikely edge cases. diff --git a/docs/architecture/adp_implementation.md b/docs/architecture/adp_implementation.md new file mode 100644 index 000000000..4d66e0b74 --- /dev/null +++ b/docs/architecture/adp_implementation.md @@ -0,0 +1,321 @@ +# ADP Implementation Plan + +**Date:** 2026-04-12 **Status:** Design approved — awaiting +implementation + +--- + +## 1. Goal + +Extend ADP (Atomic Displacement Parameter) support from the current +Biso-only implementation to all four CIF-standard types: **Biso**, +**Uiso**, **Bani**, **Uani**. The design uses type-neutral parameter +names (`adp_iso`, `adp_11`…`adp_23`) so that switching ADP type is a +one-line operation on `adp_type` without creating or destroying +parameters. + +--- + +## 2. Design Summary + +### 2.1 Two Sibling Collections on Structure + +Following CIF conventions (`_atom_site` + `_atom_site_aniso` are +separate loops), the structure owns two sibling collections: + +``` +Structure +├── cell (CategoryItem) +├── space_group (CategoryItem) +├── atom_sites (CategoryCollection of AtomSite) +└── atom_site_aniso (CategoryCollection of AtomSiteAniso) +``` + +Every atom always has an entry in both collections, kept in sync by +`Structure._update_categories()`. This eliminates conditional existence +checks throughout the codebase. + +### 2.2 Type-Neutral Parameter Names + +Parameters on `AtomSite` and `AtomSiteAniso` use type-neutral names +whose physical meaning is determined by `atom_site.adp_type`: + +| Parameter | Location | CIF names (order depends on `adp_type`) | +| ---------- | --------------- | -------------------------------------------------------- | +| `adp_type` | `AtomSite` | `_atom_site.adp_type` | +| `adp_iso` | `AtomSite` | `_atom_site.B_iso_or_equiv`, `_atom_site.U_iso_or_equiv` | +| `adp_11` | `AtomSiteAniso` | `_atom_site_aniso.B_11`, `_atom_site_aniso.U_11` | +| `adp_22` | `AtomSiteAniso` | `_atom_site_aniso.B_22`, `_atom_site_aniso.U_22` | +| `adp_33` | `AtomSiteAniso` | `_atom_site_aniso.B_33`, `_atom_site_aniso.U_33` | +| `adp_12` | `AtomSiteAniso` | `_atom_site_aniso.B_12`, `_atom_site_aniso.U_12` | +| `adp_13` | `AtomSiteAniso` | `_atom_site_aniso.B_13`, `_atom_site_aniso.U_13` | +| `adp_23` | `AtomSiteAniso` | `_atom_site_aniso.B_23`, `_atom_site_aniso.U_23` | + +### 2.3 Dual CIF Names — Static Read, Reordered Write + +Each parameter's `CifHandler` carries both CIF name variants. The +existing infrastructure handles this: + +- **Reading (deserialization):** `param_from_cif()` and + `category_collection_from_cif()` iterate `_cif_handler.names` and stop + at the first match. A CIF file with `_atom_site.U_iso_or_equiv` is + read correctly regardless of name order. +- **Writing (serialization):** `param_to_cif()` and + `category_collection_to_cif()` always use `names[0]`. The `adp_type` + setter reorders the `names` list so that the correct CIF tag is + emitted first. + +Example — when `adp_type` changes from `'Biso'` to `'Uiso'`: + +```python +# adp_type setter reorders CIF names on adp_iso +self._adp_iso._cif_handler._names = [ + '_atom_site.U_iso_or_equiv', + '_atom_site.B_iso_or_equiv', +] +``` + +No new core CIF infrastructure is needed. + +### 2.4 ADP Type Enum + +```python +class AdpTypeEnum(str, Enum): + BISO = 'Biso' + UISO = 'Uiso' + BANI = 'Bani' + UANI = 'Uani' +``` + +`adp_type` on `AtomSite` is a `StringDescriptor` validated by +`MembershipValidator(allowed=...)` using all four enum values. + +### 2.5 Auto-Conversion on Type Switch + +Setting `adp_type` triggers value conversion. The physics: + +- **B ↔ U (isotropic):** `B = 8π²U` +- **Iso → Ani:** diagonal `adp_11 = adp_22 = adp_33 = adp_iso`, + off-diagonal `adp_12 = adp_13 = adp_23 = 0` +- **Ani → Iso:** `adp_iso = (adp_11 + adp_22 + adp_33) / 3` + +The `adp_type` setter on `AtomSite` performs the conversion and updates +both the isotropic parameter and the aniso parameters on the sibling +collection. + +### 2.6 Collection Sync via `_update_categories()` + +`Structure._update_categories()` reconciles the two collections: + +| Event | Sync action | +| ---------------------------------- | --------------------------------------------------------- | +| Atom added to `atom_sites` | Create matching `AtomSiteAniso` entry with defaults (0.0) | +| Atom removed from `atom_sites` | Remove matching `AtomSiteAniso` entry | +| Atom label renamed in `atom_sites` | Rekey the matching `AtomSiteAniso` entry | + +The sync is driven by the dirty flag — any parameter or collection +change sets `_need_categories_update = True`, and the next +serialization, plot, or fit call triggers `_update_categories()`. + +### 2.7 Inactive Aniso Values + +When `adp_type` is `'Biso'` or `'Uiso'`, the aniso parameters exist with +value `0.0` but are not read by calculators. This avoids introducing +`None` into the `float`-based `Parameter` system. + +--- + +## 3. User-Facing API + +### 3.1 Parameter Access Pattern + +Parameters are accessed via the standard two-level pattern: + +```python +# CategoryItem.Parameter +structure.cell.length_a = 3.88 + +# CategoryCollection[item_id].Parameter +structure.atom_sites['Si'].adp_type = 'Biso' +structure.atom_sites['Si'].adp_iso = 0.47 +structure.atom_site_aniso['Si'].adp_11 = 0.05 +``` + +### 3.2 Switching ADP Type + +```python +# Switch from Biso to Uiso — auto-converts value +structure.atom_sites['Si'].adp_type = 'Uiso' +# adp_iso now holds U_iso value (B / 8π²) + +# Switch to anisotropic — seeds diagonal from iso +structure.atom_sites['Si'].adp_type = 'Uani' +# atom_site_aniso['Si'].adp_11/22/33 seeded from adp_iso +# adp_iso recalculated as mean of diagonal + +# Switch back to isotropic — collapses tensor to scalar +structure.atom_sites['Si'].adp_type = 'Biso' +# adp_iso = mean(adp_11, adp_22, adp_33), converted B→U if needed +``` + +### 3.3 Creating Atoms + +```python +# adp_iso replaces the old b_iso keyword +structure.atom_sites.create( + label='Si', + type_symbol='Si', + fract_x=0.0, + fract_y=0.0, + fract_z=0.0, + adp_type='Biso', + adp_iso=0.47, +) +# atom_site_aniso['Si'] is auto-created by _update_categories() +``` + +### 3.4 CIF Output + +```cif +loop_ +_atom_site.label +_atom_site.type_symbol +_atom_site.fract_x +_atom_site.fract_y +_atom_site.fract_z +_atom_site.adp_type +_atom_site.B_iso_or_equiv +_atom_site.occupancy +Si Si 0.00000000 0.00000000 0.00000000 Biso 0.47000000 1.00000000 + +loop_ +_atom_site_aniso.label +_atom_site_aniso.B_11 +_atom_site_aniso.B_22 +_atom_site_aniso.B_33 +_atom_site_aniso.B_12 +_atom_site_aniso.B_13 +_atom_site_aniso.B_23 +Si 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 +``` + +When `adp_type = 'Uiso'`, the CIF tag becomes +`_atom_site.U_iso_or_equiv` and the aniso loop uses +`_atom_site_aniso.U_*` tags. + +--- + +## 4. Implementation Phases + +### Phase 1: Rename `b_iso` → `adp_iso` and Expand `adp_type` + +**Files to modify:** + +1. **`atom_sites/default.py`** — `AtomSite`: + - Rename `_b_iso` Parameter to `_adp_iso` with dual CIF names + `['_atom_site.B_iso_or_equiv', '_atom_site.U_iso_or_equiv']`. + - Expand `_adp_type` validator to accept all four values from + `AdpTypeEnum`. + - Add `adp_type` setter logic: reorder CIF names on `_adp_iso`, + perform B↔U conversion. + - Rename property `b_iso` → `adp_iso`. + +2. **`atom_sites/enums.py`** (new) — `AdpTypeEnum` with BISO, UISO, + BANI, UANI members plus `default()` and `description()` methods. + +3. **Calculator bridges** — update `cryspy.py` and `crysfml.py` to read + `atom.adp_iso.value` instead of `atom.b_iso.value`, and pass the + correct type based on `atom.adp_type.value`. + +4. **CIF data files** — update all `.cif` files in `data/` that + reference `b_iso`. + +5. **Tutorials** — update all `*.py` scripts that use `b_iso`. + +6. **Tests** — update all unit/functional/integration tests. + +### Phase 2: Add `AtomSiteAniso` Sibling Collection + +**Files to create:** + +1. **`atom_site_aniso/`** package under + `datablocks/structure/categories/`: + - `__init__.py` — imports `AtomSiteAniso` and + `AtomSiteAnisoCollection`. + - `default.py` — `AtomSiteAniso` (CategoryItem) with `label` + (StringDescriptor) and six Parameters (`adp_11`…`adp_23`) each with + dual CIF names. `AtomSiteAnisoCollection` (CategoryCollection). + - `factory.py` — `AtomSiteAnisoFactory`. + - `enums.py` — if needed (likely shared with Phase 1 enum). + +2. **`structure/item/base.py`** — add `_atom_site_aniso` attribute and + `atom_site_aniso` read-only property on Structure. + +3. **`structure/item/base.py`** — override `_update_categories()` to + reconcile `atom_sites` and `atom_site_aniso` collections (add + missing, remove stale, rekey on label change). + +**Files to modify:** + +4. **`atom_sites/default.py`** — `adp_type` setter also reorders CIF + names on all six aniso parameters (accessed via parent structure's + `atom_site_aniso` collection). + +5. **Calculator bridges** — when `adp_type` is `'Bani'` or `'Uani'`, + read from `atom_site_aniso[label]` instead of `adp_iso`. + +6. **CIF serialization** — works automatically (Structure's `as_cif` + emits all CategoryCollections found in `vars(self)`). + +### Phase 3: ADP Symmetry Constraints + +1. **`crystallography.py`** — add symmetry constraint functions for + anisotropic ADPs based on space group and Wyckoff position. + +2. **`AtomSites._update()`** — call aniso symmetry constraints in + addition to coordinate constraints. + +--- + +## 5. Breaking Changes + +| Change | Scope | Migration | +| ----------------------------------------- | --------------------------------- | ---------------------------------- | +| `b_iso` → `adp_iso` | All code referencing `atom.b_iso` | Mechanical rename (greppable) | +| `b_iso=0.5` → `adp_iso=0.5` in `create()` | Tutorials, tests, user scripts | Mechanical rename | +| New `atom_site_aniso` on Structure | Structure API surface grows | Additive — no existing code breaks | + +The project is in beta, so no deprecation path is needed. + +--- + +## 6. Design Decisions + +### Why type-neutral names (`adp_iso`) instead of type-specific (`b_iso`, `u_iso`)? + +With type-specific names, switching ADP type would require +creating/destroying parameters, migrating constraints and free flags, +and updating every reference. Type-neutral names make switching a +one-liner on `adp_type` — the parameter object stays the same, only its +value and CIF tag change. + +### Why always-present aniso collection instead of on-demand? + +Conditional existence of `atom_site_aniso` would require guards +everywhere: serialization, calculators, parameter tables, constraint +wiring, UI. Always-present with 0.0 defaults eliminates all those +branches. + +### Why sync via `_update_categories()` instead of coupled add/remove? + +Loose coupling: `AtomSites` and `AtomSiteAnisoCollection` don't know +about each other. `Structure` coordinates them at update time. This +follows the existing dirty-flag pattern and keeps categories +independent. + +### Why reorder `_cif_handler.names` instead of dynamic CIF handler? + +The existing serialization/deserialization pipeline uses `names[0]` for +writing and iterates all names for reading. Reordering the list is a +2-line operation in the `adp_type` setter with zero core infrastructure +changes. diff --git a/docs/architecture/architecture.md b/docs/architecture/architecture.md index 1615307d1..cd14d099e 100644 --- a/docs/architecture/architecture.md +++ b/docs/architecture/architecture.md @@ -149,6 +149,28 @@ def _set_sample_form(self, value: str) -> None: ### 2.3 CategoryItem and CategoryCollection +**Parameter access pattern.** Users reach any parameter through at most +two levels of navigation from the datablock: + +```python +# CategoryItem → Parameter +structure.cell.length_a = 3.88 +experiment.instrument.setup_wavelength = 1.494 + +# CategoryCollection[item_id] → Parameter +structure.atom_sites['Si'].adp_iso = 0.47 +experiment.background['10'].y = 170 +``` + +The general forms are: + +- `DATABLOCK.CATEGORY_ITEM.PARAMETER` +- `DATABLOCK.CATEGORY_COLLECTION[ITEM_ID].PARAMETER` + +This two-level convention (category then parameter) is a deliberate +design constraint. Categories are never nested inside other categories +(see § 9.7), which keeps the path depth uniform and the API predictable. + | Aspect | `CategoryItem` | `CategoryCollection` | | --------------- | ---------------------------------- | ----------------------------------------- | | CIF analogy | Single category row | Loop (table) of rows | @@ -285,18 +307,55 @@ being replaced. ```shell DatablockItem -└── Structure # name, cell, space_group, atom_sites +└── Structure # name, cell, space_group, atom_sites, atom_site_aniso ``` -A `Structure` contains three categories: +A `Structure` contains four categories: - `Cell` — unit cell parameters (`CategoryItem`) - `SpaceGroup` — symmetry information (`CategoryItem`) -- `AtomSites` — atomic positions collection (`CategoryCollection`) +- `AtomSites` — atomic positions and isotropic ADP + (`CategoryCollection`) +- `AtomSiteAniso` — anisotropic ADP tensor components + (`CategoryCollection`) Symmetry constraints (cell metric, atomic coordinates, ADPs) are applied via the `crystallography` module during `_update_categories()`. +### 4.2 Atomic Displacement Parameters (ADP) + +ADP support covers four CIF-standard types: **Biso**, **Uiso**, +**Bani**, **Uani**. The design uses **type-neutral parameter names** so +that switching type is a one-line operation on `adp_type`. + +**Two sibling collections.** Following CIF conventions (`_atom_site` and +`_atom_site_aniso` are separate loops), isotropic and anisotropic data +live in separate collections on `Structure`. Every atom always has an +entry in both collections; when `adp_type` is isotropic, the aniso +parameters hold `0.0` and are ignored by calculators. + +**Type-neutral names.** `atom_site.adp_iso` is the type-neutral +isotropic ADP parameter. Its physical meaning (B or U) is determined by +`atom_site.adp_type`. Similarly, `atom_site_aniso.adp_11`…`adp_23` are +type-neutral tensor components. + +**Dual CIF names.** Each parameter's `CifHandler` carries both CIF name +variants (e.g. +`['_atom_site.B_iso_or_equiv', '_atom_site.U_iso_or_equiv']`). Reading +tries each name until a match is found; writing uses `names[0]`. The +`adp_type` setter reorders the list so the correct tag is emitted. + +**Auto-conversion.** Setting `adp_type` triggers value conversion: B ↔ U +via `B = 8π²U`; iso → ani seeds the diagonal; ani → iso averages the +diagonal. + +**Collection sync.** `Structure._update_categories()` reconciles the two +collections: adds missing aniso entries, removes stale ones, and rekeys +on label rename. + +See [`adp_implementation.md`](adp_implementation.md) for the full +implementation plan. + --- ## 5. Factory System @@ -400,6 +459,7 @@ from .line_segment import LineSegmentBackground | `CellFactory` | Unit cells | `Cell` | | `SpaceGroupFactory` | Space groups | `SpaceGroup` | | `AtomSitesFactory` | Atom sites | `AtomSites` | +| `AtomSiteAnisoFactory` | Anisotropic ADPs | `AtomSiteAnisoCollection` | | `AliasesFactory` | Parameter aliases | `Aliases` | | `ConstraintsFactory` | Parameter constraints | `Constraints` | | `FitModeFactory` | Fit-mode category | `FitMode` | @@ -572,6 +632,7 @@ line-segment points. | `ExcludedRegions` | `ExcludedRegionsFactory` | | `LinkedPhases` | `LinkedPhasesFactory` | | `AtomSites` | `AtomSitesFactory` | +| `AtomSiteAnisoCollection` | `AtomSiteAnisoFactory` | | `Aliases` | `AliasesFactory` | | `Constraints` | `ConstraintsFactory` | | `JointFitExperiments` | `JointFitExperimentsFactory` | @@ -583,6 +644,7 @@ line-segment points. | `LineSegment` | `LineSegmentBackground` | | `PolynomialTerm` | `ChebyshevPolynomialBackground` | | `AtomSite` | `AtomSites` | +| `AtomSiteAniso` | `AtomSiteAnisoCollection` | | `PdCwlDataPoint` | `PdCwlData` | | `PdTofDataPoint` | `PdTofData` | | `TotalDataPoint` | `TotalData` | @@ -806,7 +868,7 @@ project.structures['lbco'].atom_sites.create( fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.5, + adp_iso=0.5, occupancy=0.5, ) @@ -991,7 +1053,7 @@ Single-type categories (no public `_type` property): - **Experiment:** `diffrn`, `linked_crystal`, `excluded_regions`, `linked_phases`. -- **Structure:** `cell`, `space_group`, `atom_sites`. +- **Structure:** `cell`, `space_group`, `atom_sites`, `atom_site_aniso`. - **Analysis:** `aliases`, `constraints`. `fit_mode` has show methods (`show_supported_fit_mode_types()`, diff --git a/docs/architecture/cryspy-dwf-bug.md b/docs/architecture/cryspy-dwf-bug.md new file mode 100644 index 000000000..5f475ecc6 --- /dev/null +++ b/docs/architecture/cryspy-dwf-bug.md @@ -0,0 +1,126 @@ +# CrysPy Bug: Wrong Rotation Matrix Indices in `calc_power_dwf_aniso` + +## Summary + +`calc_power_dwf_aniso` in CrysPy 0.7.8 reads the rotation matrix from +the wrong slice of `reduced_symm_elems`, producing incorrect +Debye–Waller factors for every anisotropic atom. + +## Affected Version + +CrysPy **0.7.8** (and likely all versions sharing this code path). + +## Location + +`cryspy/A_functions_base/debye_waller_factor.py`, function +`calc_power_dwf_aniso`, around line 177. + +## Root Cause + +`reduced_symm_elems` has shape `(13, N_symmetry_operations)` with the +following layout per column: + +| Indices | Content | +| ------- | ----------------------------------- | +| 0–3 | Translation: $b_1, b_2, b_3, b_d$ | +| 4–12 | Rotation matrix $R$ (row-major 3×3) | + +The buggy code extracts the rotation matrix from indices **0–8** (i.e. +`symm_elems_r[0:9]`), which mixes the translation vector into the +rotation matrix: + +```python +# BUGGY (current code) +r_11, r_12, r_13 = symm_elems_r[0], symm_elems_r[1], symm_elems_r[2] +r_21, r_22, r_23 = symm_elems_r[3], symm_elems_r[4], symm_elems_r[5] +r_31, r_32, r_33 = symm_elems_r[6], symm_elems_r[7], symm_elems_r[8] +``` + +The correct indices are **4–12**: + +```python +# FIXED +r_11, r_12, r_13 = symm_elems_r[4], symm_elems_r[5], symm_elems_r[6] +r_21, r_22, r_23 = symm_elems_r[7], symm_elems_r[8], symm_elems_r[9] +r_31, r_32, r_33 = symm_elems_r[10], symm_elems_r[11], symm_elems_r[12] +``` + +For comparison, `calc_pr1` in the same codebase (structure factor phase +calculation) correctly uses indices 4–12 for the rotation. + +## Impact + +Every structure-factor calculation that uses anisotropic ADPs produces +wrong results. The isotropic DWF (`calc_power_dwf_iso`) is unaffected +and works correctly, so the bug only manifests when anisotropic +displacement parameters ($B_\text{ani}$ or $U_\text{ani}$) are used. + +## Verification + +We verified the fix by comparing isotropic and anisotropic calculations +for the LBCO structure (space group $I\,4/m\,m\,m$) where $B_\text{iso}$ +and the equivalent diagonal anisotropic tensor must give identical +$|F|^2$ values: + +| Metric | Buggy code | Patched code | +| --------------------------- | --------------------------- | ------------ | ------------------------------ | ---------------------- | +| $\max | y*\text{iso} - y*\text{ani} | $ | ~11 (first peak: 72.1 vs 61.0) | $1.78 \times 10^{-13}$ | +| $\chi^2$ (Biso) | 14.98 | 14.98 | +| $\chi^2$ (Bani, equivalent) | 184.10 | 14.98 | + +## Workaround + +Monkey-patch at import time (used in EasyDiffraction): + +```python +from cryspy.A_functions_base import debye_waller_factor as _dwf_mod + +def _patched_calc_power_dwf_aniso(index_hkl, beta, symm_elems_r, flag_beta=False): + b_11, b_22, b_33 = beta[0], beta[1], beta[2] + b_12, b_13, b_23 = beta[3], beta[4], beta[5] + h, k, l = index_hkl[0], index_hkl[1], index_hkl[2] + # Corrected indices: rotation starts at 4, not 0 + r_11, r_12, r_13 = symm_elems_r[4], symm_elems_r[5], symm_elems_r[6] + r_21, r_22, r_23 = symm_elems_r[7], symm_elems_r[8], symm_elems_r[9] + r_31, r_32, r_33 = symm_elems_r[10], symm_elems_r[11], symm_elems_r[12] + h_s = h * r_11 + k * r_21 + l * r_31 + k_s = h * r_12 + k * r_22 + l * r_32 + l_s = h * r_13 + k * r_23 + l * r_33 + power = ( + b_11 * np.square(h_s) + b_22 * np.square(k_s) + b_33 * np.square(l_s) + + 2.0 * b_12 * h_s * k_s + + 2.0 * b_13 * h_s * l_s + + 2.0 * b_23 * k_s * l_s + ) + dder = {} + if flag_beta: + ones_b = np.ones_like(b_11) + dder['beta'] = np.stack([ + ones_b * np.square(h_s), + ones_b * np.square(k_s), + ones_b * np.square(l_s), + ones_b * 2.0 * h_s * k_s, + ones_b * 2.0 * h_s * l_s, + ones_b * 2.0 * k_s * l_s, + ], axis=0) + return power, dder + +_dwf_mod.calc_power_dwf_aniso = _patched_calc_power_dwf_aniso +``` + +## Suggested Fix + +In `cryspy/A_functions_base/debye_waller_factor.py`, function +`calc_power_dwf_aniso`, change: + +```diff +- r_11, r_12, r_13 = symm_elems_r[0], symm_elems_r[1], symm_elems_r[2] +- r_21, r_22, r_23 = symm_elems_r[3], symm_elems_r[4], symm_elems_r[5] +- r_31, r_32, r_33 = symm_elems_r[6], symm_elems_r[7], symm_elems_r[8] ++ r_11, r_12, r_13 = symm_elems_r[4], symm_elems_r[5], symm_elems_r[6] ++ r_21, r_22, r_23 = symm_elems_r[7], symm_elems_r[8], symm_elems_r[9] ++ r_31, r_32, r_33 = symm_elems_r[10], symm_elems_r[11], symm_elems_r[12] +``` + +The same correction must be applied to the analytical-derivative branch +of the same function if it shares the same index convention. diff --git a/docs/architecture/package-structure-full.md b/docs/architecture/package-structure-full.md index c4bf5b5f1..3f16dadfd 100644 --- a/docs/architecture/package-structure-full.md +++ b/docs/architecture/package-structure-full.md @@ -279,11 +279,20 @@ │ │ └── 🏷️ class Experiments │ ├── 📁 structure │ │ ├── 📁 categories +│ │ │ ├── 📁 atom_site_aniso +│ │ │ │ ├── 📄 __init__.py +│ │ │ │ ├── 📄 default.py +│ │ │ │ │ ├── 🏷️ class AtomSiteAniso +│ │ │ │ │ └── 🏷️ class AtomSiteAnisoCollection +│ │ │ │ └── 📄 factory.py +│ │ │ │ └── 🏷️ class AtomSiteAnisoFactory │ │ │ ├── 📁 atom_sites │ │ │ │ ├── 📄 __init__.py │ │ │ │ ├── 📄 default.py │ │ │ │ │ ├── 🏷️ class AtomSite │ │ │ │ │ └── 🏷️ class AtomSites +│ │ │ │ ├── 📄 enums.py +│ │ │ │ │ └── 🏷️ class AdpTypeEnum │ │ │ │ └── 📄 factory.py │ │ │ │ └── 🏷️ class AtomSitesFactory │ │ │ ├── 📁 cell diff --git a/docs/architecture/package-structure-short.md b/docs/architecture/package-structure-short.md index 5c570ad9f..3fc6b860e 100644 --- a/docs/architecture/package-structure-short.md +++ b/docs/architecture/package-structure-short.md @@ -137,9 +137,14 @@ │ │ └── 📄 collection.py │ ├── 📁 structure │ │ ├── 📁 categories +│ │ │ ├── 📁 atom_site_aniso +│ │ │ │ ├── 📄 __init__.py +│ │ │ │ ├── 📄 default.py +│ │ │ │ └── 📄 factory.py │ │ │ ├── 📁 atom_sites │ │ │ │ ├── 📄 __init__.py │ │ │ │ ├── 📄 default.py +│ │ │ │ ├── 📄 enums.py │ │ │ │ └── 📄 factory.py │ │ │ ├── 📁 cell │ │ │ │ ├── 📄 __init__.py diff --git a/docs/docs/tutorials/ed-1.ipynb b/docs/docs/tutorials/ed-1.ipynb index 604fe72da..22b33c7ce 100644 --- a/docs/docs/tutorials/ed-1.ipynb +++ b/docs/docs/tutorials/ed-1.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ab0fa7f5", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Structure Refinement: LBCO, HRPT\n", @@ -44,7 +44,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -53,7 +53,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -62,7 +62,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Step 1: Define Project" @@ -71,7 +71,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -81,7 +81,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "## Step 2: Define Crystal Structure" @@ -90,7 +90,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -101,7 +101,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7", + "id": "8", "metadata": {}, "outputs": [], "source": [ @@ -111,7 +111,7 @@ }, { "cell_type": "markdown", - "id": "8", + "id": "9", "metadata": {}, "source": [ "## Step 3: Define Experiment" @@ -120,7 +120,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9", + "id": "10", "metadata": {}, "outputs": [], "source": [ @@ -131,7 +131,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -141,7 +141,7 @@ }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "## Step 4: Perform Analysis (no constraints)" @@ -150,7 +150,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -162,7 +162,7 @@ { "cell_type": "code", "execution_count": null, - "id": "13", + "id": "14", "metadata": {}, "outputs": [], "source": [ @@ -173,7 +173,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -183,7 +183,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "16", "metadata": {}, "source": [ "## Step 5: Perform Analysis (with constraints)" @@ -192,7 +192,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -205,11 +205,11 @@ "# define aliases and then use them to create a constraint.\n", "project.analysis.aliases.create(\n", " label='biso_La',\n", - " param=project.structures['lbco'].atom_sites['La'].b_iso,\n", + " param=project.structures['lbco'].atom_sites['La'].adp_iso,\n", ")\n", "project.analysis.aliases.create(\n", " label='biso_Ba',\n", - " param=project.structures['lbco'].atom_sites['Ba'].b_iso,\n", + " param=project.structures['lbco'].atom_sites['Ba'].adp_iso,\n", ")\n", "project.analysis.constraints.create(expression='biso_Ba = biso_La')" ] @@ -217,7 +217,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -229,7 +229,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -240,7 +240,7 @@ { "cell_type": "code", "execution_count": null, - "id": "19", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -251,7 +251,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -262,7 +262,7 @@ { "cell_type": "code", "execution_count": null, - "id": "21", + "id": "22", "metadata": {}, "outputs": [], "source": [ diff --git a/docs/docs/tutorials/ed-1.py b/docs/docs/tutorials/ed-1.py index 3fcd9aab7..fde60b0c9 100644 --- a/docs/docs/tutorials/ed-1.py +++ b/docs/docs/tutorials/ed-1.py @@ -80,11 +80,11 @@ # define aliases and then use them to create a constraint. project.analysis.aliases.create( label='biso_La', - param=project.structures['lbco'].atom_sites['La'].b_iso, + param=project.structures['lbco'].atom_sites['La'].adp_iso, ) project.analysis.aliases.create( label='biso_Ba', - param=project.structures['lbco'].atom_sites['Ba'].b_iso, + param=project.structures['lbco'].atom_sites['Ba'].adp_iso, ) project.analysis.constraints.create(expression='biso_Ba = biso_La') diff --git a/docs/docs/tutorials/ed-10.ipynb b/docs/docs/tutorials/ed-10.ipynb index b0cc149c4..d26ce4db3 100644 --- a/docs/docs/tutorials/ed-10.ipynb +++ b/docs/docs/tutorials/ed-10.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "dc88a9ac", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Pair Distribution Function: Ni, NPD\n", @@ -36,7 +36,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -45,7 +45,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -54,7 +54,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Create Project" @@ -63,7 +63,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -72,7 +72,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "## Add Structure" @@ -81,7 +81,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -91,7 +91,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7", + "id": "8", "metadata": {}, "outputs": [], "source": [ @@ -105,13 +105,13 @@ " fract_y=0.0,\n", " fract_z=0.0,\n", " wyckoff_letter='a',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")" ] }, { "cell_type": "markdown", - "id": "8", + "id": "9", "metadata": {}, "source": [ "## Add Experiment" @@ -120,7 +120,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9", + "id": "10", "metadata": {}, "outputs": [], "source": [ @@ -130,7 +130,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -147,7 +147,7 @@ { "cell_type": "code", "execution_count": null, - "id": "11", + "id": "12", "metadata": {}, "outputs": [], "source": [ @@ -162,7 +162,7 @@ }, { "cell_type": "markdown", - "id": "12", + "id": "13", "metadata": {}, "source": [ "## Select Fitting Parameters" @@ -171,18 +171,18 @@ { "cell_type": "code", "execution_count": null, - "id": "13", + "id": "14", "metadata": {}, "outputs": [], "source": [ "project.structures['ni'].cell.length_a.free = True\n", - "project.structures['ni'].atom_sites['Ni'].b_iso.free = True" + "project.structures['ni'].atom_sites['Ni'].adp_iso.free = True" ] }, { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -193,7 +193,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "16", "metadata": {}, "source": [ "## Run Fitting" @@ -202,17 +202,18 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ "project.analysis.fit()\n", - "project.analysis.display.fit_results()" + "project.analysis.display.fit_results()\n", + "project.plotter.plot_param_correlations()" ] }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "## Plot Measured vs Calculated" @@ -221,7 +222,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ diff --git a/docs/docs/tutorials/ed-10.py b/docs/docs/tutorials/ed-10.py index aafde761b..7586c1fbb 100644 --- a/docs/docs/tutorials/ed-10.py +++ b/docs/docs/tutorials/ed-10.py @@ -37,7 +37,7 @@ fract_y=0.0, fract_z=0.0, wyckoff_letter='a', - b_iso=0.5, + adp_iso=0.5, ) # %% [markdown] @@ -70,7 +70,7 @@ # %% project.structures['ni'].cell.length_a.free = True -project.structures['ni'].atom_sites['Ni'].b_iso.free = True +project.structures['ni'].atom_sites['Ni'].adp_iso.free = True # %% project.experiments['pdf'].linked_phases['ni'].scale.free = True @@ -83,6 +83,7 @@ # %% project.analysis.fit() project.analysis.display.fit_results() +project.plotter.plot_param_correlations() # %% [markdown] # ## Plot Measured vs Calculated diff --git a/docs/docs/tutorials/ed-11.ipynb b/docs/docs/tutorials/ed-11.ipynb index 7aba32c38..9eb951673 100644 --- a/docs/docs/tutorials/ed-11.ipynb +++ b/docs/docs/tutorials/ed-11.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9736040b", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Pair Distribution Function: Si, NPD\n", @@ -33,7 +33,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -42,7 +42,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -51,7 +51,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Create Project" @@ -60,7 +60,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -69,7 +69,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "## Set Plotting Engine" @@ -78,7 +78,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -90,7 +90,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7", + "id": "8", "metadata": {}, "outputs": [], "source": [ @@ -100,7 +100,7 @@ }, { "cell_type": "markdown", - "id": "8", + "id": "9", "metadata": {}, "source": [ "## Add Structure" @@ -109,7 +109,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9", + "id": "10", "metadata": {}, "outputs": [], "source": [ @@ -119,7 +119,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -134,13 +134,13 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")" ] }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "## Add Experiment" @@ -149,7 +149,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -159,7 +159,7 @@ { "cell_type": "code", "execution_count": null, - "id": "13", + "id": "14", "metadata": {}, "outputs": [], "source": [ @@ -176,7 +176,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -192,7 +192,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "16", "metadata": {}, "source": [ "## Select Fitting Parameters" @@ -201,19 +201,19 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ "project.structures['si'].cell.length_a.free = True\n", - "project.structures['si'].atom_sites['Si'].b_iso.free = True\n", + "project.structures['si'].atom_sites['Si'].adp_iso.free = True\n", "experiment.linked_phases['si'].scale.free = True" ] }, { "cell_type": "code", "execution_count": null, - "id": "17", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -225,7 +225,7 @@ }, { "cell_type": "markdown", - "id": "18", + "id": "19", "metadata": {}, "source": [ "## Run Fitting" @@ -234,17 +234,18 @@ { "cell_type": "code", "execution_count": null, - "id": "19", + "id": "20", "metadata": {}, "outputs": [], "source": [ "project.analysis.fit()\n", - "project.analysis.display.fit_results()" + "project.analysis.display.fit_results()\n", + "project.plotter.plot_param_correlations()" ] }, { "cell_type": "markdown", - "id": "20", + "id": "21", "metadata": {}, "source": [ "## Plot Measured vs Calculated" @@ -253,7 +254,7 @@ { "cell_type": "code", "execution_count": null, - "id": "21", + "id": "22", "metadata": {}, "outputs": [], "source": [ diff --git a/docs/docs/tutorials/ed-11.py b/docs/docs/tutorials/ed-11.py index 24d7795e8..795c31bfe 100644 --- a/docs/docs/tutorials/ed-11.py +++ b/docs/docs/tutorials/ed-11.py @@ -47,7 +47,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.5, + adp_iso=0.5, ) # %% [markdown] @@ -81,7 +81,7 @@ # %% project.structures['si'].cell.length_a.free = True -project.structures['si'].atom_sites['Si'].b_iso.free = True +project.structures['si'].atom_sites['Si'].adp_iso.free = True experiment.linked_phases['si'].scale.free = True # %% @@ -96,6 +96,7 @@ # %% project.analysis.fit() project.analysis.display.fit_results() +project.plotter.plot_param_correlations() # %% [markdown] # ## Plot Measured vs Calculated diff --git a/docs/docs/tutorials/ed-12.ipynb b/docs/docs/tutorials/ed-12.ipynb index 75d6c515c..0f4be8f4e 100644 --- a/docs/docs/tutorials/ed-12.ipynb +++ b/docs/docs/tutorials/ed-12.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "44960a4c", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Pair Distribution Function: NaCl, XRD\n", @@ -36,7 +36,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -45,7 +45,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -54,7 +54,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Create Project" @@ -63,7 +63,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -72,7 +72,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "## Set Plotting Engine" @@ -81,7 +81,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -93,7 +93,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7", + "id": "8", "metadata": {}, "outputs": [], "source": [ @@ -104,7 +104,7 @@ }, { "cell_type": "markdown", - "id": "8", + "id": "9", "metadata": {}, "source": [ "## Add Structure" @@ -113,7 +113,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9", + "id": "10", "metadata": {}, "outputs": [], "source": [ @@ -123,7 +123,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -137,7 +137,7 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=1.0,\n", + " adp_iso=1.0,\n", ")\n", "project.structures['nacl'].atom_sites.create(\n", " label='Cl',\n", @@ -146,13 +146,13 @@ " fract_y=0.5,\n", " fract_z=0.5,\n", " wyckoff_letter='b',\n", - " b_iso=1.0,\n", + " adp_iso=1.0,\n", ")" ] }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "## Add Experiment" @@ -161,7 +161,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -171,7 +171,7 @@ { "cell_type": "code", "execution_count": null, - "id": "13", + "id": "14", "metadata": {}, "outputs": [], "source": [ @@ -188,7 +188,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -198,7 +198,7 @@ { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -208,7 +208,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -218,7 +218,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -233,7 +233,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -242,7 +242,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "20", "metadata": {}, "source": [ "## Select Fitting Parameters" @@ -251,19 +251,19 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ "project.structures['nacl'].cell.length_a.free = True\n", - "project.structures['nacl'].atom_sites['Na'].b_iso.free = True\n", - "project.structures['nacl'].atom_sites['Cl'].b_iso.free = True" + "project.structures['nacl'].atom_sites['Na'].adp_iso.free = True\n", + "project.structures['nacl'].atom_sites['Cl'].adp_iso.free = True" ] }, { "cell_type": "code", "execution_count": null, - "id": "21", + "id": "22", "metadata": {}, "outputs": [], "source": [ @@ -274,7 +274,7 @@ }, { "cell_type": "markdown", - "id": "22", + "id": "23", "metadata": {}, "source": [ "## Run Fitting" @@ -283,17 +283,18 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "24", "metadata": {}, "outputs": [], "source": [ "project.analysis.fit()\n", - "project.analysis.display.fit_results()" + "project.analysis.display.fit_results()\n", + "project.plotter.plot_param_correlations()" ] }, { "cell_type": "markdown", - "id": "24", + "id": "25", "metadata": {}, "source": [ "## Plot Measured vs Calculated" @@ -302,7 +303,7 @@ { "cell_type": "code", "execution_count": null, - "id": "25", + "id": "26", "metadata": {}, "outputs": [], "source": [ diff --git a/docs/docs/tutorials/ed-12.py b/docs/docs/tutorials/ed-12.py index d14c42fe1..e6d4d94fa 100644 --- a/docs/docs/tutorials/ed-12.py +++ b/docs/docs/tutorials/ed-12.py @@ -50,7 +50,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=1.0, + adp_iso=1.0, ) project.structures['nacl'].atom_sites.create( label='Cl', @@ -59,7 +59,7 @@ fract_y=0.5, fract_z=0.5, wyckoff_letter='b', - b_iso=1.0, + adp_iso=1.0, ) # %% [markdown] @@ -103,8 +103,8 @@ # %% project.structures['nacl'].cell.length_a.free = True -project.structures['nacl'].atom_sites['Na'].b_iso.free = True -project.structures['nacl'].atom_sites['Cl'].b_iso.free = True +project.structures['nacl'].atom_sites['Na'].adp_iso.free = True +project.structures['nacl'].atom_sites['Cl'].adp_iso.free = True # %% project.experiments['xray_pdf'].linked_phases['nacl'].scale.free = True @@ -117,6 +117,7 @@ # %% project.analysis.fit() project.analysis.display.fit_results() +project.plotter.plot_param_correlations() # %% [markdown] # ## Plot Measured vs Calculated diff --git a/docs/docs/tutorials/ed-13.ipynb b/docs/docs/tutorials/ed-13.ipynb index 254d49e00..2794df54f 100644 --- a/docs/docs/tutorials/ed-13.ipynb +++ b/docs/docs/tutorials/ed-13.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1ac207fe", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Fitting Powder Diffraction data\n", @@ -55,7 +55,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "📖 See\n", @@ -67,7 +67,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -76,7 +76,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## 📘 Introduction: Simple Reference Fit – Si\n", @@ -103,7 +103,7 @@ }, { "cell_type": "markdown", - "id": "4", + "id": "5", "metadata": {}, "source": [ "📖 See\n", @@ -115,7 +115,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5", + "id": "6", "metadata": {}, "outputs": [], "source": [ @@ -124,7 +124,7 @@ }, { "cell_type": "markdown", - "id": "6", + "id": "7", "metadata": {}, "source": [ "You can set the title and description of the project to provide\n", @@ -136,7 +136,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7", + "id": "8", "metadata": {}, "outputs": [], "source": [ @@ -146,7 +146,7 @@ }, { "cell_type": "markdown", - "id": "8", + "id": "9", "metadata": {}, "source": [ "### 🔬 Create an Experiment\n", @@ -159,7 +159,7 @@ }, { "cell_type": "markdown", - "id": "9", + "id": "10", "metadata": {}, "source": [ "📖 See\n", @@ -171,7 +171,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -182,7 +182,7 @@ }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "Uncomment the following cell if your data reduction failed and the\n", @@ -196,7 +196,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -205,7 +205,7 @@ }, { "cell_type": "markdown", - "id": "13", + "id": "14", "metadata": {}, "source": [ "Now we can create the experiment and load the measured data. In this\n", @@ -217,7 +217,7 @@ }, { "cell_type": "markdown", - "id": "14", + "id": "15", "metadata": {}, "source": [ "📖 See\n", @@ -228,7 +228,7 @@ { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -243,7 +243,7 @@ }, { "cell_type": "markdown", - "id": "16", + "id": "17", "metadata": {}, "source": [ "#### Inspect Measured Data\n", @@ -259,7 +259,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "📖 See\n", @@ -273,7 +273,7 @@ }, { "cell_type": "markdown", - "id": "18", + "id": "19", "metadata": {}, "source": [ "📖 See\n", @@ -284,7 +284,7 @@ { "cell_type": "code", "execution_count": null, - "id": "19", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -296,7 +296,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -305,7 +305,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "If you zoom in on the highest TOF peak (around 120,000 μs), you will\n", @@ -328,7 +328,7 @@ }, { "cell_type": "markdown", - "id": "22", + "id": "23", "metadata": {}, "source": [ "📖 See\n", @@ -339,7 +339,7 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -349,7 +349,7 @@ }, { "cell_type": "markdown", - "id": "24", + "id": "25", "metadata": {}, "source": [ "To visualize the effect of excluding the high TOF region, we can plot\n", @@ -360,7 +360,7 @@ { "cell_type": "code", "execution_count": null, - "id": "25", + "id": "26", "metadata": {}, "outputs": [], "source": [ @@ -369,7 +369,7 @@ }, { "cell_type": "markdown", - "id": "26", + "id": "27", "metadata": {}, "source": [ "#### Set Instrument Parameters\n", @@ -392,7 +392,7 @@ }, { "cell_type": "markdown", - "id": "27", + "id": "28", "metadata": {}, "source": [ "📖 See\n", @@ -403,7 +403,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -417,7 +417,7 @@ }, { "cell_type": "markdown", - "id": "29", + "id": "30", "metadata": {}, "source": [ "Before proceeding, let's take a quick look at the concept of\n", @@ -437,7 +437,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -446,7 +446,7 @@ }, { "cell_type": "markdown", - "id": "31", + "id": "32", "metadata": {}, "source": [ "The `value` attribute represents the current value of the parameter as\n", @@ -460,7 +460,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -469,7 +469,7 @@ }, { "cell_type": "markdown", - "id": "33", + "id": "34", "metadata": {}, "source": [ "Note that to set the value of the parameter, you can simply assign a\n", @@ -479,7 +479,7 @@ }, { "cell_type": "markdown", - "id": "34", + "id": "35", "metadata": {}, "source": [ "📖 See\n", @@ -490,15 +490,14 @@ }, { "cell_type": "markdown", - "id": "35", + "id": "36", "metadata": {}, "source": [ "#### Set Peak Profile Parameters\n", "\n", "The next set of parameters is needed to define the peak profile used\n", "in the fitting process. The peak profile describes the shape of the\n", - "diffraction peaks. They include parameters for the broadening and\n", - "asymmetry of the peaks.\n", + "diffraction peaks.\n", "\n", "There are several commonly used peak profile functions:\n", "- **Gaussian**: Describes peaks with a symmetric bell-shaped curve,\n", @@ -532,7 +531,7 @@ }, { "cell_type": "markdown", - "id": "36", + "id": "37", "metadata": {}, "source": [ "📖 See\n", @@ -543,23 +542,23 @@ { "cell_type": "code", "execution_count": null, - "id": "37", + "id": "38", "metadata": {}, "outputs": [], "source": [ - "project_1.experiments['sim_si'].peak_profile_type = 'pseudo-voigt * ikeda-carpenter'\n", + "project_1.experiments['sim_si'].peak_profile_type = 'jorgensen'\n", "project_1.experiments['sim_si'].peak.broad_gauss_sigma_0 = 69498\n", "project_1.experiments['sim_si'].peak.broad_gauss_sigma_1 = -55578\n", "project_1.experiments['sim_si'].peak.broad_gauss_sigma_2 = 14560\n", - "project_1.experiments['sim_si'].peak.broad_mix_beta_0 = 0.0019\n", - "project_1.experiments['sim_si'].peak.broad_mix_beta_1 = 0.0137\n", - "project_1.experiments['sim_si'].peak.asym_alpha_0 = -0.0055\n", - "project_1.experiments['sim_si'].peak.asym_alpha_1 = 0.0147" + "project_1.experiments['sim_si'].peak.exp_decay_beta_0 = 0.0019\n", + "project_1.experiments['sim_si'].peak.exp_decay_beta_1 = 0.0137\n", + "project_1.experiments['sim_si'].peak.exp_rise_alpha_0 = -0.0055\n", + "project_1.experiments['sim_si'].peak.exp_rise_alpha_1 = 0.0147" ] }, { "cell_type": "markdown", - "id": "38", + "id": "39", "metadata": {}, "source": [ "#### Set Background\n", @@ -594,7 +593,7 @@ }, { "cell_type": "markdown", - "id": "39", + "id": "40", "metadata": {}, "source": [ "📖 See\n", @@ -605,7 +604,7 @@ { "cell_type": "code", "execution_count": null, - "id": "40", + "id": "41", "metadata": {}, "outputs": [], "source": [ @@ -621,7 +620,7 @@ }, { "cell_type": "markdown", - "id": "41", + "id": "42", "metadata": {}, "source": [ "### 🧩 Create a Structure – Si\n", @@ -664,7 +663,7 @@ }, { "cell_type": "markdown", - "id": "42", + "id": "43", "metadata": {}, "source": [ "📖 See\n", @@ -674,7 +673,7 @@ }, { "cell_type": "markdown", - "id": "43", + "id": "44", "metadata": {}, "source": [ "```\n", @@ -706,7 +705,7 @@ }, { "cell_type": "markdown", - "id": "44", + "id": "45", "metadata": {}, "source": [ "As with adding the experiment in the previous step, we will create a\n", @@ -716,7 +715,7 @@ }, { "cell_type": "markdown", - "id": "45", + "id": "46", "metadata": {}, "source": [ "📖 See\n", @@ -727,7 +726,7 @@ }, { "cell_type": "markdown", - "id": "46", + "id": "47", "metadata": {}, "source": [ "#### Add Structure" @@ -736,7 +735,7 @@ { "cell_type": "code", "execution_count": null, - "id": "47", + "id": "48", "metadata": {}, "outputs": [], "source": [ @@ -745,7 +744,7 @@ }, { "cell_type": "markdown", - "id": "48", + "id": "49", "metadata": {}, "source": [ "#### Set Space Group" @@ -753,7 +752,7 @@ }, { "cell_type": "markdown", - "id": "49", + "id": "50", "metadata": {}, "source": [ "📖 See\n", @@ -764,7 +763,7 @@ { "cell_type": "code", "execution_count": null, - "id": "50", + "id": "51", "metadata": {}, "outputs": [], "source": [ @@ -774,7 +773,7 @@ }, { "cell_type": "markdown", - "id": "51", + "id": "52", "metadata": {}, "source": [ "#### Set Lattice Parameters" @@ -782,7 +781,7 @@ }, { "cell_type": "markdown", - "id": "52", + "id": "53", "metadata": {}, "source": [ "📖 See\n", @@ -793,7 +792,7 @@ { "cell_type": "code", "execution_count": null, - "id": "53", + "id": "54", "metadata": {}, "outputs": [], "source": [ @@ -802,7 +801,7 @@ }, { "cell_type": "markdown", - "id": "54", + "id": "55", "metadata": {}, "source": [ "#### Set Atom Sites" @@ -810,7 +809,7 @@ }, { "cell_type": "markdown", - "id": "55", + "id": "56", "metadata": {}, "source": [ "📖 See\n", @@ -821,7 +820,7 @@ { "cell_type": "code", "execution_count": null, - "id": "56", + "id": "57", "metadata": {}, "outputs": [], "source": [ @@ -832,13 +831,13 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=0.89,\n", + " adp_iso=0.89,\n", ")" ] }, { "cell_type": "markdown", - "id": "57", + "id": "58", "metadata": {}, "source": [ "### 🔗 Assign Structure to Experiment\n", @@ -851,7 +850,7 @@ }, { "cell_type": "markdown", - "id": "58", + "id": "59", "metadata": {}, "source": [ "📖 See\n", @@ -862,7 +861,7 @@ { "cell_type": "code", "execution_count": null, - "id": "59", + "id": "60", "metadata": {}, "outputs": [], "source": [ @@ -871,7 +870,7 @@ }, { "cell_type": "markdown", - "id": "60", + "id": "61", "metadata": {}, "source": [ "### 🚀 Analyze and Fit the Data\n", @@ -893,7 +892,7 @@ }, { "cell_type": "markdown", - "id": "61", + "id": "62", "metadata": { "title": "**Reminder:**" }, @@ -910,7 +909,7 @@ }, { "cell_type": "markdown", - "id": "62", + "id": "63", "metadata": {}, "source": [ "📖 See\n", @@ -920,7 +919,7 @@ }, { "cell_type": "markdown", - "id": "63", + "id": "64", "metadata": {}, "source": [ "#### Set Fit Parameters\n", @@ -943,7 +942,7 @@ { "cell_type": "code", "execution_count": null, - "id": "64", + "id": "65", "metadata": {}, "outputs": [], "source": [ @@ -955,15 +954,15 @@ "project_1.experiments['sim_si'].peak.broad_gauss_sigma_0.free = True\n", "project_1.experiments['sim_si'].peak.broad_gauss_sigma_1.free = True\n", "project_1.experiments['sim_si'].peak.broad_gauss_sigma_2.free = True\n", - "project_1.experiments['sim_si'].peak.broad_mix_beta_0.free = True\n", - "project_1.experiments['sim_si'].peak.broad_mix_beta_1.free = True\n", - "project_1.experiments['sim_si'].peak.asym_alpha_0.free = True\n", - "project_1.experiments['sim_si'].peak.asym_alpha_1.free = True" + "project_1.experiments['sim_si'].peak.exp_decay_beta_0.free = True\n", + "project_1.experiments['sim_si'].peak.exp_decay_beta_1.free = True\n", + "project_1.experiments['sim_si'].peak.exp_rise_alpha_0.free = True\n", + "project_1.experiments['sim_si'].peak.exp_rise_alpha_1.free = True" ] }, { "cell_type": "markdown", - "id": "65", + "id": "66", "metadata": {}, "source": [ "#### Show Free Parameters\n", @@ -974,7 +973,7 @@ }, { "cell_type": "markdown", - "id": "66", + "id": "67", "metadata": {}, "source": [ "📖 See\n", @@ -988,7 +987,7 @@ { "cell_type": "code", "execution_count": null, - "id": "67", + "id": "68", "metadata": {}, "outputs": [], "source": [ @@ -997,7 +996,7 @@ }, { "cell_type": "markdown", - "id": "68", + "id": "69", "metadata": {}, "source": [ "#### Visualize Diffraction Patterns\n", @@ -1013,7 +1012,7 @@ { "cell_type": "code", "execution_count": null, - "id": "69", + "id": "70", "metadata": {}, "outputs": [], "source": [ @@ -1022,7 +1021,7 @@ }, { "cell_type": "markdown", - "id": "70", + "id": "71", "metadata": {}, "source": [ "#### Run Fitting\n", @@ -1033,7 +1032,7 @@ }, { "cell_type": "markdown", - "id": "71", + "id": "72", "metadata": {}, "source": [ "📖 See\n", @@ -1044,7 +1043,7 @@ { "cell_type": "code", "execution_count": null, - "id": "72", + "id": "73", "metadata": {}, "outputs": [], "source": [ @@ -1054,7 +1053,7 @@ }, { "cell_type": "markdown", - "id": "73", + "id": "74", "metadata": {}, "source": [ "#### Check Fit Results\n", @@ -1073,7 +1072,7 @@ }, { "cell_type": "markdown", - "id": "74", + "id": "75", "metadata": {}, "source": [ "#### Visualize Fit Results\n", @@ -1087,7 +1086,7 @@ { "cell_type": "code", "execution_count": null, - "id": "75", + "id": "76", "metadata": {}, "outputs": [], "source": [ @@ -1096,7 +1095,7 @@ }, { "cell_type": "markdown", - "id": "76", + "id": "77", "metadata": {}, "source": [ "#### TOF vs d-spacing\n", @@ -1130,7 +1129,7 @@ { "cell_type": "code", "execution_count": null, - "id": "77", + "id": "78", "metadata": {}, "outputs": [], "source": [ @@ -1139,7 +1138,7 @@ }, { "cell_type": "markdown", - "id": "78", + "id": "79", "metadata": {}, "source": [ "As you can see, the calculated diffraction pattern now matches the\n", @@ -1165,7 +1164,7 @@ { "cell_type": "code", "execution_count": null, - "id": "79", + "id": "80", "metadata": {}, "outputs": [], "source": [ @@ -1174,7 +1173,7 @@ }, { "cell_type": "markdown", - "id": "80", + "id": "81", "metadata": {}, "source": [ "## 💪 Exercise: Complex Fit – LBCO\n", @@ -1195,7 +1194,7 @@ }, { "cell_type": "markdown", - "id": "81", + "id": "82", "metadata": {}, "source": [ "**Hint:**" @@ -1203,7 +1202,7 @@ }, { "cell_type": "markdown", - "id": "82", + "id": "83", "metadata": {}, "source": [ "You can use the same approach as in the previous part of the notebook,\n", @@ -1212,7 +1211,7 @@ }, { "cell_type": "markdown", - "id": "83", + "id": "84", "metadata": {}, "source": [ "**Solution:**" @@ -1221,7 +1220,7 @@ { "cell_type": "code", "execution_count": null, - "id": "84", + "id": "85", "metadata": {}, "outputs": [], "source": [ @@ -1232,7 +1231,7 @@ }, { "cell_type": "markdown", - "id": "85", + "id": "86", "metadata": {}, "source": [ "### 🔬 Exercise 2: Define an Experiment\n", @@ -1245,7 +1244,7 @@ }, { "cell_type": "markdown", - "id": "86", + "id": "87", "metadata": {}, "source": [ "**Hint:**" @@ -1253,7 +1252,7 @@ }, { "cell_type": "markdown", - "id": "87", + "id": "88", "metadata": {}, "source": [ "You can use the same approach as in the previous part of the notebook,\n", @@ -1262,7 +1261,7 @@ }, { "cell_type": "markdown", - "id": "88", + "id": "89", "metadata": {}, "source": [ "**Solution:**" @@ -1271,7 +1270,7 @@ { "cell_type": "code", "execution_count": null, - "id": "89", + "id": "90", "metadata": {}, "outputs": [], "source": [ @@ -1294,7 +1293,7 @@ }, { "cell_type": "markdown", - "id": "90", + "id": "91", "metadata": {}, "source": [ "#### Exercise 2.1: Inspect Measured Data\n", @@ -1306,7 +1305,7 @@ }, { "cell_type": "markdown", - "id": "91", + "id": "92", "metadata": {}, "source": [ "**Hint:**" @@ -1314,7 +1313,7 @@ }, { "cell_type": "markdown", - "id": "92", + "id": "93", "metadata": {}, "source": [ "You can use the `plot_meas` method of the project to visualize the\n", @@ -1325,7 +1324,7 @@ }, { "cell_type": "markdown", - "id": "93", + "id": "94", "metadata": {}, "source": [ "**Solution:**" @@ -1334,7 +1333,7 @@ { "cell_type": "code", "execution_count": null, - "id": "94", + "id": "95", "metadata": {}, "outputs": [], "source": [ @@ -1348,7 +1347,7 @@ }, { "cell_type": "markdown", - "id": "95", + "id": "96", "metadata": {}, "source": [ "#### Exercise 2.2: Set Instrument Parameters\n", @@ -1358,7 +1357,7 @@ }, { "cell_type": "markdown", - "id": "96", + "id": "97", "metadata": {}, "source": [ "**Hint:**" @@ -1366,7 +1365,7 @@ }, { "cell_type": "markdown", - "id": "97", + "id": "98", "metadata": {}, "source": [ "Use the values from the data reduction process for the LBCO and\n", @@ -1375,7 +1374,7 @@ }, { "cell_type": "markdown", - "id": "98", + "id": "99", "metadata": {}, "source": [ "**Solution:**" @@ -1384,7 +1383,7 @@ { "cell_type": "code", "execution_count": null, - "id": "99", + "id": "100", "metadata": {}, "outputs": [], "source": [ @@ -1398,7 +1397,7 @@ }, { "cell_type": "markdown", - "id": "100", + "id": "101", "metadata": {}, "source": [ "#### Exercise 2.3: Set Peak Profile Parameters\n", @@ -1408,7 +1407,7 @@ }, { "cell_type": "markdown", - "id": "101", + "id": "102", "metadata": {}, "source": [ "**Hint:**" @@ -1416,7 +1415,7 @@ }, { "cell_type": "markdown", - "id": "102", + "id": "103", "metadata": {}, "source": [ "Use the values from the\n", @@ -1428,7 +1427,7 @@ }, { "cell_type": "markdown", - "id": "103", + "id": "104", "metadata": {}, "source": [ "**Solution:**" @@ -1437,25 +1436,25 @@ { "cell_type": "code", "execution_count": null, - "id": "104", + "id": "105", "metadata": {}, "outputs": [], "source": [ "# # Create a reference to the peak profile parameters from the Si\n", "sim_si_peak = project_1.experiments['sim_si'].peak\n", - "project_2.experiments['sim_lbco'].peak_profile_type = 'pseudo-voigt * ikeda-carpenter'\n", + "project_2.experiments['sim_lbco'].peak_profile_type = 'jorgensen'\n", "project_2.experiments['sim_lbco'].peak.broad_gauss_sigma_0 = sim_si_peak.broad_gauss_sigma_0.value\n", "project_2.experiments['sim_lbco'].peak.broad_gauss_sigma_1 = sim_si_peak.broad_gauss_sigma_1.value\n", "project_2.experiments['sim_lbco'].peak.broad_gauss_sigma_2 = sim_si_peak.broad_gauss_sigma_2.value\n", - "project_2.experiments['sim_lbco'].peak.broad_mix_beta_0 = sim_si_peak.broad_mix_beta_0.value\n", - "project_2.experiments['sim_lbco'].peak.broad_mix_beta_1 = sim_si_peak.broad_mix_beta_1.value\n", - "project_2.experiments['sim_lbco'].peak.asym_alpha_0 = sim_si_peak.asym_alpha_0.value\n", - "project_2.experiments['sim_lbco'].peak.asym_alpha_1 = sim_si_peak.asym_alpha_1.value" + "project_2.experiments['sim_lbco'].peak.exp_decay_beta_0 = sim_si_peak.exp_decay_beta_0.value\n", + "project_2.experiments['sim_lbco'].peak.exp_decay_beta_1 = sim_si_peak.exp_decay_beta_1.value\n", + "project_2.experiments['sim_lbco'].peak.exp_rise_alpha_0 = sim_si_peak.exp_rise_alpha_0.value\n", + "project_2.experiments['sim_lbco'].peak.exp_rise_alpha_1 = sim_si_peak.exp_rise_alpha_1.value" ] }, { "cell_type": "markdown", - "id": "105", + "id": "106", "metadata": {}, "source": [ "#### Exercise 2.4: Set Background\n", @@ -1466,7 +1465,7 @@ }, { "cell_type": "markdown", - "id": "106", + "id": "107", "metadata": {}, "source": [ "**Hint:**" @@ -1474,7 +1473,7 @@ }, { "cell_type": "markdown", - "id": "107", + "id": "108", "metadata": {}, "source": [ "Use the same approach as in the previous part of the notebook, but\n", @@ -1485,7 +1484,7 @@ }, { "cell_type": "markdown", - "id": "108", + "id": "109", "metadata": {}, "source": [ "**Solution:**" @@ -1494,7 +1493,7 @@ { "cell_type": "code", "execution_count": null, - "id": "109", + "id": "110", "metadata": {}, "outputs": [], "source": [ @@ -1510,7 +1509,7 @@ }, { "cell_type": "markdown", - "id": "110", + "id": "111", "metadata": {}, "source": [ "### 🧩 Exercise 3: Define a Structure – LBCO\n", @@ -1526,7 +1525,7 @@ }, { "cell_type": "markdown", - "id": "111", + "id": "112", "metadata": {}, "source": [ "```\n", @@ -1561,7 +1560,7 @@ }, { "cell_type": "markdown", - "id": "112", + "id": "113", "metadata": {}, "source": [ "Note that the `occupancy` of the La and Ba atoms is 0.5\n", @@ -1591,7 +1590,7 @@ }, { "cell_type": "markdown", - "id": "113", + "id": "114", "metadata": {}, "source": [ "#### Exercise 3.1: Create Structure\n", @@ -1602,7 +1601,7 @@ }, { "cell_type": "markdown", - "id": "114", + "id": "115", "metadata": {}, "source": [ "**Hint:**" @@ -1610,7 +1609,7 @@ }, { "cell_type": "markdown", - "id": "115", + "id": "116", "metadata": {}, "source": [ "You can use the same approach as in the previous part of the notebook,\n", @@ -1620,7 +1619,7 @@ }, { "cell_type": "markdown", - "id": "116", + "id": "117", "metadata": {}, "source": [ "**Solution:**" @@ -1629,7 +1628,7 @@ { "cell_type": "code", "execution_count": null, - "id": "117", + "id": "118", "metadata": {}, "outputs": [], "source": [ @@ -1638,7 +1637,7 @@ }, { "cell_type": "markdown", - "id": "118", + "id": "119", "metadata": {}, "source": [ "#### Exercise 3.2: Set Space Group\n", @@ -1648,7 +1647,7 @@ }, { "cell_type": "markdown", - "id": "119", + "id": "120", "metadata": {}, "source": [ "**Hint:**" @@ -1656,7 +1655,7 @@ }, { "cell_type": "markdown", - "id": "120", + "id": "121", "metadata": {}, "source": [ "Use the space group name and IT coordinate system code from the CIF\n", @@ -1665,7 +1664,7 @@ }, { "cell_type": "markdown", - "id": "121", + "id": "122", "metadata": {}, "source": [ "**Solution:**" @@ -1674,7 +1673,7 @@ { "cell_type": "code", "execution_count": null, - "id": "122", + "id": "123", "metadata": {}, "outputs": [], "source": [ @@ -1684,7 +1683,7 @@ }, { "cell_type": "markdown", - "id": "123", + "id": "124", "metadata": {}, "source": [ "#### Exercise 3.3: Set Lattice Parameters\n", @@ -1694,7 +1693,7 @@ }, { "cell_type": "markdown", - "id": "124", + "id": "125", "metadata": {}, "source": [ "**Hint:**" @@ -1702,7 +1701,7 @@ }, { "cell_type": "markdown", - "id": "125", + "id": "126", "metadata": {}, "source": [ "Use the lattice parameters from the CIF data." @@ -1710,7 +1709,7 @@ }, { "cell_type": "markdown", - "id": "126", + "id": "127", "metadata": {}, "source": [ "**Solution:**" @@ -1719,7 +1718,7 @@ { "cell_type": "code", "execution_count": null, - "id": "127", + "id": "128", "metadata": {}, "outputs": [], "source": [ @@ -1728,7 +1727,7 @@ }, { "cell_type": "markdown", - "id": "128", + "id": "129", "metadata": {}, "source": [ "#### Exercise 3.4: Set Atom Sites\n", @@ -1738,7 +1737,7 @@ }, { "cell_type": "markdown", - "id": "129", + "id": "130", "metadata": {}, "source": [ "**Hint:**" @@ -1746,7 +1745,7 @@ }, { "cell_type": "markdown", - "id": "130", + "id": "131", "metadata": {}, "source": [ "Use the atom sites from the CIF data. You can use the `add` method of\n", @@ -1755,7 +1754,7 @@ }, { "cell_type": "markdown", - "id": "131", + "id": "132", "metadata": {}, "source": [ "**Solution:**" @@ -1764,7 +1763,7 @@ { "cell_type": "code", "execution_count": null, - "id": "132", + "id": "133", "metadata": {}, "outputs": [], "source": [ @@ -1775,7 +1774,7 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=0.95,\n", + " adp_iso=0.95,\n", " occupancy=0.5,\n", ")\n", "project_2.structures['lbco'].atom_sites.create(\n", @@ -1785,7 +1784,7 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=0.95,\n", + " adp_iso=0.95,\n", " occupancy=0.5,\n", ")\n", "project_2.structures['lbco'].atom_sites.create(\n", @@ -1795,7 +1794,7 @@ " fract_y=0.5,\n", " fract_z=0.5,\n", " wyckoff_letter='b',\n", - " b_iso=0.80,\n", + " adp_iso=0.80,\n", ")\n", "project_2.structures['lbco'].atom_sites.create(\n", " label='O',\n", @@ -1804,13 +1803,13 @@ " fract_y=0.5,\n", " fract_z=0.5,\n", " wyckoff_letter='c',\n", - " b_iso=1.66,\n", + " adp_iso=1.66,\n", ")" ] }, { "cell_type": "markdown", - "id": "133", + "id": "134", "metadata": {}, "source": [ "### 🔗 Exercise 4: Assign Structure to Experiment\n", @@ -1820,7 +1819,7 @@ }, { "cell_type": "markdown", - "id": "134", + "id": "135", "metadata": {}, "source": [ "**Hint:**" @@ -1828,7 +1827,7 @@ }, { "cell_type": "markdown", - "id": "135", + "id": "136", "metadata": {}, "source": [ "Use the `linked_phases` attribute of the experiment to link the\n", @@ -1837,7 +1836,7 @@ }, { "cell_type": "markdown", - "id": "136", + "id": "137", "metadata": {}, "source": [ "**Solution:**" @@ -1846,7 +1845,7 @@ { "cell_type": "code", "execution_count": null, - "id": "137", + "id": "138", "metadata": {}, "outputs": [], "source": [ @@ -1855,7 +1854,7 @@ }, { "cell_type": "markdown", - "id": "138", + "id": "139", "metadata": {}, "source": [ "### 🚀 Exercise 5: Analyze and Fit the Data\n", @@ -1868,7 +1867,7 @@ }, { "cell_type": "markdown", - "id": "139", + "id": "140", "metadata": {}, "source": [ "**Hint:**" @@ -1876,7 +1875,7 @@ }, { "cell_type": "markdown", - "id": "140", + "id": "141", "metadata": {}, "source": [ "You can start with the scale factor and the background points, as in\n", @@ -1885,7 +1884,7 @@ }, { "cell_type": "markdown", - "id": "141", + "id": "142", "metadata": {}, "source": [ "**Solution:**" @@ -1894,7 +1893,7 @@ { "cell_type": "code", "execution_count": null, - "id": "142", + "id": "143", "metadata": {}, "outputs": [], "source": [ @@ -1906,7 +1905,7 @@ }, { "cell_type": "markdown", - "id": "143", + "id": "144", "metadata": {}, "source": [ "#### Exercise 5.2: Run Fitting\n", @@ -1917,7 +1916,7 @@ }, { "cell_type": "markdown", - "id": "144", + "id": "145", "metadata": {}, "source": [ "**Hint:**" @@ -1925,7 +1924,7 @@ }, { "cell_type": "markdown", - "id": "145", + "id": "146", "metadata": {}, "source": [ "Use the `plot_meas_vs_calc` method of the project to visualize the\n", @@ -1936,7 +1935,7 @@ }, { "cell_type": "markdown", - "id": "146", + "id": "147", "metadata": {}, "source": [ "**Solution:**" @@ -1945,7 +1944,7 @@ { "cell_type": "code", "execution_count": null, - "id": "147", + "id": "148", "metadata": {}, "outputs": [], "source": [ @@ -1957,7 +1956,7 @@ }, { "cell_type": "markdown", - "id": "148", + "id": "149", "metadata": {}, "source": [ "#### Exercise 5.3: Find the Misfit in the Fit\n", @@ -1972,7 +1971,7 @@ }, { "cell_type": "markdown", - "id": "149", + "id": "150", "metadata": {}, "source": [ "**Hint:**" @@ -1980,7 +1979,7 @@ }, { "cell_type": "markdown", - "id": "150", + "id": "151", "metadata": {}, "source": [ "Consider the following options:\n", @@ -1992,7 +1991,7 @@ }, { "cell_type": "markdown", - "id": "151", + "id": "152", "metadata": {}, "source": [ "**Solution:**" @@ -2000,7 +1999,7 @@ }, { "cell_type": "markdown", - "id": "152", + "id": "153", "metadata": {}, "source": [ "\n", @@ -2022,7 +2021,7 @@ { "cell_type": "code", "execution_count": null, - "id": "153", + "id": "154", "metadata": {}, "outputs": [], "source": [ @@ -2031,7 +2030,7 @@ }, { "cell_type": "markdown", - "id": "154", + "id": "155", "metadata": {}, "source": [ "#### Exercise 5.4: Refine the LBCO Lattice Parameter\n", @@ -2041,7 +2040,7 @@ }, { "cell_type": "markdown", - "id": "155", + "id": "156", "metadata": {}, "source": [ "**Hint:**" @@ -2049,7 +2048,7 @@ }, { "cell_type": "markdown", - "id": "156", + "id": "157", "metadata": {}, "source": [ "To achieve this, we will set the `free` attribute of the `length_a`\n", @@ -2064,7 +2063,7 @@ }, { "cell_type": "markdown", - "id": "157", + "id": "158", "metadata": {}, "source": [ "**Solution:**" @@ -2073,7 +2072,7 @@ { "cell_type": "code", "execution_count": null, - "id": "158", + "id": "159", "metadata": {}, "outputs": [], "source": [ @@ -2087,7 +2086,7 @@ }, { "cell_type": "markdown", - "id": "159", + "id": "160", "metadata": {}, "source": [ "One of the main goals of this study was to refine the lattice\n", @@ -2100,7 +2099,7 @@ }, { "cell_type": "markdown", - "id": "160", + "id": "161", "metadata": {}, "source": [ "#### Exercise 5.5: Visualize the Fit Results in d-spacing\n", @@ -2111,7 +2110,7 @@ }, { "cell_type": "markdown", - "id": "161", + "id": "162", "metadata": {}, "source": [ "**Hint:**" @@ -2119,7 +2118,7 @@ }, { "cell_type": "markdown", - "id": "162", + "id": "163", "metadata": {}, "source": [ "Use the `plot_meas_vs_calc` method of the project and set the\n", @@ -2128,7 +2127,7 @@ }, { "cell_type": "markdown", - "id": "163", + "id": "164", "metadata": {}, "source": [ "**Solution:**" @@ -2137,7 +2136,7 @@ { "cell_type": "code", "execution_count": null, - "id": "164", + "id": "165", "metadata": {}, "outputs": [], "source": [ @@ -2146,7 +2145,7 @@ }, { "cell_type": "markdown", - "id": "165", + "id": "166", "metadata": {}, "source": [ "#### Exercise 5.6: Refine the Peak Profile Parameters\n", @@ -2166,7 +2165,7 @@ { "cell_type": "code", "execution_count": null, - "id": "166", + "id": "167", "metadata": {}, "outputs": [], "source": [ @@ -2175,7 +2174,7 @@ }, { "cell_type": "markdown", - "id": "167", + "id": "168", "metadata": {}, "source": [ "The peak profile parameters are determined based on both the\n", @@ -2189,7 +2188,7 @@ }, { "cell_type": "markdown", - "id": "168", + "id": "169", "metadata": {}, "source": [ "**Hint:**" @@ -2197,7 +2196,7 @@ }, { "cell_type": "markdown", - "id": "169", + "id": "170", "metadata": {}, "source": [ "You can set the `free` attribute of the peak profile parameters to\n", @@ -2208,7 +2207,7 @@ }, { "cell_type": "markdown", - "id": "170", + "id": "171", "metadata": {}, "source": [ "**Solution:**" @@ -2217,17 +2216,17 @@ { "cell_type": "code", "execution_count": null, - "id": "171", + "id": "172", "metadata": {}, "outputs": [], "source": [ "project_2.experiments['sim_lbco'].peak.broad_gauss_sigma_0.free = True\n", "project_2.experiments['sim_lbco'].peak.broad_gauss_sigma_1.free = True\n", "project_2.experiments['sim_lbco'].peak.broad_gauss_sigma_2.free = True\n", - "project_2.experiments['sim_lbco'].peak.broad_mix_beta_0.free = True\n", - "project_2.experiments['sim_lbco'].peak.broad_mix_beta_1.free = True\n", - "project_2.experiments['sim_lbco'].peak.asym_alpha_0.free = True\n", - "project_2.experiments['sim_lbco'].peak.asym_alpha_1.free = True\n", + "project_2.experiments['sim_lbco'].peak.exp_decay_beta_0.free = True\n", + "project_2.experiments['sim_lbco'].peak.exp_decay_beta_1.free = True\n", + "project_2.experiments['sim_lbco'].peak.exp_rise_alpha_0.free = True\n", + "project_2.experiments['sim_lbco'].peak.exp_rise_alpha_1.free = True\n", "\n", "project_2.analysis.fit()\n", "project_2.analysis.display.fit_results()\n", @@ -2237,7 +2236,7 @@ }, { "cell_type": "markdown", - "id": "172", + "id": "173", "metadata": {}, "source": [ "#### Exercise 5.7: Find Undefined Features\n", @@ -2249,7 +2248,7 @@ }, { "cell_type": "markdown", - "id": "173", + "id": "174", "metadata": {}, "source": [ "**Hint:**" @@ -2257,7 +2256,7 @@ }, { "cell_type": "markdown", - "id": "174", + "id": "175", "metadata": {}, "source": [ "While the fit is now significantly better, there are still some\n", @@ -2269,7 +2268,7 @@ }, { "cell_type": "markdown", - "id": "175", + "id": "176", "metadata": {}, "source": [ "**Solution:**" @@ -2278,7 +2277,7 @@ { "cell_type": "code", "execution_count": null, - "id": "176", + "id": "177", "metadata": {}, "outputs": [], "source": [ @@ -2287,7 +2286,7 @@ }, { "cell_type": "markdown", - "id": "177", + "id": "178", "metadata": {}, "source": [ "#### Exercise 5.8: Identify the Cause of the Unexplained Peaks\n", @@ -2300,7 +2299,7 @@ }, { "cell_type": "markdown", - "id": "178", + "id": "179", "metadata": {}, "source": [ "**Hint:**" @@ -2308,7 +2307,7 @@ }, { "cell_type": "markdown", - "id": "179", + "id": "180", "metadata": {}, "source": [ "Consider the following options:\n", @@ -2320,7 +2319,7 @@ }, { "cell_type": "markdown", - "id": "180", + "id": "181", "metadata": {}, "source": [ "**Solution:**" @@ -2328,7 +2327,7 @@ }, { "cell_type": "markdown", - "id": "181", + "id": "182", "metadata": {}, "source": [ "1. ❌ In principle, this could be the case, as sometimes the presence\n", @@ -2348,7 +2347,7 @@ }, { "cell_type": "markdown", - "id": "182", + "id": "183", "metadata": {}, "source": [ "#### Exercise 5.9: Identify the impurity phase\n", @@ -2359,7 +2358,7 @@ }, { "cell_type": "markdown", - "id": "183", + "id": "184", "metadata": {}, "source": [ "**Hint:**" @@ -2367,7 +2366,7 @@ }, { "cell_type": "markdown", - "id": "184", + "id": "185", "metadata": {}, "source": [ "Check the positions of the unexplained peaks in the diffraction\n", @@ -2377,7 +2376,7 @@ }, { "cell_type": "markdown", - "id": "185", + "id": "186", "metadata": {}, "source": [ "**Solution:**" @@ -2385,7 +2384,7 @@ }, { "cell_type": "markdown", - "id": "186", + "id": "187", "metadata": {}, "source": [ "The unexplained peaks are likely due to the presence of a small amount\n", @@ -2400,7 +2399,7 @@ { "cell_type": "code", "execution_count": null, - "id": "187", + "id": "188", "metadata": {}, "outputs": [], "source": [ @@ -2410,7 +2409,7 @@ }, { "cell_type": "markdown", - "id": "188", + "id": "189", "metadata": {}, "source": [ "#### Exercise 5.10: Create a Second Structure – Si as Impurity\n", @@ -2422,7 +2421,7 @@ }, { "cell_type": "markdown", - "id": "189", + "id": "190", "metadata": {}, "source": [ "**Hint:**" @@ -2430,7 +2429,7 @@ }, { "cell_type": "markdown", - "id": "190", + "id": "191", "metadata": {}, "source": [ "You can use the same approach as in the previous part of the notebook,\n", @@ -2440,7 +2439,7 @@ }, { "cell_type": "markdown", - "id": "191", + "id": "192", "metadata": {}, "source": [ "**Solution:**" @@ -2449,7 +2448,7 @@ { "cell_type": "code", "execution_count": null, - "id": "192", + "id": "193", "metadata": {}, "outputs": [], "source": [ @@ -2469,7 +2468,7 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=0.89,\n", + " adp_iso=0.89,\n", ")\n", "\n", "# Assign Structure to Experiment\n", @@ -2478,7 +2477,7 @@ }, { "cell_type": "markdown", - "id": "193", + "id": "194", "metadata": {}, "source": [ "#### Exercise 5.11: Refine the Scale of the Si Phase\n", @@ -2491,7 +2490,7 @@ }, { "cell_type": "markdown", - "id": "194", + "id": "195", "metadata": {}, "source": [ "**Hint:**" @@ -2499,7 +2498,7 @@ }, { "cell_type": "markdown", - "id": "195", + "id": "196", "metadata": {}, "source": [ "You can use the `plot_meas_vs_calc` method of the project to visualize\n", @@ -2510,7 +2509,7 @@ }, { "cell_type": "markdown", - "id": "196", + "id": "197", "metadata": {}, "source": [ "**Solution:**" @@ -2519,7 +2518,7 @@ { "cell_type": "code", "execution_count": null, - "id": "197", + "id": "198", "metadata": {}, "outputs": [], "source": [ @@ -2548,7 +2547,7 @@ }, { "cell_type": "markdown", - "id": "198", + "id": "199", "metadata": {}, "source": [ "All previously unexplained peaks are now accounted for in the pattern,\n", @@ -2571,7 +2570,7 @@ { "cell_type": "code", "execution_count": null, - "id": "199", + "id": "200", "metadata": {}, "outputs": [], "source": [ @@ -2580,7 +2579,7 @@ }, { "cell_type": "markdown", - "id": "200", + "id": "201", "metadata": {}, "source": [ "Finally, we save the project to disk to preserve the current state of\n", @@ -2590,7 +2589,7 @@ { "cell_type": "code", "execution_count": null, - "id": "201", + "id": "202", "metadata": {}, "outputs": [], "source": [ @@ -2599,7 +2598,7 @@ }, { "cell_type": "markdown", - "id": "202", + "id": "203", "metadata": {}, "source": [ "#### Final Remarks\n", @@ -2618,7 +2617,7 @@ }, { "cell_type": "markdown", - "id": "203", + "id": "204", "metadata": {}, "source": [ "## 🎁 Bonus\n", diff --git a/docs/docs/tutorials/ed-13.py b/docs/docs/tutorials/ed-13.py index 20addf9a8..597882801 100644 --- a/docs/docs/tutorials/ed-13.py +++ b/docs/docs/tutorials/ed-13.py @@ -488,7 +488,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.89, + adp_iso=0.89, ) # %% [markdown] @@ -1013,7 +1013,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.95, + adp_iso=0.95, occupancy=0.5, ) project_2.structures['lbco'].atom_sites.create( @@ -1023,7 +1023,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.95, + adp_iso=0.95, occupancy=0.5, ) project_2.structures['lbco'].atom_sites.create( @@ -1033,7 +1033,7 @@ fract_y=0.5, fract_z=0.5, wyckoff_letter='b', - b_iso=0.80, + adp_iso=0.80, ) project_2.structures['lbco'].atom_sites.create( label='O', @@ -1042,7 +1042,7 @@ fract_y=0.5, fract_z=0.5, wyckoff_letter='c', - b_iso=1.66, + adp_iso=1.66, ) # %% [markdown] @@ -1385,7 +1385,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.89, + adp_iso=0.89, ) # Assign Structure to Experiment diff --git a/docs/docs/tutorials/ed-14.ipynb b/docs/docs/tutorials/ed-14.ipynb index 9d2a9c5b0..deef9c1f3 100644 --- a/docs/docs/tutorials/ed-14.ipynb +++ b/docs/docs/tutorials/ed-14.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "86c9f966", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Structure Refinement: Tb2TiO7, HEiDi\n", @@ -32,7 +32,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -41,7 +41,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -50,7 +50,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Step 1: Define Project" @@ -59,7 +59,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -69,7 +69,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "## Step 2: Define Structure" @@ -78,7 +78,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -89,7 +89,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7", + "id": "8", "metadata": {}, "outputs": [], "source": [ @@ -99,7 +99,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -109,7 +109,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9", + "id": "10", "metadata": {}, "outputs": [], "source": [ @@ -119,29 +119,52 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ - "structure.atom_sites['Tb'].b_iso = 0.0\n", - "structure.atom_sites['Ti'].b_iso = 0.0\n", - "structure.atom_sites['O1'].b_iso = 0.0\n", - "structure.atom_sites['O2'].b_iso = 0.0" + "structure.show_as_cif()" ] }, { "cell_type": "code", "execution_count": null, - "id": "11", + "id": "12", "metadata": {}, "outputs": [], "source": [ - "structure.show_as_cif()" + "structure.atom_sites['Tb'].adp_type = 'Uiso'\n", + "structure.atom_sites['Ti'].adp_type = 'Uiso'\n", + "structure.atom_sites['O1'].adp_type = 'Uiso'\n", + "structure.atom_sites['O2'].adp_type = 'Uiso'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13", + "metadata": {}, + "outputs": [], + "source": [ + "print(structure.atom_sites.as_cif)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14", + "metadata": {}, + "outputs": [], + "source": [ + "structure.atom_sites['Tb'].adp_iso = 0.0\n", + "structure.atom_sites['Ti'].adp_iso = 0.0\n", + "structure.atom_sites['O1'].adp_iso = 0.0\n", + "structure.atom_sites['O2'].adp_iso = 0.0" ] }, { "cell_type": "markdown", - "id": "12", + "id": "15", "metadata": {}, "source": [ "## Step 3: Define Experiment" @@ -150,17 +173,18 @@ { "cell_type": "code", "execution_count": null, - "id": "13", + "id": "16", "metadata": {}, "outputs": [], "source": [ + "# Download data file from repository\n", "data_path = ed.download_data(id=19, destination='data')" ] }, { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -176,17 +200,17 @@ { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "18", "metadata": {}, "outputs": [], "source": [ - "experiment = project.experiments['heidi'] # TODO: " + "experiment = project.experiments['heidi']" ] }, { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -197,7 +221,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -207,26 +231,26 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "21", "metadata": {}, "outputs": [], "source": [ - "experiment.extinction.mosaicity = 29820\n", - "experiment.extinction.radius = 30" + "experiment.extinction.mosaicity = 35000\n", + "experiment.extinction.radius = 10" ] }, { "cell_type": "markdown", - "id": "19", + "id": "22", "metadata": {}, "source": [ - "## Step 4: Perform Analysis" + "## Step 4: Perform Analysis I (ADP iso)" ] }, { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -236,28 +260,37 @@ { "cell_type": "code", "execution_count": null, - "id": "21", + "id": "24", "metadata": {}, "outputs": [], "source": [ - "experiment.linked_crystal.scale.free = True\n", - "experiment.extinction.radius.free = True" + "structure.atom_sites['O1'].fract_x.free = True\n", + "\n", + "structure.atom_sites['Ti'].occupancy.free = True\n", + "structure.atom_sites['O1'].occupancy.free = True\n", + "structure.atom_sites['O2'].occupancy.free = True\n", + "\n", + "structure.atom_sites['Tb'].adp_iso.free = True\n", + "structure.atom_sites['Ti'].adp_iso.free = True\n", + "structure.atom_sites['O1'].adp_iso.free = True\n", + "structure.atom_sites['O2'].adp_iso.free = True" ] }, { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "25", "metadata": {}, "outputs": [], "source": [ - "experiment.show_as_cif()" + "experiment.linked_crystal.scale.free = True\n", + "experiment.extinction.radius.free = True" ] }, { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "26", "metadata": {}, "outputs": [], "source": [ @@ -269,7 +302,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -280,17 +313,17 @@ { "cell_type": "code", "execution_count": null, - "id": "25", + "id": "28", "metadata": {}, "outputs": [], "source": [ - "experiment.show_as_cif()" + "structure.show_as_cif()" ] }, { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -300,7 +333,7 @@ { "cell_type": "code", "execution_count": null, - "id": "27", + "id": "30", "metadata": {}, "outputs": [], "source": [ @@ -309,20 +342,100 @@ }, { "cell_type": "markdown", - "id": "28", + "id": "31", "metadata": {}, "source": [ - "## Step 5: Show Project Summary" + "## Step 5: Perform Analysis (ADP aniso)" ] }, { "cell_type": "code", "execution_count": null, - "id": "29", + "id": "32", + "metadata": {}, + "outputs": [], + "source": [ + "structure.atom_sites['Tb'].adp_type = 'Uani'\n", + "structure.atom_sites['Ti'].adp_type = 'Uani'\n", + "structure.atom_sites['O1'].adp_type = 'Uani'\n", + "# structure.atom_sites['O2'].adp_type = 'Uani'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33", + "metadata": {}, + "outputs": [], + "source": [ + "print(structure.atom_site_aniso.as_cif)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34", + "metadata": {}, + "outputs": [], + "source": [ + "structure.atom_site_aniso['Tb'].adp_11.free = True\n", + "structure.atom_site_aniso['Tb'].adp_12.free = True\n", + "structure.atom_site_aniso['Ti'].adp_11.free = True\n", + "structure.atom_site_aniso['Ti'].adp_12.free = True\n", + "structure.atom_site_aniso['O1'].adp_11.free = True\n", + "structure.atom_site_aniso['O1'].adp_22.free = True\n", + "structure.atom_site_aniso['O1'].adp_23.free = True\n", + "# structure.atom_site_aniso['O2'].adp_11.free = True" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35", "metadata": {}, "outputs": [], "source": [ - "project.summary.show_report()" + "project.analysis.fit()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36", + "metadata": {}, + "outputs": [], + "source": [ + "project.analysis.display.fit_results()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37", + "metadata": {}, + "outputs": [], + "source": [ + "project.plotter.plot_param_correlations()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38", + "metadata": {}, + "outputs": [], + "source": [ + "project.plotter.plot_meas_vs_calc(expt_name='heidi')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39", + "metadata": {}, + "outputs": [], + "source": [ + "structure.show_as_cif()" ] } ], diff --git a/docs/docs/tutorials/ed-14.py b/docs/docs/tutorials/ed-14.py index 22502ecd9..6bf496ff8 100644 --- a/docs/docs/tutorials/ed-14.py +++ b/docs/docs/tutorials/ed-14.py @@ -34,18 +34,28 @@ structure = project.structures['tbti'] # %% -structure.atom_sites['Tb'].b_iso = 0.0 -structure.atom_sites['Ti'].b_iso = 0.0 -structure.atom_sites['O1'].b_iso = 0.0 -structure.atom_sites['O2'].b_iso = 0.0 +structure.show_as_cif() # %% -structure.show_as_cif() +structure.atom_sites['Tb'].adp_type = 'Uiso' +structure.atom_sites['Ti'].adp_type = 'Uiso' +structure.atom_sites['O1'].adp_type = 'Uiso' +structure.atom_sites['O2'].adp_type = 'Uiso' + +# %% +print(structure.atom_sites.as_cif) + +# %% +structure.atom_sites['Tb'].adp_iso = 0.0 +structure.atom_sites['Ti'].adp_iso = 0.0 +structure.atom_sites['O1'].adp_iso = 0.0 +structure.atom_sites['O2'].adp_iso = 0.0 # %% [markdown] # ## Step 3: Define Experiment # %% +# Download data file from repository data_path = ed.download_data(id=19, destination='data') # %% @@ -58,7 +68,7 @@ ) # %% -experiment = project.experiments['heidi'] # TODO: +experiment = project.experiments['heidi'] # %% experiment.linked_crystal.id = 'tbti' @@ -68,21 +78,30 @@ experiment.instrument.setup_wavelength = 0.793 # %% -experiment.extinction.mosaicity = 29820 -experiment.extinction.radius = 30 +experiment.extinction.mosaicity = 35000 +experiment.extinction.radius = 10 # %% [markdown] -# ## Step 4: Perform Analysis +# ## Step 4: Perform Analysis I (ADP iso) # %% project.plotter.plot_meas_vs_calc(expt_name='heidi') # %% -experiment.linked_crystal.scale.free = True -experiment.extinction.radius.free = True +structure.atom_sites['O1'].fract_x.free = True + +structure.atom_sites['Ti'].occupancy.free = True +structure.atom_sites['O1'].occupancy.free = True +structure.atom_sites['O2'].occupancy.free = True + +structure.atom_sites['Tb'].adp_iso.free = True +structure.atom_sites['Ti'].adp_iso.free = True +structure.atom_sites['O1'].adp_iso.free = True +structure.atom_sites['O2'].adp_iso.free = True # %% -experiment.show_as_cif() +experiment.linked_crystal.scale.free = True +experiment.extinction.radius.free = True # %% # Start refinement. All parameters, which have standard uncertainties @@ -94,7 +113,7 @@ project.analysis.display.fit_results() # %% -experiment.show_as_cif() +structure.show_as_cif() # %% project.experiments.show_names() @@ -103,7 +122,38 @@ project.plotter.plot_meas_vs_calc(expt_name='heidi') # %% [markdown] -# ## Step 5: Show Project Summary +# ## Step 5: Perform Analysis (ADP aniso) + +# %% +structure.atom_sites['Tb'].adp_type = 'Uani' +structure.atom_sites['Ti'].adp_type = 'Uani' +structure.atom_sites['O1'].adp_type = 'Uani' +# structure.atom_sites['O2'].adp_type = 'Uani' # %% -project.summary.show_report() +print(structure.atom_site_aniso.as_cif) + +# %% +structure.atom_site_aniso['Tb'].adp_11.free = True +structure.atom_site_aniso['Tb'].adp_12.free = True +structure.atom_site_aniso['Ti'].adp_11.free = True +structure.atom_site_aniso['Ti'].adp_12.free = True +structure.atom_site_aniso['O1'].adp_11.free = True +structure.atom_site_aniso['O1'].adp_22.free = True +structure.atom_site_aniso['O1'].adp_23.free = True +# structure.atom_site_aniso['O2'].adp_11.free = True + +# %% +project.analysis.fit() + +# %% +project.analysis.display.fit_results() + +# %% +project.plotter.plot_param_correlations() + +# %% +project.plotter.plot_meas_vs_calc(expt_name='heidi') + +# %% +structure.show_as_cif() diff --git a/docs/docs/tutorials/ed-15.ipynb b/docs/docs/tutorials/ed-15.ipynb index 12e88c10a..964b988a9 100644 --- a/docs/docs/tutorials/ed-15.ipynb +++ b/docs/docs/tutorials/ed-15.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c631fd19", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Structure Refinement: Taurine, SENJU\n", @@ -32,7 +32,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -41,7 +41,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -50,7 +50,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Step 1: Define Project" @@ -59,7 +59,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -69,7 +69,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "## Step 2: Define Structure" @@ -78,7 +78,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -89,7 +89,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7", + "id": "8", "metadata": {}, "outputs": [], "source": [ @@ -99,7 +99,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -109,7 +109,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9", + "id": "10", "metadata": {}, "outputs": [], "source": [ @@ -119,16 +119,16 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ - "# structure.show_as_cif()" + "structure.show_as_cif()" ] }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "## Step 3: Define Experiment" @@ -137,17 +137,18 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ + "# Download data file from repository\n", "data_path = ed.download_data(id=22, destination='data')" ] }, { "cell_type": "code", "execution_count": null, - "id": "13", + "id": "14", "metadata": {}, "outputs": [], "source": [ @@ -163,7 +164,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -173,7 +174,7 @@ { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -184,7 +185,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -194,16 +195,16 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ - "## Step 4: Perform Analysis" + "## Step 4: Perform Analysis I (ADP iso)" ] }, { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -213,7 +214,7 @@ { "cell_type": "code", "execution_count": null, - "id": "19", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -224,17 +225,17 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ - "# experiment.show_as_cif()" + "project.analysis.current_minimizer = 'lmfit'" ] }, { "cell_type": "code", "execution_count": null, - "id": "21", + "id": "22", "metadata": {}, "outputs": [], "source": [ @@ -246,7 +247,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -257,17 +258,17 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "24", "metadata": {}, "outputs": [], "source": [ - "# experiment.show_as_cif()" + "structure.show_as_cif()" ] }, { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -277,7 +278,7 @@ { "cell_type": "code", "execution_count": null, - "id": "25", + "id": "26", "metadata": {}, "outputs": [], "source": [ @@ -286,20 +287,104 @@ }, { "cell_type": "markdown", - "id": "26", + "id": "27", "metadata": {}, "source": [ - "## Step 5: Show Project Summary" + "## Step 5: Perform Analysis (ADP aniso)" ] }, { "cell_type": "code", "execution_count": null, - "id": "27", + "id": "28", + "metadata": {}, + "outputs": [], + "source": [ + "for atom_site in structure.atom_sites:\n", + " atom_site.adp_type = 'Uani'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29", + "metadata": {}, + "outputs": [], + "source": [ + "adp_components = ('adp_11', 'adp_22', 'adp_33', 'adp_12', 'adp_13', 'adp_23')\n", + "for atom_site in structure.atom_site_aniso:\n", + " for component in adp_components:\n", + " getattr(atom_site, component).free = True" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30", + "metadata": {}, + "outputs": [], + "source": [ + "structure.show_as_cif()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31", + "metadata": {}, + "outputs": [], + "source": [ + "project.analysis.display.free_params()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32", + "metadata": {}, + "outputs": [], + "source": [ + "project.analysis.fit()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33", + "metadata": {}, + "outputs": [], + "source": [ + "project.analysis.display.fit_results()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34", + "metadata": {}, + "outputs": [], + "source": [ + "project.plotter.plot_param_correlations()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35", + "metadata": {}, + "outputs": [], + "source": [ + "project.plotter.plot_meas_vs_calc(expt_name='senju')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36", "metadata": {}, "outputs": [], "source": [ - "project.summary.show_report()" + "structure.show_as_cif()" ] } ], diff --git a/docs/docs/tutorials/ed-15.py b/docs/docs/tutorials/ed-15.py index 617cad88f..0827efae4 100644 --- a/docs/docs/tutorials/ed-15.py +++ b/docs/docs/tutorials/ed-15.py @@ -34,12 +34,13 @@ structure = project.structures['taurine'] # %% -# structure.show_as_cif() +structure.show_as_cif() # %% [markdown] # ## Step 3: Define Experiment # %% +# Download data file from repository data_path = ed.download_data(id=22, destination='data') # %% @@ -63,7 +64,7 @@ experiment.extinction.radius = 100.0 # %% [markdown] -# ## Step 4: Perform Analysis +# ## Step 4: Perform Analysis I (ADP iso) # %% project.plotter.plot_meas_vs_calc(expt_name='senju') @@ -73,7 +74,7 @@ experiment.extinction.radius.free = True # %% -# experiment.show_as_cif() +project.analysis.current_minimizer = 'lmfit' # %% # Start refinement. All parameters, which have standard uncertainties @@ -85,7 +86,7 @@ project.analysis.display.fit_results() # %% -# experiment.show_as_cif() +structure.show_as_cif() # %% project.experiments.show_names() @@ -94,7 +95,35 @@ project.plotter.plot_meas_vs_calc(expt_name='senju') # %% [markdown] -# ## Step 5: Show Project Summary +# ## Step 5: Perform Analysis (ADP aniso) # %% -project.summary.show_report() +for atom_site in structure.atom_sites: + atom_site.adp_type = 'Uani' + +# %% +adp_components = ('adp_11', 'adp_22', 'adp_33', 'adp_12', 'adp_13', 'adp_23') +for atom_site in structure.atom_site_aniso: + for component in adp_components: + getattr(atom_site, component).free = True + +# %% +structure.show_as_cif() + +# %% +project.analysis.display.free_params() + +# %% +project.analysis.fit() + +# %% +project.analysis.display.fit_results() + +# %% +project.plotter.plot_param_correlations() + +# %% +project.plotter.plot_meas_vs_calc(expt_name='senju') + +# %% +structure.show_as_cif() diff --git a/docs/docs/tutorials/ed-16.ipynb b/docs/docs/tutorials/ed-16.ipynb index 68dd7243f..cea753497 100644 --- a/docs/docs/tutorials/ed-16.ipynb +++ b/docs/docs/tutorials/ed-16.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d0fcc613", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Joint Refinement: Si, Bragg + PDF\n", @@ -36,7 +36,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -45,7 +45,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -57,7 +57,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Define Structure\n", @@ -72,7 +72,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -81,7 +81,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "#### Set Space Group" @@ -90,7 +90,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -100,7 +100,7 @@ }, { "cell_type": "markdown", - "id": "7", + "id": "8", "metadata": {}, "source": [ "#### Set Unit Cell" @@ -109,7 +109,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -118,7 +118,7 @@ }, { "cell_type": "markdown", - "id": "9", + "id": "10", "metadata": {}, "source": [ "#### Set Atom Sites" @@ -127,7 +127,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -138,13 +138,13 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=0.2,\n", + " adp_iso=0.2,\n", ")" ] }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "## Define Experiments\n", @@ -160,7 +160,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -169,7 +169,7 @@ }, { "cell_type": "markdown", - "id": "13", + "id": "14", "metadata": {}, "source": [ "#### Create Experiment" @@ -178,7 +178,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -189,7 +189,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "16", "metadata": {}, "source": [ "#### Set Instrument" @@ -198,7 +198,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -210,7 +210,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "#### Set Peak Profile" @@ -219,23 +219,23 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ - "bragg_expt.peak_profile_type = 'pseudo-voigt * ikeda-carpenter'\n", + "bragg_expt.peak_profile_type = 'jorgensen'\n", "bragg_expt.peak.broad_gauss_sigma_0 = 5.0\n", "bragg_expt.peak.broad_gauss_sigma_1 = 45.0\n", "bragg_expt.peak.broad_gauss_sigma_2 = 1.0\n", - "bragg_expt.peak.broad_mix_beta_0 = 0.04221\n", - "bragg_expt.peak.broad_mix_beta_1 = 0.00946\n", - "bragg_expt.peak.asym_alpha_0 = 0.0\n", - "bragg_expt.peak.asym_alpha_1 = 0.5971" + "bragg_expt.peak.exp_decay_beta_0 = 0.04221\n", + "bragg_expt.peak.exp_decay_beta_1 = 0.00946\n", + "bragg_expt.peak.exp_rise_alpha_0 = 0.0\n", + "bragg_expt.peak.exp_rise_alpha_1 = 0.5971" ] }, { "cell_type": "markdown", - "id": "19", + "id": "20", "metadata": {}, "source": [ "#### Set Background" @@ -244,7 +244,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -255,7 +255,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "#### Set Linked Phases" @@ -264,7 +264,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -273,7 +273,7 @@ }, { "cell_type": "markdown", - "id": "23", + "id": "24", "metadata": {}, "source": [ "### Experiment 2: PDF (NOMAD, TOF)\n", @@ -284,7 +284,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -293,7 +293,7 @@ }, { "cell_type": "markdown", - "id": "25", + "id": "26", "metadata": {}, "source": [ "#### Create Experiment" @@ -302,7 +302,7 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -316,7 +316,7 @@ }, { "cell_type": "markdown", - "id": "27", + "id": "28", "metadata": {}, "source": [ "#### Set Peak Profile (PDF Parameters)" @@ -325,7 +325,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -339,7 +339,7 @@ }, { "cell_type": "markdown", - "id": "29", + "id": "30", "metadata": {}, "source": [ "#### Set Linked Phases" @@ -348,7 +348,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -357,7 +357,7 @@ }, { "cell_type": "markdown", - "id": "31", + "id": "32", "metadata": {}, "source": [ "## Define Project\n", @@ -371,7 +371,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -380,7 +380,7 @@ }, { "cell_type": "markdown", - "id": "33", + "id": "34", "metadata": {}, "source": [ "#### Add Structure" @@ -389,7 +389,7 @@ { "cell_type": "code", "execution_count": null, - "id": "34", + "id": "35", "metadata": {}, "outputs": [], "source": [ @@ -398,7 +398,7 @@ }, { "cell_type": "markdown", - "id": "35", + "id": "36", "metadata": {}, "source": [ "#### Add Experiments" @@ -407,7 +407,7 @@ { "cell_type": "code", "execution_count": null, - "id": "36", + "id": "37", "metadata": {}, "outputs": [], "source": [ @@ -417,7 +417,7 @@ }, { "cell_type": "markdown", - "id": "37", + "id": "38", "metadata": {}, "source": [ "## Perform Analysis\n", @@ -431,7 +431,7 @@ { "cell_type": "code", "execution_count": null, - "id": "38", + "id": "39", "metadata": {}, "outputs": [], "source": [ @@ -442,7 +442,7 @@ }, { "cell_type": "markdown", - "id": "39", + "id": "40", "metadata": {}, "source": [ "#### Set Minimizer" @@ -451,7 +451,7 @@ { "cell_type": "code", "execution_count": null, - "id": "40", + "id": "41", "metadata": {}, "outputs": [], "source": [ @@ -460,7 +460,7 @@ }, { "cell_type": "markdown", - "id": "41", + "id": "42", "metadata": {}, "source": [ "#### Plot Measured vs Calculated (Before Fit)" @@ -469,7 +469,7 @@ { "cell_type": "code", "execution_count": null, - "id": "42", + "id": "43", "metadata": {}, "outputs": [], "source": [ @@ -479,7 +479,7 @@ { "cell_type": "code", "execution_count": null, - "id": "43", + "id": "44", "metadata": {}, "outputs": [], "source": [ @@ -488,7 +488,7 @@ }, { "cell_type": "markdown", - "id": "44", + "id": "45", "metadata": {}, "source": [ "#### Set Fitting Parameters\n", @@ -500,17 +500,17 @@ { "cell_type": "code", "execution_count": null, - "id": "45", + "id": "46", "metadata": {}, "outputs": [], "source": [ "structure.cell.length_a.free = True\n", - "structure.atom_sites['Si'].b_iso.free = True" + "structure.atom_sites['Si'].adp_iso.free = True" ] }, { "cell_type": "markdown", - "id": "46", + "id": "47", "metadata": {}, "source": [ "Bragg experiment parameters." @@ -519,7 +519,7 @@ { "cell_type": "code", "execution_count": null, - "id": "47", + "id": "48", "metadata": {}, "outputs": [], "source": [ @@ -534,7 +534,7 @@ }, { "cell_type": "markdown", - "id": "48", + "id": "49", "metadata": {}, "source": [ "PDF experiment parameters." @@ -543,7 +543,7 @@ { "cell_type": "code", "execution_count": null, - "id": "49", + "id": "50", "metadata": {}, "outputs": [], "source": [ @@ -556,7 +556,7 @@ }, { "cell_type": "markdown", - "id": "50", + "id": "51", "metadata": {}, "source": [ "#### Show Free Parameters" @@ -565,7 +565,7 @@ { "cell_type": "code", "execution_count": null, - "id": "51", + "id": "52", "metadata": {}, "outputs": [], "source": [ @@ -574,7 +574,7 @@ }, { "cell_type": "markdown", - "id": "52", + "id": "53", "metadata": {}, "source": [ "#### Run Fitting" @@ -583,17 +583,18 @@ { "cell_type": "code", "execution_count": null, - "id": "53", + "id": "54", "metadata": {}, "outputs": [], "source": [ "project.analysis.fit()\n", - "project.analysis.display.fit_results()" + "project.analysis.display.fit_results()\n", + "project.plotter.plot_param_correlations()" ] }, { "cell_type": "markdown", - "id": "54", + "id": "55", "metadata": {}, "source": [ "#### Plot Measured vs Calculated (After Fit)" @@ -602,7 +603,7 @@ { "cell_type": "code", "execution_count": null, - "id": "55", + "id": "56", "metadata": {}, "outputs": [], "source": [ @@ -612,7 +613,7 @@ { "cell_type": "code", "execution_count": null, - "id": "56", + "id": "57", "metadata": {}, "outputs": [], "source": [ diff --git a/docs/docs/tutorials/ed-16.py b/docs/docs/tutorials/ed-16.py index 96c1b3484..d26e149e1 100644 --- a/docs/docs/tutorials/ed-16.py +++ b/docs/docs/tutorials/ed-16.py @@ -53,7 +53,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.2, + adp_iso=0.2, ) # %% [markdown] @@ -209,7 +209,7 @@ # %% structure.cell.length_a.free = True -structure.atom_sites['Si'].b_iso.free = True +structure.atom_sites['Si'].adp_iso.free = True # %% [markdown] # Bragg experiment parameters. @@ -245,6 +245,7 @@ # %% project.analysis.fit() project.analysis.display.fit_results() +project.plotter.plot_param_correlations() # %% [markdown] # #### Plot Measured vs Calculated (After Fit) diff --git a/docs/docs/tutorials/ed-17.ipynb b/docs/docs/tutorials/ed-17.ipynb index 871d18890..484bf20b9 100644 --- a/docs/docs/tutorials/ed-17.ipynb +++ b/docs/docs/tutorials/ed-17.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0c20dcfb", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Structure Refinement: Co2SiO4, D20 (T-scan)\n", @@ -35,7 +35,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -44,7 +44,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -53,7 +53,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Step 1: Define Project\n", @@ -64,7 +64,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -73,7 +73,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "The project must be saved before running sequential fitting, so that\n", @@ -83,7 +83,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -92,7 +92,7 @@ }, { "cell_type": "markdown", - "id": "7", + "id": "8", "metadata": {}, "source": [ "## Step 2: Define Crystal Structure\n", @@ -106,7 +106,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -116,7 +116,7 @@ }, { "cell_type": "markdown", - "id": "9", + "id": "10", "metadata": {}, "source": [ "#### Set Space Group" @@ -125,7 +125,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -135,7 +135,7 @@ }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "#### Set Unit Cell" @@ -144,7 +144,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -155,7 +155,7 @@ }, { "cell_type": "markdown", - "id": "13", + "id": "14", "metadata": {}, "source": [ "#### Set Atom Sites" @@ -164,7 +164,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -175,7 +175,7 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=0.3,\n", + " adp_iso=0.3,\n", ")\n", "structure.atom_sites.create(\n", " label='Co2',\n", @@ -184,7 +184,7 @@ " fract_y=0.25,\n", " fract_z=0.985,\n", " wyckoff_letter='c',\n", - " b_iso=0.3,\n", + " adp_iso=0.3,\n", ")\n", "structure.atom_sites.create(\n", " label='Si',\n", @@ -193,7 +193,7 @@ " fract_y=0.25,\n", " fract_z=0.429,\n", " wyckoff_letter='c',\n", - " b_iso=0.34,\n", + " adp_iso=0.34,\n", ")\n", "structure.atom_sites.create(\n", " label='O1',\n", @@ -202,7 +202,7 @@ " fract_y=0.25,\n", " fract_z=0.771,\n", " wyckoff_letter='c',\n", - " b_iso=0.63,\n", + " adp_iso=0.63,\n", ")\n", "structure.atom_sites.create(\n", " label='O2',\n", @@ -211,7 +211,7 @@ " fract_y=0.25,\n", " fract_z=0.217,\n", " wyckoff_letter='c',\n", - " b_iso=0.59,\n", + " adp_iso=0.59,\n", ")\n", "structure.atom_sites.create(\n", " label='O3',\n", @@ -220,13 +220,13 @@ " fract_y=0.032,\n", " fract_z=0.28,\n", " wyckoff_letter='d',\n", - " b_iso=0.83,\n", + " adp_iso=0.83,\n", ")" ] }, { "cell_type": "markdown", - "id": "15", + "id": "16", "metadata": {}, "source": [ "## Step 3: Define Template Experiment\n", @@ -242,7 +242,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -251,7 +251,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "#### Extract Data Files" @@ -260,7 +260,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -270,7 +270,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "20", "metadata": {}, "source": [ "#### Create Template Experiment from the First File" @@ -279,7 +279,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -292,7 +292,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "#### Set Instrument" @@ -301,7 +301,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -311,7 +311,7 @@ }, { "cell_type": "markdown", - "id": "23", + "id": "24", "metadata": {}, "source": [ "#### Set Peak Profile" @@ -320,7 +320,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -332,7 +332,7 @@ }, { "cell_type": "markdown", - "id": "25", + "id": "26", "metadata": {}, "source": [ "#### Set Excluded Regions" @@ -341,7 +341,7 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -351,7 +351,7 @@ }, { "cell_type": "markdown", - "id": "27", + "id": "28", "metadata": {}, "source": [ "#### Set Background" @@ -360,7 +360,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -382,7 +382,7 @@ }, { "cell_type": "markdown", - "id": "29", + "id": "30", "metadata": {}, "source": [ "#### Set Linked Phases" @@ -391,7 +391,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -400,7 +400,7 @@ }, { "cell_type": "markdown", - "id": "31", + "id": "32", "metadata": {}, "source": [ "## Step 4: Perform Analysis\n", @@ -411,7 +411,7 @@ }, { "cell_type": "markdown", - "id": "32", + "id": "33", "metadata": {}, "source": [ "#### Set Free Parameters" @@ -420,7 +420,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33", + "id": "34", "metadata": {}, "outputs": [], "source": [ @@ -440,18 +440,18 @@ "structure.atom_sites['O3'].fract_y.free = True\n", "structure.atom_sites['O3'].fract_z.free = True\n", "\n", - "structure.atom_sites['Co1'].b_iso.free = True\n", - "structure.atom_sites['Co2'].b_iso.free = True\n", - "structure.atom_sites['Si'].b_iso.free = True\n", - "structure.atom_sites['O1'].b_iso.free = True\n", - "structure.atom_sites['O2'].b_iso.free = True\n", - "structure.atom_sites['O3'].b_iso.free = True" + "structure.atom_sites['Co1'].adp_iso.free = True\n", + "structure.atom_sites['Co2'].adp_iso.free = True\n", + "structure.atom_sites['Si'].adp_iso.free = True\n", + "structure.atom_sites['O1'].adp_iso.free = True\n", + "structure.atom_sites['O2'].adp_iso.free = True\n", + "structure.atom_sites['O3'].adp_iso.free = True" ] }, { "cell_type": "code", "execution_count": null, - "id": "34", + "id": "35", "metadata": {}, "outputs": [], "source": [ @@ -470,7 +470,7 @@ }, { "cell_type": "markdown", - "id": "35", + "id": "36", "metadata": {}, "source": [ "#### Set Constraints\n", @@ -481,23 +481,23 @@ { "cell_type": "code", "execution_count": null, - "id": "36", + "id": "37", "metadata": {}, "outputs": [], "source": [ "project.analysis.aliases.create(\n", " label='biso_Co1',\n", - " param=structure.atom_sites['Co1'].b_iso,\n", + " param=structure.atom_sites['Co1'].adp_iso,\n", ")\n", "project.analysis.aliases.create(\n", " label='biso_Co2',\n", - " param=structure.atom_sites['Co2'].b_iso,\n", + " param=structure.atom_sites['Co2'].adp_iso,\n", ")" ] }, { "cell_type": "markdown", - "id": "37", + "id": "38", "metadata": {}, "source": [ "Set constraints." @@ -506,7 +506,7 @@ { "cell_type": "code", "execution_count": null, - "id": "38", + "id": "39", "metadata": {}, "outputs": [], "source": [ @@ -515,7 +515,25 @@ }, { "cell_type": "markdown", - "id": "39", + "id": "40", + "metadata": {}, + "source": [ + "#### Set Minimizer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41", + "metadata": {}, + "outputs": [], + "source": [ + "project.analysis.current_minimizer = 'bumps (lm)'" + ] + }, + { + "cell_type": "markdown", + "id": "42", "metadata": {}, "source": [ "#### Run Single Fitting\n", @@ -529,7 +547,7 @@ { "cell_type": "code", "execution_count": null, - "id": "40", + "id": "43", "metadata": {}, "outputs": [], "source": [ @@ -538,7 +556,25 @@ }, { "cell_type": "markdown", - "id": "41", + "id": "44", + "metadata": {}, + "source": [ + "#### Show parameter correlations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45", + "metadata": {}, + "outputs": [], + "source": [ + "project.plotter.plot_param_correlations()" + ] + }, + { + "cell_type": "markdown", + "id": "46", "metadata": {}, "source": [ "#### Compare measured and calculated patterns for the first fit." @@ -547,7 +583,7 @@ { "cell_type": "code", "execution_count": null, - "id": "42", + "id": "47", "metadata": {}, "outputs": [], "source": [ @@ -556,7 +592,7 @@ }, { "cell_type": "markdown", - "id": "43", + "id": "48", "metadata": {}, "source": [ "#### Run Sequential Fitting\n", @@ -568,7 +604,7 @@ { "cell_type": "code", "execution_count": null, - "id": "44", + "id": "49", "metadata": {}, "outputs": [], "source": [ @@ -577,7 +613,7 @@ }, { "cell_type": "markdown", - "id": "45", + "id": "50", "metadata": { "lines_to_next_cell": 2 }, @@ -589,7 +625,7 @@ { "cell_type": "code", "execution_count": null, - "id": "46", + "id": "51", "metadata": {}, "outputs": [], "source": [ @@ -603,7 +639,7 @@ }, { "cell_type": "markdown", - "id": "47", + "id": "52", "metadata": {}, "source": [ "Run the sequential fit over all data files in the scan directory." @@ -612,7 +648,7 @@ { "cell_type": "code", "execution_count": null, - "id": "48", + "id": "53", "metadata": {}, "outputs": [], "source": [ @@ -626,7 +662,7 @@ }, { "cell_type": "markdown", - "id": "49", + "id": "54", "metadata": {}, "source": [ "#### Replay a Dataset\n", @@ -637,7 +673,7 @@ { "cell_type": "code", "execution_count": null, - "id": "50", + "id": "55", "metadata": {}, "outputs": [], "source": [ @@ -647,7 +683,7 @@ }, { "cell_type": "markdown", - "id": "51", + "id": "56", "metadata": {}, "source": [ "\n", @@ -657,7 +693,7 @@ { "cell_type": "code", "execution_count": null, - "id": "52", + "id": "57", "metadata": {}, "outputs": [], "source": [ @@ -667,7 +703,7 @@ }, { "cell_type": "markdown", - "id": "53", + "id": "58", "metadata": {}, "source": [ "#### Plot Parameter Evolution\n", @@ -678,7 +714,7 @@ { "cell_type": "code", "execution_count": null, - "id": "54", + "id": "59", "metadata": {}, "outputs": [], "source": [ @@ -687,7 +723,7 @@ }, { "cell_type": "markdown", - "id": "55", + "id": "60", "metadata": {}, "source": [ "Plot unit cell parameters vs. temperature." @@ -696,7 +732,7 @@ { "cell_type": "code", "execution_count": null, - "id": "56", + "id": "61", "metadata": {}, "outputs": [], "source": [ @@ -707,7 +743,7 @@ }, { "cell_type": "markdown", - "id": "57", + "id": "62", "metadata": {}, "source": [ "Plot isotropic displacement parameters vs. temperature." @@ -716,20 +752,20 @@ { "cell_type": "code", "execution_count": null, - "id": "58", + "id": "63", "metadata": {}, "outputs": [], "source": [ - "project.plotter.plot_param_series(structure.atom_sites['Co1'].b_iso, versus=temperature)\n", - "project.plotter.plot_param_series(structure.atom_sites['Si'].b_iso, versus=temperature)\n", - "project.plotter.plot_param_series(structure.atom_sites['O1'].b_iso, versus=temperature)\n", - "project.plotter.plot_param_series(structure.atom_sites['O2'].b_iso, versus=temperature)\n", - "project.plotter.plot_param_series(structure.atom_sites['O3'].b_iso, versus=temperature)" + "project.plotter.plot_param_series(structure.atom_sites['Co1'].adp_iso, versus=temperature)\n", + "project.plotter.plot_param_series(structure.atom_sites['Si'].adp_iso, versus=temperature)\n", + "project.plotter.plot_param_series(structure.atom_sites['O1'].adp_iso, versus=temperature)\n", + "project.plotter.plot_param_series(structure.atom_sites['O2'].adp_iso, versus=temperature)\n", + "project.plotter.plot_param_series(structure.atom_sites['O3'].adp_iso, versus=temperature)" ] }, { "cell_type": "markdown", - "id": "59", + "id": "64", "metadata": {}, "source": [ "Plot selected fractional coordinates vs. temperature." @@ -738,7 +774,7 @@ { "cell_type": "code", "execution_count": null, - "id": "60", + "id": "65", "metadata": {}, "outputs": [], "source": [ diff --git a/docs/docs/tutorials/ed-17.py b/docs/docs/tutorials/ed-17.py index 5feb94e83..e0a0299ae 100644 --- a/docs/docs/tutorials/ed-17.py +++ b/docs/docs/tutorials/ed-17.py @@ -66,7 +66,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.3, + adp_iso=0.3, ) structure.atom_sites.create( label='Co2', @@ -75,7 +75,7 @@ fract_y=0.25, fract_z=0.985, wyckoff_letter='c', - b_iso=0.3, + adp_iso=0.3, ) structure.atom_sites.create( label='Si', @@ -84,7 +84,7 @@ fract_y=0.25, fract_z=0.429, wyckoff_letter='c', - b_iso=0.34, + adp_iso=0.34, ) structure.atom_sites.create( label='O1', @@ -93,7 +93,7 @@ fract_y=0.25, fract_z=0.771, wyckoff_letter='c', - b_iso=0.63, + adp_iso=0.63, ) structure.atom_sites.create( label='O2', @@ -102,7 +102,7 @@ fract_y=0.25, fract_z=0.217, wyckoff_letter='c', - b_iso=0.59, + adp_iso=0.59, ) structure.atom_sites.create( label='O3', @@ -111,7 +111,7 @@ fract_y=0.032, fract_z=0.28, wyckoff_letter='d', - b_iso=0.83, + adp_iso=0.83, ) # %% [markdown] @@ -218,12 +218,12 @@ structure.atom_sites['O3'].fract_y.free = True structure.atom_sites['O3'].fract_z.free = True -structure.atom_sites['Co1'].b_iso.free = True -structure.atom_sites['Co2'].b_iso.free = True -structure.atom_sites['Si'].b_iso.free = True -structure.atom_sites['O1'].b_iso.free = True -structure.atom_sites['O2'].b_iso.free = True -structure.atom_sites['O3'].b_iso.free = True +structure.atom_sites['Co1'].adp_iso.free = True +structure.atom_sites['Co2'].adp_iso.free = True +structure.atom_sites['Si'].adp_iso.free = True +structure.atom_sites['O1'].adp_iso.free = True +structure.atom_sites['O2'].adp_iso.free = True +structure.atom_sites['O3'].adp_iso.free = True # %% expt.linked_phases['cosio'].scale.free = True @@ -246,11 +246,11 @@ # %% project.analysis.aliases.create( label='biso_Co1', - param=structure.atom_sites['Co1'].b_iso, + param=structure.atom_sites['Co1'].adp_iso, ) project.analysis.aliases.create( label='biso_Co2', - param=structure.atom_sites['Co2'].b_iso, + param=structure.atom_sites['Co2'].adp_iso, ) # %% [markdown] @@ -276,6 +276,12 @@ # %% project.analysis.fit() +# %% [markdown] +# #### Show parameter correlations + +# %% +project.plotter.plot_param_correlations() + # %% [markdown] # #### Compare measured and calculated patterns for the first fit. @@ -353,11 +359,11 @@ def extract_diffrn(file_path): # Plot isotropic displacement parameters vs. temperature. # %% -project.plotter.plot_param_series(structure.atom_sites['Co1'].b_iso, versus=temperature) -project.plotter.plot_param_series(structure.atom_sites['Si'].b_iso, versus=temperature) -project.plotter.plot_param_series(structure.atom_sites['O1'].b_iso, versus=temperature) -project.plotter.plot_param_series(structure.atom_sites['O2'].b_iso, versus=temperature) -project.plotter.plot_param_series(structure.atom_sites['O3'].b_iso, versus=temperature) +project.plotter.plot_param_series(structure.atom_sites['Co1'].adp_iso, versus=temperature) +project.plotter.plot_param_series(structure.atom_sites['Si'].adp_iso, versus=temperature) +project.plotter.plot_param_series(structure.atom_sites['O1'].adp_iso, versus=temperature) +project.plotter.plot_param_series(structure.atom_sites['O2'].adp_iso, versus=temperature) +project.plotter.plot_param_series(structure.atom_sites['O3'].adp_iso, versus=temperature) # %% [markdown] # Plot selected fractional coordinates vs. temperature. diff --git a/docs/docs/tutorials/ed-18.ipynb b/docs/docs/tutorials/ed-18.ipynb index 655a0b808..2cc2b7fde 100644 --- a/docs/docs/tutorials/ed-18.ipynb +++ b/docs/docs/tutorials/ed-18.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f9d269b5", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Load Project and Fit: LBCO, HRPT\n", @@ -39,7 +39,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Modules" @@ -48,7 +48,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -59,7 +59,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Download Project Archive" @@ -68,16 +68,16 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ - "zip_path = download_data(id=28, destination='data')" + "zip_path = download_data(id=30, destination='data')" ] }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "## Extract Project" @@ -86,7 +86,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -95,7 +95,7 @@ }, { "cell_type": "markdown", - "id": "7", + "id": "8", "metadata": {}, "source": [ "## Load Project" @@ -104,7 +104,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -113,7 +113,7 @@ }, { "cell_type": "markdown", - "id": "9", + "id": "10", "metadata": {}, "source": [ "## Perform Analysis" @@ -122,7 +122,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -131,7 +131,7 @@ }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "## Show Results" @@ -140,7 +140,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -149,7 +149,25 @@ }, { "cell_type": "markdown", - "id": "13", + "id": "14", + "metadata": {}, + "source": [ + "#### Show parameter correlations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15", + "metadata": {}, + "outputs": [], + "source": [ + "project.plotter.plot_param_correlations()" + ] + }, + { + "cell_type": "markdown", + "id": "16", "metadata": {}, "source": [ "## Plot Meas vs Calc" @@ -158,7 +176,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "17", "metadata": {}, "outputs": [], "source": [ diff --git a/docs/docs/tutorials/ed-18.py b/docs/docs/tutorials/ed-18.py index fbfd39e58..07310726f 100644 --- a/docs/docs/tutorials/ed-18.py +++ b/docs/docs/tutorials/ed-18.py @@ -23,7 +23,7 @@ # ## Download Project Archive # %% -zip_path = download_data(id=28, destination='data') +zip_path = download_data(id=30, destination='data') # %% [markdown] # ## Extract Project @@ -49,6 +49,12 @@ # %% project.analysis.display.fit_results() +# %% [markdown] +# #### Show parameter correlations + +# %% +project.plotter.plot_param_correlations() + # %% [markdown] # ## Plot Meas vs Calc diff --git a/docs/docs/tutorials/ed-2.ipynb b/docs/docs/tutorials/ed-2.ipynb index 3b359bcb1..ab01aee03 100644 --- a/docs/docs/tutorials/ed-2.ipynb +++ b/docs/docs/tutorials/ed-2.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9e18bf0f", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Structure Refinement: LBCO, HRPT\n", @@ -48,7 +48,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -57,7 +57,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -66,7 +66,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Step 1: Define Project" @@ -75,7 +75,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -84,7 +84,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "## Step 2: Define Structure" @@ -93,7 +93,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -103,7 +103,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7", + "id": "8", "metadata": {}, "outputs": [], "source": [ @@ -113,7 +113,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -124,7 +124,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9", + "id": "10", "metadata": {}, "outputs": [], "source": [ @@ -134,7 +134,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -145,7 +145,7 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", " occupancy=0.5,\n", ")\n", "structure.atom_sites.create(\n", @@ -155,7 +155,7 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", " occupancy=0.5,\n", ")\n", "structure.atom_sites.create(\n", @@ -165,7 +165,7 @@ " fract_y=0.5,\n", " fract_z=0.5,\n", " wyckoff_letter='b',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", " label='O',\n", @@ -174,13 +174,13 @@ " fract_y=0.5,\n", " fract_z=0.5,\n", " wyckoff_letter='c',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")" ] }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "## Step 3: Define Experiment" @@ -189,7 +189,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -199,7 +199,7 @@ { "cell_type": "code", "execution_count": null, - "id": "13", + "id": "14", "metadata": {}, "outputs": [], "source": [ @@ -215,7 +215,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -225,7 +225,7 @@ { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -236,7 +236,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -249,7 +249,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -263,7 +263,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -274,7 +274,7 @@ { "cell_type": "code", "execution_count": null, - "id": "19", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -283,34 +283,32 @@ }, { "cell_type": "markdown", - "id": "20", + "id": "21", "metadata": {}, "source": [ - "## Step 4: Perform Analysis" + "## Step 4: Perform Analysis (no constraints)" ] }, { "cell_type": "code", "execution_count": null, - "id": "21", + "id": "22", "metadata": {}, "outputs": [], "source": [ "structure.cell.length_a.free = True\n", "\n", - "structure.atom_sites['La'].b_iso.free = True\n", - "structure.atom_sites['Ba'].b_iso.free = True\n", - "structure.atom_sites['Co'].b_iso.free = True\n", - "structure.atom_sites['O'].b_iso.free = True" + "structure.atom_sites['La'].adp_iso.free = True\n", + "structure.atom_sites['Ba'].adp_iso.free = True\n", + "structure.atom_sites['Co'].adp_iso.free = True\n", + "structure.atom_sites['O'].adp_iso.free = True" ] }, { "cell_type": "code", "execution_count": null, - "id": "22", - "metadata": { - "lines_to_next_cell": 2 - }, + "id": "23", + "metadata": {}, "outputs": [], "source": [ "experiment.instrument.calib_twotheta_offset.free = True\n", @@ -332,18 +330,110 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "24", + "metadata": {}, + "outputs": [], + "source": [ + "project.analysis.fit()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25", "metadata": {}, "outputs": [], "source": [ - "project.analysis.fit()\n", "project.analysis.display.fit_results()" ] }, { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "26", + "metadata": {}, + "outputs": [], + "source": [ + "project.plotter.plot_param_correlations()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27", + "metadata": {}, + "outputs": [], + "source": [ + "project.plotter.plot_meas_vs_calc(expt_name='hrpt', show_residual=True)" + ] + }, + { + "cell_type": "markdown", + "id": "28", + "metadata": {}, + "source": [ + "## Step 5: Perform Analysis (with constraints)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29", + "metadata": {}, + "outputs": [], + "source": [ + "# As can be seen from the parameter-correlation plot, the isotropic\n", + "# displacement parameters of La and Ba are highly correlated. Because\n", + "# La and Ba share the same mixed-occupancy site, their contributions to\n", + "# the neutron diffraction pattern are difficult to separate, especially\n", + "# since their coherent scattering lengths are not very different.\n", + "# Therefore, it is necessary to constrain them to be equal. First we\n", + "# define aliases and then use them to create a constraint.\n", + "project.analysis.aliases.create(\n", + " label='biso_La',\n", + " param=project.structures['lbco'].atom_sites['La'].adp_iso,\n", + ")\n", + "project.analysis.aliases.create(\n", + " label='biso_Ba',\n", + " param=project.structures['lbco'].atom_sites['Ba'].adp_iso,\n", + ")\n", + "project.analysis.constraints.create(expression='biso_Ba = biso_La')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30", + "metadata": {}, + "outputs": [], + "source": [ + "project.analysis.fit()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31", + "metadata": {}, + "outputs": [], + "source": [ + "project.analysis.display.fit_results()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32", + "metadata": {}, + "outputs": [], + "source": [ + "project.plotter.plot_param_correlations()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33", "metadata": {}, "outputs": [], "source": [ diff --git a/docs/docs/tutorials/ed-2.py b/docs/docs/tutorials/ed-2.py index 609f54db9..b5d1d8e6f 100644 --- a/docs/docs/tutorials/ed-2.py +++ b/docs/docs/tutorials/ed-2.py @@ -56,7 +56,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.5, + adp_iso=0.5, occupancy=0.5, ) structure.atom_sites.create( @@ -66,7 +66,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.5, + adp_iso=0.5, occupancy=0.5, ) structure.atom_sites.create( @@ -76,7 +76,7 @@ fract_y=0.5, fract_z=0.5, wyckoff_letter='b', - b_iso=0.5, + adp_iso=0.5, ) structure.atom_sites.create( label='O', @@ -85,7 +85,7 @@ fract_y=0.5, fract_z=0.5, wyckoff_letter='c', - b_iso=0.5, + adp_iso=0.5, ) # %% [markdown] @@ -131,15 +131,15 @@ experiment.linked_phases.create(id='lbco', scale=10.0) # %% [markdown] -# ## Step 4: Perform Analysis +# ## Step 4: Perform Analysis (no constraints) # %% structure.cell.length_a.free = True -structure.atom_sites['La'].b_iso.free = True -structure.atom_sites['Ba'].b_iso.free = True -structure.atom_sites['Co'].b_iso.free = True -structure.atom_sites['O'].b_iso.free = True +structure.atom_sites['La'].adp_iso.free = True +structure.atom_sites['Ba'].adp_iso.free = True +structure.atom_sites['Co'].adp_iso.free = True +structure.atom_sites['O'].adp_iso.free = True # %% experiment.instrument.calib_twotheta_offset.free = True @@ -157,10 +157,47 @@ experiment.linked_phases['lbco'].scale.free = True +# %% +project.analysis.fit() + +# %% +project.analysis.display.fit_results() + +# %% +project.plotter.plot_param_correlations() + +# %% +project.plotter.plot_meas_vs_calc(expt_name='hrpt', show_residual=True) + +# %% [markdown] +# ## Step 5: Perform Analysis (with constraints) + +# %% +# As can be seen from the parameter-correlation plot, the isotropic +# displacement parameters of La and Ba are highly correlated. Because +# La and Ba share the same mixed-occupancy site, their contributions to +# the neutron diffraction pattern are difficult to separate, especially +# since their coherent scattering lengths are not very different. +# Therefore, it is necessary to constrain them to be equal. First we +# define aliases and then use them to create a constraint. +project.analysis.aliases.create( + label='biso_La', + param=project.structures['lbco'].atom_sites['La'].adp_iso, +) +project.analysis.aliases.create( + label='biso_Ba', + param=project.structures['lbco'].atom_sites['Ba'].adp_iso, +) +project.analysis.constraints.create(expression='biso_Ba = biso_La') # %% project.analysis.fit() + +# %% project.analysis.display.fit_results() +# %% +project.plotter.plot_param_correlations() + # %% project.plotter.plot_meas_vs_calc(expt_name='hrpt', show_residual=True) diff --git a/docs/docs/tutorials/ed-3.ipynb b/docs/docs/tutorials/ed-3.ipynb index 7b4099b1d..8bc929ff8 100644 --- a/docs/docs/tutorials/ed-3.ipynb +++ b/docs/docs/tutorials/ed-3.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3e463ed0", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Structure Refinement: LBCO, HRPT\n", @@ -46,7 +46,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -55,7 +55,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -64,7 +64,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Step 1: Create a Project\n", @@ -74,7 +74,7 @@ }, { "cell_type": "markdown", - "id": "4", + "id": "5", "metadata": {}, "source": [ "#### Create Project" @@ -83,7 +83,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5", + "id": "6", "metadata": {}, "outputs": [], "source": [ @@ -92,7 +92,7 @@ }, { "cell_type": "markdown", - "id": "6", + "id": "7", "metadata": {}, "source": [ "#### Set Project Metadata" @@ -101,7 +101,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7", + "id": "8", "metadata": {}, "outputs": [], "source": [ @@ -114,7 +114,7 @@ }, { "cell_type": "markdown", - "id": "8", + "id": "9", "metadata": {}, "source": [ "#### Show Project Metadata as CIF" @@ -123,7 +123,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9", + "id": "10", "metadata": {}, "outputs": [], "source": [ @@ -132,7 +132,7 @@ }, { "cell_type": "markdown", - "id": "10", + "id": "11", "metadata": {}, "source": [ "#### Save Project\n", @@ -145,7 +145,7 @@ { "cell_type": "code", "execution_count": null, - "id": "11", + "id": "12", "metadata": {}, "outputs": [], "source": [ @@ -154,7 +154,7 @@ }, { "cell_type": "markdown", - "id": "12", + "id": "13", "metadata": {}, "source": [ "#### Set Up Data Plotter" @@ -162,7 +162,7 @@ }, { "cell_type": "markdown", - "id": "13", + "id": "14", "metadata": {}, "source": [ "Show supported plotting engines." @@ -171,7 +171,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -180,7 +180,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "16", "metadata": {}, "source": [ "Show current plotting configuration." @@ -189,7 +189,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -198,28 +198,8 @@ }, { "cell_type": "markdown", - "id": "17", - "metadata": {}, - "source": [ - "Set plotting engine." - ] - }, - { - "cell_type": "code", - "execution_count": null, "id": "18", "metadata": {}, - "outputs": [], - "source": [ - "# Keep the auto-selected engine. Alternatively, you can uncomment the\n", - "# line below to explicitly set the engine to the required one.\n", - "# project.plotter.engine = 'plotly'" - ] - }, - { - "cell_type": "markdown", - "id": "19", - "metadata": {}, "source": [ "## Step 2: Define Structure\n", "\n", @@ -229,7 +209,7 @@ }, { "cell_type": "markdown", - "id": "20", + "id": "19", "metadata": {}, "source": [ "#### Add Structure" @@ -238,7 +218,7 @@ { "cell_type": "code", "execution_count": null, - "id": "21", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -247,7 +227,7 @@ }, { "cell_type": "markdown", - "id": "22", + "id": "21", "metadata": {}, "source": [ "#### Show Defined Structures\n", @@ -261,7 +241,7 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "22", "metadata": {}, "outputs": [], "source": [ @@ -270,7 +250,7 @@ }, { "cell_type": "markdown", - "id": "24", + "id": "23", "metadata": {}, "source": [ "#### Set Space Group\n", @@ -281,7 +261,7 @@ { "cell_type": "code", "execution_count": null, - "id": "25", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -291,7 +271,7 @@ }, { "cell_type": "markdown", - "id": "26", + "id": "25", "metadata": {}, "source": [ "#### Set Unit Cell\n", @@ -302,7 +282,7 @@ { "cell_type": "code", "execution_count": null, - "id": "27", + "id": "26", "metadata": {}, "outputs": [], "source": [ @@ -311,7 +291,7 @@ }, { "cell_type": "markdown", - "id": "28", + "id": "27", "metadata": {}, "source": [ "#### Set Atom Sites\n", @@ -322,7 +302,7 @@ { "cell_type": "code", "execution_count": null, - "id": "29", + "id": "28", "metadata": {}, "outputs": [], "source": [ @@ -333,7 +313,7 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", " occupancy=0.5,\n", ")\n", "project.structures['lbco'].atom_sites.create(\n", @@ -343,7 +323,7 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", " occupancy=0.5,\n", ")\n", "project.structures['lbco'].atom_sites.create(\n", @@ -353,7 +333,7 @@ " fract_y=0.5,\n", " fract_z=0.5,\n", " wyckoff_letter='b',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")\n", "project.structures['lbco'].atom_sites.create(\n", " label='O',\n", @@ -362,13 +342,13 @@ " fract_y=0.5,\n", " fract_z=0.5,\n", " wyckoff_letter='c',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")" ] }, { "cell_type": "markdown", - "id": "30", + "id": "29", "metadata": {}, "source": [ "#### Show Structure as CIF" @@ -377,7 +357,7 @@ { "cell_type": "code", "execution_count": null, - "id": "31", + "id": "30", "metadata": {}, "outputs": [], "source": [ @@ -386,7 +366,7 @@ }, { "cell_type": "markdown", - "id": "32", + "id": "31", "metadata": {}, "source": [ "#### Show Structure Structure" @@ -395,7 +375,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33", + "id": "32", "metadata": {}, "outputs": [], "source": [ @@ -404,7 +384,7 @@ }, { "cell_type": "markdown", - "id": "34", + "id": "33", "metadata": {}, "source": [ "#### Save Project State\n", @@ -417,7 +397,7 @@ { "cell_type": "code", "execution_count": null, - "id": "35", + "id": "34", "metadata": {}, "outputs": [], "source": [ @@ -426,7 +406,7 @@ }, { "cell_type": "markdown", - "id": "36", + "id": "35", "metadata": {}, "source": [ "## Step 3: Define Experiment\n", @@ -437,7 +417,7 @@ }, { "cell_type": "markdown", - "id": "37", + "id": "36", "metadata": {}, "source": [ "#### Download Measured Data\n", @@ -448,7 +428,7 @@ { "cell_type": "code", "execution_count": null, - "id": "38", + "id": "37", "metadata": {}, "outputs": [], "source": [ @@ -457,7 +437,7 @@ }, { "cell_type": "markdown", - "id": "39", + "id": "38", "metadata": {}, "source": [ "#### Add Diffraction Experiment" @@ -466,7 +446,7 @@ { "cell_type": "code", "execution_count": null, - "id": "40", + "id": "39", "metadata": {}, "outputs": [], "source": [ @@ -481,7 +461,7 @@ }, { "cell_type": "markdown", - "id": "41", + "id": "40", "metadata": {}, "source": [ "#### Show Defined Experiments" @@ -490,7 +470,7 @@ { "cell_type": "code", "execution_count": null, - "id": "42", + "id": "41", "metadata": {}, "outputs": [], "source": [ @@ -499,7 +479,7 @@ }, { "cell_type": "markdown", - "id": "43", + "id": "42", "metadata": {}, "source": [ "#### Show Measured Data" @@ -508,7 +488,7 @@ { "cell_type": "code", "execution_count": null, - "id": "44", + "id": "43", "metadata": {}, "outputs": [], "source": [ @@ -517,7 +497,7 @@ }, { "cell_type": "markdown", - "id": "45", + "id": "44", "metadata": {}, "source": [ "#### Set Instrument\n", @@ -528,7 +508,7 @@ { "cell_type": "code", "execution_count": null, - "id": "46", + "id": "45", "metadata": {}, "outputs": [], "source": [ @@ -538,7 +518,7 @@ }, { "cell_type": "markdown", - "id": "47", + "id": "46", "metadata": {}, "source": [ "#### Set Peak Profile\n", @@ -549,7 +529,7 @@ { "cell_type": "code", "execution_count": null, - "id": "48", + "id": "47", "metadata": {}, "outputs": [], "source": [ @@ -558,7 +538,7 @@ }, { "cell_type": "markdown", - "id": "49", + "id": "48", "metadata": {}, "source": [ "Show the current peak profile type." @@ -567,7 +547,7 @@ { "cell_type": "code", "execution_count": null, - "id": "50", + "id": "49", "metadata": {}, "outputs": [], "source": [ @@ -576,7 +556,7 @@ }, { "cell_type": "markdown", - "id": "51", + "id": "50", "metadata": {}, "source": [ "Select the desired peak profile type." @@ -585,7 +565,7 @@ { "cell_type": "code", "execution_count": null, - "id": "52", + "id": "51", "metadata": {}, "outputs": [], "source": [ @@ -594,7 +574,7 @@ }, { "cell_type": "markdown", - "id": "53", + "id": "52", "metadata": {}, "source": [ "Modify default peak profile parameters." @@ -603,7 +583,7 @@ { "cell_type": "code", "execution_count": null, - "id": "54", + "id": "53", "metadata": {}, "outputs": [], "source": [ @@ -616,7 +596,7 @@ }, { "cell_type": "markdown", - "id": "55", + "id": "54", "metadata": {}, "source": [ "#### Set Background" @@ -624,7 +604,7 @@ }, { "cell_type": "markdown", - "id": "56", + "id": "55", "metadata": {}, "source": [ "Show supported background types." @@ -633,7 +613,7 @@ { "cell_type": "code", "execution_count": null, - "id": "57", + "id": "56", "metadata": {}, "outputs": [], "source": [ @@ -642,7 +622,7 @@ }, { "cell_type": "markdown", - "id": "58", + "id": "57", "metadata": {}, "source": [ "Show current background type." @@ -651,7 +631,7 @@ { "cell_type": "code", "execution_count": null, - "id": "59", + "id": "58", "metadata": {}, "outputs": [], "source": [ @@ -660,7 +640,7 @@ }, { "cell_type": "markdown", - "id": "60", + "id": "59", "metadata": {}, "source": [ "Select the desired background type." @@ -669,7 +649,7 @@ { "cell_type": "code", "execution_count": null, - "id": "61", + "id": "60", "metadata": {}, "outputs": [], "source": [ @@ -678,7 +658,7 @@ }, { "cell_type": "markdown", - "id": "62", + "id": "61", "metadata": {}, "source": [ "Add background points." @@ -687,7 +667,7 @@ { "cell_type": "code", "execution_count": null, - "id": "63", + "id": "62", "metadata": {}, "outputs": [], "source": [ @@ -700,7 +680,7 @@ }, { "cell_type": "markdown", - "id": "64", + "id": "63", "metadata": {}, "source": [ "Show current background points." @@ -709,7 +689,7 @@ { "cell_type": "code", "execution_count": null, - "id": "65", + "id": "64", "metadata": {}, "outputs": [], "source": [ @@ -718,7 +698,7 @@ }, { "cell_type": "markdown", - "id": "66", + "id": "65", "metadata": {}, "source": [ "#### Set Linked Phases\n", @@ -729,7 +709,7 @@ { "cell_type": "code", "execution_count": null, - "id": "67", + "id": "66", "metadata": {}, "outputs": [], "source": [ @@ -738,7 +718,7 @@ }, { "cell_type": "markdown", - "id": "68", + "id": "67", "metadata": {}, "source": [ "#### Show Experiment as CIF" @@ -747,7 +727,7 @@ { "cell_type": "code", "execution_count": null, - "id": "69", + "id": "68", "metadata": {}, "outputs": [], "source": [ @@ -756,7 +736,7 @@ }, { "cell_type": "markdown", - "id": "70", + "id": "69", "metadata": {}, "source": [ "#### Save Project State" @@ -765,7 +745,7 @@ { "cell_type": "code", "execution_count": null, - "id": "71", + "id": "70", "metadata": {}, "outputs": [], "source": [ @@ -774,7 +754,7 @@ }, { "cell_type": "markdown", - "id": "72", + "id": "71", "metadata": {}, "source": [ "## Step 4: Perform Analysis\n", @@ -790,7 +770,7 @@ { "cell_type": "code", "execution_count": null, - "id": "73", + "id": "72", "metadata": {}, "outputs": [], "source": [ @@ -799,7 +779,7 @@ }, { "cell_type": "markdown", - "id": "74", + "id": "73", "metadata": {}, "source": [ "Show current calculation engine for this experiment." @@ -808,7 +788,7 @@ { "cell_type": "code", "execution_count": null, - "id": "75", + "id": "74", "metadata": {}, "outputs": [], "source": [ @@ -817,7 +797,7 @@ }, { "cell_type": "markdown", - "id": "76", + "id": "75", "metadata": {}, "source": [ "Select the desired calculation engine." @@ -826,7 +806,7 @@ { "cell_type": "code", "execution_count": null, - "id": "77", + "id": "76", "metadata": {}, "outputs": [], "source": [ @@ -835,7 +815,7 @@ }, { "cell_type": "markdown", - "id": "78", + "id": "77", "metadata": {}, "source": [ "#### Show Calculated Data" @@ -844,7 +824,7 @@ { "cell_type": "code", "execution_count": null, - "id": "79", + "id": "78", "metadata": {}, "outputs": [], "source": [ @@ -853,7 +833,7 @@ }, { "cell_type": "markdown", - "id": "80", + "id": "79", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -862,7 +842,7 @@ { "cell_type": "code", "execution_count": null, - "id": "81", + "id": "80", "metadata": {}, "outputs": [], "source": [ @@ -872,7 +852,7 @@ { "cell_type": "code", "execution_count": null, - "id": "82", + "id": "81", "metadata": {}, "outputs": [], "source": [ @@ -881,7 +861,7 @@ }, { "cell_type": "markdown", - "id": "83", + "id": "82", "metadata": {}, "source": [ "#### Show Parameters\n", @@ -892,7 +872,7 @@ { "cell_type": "code", "execution_count": null, - "id": "84", + "id": "83", "metadata": {}, "outputs": [], "source": [ @@ -901,7 +881,7 @@ }, { "cell_type": "markdown", - "id": "85", + "id": "84", "metadata": {}, "source": [ "Show all fittable parameters." @@ -910,7 +890,7 @@ { "cell_type": "code", "execution_count": null, - "id": "86", + "id": "85", "metadata": {}, "outputs": [], "source": [ @@ -919,7 +899,7 @@ }, { "cell_type": "markdown", - "id": "87", + "id": "86", "metadata": {}, "source": [ "Show only free parameters." @@ -928,7 +908,7 @@ { "cell_type": "code", "execution_count": null, - "id": "88", + "id": "87", "metadata": {}, "outputs": [], "source": [ @@ -937,7 +917,7 @@ }, { "cell_type": "markdown", - "id": "89", + "id": "88", "metadata": {}, "source": [ "Show how to access parameters in the code." @@ -946,7 +926,7 @@ { "cell_type": "code", "execution_count": null, - "id": "90", + "id": "89", "metadata": {}, "outputs": [], "source": [ @@ -955,7 +935,7 @@ }, { "cell_type": "markdown", - "id": "91", + "id": "90", "metadata": {}, "source": [ "#### Set Fit Mode\n", @@ -966,7 +946,7 @@ { "cell_type": "code", "execution_count": null, - "id": "92", + "id": "91", "metadata": {}, "outputs": [], "source": [ @@ -975,7 +955,7 @@ }, { "cell_type": "markdown", - "id": "93", + "id": "92", "metadata": {}, "source": [ "Show current fit mode." @@ -984,7 +964,7 @@ { "cell_type": "code", "execution_count": null, - "id": "94", + "id": "93", "metadata": {}, "outputs": [], "source": [ @@ -993,7 +973,7 @@ }, { "cell_type": "markdown", - "id": "95", + "id": "94", "metadata": {}, "source": [ "Select desired fit mode." @@ -1002,7 +982,7 @@ { "cell_type": "code", "execution_count": null, - "id": "96", + "id": "95", "metadata": {}, "outputs": [], "source": [ @@ -1011,7 +991,7 @@ }, { "cell_type": "markdown", - "id": "97", + "id": "96", "metadata": {}, "source": [ "#### Set Minimizer\n", @@ -1022,7 +1002,7 @@ { "cell_type": "code", "execution_count": null, - "id": "98", + "id": "97", "metadata": {}, "outputs": [], "source": [ @@ -1031,7 +1011,7 @@ }, { "cell_type": "markdown", - "id": "99", + "id": "98", "metadata": {}, "source": [ "Show current fitting engine." @@ -1040,7 +1020,7 @@ { "cell_type": "code", "execution_count": null, - "id": "100", + "id": "99", "metadata": {}, "outputs": [], "source": [ @@ -1049,7 +1029,7 @@ }, { "cell_type": "markdown", - "id": "101", + "id": "100", "metadata": {}, "source": [ "Select desired fitting engine." @@ -1058,7 +1038,7 @@ { "cell_type": "code", "execution_count": null, - "id": "102", + "id": "101", "metadata": {}, "outputs": [], "source": [ @@ -1067,7 +1047,7 @@ }, { "cell_type": "markdown", - "id": "103", + "id": "102", "metadata": {}, "source": [ "### Perform Fit 1/5\n", @@ -1078,7 +1058,7 @@ { "cell_type": "code", "execution_count": null, - "id": "104", + "id": "103", "metadata": {}, "outputs": [], "source": [ @@ -1087,7 +1067,7 @@ }, { "cell_type": "markdown", - "id": "105", + "id": "104", "metadata": {}, "source": [ "Set experiment parameters to be refined." @@ -1096,7 +1076,7 @@ { "cell_type": "code", "execution_count": null, - "id": "106", + "id": "105", "metadata": {}, "outputs": [], "source": [ @@ -1111,7 +1091,7 @@ }, { "cell_type": "markdown", - "id": "107", + "id": "106", "metadata": {}, "source": [ "Show free parameters after selection." @@ -1120,7 +1100,7 @@ { "cell_type": "code", "execution_count": null, - "id": "108", + "id": "107", "metadata": {}, "outputs": [], "source": [ @@ -1129,7 +1109,7 @@ }, { "cell_type": "markdown", - "id": "109", + "id": "108", "metadata": {}, "source": [ "#### Run Fitting" @@ -1138,7 +1118,7 @@ { "cell_type": "code", "execution_count": null, - "id": "110", + "id": "109", "metadata": {}, "outputs": [], "source": [ @@ -1148,7 +1128,7 @@ }, { "cell_type": "markdown", - "id": "111", + "id": "110", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -1157,7 +1137,7 @@ { "cell_type": "code", "execution_count": null, - "id": "112", + "id": "111", "metadata": {}, "outputs": [], "source": [ @@ -1167,7 +1147,7 @@ { "cell_type": "code", "execution_count": null, - "id": "113", + "id": "112", "metadata": {}, "outputs": [], "source": [ @@ -1176,7 +1156,7 @@ }, { "cell_type": "markdown", - "id": "114", + "id": "113", "metadata": {}, "source": [ "#### Save Project State" @@ -1185,7 +1165,7 @@ { "cell_type": "code", "execution_count": null, - "id": "115", + "id": "114", "metadata": {}, "outputs": [], "source": [ @@ -1194,7 +1174,7 @@ }, { "cell_type": "markdown", - "id": "116", + "id": "115", "metadata": {}, "source": [ "### Perform Fit 2/5\n", @@ -1205,7 +1185,7 @@ { "cell_type": "code", "execution_count": null, - "id": "117", + "id": "116", "metadata": {}, "outputs": [], "source": [ @@ -1217,7 +1197,7 @@ }, { "cell_type": "markdown", - "id": "118", + "id": "117", "metadata": {}, "source": [ "Show free parameters after selection." @@ -1226,7 +1206,7 @@ { "cell_type": "code", "execution_count": null, - "id": "119", + "id": "118", "metadata": {}, "outputs": [], "source": [ @@ -1235,7 +1215,7 @@ }, { "cell_type": "markdown", - "id": "120", + "id": "119", "metadata": {}, "source": [ "#### Run Fitting" @@ -1244,7 +1224,7 @@ { "cell_type": "code", "execution_count": null, - "id": "121", + "id": "120", "metadata": {}, "outputs": [], "source": [ @@ -1254,7 +1234,7 @@ }, { "cell_type": "markdown", - "id": "122", + "id": "121", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -1263,7 +1243,7 @@ { "cell_type": "code", "execution_count": null, - "id": "123", + "id": "122", "metadata": {}, "outputs": [], "source": [ @@ -1273,7 +1253,7 @@ { "cell_type": "code", "execution_count": null, - "id": "124", + "id": "123", "metadata": {}, "outputs": [], "source": [ @@ -1282,7 +1262,7 @@ }, { "cell_type": "markdown", - "id": "125", + "id": "124", "metadata": {}, "source": [ "#### Save Project State" @@ -1291,7 +1271,7 @@ { "cell_type": "code", "execution_count": null, - "id": "126", + "id": "125", "metadata": {}, "outputs": [], "source": [ @@ -1300,7 +1280,7 @@ }, { "cell_type": "markdown", - "id": "127", + "id": "126", "metadata": {}, "source": [ "### Perform Fit 3/5\n", @@ -1311,19 +1291,19 @@ { "cell_type": "code", "execution_count": null, - "id": "128", + "id": "127", "metadata": {}, "outputs": [], "source": [ - "project.structures['lbco'].atom_sites['La'].b_iso.free = True\n", - "project.structures['lbco'].atom_sites['Ba'].b_iso.free = True\n", - "project.structures['lbco'].atom_sites['Co'].b_iso.free = True\n", - "project.structures['lbco'].atom_sites['O'].b_iso.free = True" + "project.structures['lbco'].atom_sites['La'].adp_iso.free = True\n", + "project.structures['lbco'].atom_sites['Ba'].adp_iso.free = True\n", + "project.structures['lbco'].atom_sites['Co'].adp_iso.free = True\n", + "project.structures['lbco'].atom_sites['O'].adp_iso.free = True" ] }, { "cell_type": "markdown", - "id": "129", + "id": "128", "metadata": {}, "source": [ "Show free parameters after selection." @@ -1332,7 +1312,7 @@ { "cell_type": "code", "execution_count": null, - "id": "130", + "id": "129", "metadata": {}, "outputs": [], "source": [ @@ -1341,7 +1321,7 @@ }, { "cell_type": "markdown", - "id": "131", + "id": "130", "metadata": {}, "source": [ "#### Run Fitting" @@ -1350,7 +1330,7 @@ { "cell_type": "code", "execution_count": null, - "id": "132", + "id": "131", "metadata": {}, "outputs": [], "source": [ @@ -1360,7 +1340,7 @@ }, { "cell_type": "markdown", - "id": "133", + "id": "132", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -1369,7 +1349,7 @@ { "cell_type": "code", "execution_count": null, - "id": "134", + "id": "133", "metadata": {}, "outputs": [], "source": [ @@ -1379,7 +1359,7 @@ { "cell_type": "code", "execution_count": null, - "id": "135", + "id": "134", "metadata": {}, "outputs": [], "source": [ @@ -1388,7 +1368,7 @@ }, { "cell_type": "markdown", - "id": "136", + "id": "135", "metadata": {}, "source": [ "#### Save Project State" @@ -1397,7 +1377,7 @@ { "cell_type": "code", "execution_count": null, - "id": "137", + "id": "136", "metadata": {}, "outputs": [], "source": [ @@ -1406,7 +1386,7 @@ }, { "cell_type": "markdown", - "id": "138", + "id": "137", "metadata": {}, "source": [ "### Perform Fit 4/5\n", @@ -1419,23 +1399,23 @@ { "cell_type": "code", "execution_count": null, - "id": "139", + "id": "138", "metadata": {}, "outputs": [], "source": [ "project.analysis.aliases.create(\n", " label='biso_La',\n", - " param=project.structures['lbco'].atom_sites['La'].b_iso,\n", + " param=project.structures['lbco'].atom_sites['La'].adp_iso,\n", ")\n", "project.analysis.aliases.create(\n", " label='biso_Ba',\n", - " param=project.structures['lbco'].atom_sites['Ba'].b_iso,\n", + " param=project.structures['lbco'].atom_sites['Ba'].adp_iso,\n", ")" ] }, { "cell_type": "markdown", - "id": "140", + "id": "139", "metadata": {}, "source": [ "Set constraints." @@ -1444,7 +1424,7 @@ { "cell_type": "code", "execution_count": null, - "id": "141", + "id": "140", "metadata": {}, "outputs": [], "source": [ @@ -1453,7 +1433,7 @@ }, { "cell_type": "markdown", - "id": "142", + "id": "141", "metadata": {}, "source": [ "Show defined constraints." @@ -1462,7 +1442,7 @@ { "cell_type": "code", "execution_count": null, - "id": "143", + "id": "142", "metadata": {}, "outputs": [], "source": [ @@ -1471,7 +1451,7 @@ }, { "cell_type": "markdown", - "id": "144", + "id": "143", "metadata": {}, "source": [ "Show free parameters." @@ -1480,7 +1460,7 @@ { "cell_type": "code", "execution_count": null, - "id": "145", + "id": "144", "metadata": {}, "outputs": [], "source": [ @@ -1489,7 +1469,7 @@ }, { "cell_type": "markdown", - "id": "146", + "id": "145", "metadata": {}, "source": [ "#### Run Fitting" @@ -1498,7 +1478,7 @@ { "cell_type": "code", "execution_count": null, - "id": "147", + "id": "146", "metadata": {}, "outputs": [], "source": [ @@ -1508,7 +1488,7 @@ }, { "cell_type": "markdown", - "id": "148", + "id": "147", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -1517,7 +1497,7 @@ { "cell_type": "code", "execution_count": null, - "id": "149", + "id": "148", "metadata": {}, "outputs": [], "source": [ @@ -1527,7 +1507,7 @@ { "cell_type": "code", "execution_count": null, - "id": "150", + "id": "149", "metadata": {}, "outputs": [], "source": [ @@ -1536,7 +1516,7 @@ }, { "cell_type": "markdown", - "id": "151", + "id": "150", "metadata": {}, "source": [ "#### Save Project State" @@ -1545,7 +1525,7 @@ { "cell_type": "code", "execution_count": null, - "id": "152", + "id": "151", "metadata": {}, "outputs": [], "source": [ @@ -1554,7 +1534,7 @@ }, { "cell_type": "markdown", - "id": "153", + "id": "152", "metadata": {}, "source": [ "### Perform Fit 5/5\n", @@ -1567,7 +1547,7 @@ { "cell_type": "code", "execution_count": null, - "id": "154", + "id": "153", "metadata": {}, "outputs": [], "source": [ @@ -1583,7 +1563,7 @@ }, { "cell_type": "markdown", - "id": "155", + "id": "154", "metadata": {}, "source": [ "Set more constraints." @@ -1592,7 +1572,7 @@ { "cell_type": "code", "execution_count": null, - "id": "156", + "id": "155", "metadata": {}, "outputs": [], "source": [ @@ -1603,7 +1583,7 @@ }, { "cell_type": "markdown", - "id": "157", + "id": "156", "metadata": {}, "source": [ "Show defined constraints." @@ -1612,7 +1592,7 @@ { "cell_type": "code", "execution_count": null, - "id": "158", + "id": "157", "metadata": { "lines_to_next_cell": 2 }, @@ -1623,7 +1603,7 @@ }, { "cell_type": "markdown", - "id": "159", + "id": "158", "metadata": {}, "source": [ "Set structure parameters to be refined." @@ -1632,7 +1612,7 @@ { "cell_type": "code", "execution_count": null, - "id": "160", + "id": "159", "metadata": {}, "outputs": [], "source": [ @@ -1641,7 +1621,7 @@ }, { "cell_type": "markdown", - "id": "161", + "id": "160", "metadata": {}, "source": [ "Show free parameters after selection." @@ -1650,7 +1630,7 @@ { "cell_type": "code", "execution_count": null, - "id": "162", + "id": "161", "metadata": {}, "outputs": [], "source": [ @@ -1659,7 +1639,7 @@ }, { "cell_type": "markdown", - "id": "163", + "id": "162", "metadata": {}, "source": [ "#### Run Fitting" @@ -1668,17 +1648,18 @@ { "cell_type": "code", "execution_count": null, - "id": "164", + "id": "163", "metadata": {}, "outputs": [], "source": [ "project.analysis.fit()\n", - "project.analysis.display.fit_results()" + "project.analysis.display.fit_results()\n", + "project.plotter.plot_param_correlations()" ] }, { "cell_type": "markdown", - "id": "165", + "id": "164", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -1687,7 +1668,7 @@ { "cell_type": "code", "execution_count": null, - "id": "166", + "id": "165", "metadata": {}, "outputs": [], "source": [ @@ -1697,7 +1678,7 @@ { "cell_type": "code", "execution_count": null, - "id": "167", + "id": "166", "metadata": {}, "outputs": [], "source": [ @@ -1706,7 +1687,7 @@ }, { "cell_type": "markdown", - "id": "168", + "id": "167", "metadata": {}, "source": [ "#### Save Project State" @@ -1715,7 +1696,7 @@ { "cell_type": "code", "execution_count": null, - "id": "169", + "id": "168", "metadata": {}, "outputs": [], "source": [ @@ -1724,7 +1705,7 @@ }, { "cell_type": "markdown", - "id": "170", + "id": "169", "metadata": {}, "source": [ "## Step 5: Summary\n", @@ -1734,7 +1715,7 @@ }, { "cell_type": "markdown", - "id": "171", + "id": "170", "metadata": {}, "source": [ "#### Show Project Summary" @@ -1743,20 +1724,12 @@ { "cell_type": "code", "execution_count": null, - "id": "172", + "id": "171", "metadata": {}, "outputs": [], "source": [ "project.summary.show_report()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "173", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-3.py b/docs/docs/tutorials/ed-3.py index d6ad73598..9f9219ac1 100644 --- a/docs/docs/tutorials/ed-3.py +++ b/docs/docs/tutorials/ed-3.py @@ -129,7 +129,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.5, + adp_iso=0.5, occupancy=0.5, ) project.structures['lbco'].atom_sites.create( @@ -139,7 +139,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.5, + adp_iso=0.5, occupancy=0.5, ) project.structures['lbco'].atom_sites.create( @@ -149,7 +149,7 @@ fract_y=0.5, fract_z=0.5, wyckoff_letter='b', - b_iso=0.5, + adp_iso=0.5, ) project.structures['lbco'].atom_sites.create( label='O', @@ -158,7 +158,7 @@ fract_y=0.5, fract_z=0.5, wyckoff_letter='c', - b_iso=0.5, + adp_iso=0.5, ) # %% [markdown] @@ -516,10 +516,10 @@ # Set more parameters to be refined. # %% -project.structures['lbco'].atom_sites['La'].b_iso.free = True -project.structures['lbco'].atom_sites['Ba'].b_iso.free = True -project.structures['lbco'].atom_sites['Co'].b_iso.free = True -project.structures['lbco'].atom_sites['O'].b_iso.free = True +project.structures['lbco'].atom_sites['La'].adp_iso.free = True +project.structures['lbco'].atom_sites['Ba'].adp_iso.free = True +project.structures['lbco'].atom_sites['Co'].adp_iso.free = True +project.structures['lbco'].atom_sites['O'].adp_iso.free = True # %% [markdown] # Show free parameters after selection. @@ -559,11 +559,11 @@ # %% project.analysis.aliases.create( label='biso_La', - param=project.structures['lbco'].atom_sites['La'].b_iso, + param=project.structures['lbco'].atom_sites['La'].adp_iso, ) project.analysis.aliases.create( label='biso_Ba', - param=project.structures['lbco'].atom_sites['Ba'].b_iso, + param=project.structures['lbco'].atom_sites['Ba'].adp_iso, ) # %% [markdown] @@ -656,6 +656,7 @@ # %% project.analysis.fit() project.analysis.display.fit_results() +project.plotter.plot_param_correlations() # %% [markdown] # #### Plot Measured vs Calculated @@ -682,5 +683,3 @@ # %% project.summary.show_report() - -# %% diff --git a/docs/docs/tutorials/ed-4.ipynb b/docs/docs/tutorials/ed-4.ipynb index 82ecbcc2f..957c90053 100644 --- a/docs/docs/tutorials/ed-4.ipynb +++ b/docs/docs/tutorials/ed-4.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d969fc08", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Structure Refinement: PbSO4, NPD + XRD\n", @@ -39,7 +39,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -48,7 +48,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -60,7 +60,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Define Structure\n", @@ -74,7 +74,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -83,7 +83,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "#### Set Space Group" @@ -92,7 +92,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -101,7 +101,7 @@ }, { "cell_type": "markdown", - "id": "7", + "id": "8", "metadata": {}, "source": [ "#### Set Unit Cell" @@ -110,7 +110,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -121,7 +121,7 @@ }, { "cell_type": "markdown", - "id": "9", + "id": "10", "metadata": {}, "source": [ "#### Set Atom Sites" @@ -130,7 +130,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": { "lines_to_next_cell": 2 }, @@ -143,7 +143,7 @@ " fract_y=0.25,\n", " fract_z=0.167,\n", " wyckoff_letter='c',\n", - " b_iso=1.37,\n", + " adp_iso=1.37,\n", ")\n", "structure.atom_sites.create(\n", " label='S',\n", @@ -152,7 +152,7 @@ " fract_y=0.25,\n", " fract_z=0.684,\n", " wyckoff_letter='c',\n", - " b_iso=0.3777,\n", + " adp_iso=0.3777,\n", ")\n", "structure.atom_sites.create(\n", " label='O1',\n", @@ -161,7 +161,7 @@ " fract_y=0.25,\n", " fract_z=0.5954,\n", " wyckoff_letter='c',\n", - " b_iso=1.9764,\n", + " adp_iso=1.9764,\n", ")\n", "structure.atom_sites.create(\n", " label='O2',\n", @@ -170,7 +170,7 @@ " fract_y=0.25,\n", " fract_z=0.5432,\n", " wyckoff_letter='c',\n", - " b_iso=1.4456,\n", + " adp_iso=1.4456,\n", ")\n", "structure.atom_sites.create(\n", " label='O3',\n", @@ -179,13 +179,13 @@ " fract_y=0.0272,\n", " fract_z=0.8086,\n", " wyckoff_letter='d',\n", - " b_iso=1.2822,\n", + " adp_iso=1.2822,\n", ")" ] }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "## Define Experiments\n", @@ -201,7 +201,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -210,7 +210,7 @@ }, { "cell_type": "markdown", - "id": "13", + "id": "14", "metadata": {}, "source": [ "#### Create Experiment" @@ -219,7 +219,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -232,7 +232,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "16", "metadata": {}, "source": [ "#### Set Instrument" @@ -241,7 +241,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -251,7 +251,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "#### Set Peak Profile" @@ -260,7 +260,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -273,7 +273,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "20", "metadata": {}, "source": [ "#### Set Background" @@ -281,7 +281,7 @@ }, { "cell_type": "markdown", - "id": "20", + "id": "21", "metadata": {}, "source": [ "Select the background type." @@ -290,7 +290,7 @@ { "cell_type": "code", "execution_count": null, - "id": "21", + "id": "22", "metadata": {}, "outputs": [], "source": [ @@ -299,7 +299,7 @@ }, { "cell_type": "markdown", - "id": "22", + "id": "23", "metadata": {}, "source": [ "Add background points." @@ -308,7 +308,7 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -327,7 +327,7 @@ }, { "cell_type": "markdown", - "id": "24", + "id": "25", "metadata": {}, "source": [ "#### Set Linked Phases" @@ -336,7 +336,7 @@ { "cell_type": "code", "execution_count": null, - "id": "25", + "id": "26", "metadata": {}, "outputs": [], "source": [ @@ -345,7 +345,7 @@ }, { "cell_type": "markdown", - "id": "26", + "id": "27", "metadata": {}, "source": [ "### Experiment 2: xrd\n", @@ -356,7 +356,7 @@ { "cell_type": "code", "execution_count": null, - "id": "27", + "id": "28", "metadata": {}, "outputs": [], "source": [ @@ -365,7 +365,7 @@ }, { "cell_type": "markdown", - "id": "28", + "id": "29", "metadata": {}, "source": [ "#### Create Experiment" @@ -374,7 +374,7 @@ { "cell_type": "code", "execution_count": null, - "id": "29", + "id": "30", "metadata": {}, "outputs": [], "source": [ @@ -387,7 +387,7 @@ }, { "cell_type": "markdown", - "id": "30", + "id": "31", "metadata": {}, "source": [ "#### Set Instrument" @@ -396,7 +396,7 @@ { "cell_type": "code", "execution_count": null, - "id": "31", + "id": "32", "metadata": {}, "outputs": [], "source": [ @@ -406,7 +406,7 @@ }, { "cell_type": "markdown", - "id": "32", + "id": "33", "metadata": {}, "source": [ "#### Set Peak Profile" @@ -415,7 +415,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33", + "id": "34", "metadata": {}, "outputs": [], "source": [ @@ -428,7 +428,7 @@ }, { "cell_type": "markdown", - "id": "34", + "id": "35", "metadata": {}, "source": [ "#### Set Background" @@ -436,7 +436,7 @@ }, { "cell_type": "markdown", - "id": "35", + "id": "36", "metadata": {}, "source": [ "Select background type." @@ -445,7 +445,7 @@ { "cell_type": "code", "execution_count": null, - "id": "36", + "id": "37", "metadata": {}, "outputs": [], "source": [ @@ -454,7 +454,7 @@ }, { "cell_type": "markdown", - "id": "37", + "id": "38", "metadata": {}, "source": [ "Add background points." @@ -463,7 +463,7 @@ { "cell_type": "code", "execution_count": null, - "id": "38", + "id": "39", "metadata": {}, "outputs": [], "source": [ @@ -480,7 +480,7 @@ }, { "cell_type": "markdown", - "id": "39", + "id": "40", "metadata": {}, "source": [ "#### Set Linked Phases" @@ -489,7 +489,7 @@ { "cell_type": "code", "execution_count": null, - "id": "40", + "id": "41", "metadata": {}, "outputs": [], "source": [ @@ -498,7 +498,7 @@ }, { "cell_type": "markdown", - "id": "41", + "id": "42", "metadata": {}, "source": [ "## Define Project\n", @@ -512,7 +512,7 @@ { "cell_type": "code", "execution_count": null, - "id": "42", + "id": "43", "metadata": {}, "outputs": [], "source": [ @@ -521,7 +521,7 @@ }, { "cell_type": "markdown", - "id": "43", + "id": "44", "metadata": {}, "source": [ "#### Add Structure" @@ -530,7 +530,7 @@ { "cell_type": "code", "execution_count": null, - "id": "44", + "id": "45", "metadata": {}, "outputs": [], "source": [ @@ -539,7 +539,7 @@ }, { "cell_type": "markdown", - "id": "45", + "id": "46", "metadata": {}, "source": [ "#### Add Experiments" @@ -548,7 +548,7 @@ { "cell_type": "code", "execution_count": null, - "id": "46", + "id": "47", "metadata": {}, "outputs": [], "source": [ @@ -558,7 +558,7 @@ }, { "cell_type": "markdown", - "id": "47", + "id": "48", "metadata": {}, "source": [ "## Perform Analysis\n", @@ -572,7 +572,7 @@ { "cell_type": "code", "execution_count": null, - "id": "48", + "id": "49", "metadata": {}, "outputs": [], "source": [ @@ -581,7 +581,7 @@ }, { "cell_type": "markdown", - "id": "49", + "id": "50", "metadata": {}, "source": [ "#### Set Minimizer" @@ -590,7 +590,7 @@ { "cell_type": "code", "execution_count": null, - "id": "50", + "id": "51", "metadata": {}, "outputs": [], "source": [ @@ -599,7 +599,7 @@ }, { "cell_type": "markdown", - "id": "51", + "id": "52", "metadata": {}, "source": [ "#### Set Fitting Parameters\n", @@ -610,7 +610,7 @@ { "cell_type": "code", "execution_count": null, - "id": "52", + "id": "53", "metadata": {}, "outputs": [], "source": [ @@ -621,7 +621,7 @@ }, { "cell_type": "markdown", - "id": "53", + "id": "54", "metadata": {}, "source": [ "Set experiment parameters to be optimized." @@ -630,7 +630,7 @@ { "cell_type": "code", "execution_count": null, - "id": "54", + "id": "55", "metadata": {}, "outputs": [], "source": [ @@ -647,7 +647,7 @@ { "cell_type": "code", "execution_count": null, - "id": "55", + "id": "56", "metadata": {}, "outputs": [], "source": [ @@ -666,7 +666,7 @@ }, { "cell_type": "markdown", - "id": "56", + "id": "57", "metadata": {}, "source": [ "#### Perform Fit" @@ -675,17 +675,18 @@ { "cell_type": "code", "execution_count": null, - "id": "57", + "id": "58", "metadata": {}, "outputs": [], "source": [ "project.analysis.fit()\n", - "project.analysis.display.fit_results()" + "project.analysis.display.fit_results()\n", + "project.plotter.plot_param_correlations()" ] }, { "cell_type": "markdown", - "id": "58", + "id": "59", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -694,7 +695,7 @@ { "cell_type": "code", "execution_count": null, - "id": "59", + "id": "60", "metadata": {}, "outputs": [], "source": [ @@ -704,7 +705,7 @@ { "cell_type": "code", "execution_count": null, - "id": "60", + "id": "61", "metadata": {}, "outputs": [], "source": [ diff --git a/docs/docs/tutorials/ed-4.py b/docs/docs/tutorials/ed-4.py index e2e1942bc..21bbaaada 100644 --- a/docs/docs/tutorials/ed-4.py +++ b/docs/docs/tutorials/ed-4.py @@ -56,7 +56,7 @@ fract_y=0.25, fract_z=0.167, wyckoff_letter='c', - b_iso=1.37, + adp_iso=1.37, ) structure.atom_sites.create( label='S', @@ -65,7 +65,7 @@ fract_y=0.25, fract_z=0.684, wyckoff_letter='c', - b_iso=0.3777, + adp_iso=0.3777, ) structure.atom_sites.create( label='O1', @@ -74,7 +74,7 @@ fract_y=0.25, fract_z=0.5954, wyckoff_letter='c', - b_iso=1.9764, + adp_iso=1.9764, ) structure.atom_sites.create( label='O2', @@ -83,7 +83,7 @@ fract_y=0.25, fract_z=0.5432, wyckoff_letter='c', - b_iso=1.4456, + adp_iso=1.4456, ) structure.atom_sites.create( label='O3', @@ -92,7 +92,7 @@ fract_y=0.0272, fract_z=0.8086, wyckoff_letter='d', - b_iso=1.2822, + adp_iso=1.2822, ) @@ -314,6 +314,7 @@ # %% project.analysis.fit() project.analysis.display.fit_results() +project.plotter.plot_param_correlations() # %% [markdown] # #### Plot Measured vs Calculated diff --git a/docs/docs/tutorials/ed-5.ipynb b/docs/docs/tutorials/ed-5.ipynb index 9f4f53310..c78e3577d 100644 --- a/docs/docs/tutorials/ed-5.ipynb +++ b/docs/docs/tutorials/ed-5.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "645a5335", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Structure Refinement: Co2SiO4, D20\n", @@ -33,7 +33,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -42,7 +42,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -54,7 +54,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Define Structure\n", @@ -68,7 +68,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -77,7 +77,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "#### Set Space Group" @@ -86,7 +86,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -96,7 +96,7 @@ }, { "cell_type": "markdown", - "id": "7", + "id": "8", "metadata": {}, "source": [ "#### Set Unit Cell" @@ -105,7 +105,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -116,7 +116,7 @@ }, { "cell_type": "markdown", - "id": "9", + "id": "10", "metadata": {}, "source": [ "#### Set Atom Sites" @@ -125,7 +125,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -136,7 +136,7 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", " label='Co2',\n", @@ -145,7 +145,7 @@ " fract_y=0.25,\n", " fract_z=0.985,\n", " wyckoff_letter='c',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", " label='Si',\n", @@ -154,7 +154,7 @@ " fract_y=0.25,\n", " fract_z=0.429,\n", " wyckoff_letter='c',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", " label='O1',\n", @@ -163,7 +163,7 @@ " fract_y=0.25,\n", " fract_z=0.771,\n", " wyckoff_letter='c',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", " label='O2',\n", @@ -172,7 +172,7 @@ " fract_y=0.25,\n", " fract_z=0.217,\n", " wyckoff_letter='c',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", " label='O3',\n", @@ -181,13 +181,13 @@ " fract_y=0.032,\n", " fract_z=0.28,\n", " wyckoff_letter='d',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")" ] }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "## Define Experiment\n", @@ -201,7 +201,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -210,7 +210,7 @@ }, { "cell_type": "markdown", - "id": "13", + "id": "14", "metadata": {}, "source": [ "#### Create Experiment" @@ -219,7 +219,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -228,7 +228,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "16", "metadata": {}, "source": [ "#### Set Instrument" @@ -237,7 +237,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -247,7 +247,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "#### Set Peak Profile" @@ -256,10 +256,11 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ + "expt.peak_profile_type = 'pseudo-voigt + empirical asymmetry'\n", "expt.peak.broad_gauss_u = 0.3\n", "expt.peak.broad_gauss_v = -0.5\n", "expt.peak.broad_gauss_w = 0.4" @@ -267,7 +268,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "20", "metadata": {}, "source": [ "#### Set Background" @@ -276,7 +277,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -298,7 +299,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "#### Set Linked Phases" @@ -307,7 +308,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -316,7 +317,7 @@ }, { "cell_type": "markdown", - "id": "23", + "id": "24", "metadata": {}, "source": [ "## Define Project\n", @@ -330,7 +331,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -339,28 +340,8 @@ }, { "cell_type": "markdown", - "id": "25", - "metadata": {}, - "source": [ - "#### Set Plotting Engine" - ] - }, - { - "cell_type": "code", - "execution_count": null, "id": "26", "metadata": {}, - "outputs": [], - "source": [ - "# Keep the auto-selected engine. Alternatively, you can uncomment the\n", - "# line below to explicitly set the engine to the required one.\n", - "# project.plotter.engine = 'plotly'" - ] - }, - { - "cell_type": "markdown", - "id": "27", - "metadata": {}, "source": [ "#### Add Structure" ] @@ -368,7 +349,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -377,7 +358,7 @@ }, { "cell_type": "markdown", - "id": "29", + "id": "28", "metadata": {}, "source": [ "#### Add Experiment" @@ -386,7 +367,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -395,7 +376,7 @@ }, { "cell_type": "markdown", - "id": "31", + "id": "30", "metadata": {}, "source": [ "## Perform Analysis\n", @@ -409,7 +390,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -418,7 +399,7 @@ }, { "cell_type": "markdown", - "id": "33", + "id": "32", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -427,7 +408,7 @@ { "cell_type": "code", "execution_count": null, - "id": "34", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -437,7 +418,7 @@ { "cell_type": "code", "execution_count": null, - "id": "35", + "id": "34", "metadata": {}, "outputs": [], "source": [ @@ -446,7 +427,7 @@ }, { "cell_type": "markdown", - "id": "36", + "id": "35", "metadata": {}, "source": [ "#### Set Free Parameters" @@ -455,7 +436,7 @@ { "cell_type": "code", "execution_count": null, - "id": "37", + "id": "36", "metadata": {}, "outputs": [], "source": [ @@ -475,18 +456,18 @@ "structure.atom_sites['O3'].fract_y.free = True\n", "structure.atom_sites['O3'].fract_z.free = True\n", "\n", - "structure.atom_sites['Co1'].b_iso.free = True\n", - "structure.atom_sites['Co2'].b_iso.free = True\n", - "structure.atom_sites['Si'].b_iso.free = True\n", - "structure.atom_sites['O1'].b_iso.free = True\n", - "structure.atom_sites['O2'].b_iso.free = True\n", - "structure.atom_sites['O3'].b_iso.free = True" + "structure.atom_sites['Co1'].adp_iso.free = True\n", + "structure.atom_sites['Co2'].adp_iso.free = True\n", + "structure.atom_sites['Si'].adp_iso.free = True\n", + "structure.atom_sites['O1'].adp_iso.free = True\n", + "structure.atom_sites['O2'].adp_iso.free = True\n", + "structure.atom_sites['O3'].adp_iso.free = True" ] }, { "cell_type": "code", "execution_count": null, - "id": "38", + "id": "37", "metadata": {}, "outputs": [], "source": [ @@ -499,13 +480,15 @@ "expt.peak.broad_gauss_w.free = True\n", "expt.peak.broad_lorentz_y.free = True\n", "\n", + "expt.peak.asym_empir_2.free = True\n", + "\n", "for point in expt.background:\n", " point.y.free = True" ] }, { "cell_type": "markdown", - "id": "39", + "id": "38", "metadata": {}, "source": [ "#### Set Constraints\n", @@ -516,23 +499,23 @@ { "cell_type": "code", "execution_count": null, - "id": "40", + "id": "39", "metadata": {}, "outputs": [], "source": [ "project.analysis.aliases.create(\n", " label='biso_Co1',\n", - " param=project.structures['cosio'].atom_sites['Co1'].b_iso,\n", + " param=project.structures['cosio'].atom_sites['Co1'].adp_iso,\n", ")\n", "project.analysis.aliases.create(\n", " label='biso_Co2',\n", - " param=project.structures['cosio'].atom_sites['Co2'].b_iso,\n", + " param=project.structures['cosio'].atom_sites['Co2'].adp_iso,\n", ")" ] }, { "cell_type": "markdown", - "id": "41", + "id": "40", "metadata": {}, "source": [ "Set constraints." @@ -541,25 +524,33 @@ { "cell_type": "code", "execution_count": null, - "id": "42", + "id": "41", "metadata": { "lines_to_next_cell": 2 }, "outputs": [], "source": [ - "project.analysis.constraints.create(\n", - " expression='biso_Co2 = biso_Co1',\n", - ")" + "project.analysis.constraints.create(expression='biso_Co2 = biso_Co1')" ] }, { "cell_type": "markdown", - "id": "43", + "id": "42", "metadata": {}, "source": [ "#### Run Fitting" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "43", + "metadata": {}, + "outputs": [], + "source": [ + "project.analysis.fit()" + ] + }, { "cell_type": "code", "execution_count": null, @@ -567,14 +558,23 @@ "metadata": {}, "outputs": [], "source": [ - "project.analysis.fit()\n", "project.analysis.display.fit_results()" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "id": "45", "metadata": {}, + "outputs": [], + "source": [ + "project.plotter.plot_param_correlations()" + ] + }, + { + "cell_type": "markdown", + "id": "46", + "metadata": {}, "source": [ "#### Plot Measured vs Calculated" ] @@ -582,7 +582,7 @@ { "cell_type": "code", "execution_count": null, - "id": "46", + "id": "47", "metadata": {}, "outputs": [], "source": [ @@ -592,7 +592,7 @@ { "cell_type": "code", "execution_count": null, - "id": "47", + "id": "48", "metadata": {}, "outputs": [], "source": [ @@ -601,7 +601,7 @@ }, { "cell_type": "markdown", - "id": "48", + "id": "49", "metadata": {}, "source": [ "## Summary\n", @@ -611,7 +611,7 @@ }, { "cell_type": "markdown", - "id": "49", + "id": "50", "metadata": {}, "source": [ "#### Show Project Summary" @@ -620,7 +620,7 @@ { "cell_type": "code", "execution_count": null, - "id": "50", + "id": "51", "metadata": {}, "outputs": [], "source": [ diff --git a/docs/docs/tutorials/ed-5.py b/docs/docs/tutorials/ed-5.py index 2938e50de..acd563699 100644 --- a/docs/docs/tutorials/ed-5.py +++ b/docs/docs/tutorials/ed-5.py @@ -51,7 +51,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.5, + adp_iso=0.5, ) structure.atom_sites.create( label='Co2', @@ -60,7 +60,7 @@ fract_y=0.25, fract_z=0.985, wyckoff_letter='c', - b_iso=0.5, + adp_iso=0.5, ) structure.atom_sites.create( label='Si', @@ -69,7 +69,7 @@ fract_y=0.25, fract_z=0.429, wyckoff_letter='c', - b_iso=0.5, + adp_iso=0.5, ) structure.atom_sites.create( label='O1', @@ -78,7 +78,7 @@ fract_y=0.25, fract_z=0.771, wyckoff_letter='c', - b_iso=0.5, + adp_iso=0.5, ) structure.atom_sites.create( label='O2', @@ -87,7 +87,7 @@ fract_y=0.25, fract_z=0.217, wyckoff_letter='c', - b_iso=0.5, + adp_iso=0.5, ) structure.atom_sites.create( label='O3', @@ -96,7 +96,7 @@ fract_y=0.032, fract_z=0.28, wyckoff_letter='d', - b_iso=0.5, + adp_iso=0.5, ) # %% [markdown] @@ -220,12 +220,12 @@ structure.atom_sites['O3'].fract_y.free = True structure.atom_sites['O3'].fract_z.free = True -structure.atom_sites['Co1'].b_iso.free = True -structure.atom_sites['Co2'].b_iso.free = True -structure.atom_sites['Si'].b_iso.free = True -structure.atom_sites['O1'].b_iso.free = True -structure.atom_sites['O2'].b_iso.free = True -structure.atom_sites['O3'].b_iso.free = True +structure.atom_sites['Co1'].adp_iso.free = True +structure.atom_sites['Co2'].adp_iso.free = True +structure.atom_sites['Si'].adp_iso.free = True +structure.atom_sites['O1'].adp_iso.free = True +structure.atom_sites['O2'].adp_iso.free = True +structure.atom_sites['O3'].adp_iso.free = True # %% expt.linked_phases['cosio'].scale.free = True @@ -250,11 +250,11 @@ # %% project.analysis.aliases.create( label='biso_Co1', - param=project.structures['cosio'].atom_sites['Co1'].b_iso, + param=project.structures['cosio'].atom_sites['Co1'].adp_iso, ) project.analysis.aliases.create( label='biso_Co2', - param=project.structures['cosio'].atom_sites['Co2'].b_iso, + param=project.structures['cosio'].atom_sites['Co2'].adp_iso, ) # %% [markdown] diff --git a/docs/docs/tutorials/ed-6.ipynb b/docs/docs/tutorials/ed-6.ipynb index be47740f1..a2259fe9d 100644 --- a/docs/docs/tutorials/ed-6.ipynb +++ b/docs/docs/tutorials/ed-6.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fdc5cf61", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Structure Refinement: HS, HRPT\n", @@ -33,7 +33,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -42,7 +42,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -54,7 +54,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Define Structure\n", @@ -68,7 +68,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -77,7 +77,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "#### Set Space Group" @@ -86,7 +86,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -96,7 +96,7 @@ }, { "cell_type": "markdown", - "id": "7", + "id": "8", "metadata": { "lines_to_next_cell": 2 }, @@ -107,7 +107,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -117,7 +117,7 @@ }, { "cell_type": "markdown", - "id": "9", + "id": "10", "metadata": {}, "source": [ "#### Set Atom Sites" @@ -126,7 +126,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -137,7 +137,7 @@ " fract_y=0,\n", " fract_z=0.5,\n", " wyckoff_letter='b',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", " label='Cu',\n", @@ -146,7 +146,7 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='e',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", " label='O',\n", @@ -155,7 +155,7 @@ " fract_y=-0.21,\n", " fract_z=0.06,\n", " wyckoff_letter='h',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", " label='Cl',\n", @@ -164,7 +164,7 @@ " fract_y=0,\n", " fract_z=0.197,\n", " wyckoff_letter='c',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")\n", "structure.atom_sites.create(\n", " label='H',\n", @@ -173,13 +173,13 @@ " fract_y=-0.13,\n", " fract_z=0.08,\n", " wyckoff_letter='h',\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")" ] }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "## Define Experiment\n", @@ -193,7 +193,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -202,7 +202,7 @@ }, { "cell_type": "markdown", - "id": "13", + "id": "14", "metadata": {}, "source": [ "#### Create Experiment" @@ -211,7 +211,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -220,7 +220,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "16", "metadata": {}, "source": [ "#### Set Instrument" @@ -229,7 +229,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -239,7 +239,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "#### Set Peak Profile" @@ -248,7 +248,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -261,7 +261,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "20", "metadata": {}, "source": [ "#### Set Background" @@ -270,7 +270,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -287,7 +287,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "#### Set Linked Phases" @@ -296,7 +296,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -305,7 +305,7 @@ }, { "cell_type": "markdown", - "id": "23", + "id": "24", "metadata": {}, "source": [ "## Define Project\n", @@ -319,7 +319,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -328,7 +328,7 @@ }, { "cell_type": "markdown", - "id": "25", + "id": "26", "metadata": {}, "source": [ "#### Set Plotting Engine" @@ -337,7 +337,7 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -348,7 +348,7 @@ }, { "cell_type": "markdown", - "id": "27", + "id": "28", "metadata": {}, "source": [ "#### Add Structure" @@ -357,7 +357,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -366,7 +366,7 @@ }, { "cell_type": "markdown", - "id": "29", + "id": "30", "metadata": {}, "source": [ "#### Add Experiment" @@ -375,7 +375,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -384,7 +384,7 @@ }, { "cell_type": "markdown", - "id": "31", + "id": "32", "metadata": {}, "source": [ "## Perform Analysis\n", @@ -398,7 +398,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -407,7 +407,7 @@ }, { "cell_type": "markdown", - "id": "33", + "id": "34", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -416,7 +416,7 @@ { "cell_type": "code", "execution_count": null, - "id": "34", + "id": "35", "metadata": {}, "outputs": [], "source": [ @@ -426,7 +426,7 @@ { "cell_type": "code", "execution_count": null, - "id": "35", + "id": "36", "metadata": {}, "outputs": [], "source": [ @@ -435,7 +435,7 @@ }, { "cell_type": "markdown", - "id": "36", + "id": "37", "metadata": {}, "source": [ "### Perform Fit 1/5\n", @@ -446,7 +446,7 @@ { "cell_type": "code", "execution_count": null, - "id": "37", + "id": "38", "metadata": {}, "outputs": [], "source": [ @@ -459,7 +459,7 @@ }, { "cell_type": "markdown", - "id": "38", + "id": "39", "metadata": {}, "source": [ "Show free parameters after selection." @@ -468,7 +468,7 @@ { "cell_type": "code", "execution_count": null, - "id": "39", + "id": "40", "metadata": {}, "outputs": [], "source": [ @@ -477,7 +477,7 @@ }, { "cell_type": "markdown", - "id": "40", + "id": "41", "metadata": {}, "source": [ "#### Run Fitting" @@ -486,7 +486,7 @@ { "cell_type": "code", "execution_count": null, - "id": "41", + "id": "42", "metadata": {}, "outputs": [], "source": [ @@ -496,7 +496,7 @@ { "cell_type": "code", "execution_count": null, - "id": "42", + "id": "43", "metadata": {}, "outputs": [], "source": [ @@ -505,7 +505,7 @@ }, { "cell_type": "markdown", - "id": "43", + "id": "44", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -514,7 +514,7 @@ { "cell_type": "code", "execution_count": null, - "id": "44", + "id": "45", "metadata": {}, "outputs": [], "source": [ @@ -524,7 +524,7 @@ { "cell_type": "code", "execution_count": null, - "id": "45", + "id": "46", "metadata": {}, "outputs": [], "source": [ @@ -533,7 +533,7 @@ }, { "cell_type": "markdown", - "id": "46", + "id": "47", "metadata": {}, "source": [ "### Perform Fit 2/5\n", @@ -544,7 +544,7 @@ { "cell_type": "code", "execution_count": null, - "id": "47", + "id": "48", "metadata": {}, "outputs": [], "source": [ @@ -559,7 +559,7 @@ }, { "cell_type": "markdown", - "id": "48", + "id": "49", "metadata": {}, "source": [ "Show free parameters after selection." @@ -568,7 +568,7 @@ { "cell_type": "code", "execution_count": null, - "id": "49", + "id": "50", "metadata": {}, "outputs": [], "source": [ @@ -577,7 +577,7 @@ }, { "cell_type": "markdown", - "id": "50", + "id": "51", "metadata": {}, "source": [ "#### Run Fitting" @@ -586,7 +586,7 @@ { "cell_type": "code", "execution_count": null, - "id": "51", + "id": "52", "metadata": {}, "outputs": [], "source": [ @@ -596,7 +596,7 @@ { "cell_type": "code", "execution_count": null, - "id": "52", + "id": "53", "metadata": {}, "outputs": [], "source": [ @@ -605,7 +605,7 @@ }, { "cell_type": "markdown", - "id": "53", + "id": "54", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -614,7 +614,7 @@ { "cell_type": "code", "execution_count": null, - "id": "54", + "id": "55", "metadata": {}, "outputs": [], "source": [ @@ -624,7 +624,7 @@ { "cell_type": "code", "execution_count": null, - "id": "55", + "id": "56", "metadata": {}, "outputs": [], "source": [ @@ -633,7 +633,7 @@ }, { "cell_type": "markdown", - "id": "56", + "id": "57", "metadata": {}, "source": [ "### Perform Fit 3/5\n", @@ -644,7 +644,7 @@ { "cell_type": "code", "execution_count": null, - "id": "57", + "id": "58", "metadata": {}, "outputs": [], "source": [ @@ -657,7 +657,7 @@ }, { "cell_type": "markdown", - "id": "58", + "id": "59", "metadata": {}, "source": [ "Show free parameters after selection." @@ -666,7 +666,7 @@ { "cell_type": "code", "execution_count": null, - "id": "59", + "id": "60", "metadata": {}, "outputs": [], "source": [ @@ -675,7 +675,7 @@ }, { "cell_type": "markdown", - "id": "60", + "id": "61", "metadata": {}, "source": [ "#### Run Fitting" @@ -684,7 +684,7 @@ { "cell_type": "code", "execution_count": null, - "id": "61", + "id": "62", "metadata": {}, "outputs": [], "source": [ @@ -694,7 +694,7 @@ { "cell_type": "code", "execution_count": null, - "id": "62", + "id": "63", "metadata": {}, "outputs": [], "source": [ @@ -703,7 +703,7 @@ }, { "cell_type": "markdown", - "id": "63", + "id": "64", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -712,7 +712,7 @@ { "cell_type": "code", "execution_count": null, - "id": "64", + "id": "65", "metadata": {}, "outputs": [], "source": [ @@ -722,7 +722,7 @@ { "cell_type": "code", "execution_count": null, - "id": "65", + "id": "66", "metadata": {}, "outputs": [], "source": [ @@ -731,7 +731,7 @@ }, { "cell_type": "markdown", - "id": "66", + "id": "67", "metadata": {}, "source": [ "### Perform Fit 4/5\n", @@ -742,20 +742,20 @@ { "cell_type": "code", "execution_count": null, - "id": "67", + "id": "68", "metadata": {}, "outputs": [], "source": [ - "structure.atom_sites['Zn'].b_iso.free = True\n", - "structure.atom_sites['Cu'].b_iso.free = True\n", - "structure.atom_sites['O'].b_iso.free = True\n", - "structure.atom_sites['Cl'].b_iso.free = True\n", - "structure.atom_sites['H'].b_iso.free = True" + "structure.atom_sites['Zn'].adp_iso.free = True\n", + "structure.atom_sites['Cu'].adp_iso.free = True\n", + "structure.atom_sites['O'].adp_iso.free = True\n", + "structure.atom_sites['Cl'].adp_iso.free = True\n", + "structure.atom_sites['H'].adp_iso.free = True" ] }, { "cell_type": "markdown", - "id": "68", + "id": "69", "metadata": {}, "source": [ "Show free parameters after selection." @@ -764,7 +764,7 @@ { "cell_type": "code", "execution_count": null, - "id": "69", + "id": "70", "metadata": {}, "outputs": [], "source": [ @@ -773,7 +773,7 @@ }, { "cell_type": "markdown", - "id": "70", + "id": "71", "metadata": {}, "source": [ "#### Run Fitting" @@ -782,7 +782,7 @@ { "cell_type": "code", "execution_count": null, - "id": "71", + "id": "72", "metadata": {}, "outputs": [], "source": [ @@ -792,16 +792,26 @@ { "cell_type": "code", "execution_count": null, - "id": "72", + "id": "73", "metadata": {}, "outputs": [], "source": [ "project.analysis.display.fit_results()" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "74", + "metadata": {}, + "outputs": [], + "source": [ + "project.plotter.plot_param_correlations()" + ] + }, { "cell_type": "markdown", - "id": "73", + "id": "75", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -810,7 +820,7 @@ { "cell_type": "code", "execution_count": null, - "id": "74", + "id": "76", "metadata": {}, "outputs": [], "source": [ @@ -820,7 +830,7 @@ { "cell_type": "code", "execution_count": null, - "id": "75", + "id": "77", "metadata": {}, "outputs": [], "source": [ @@ -829,7 +839,7 @@ }, { "cell_type": "markdown", - "id": "76", + "id": "78", "metadata": {}, "source": [ "## Summary\n", @@ -839,7 +849,7 @@ }, { "cell_type": "markdown", - "id": "77", + "id": "79", "metadata": {}, "source": [ "#### Show Project Summary" @@ -848,7 +858,7 @@ { "cell_type": "code", "execution_count": null, - "id": "78", + "id": "80", "metadata": {}, "outputs": [], "source": [ diff --git a/docs/docs/tutorials/ed-6.py b/docs/docs/tutorials/ed-6.py index 70c1c1948..20edc504c 100644 --- a/docs/docs/tutorials/ed-6.py +++ b/docs/docs/tutorials/ed-6.py @@ -51,7 +51,7 @@ fract_y=0, fract_z=0.5, wyckoff_letter='b', - b_iso=0.5, + adp_iso=0.5, ) structure.atom_sites.create( label='Cu', @@ -60,7 +60,7 @@ fract_y=0, fract_z=0, wyckoff_letter='e', - b_iso=0.5, + adp_iso=0.5, ) structure.atom_sites.create( label='O', @@ -69,7 +69,7 @@ fract_y=-0.21, fract_z=0.06, wyckoff_letter='h', - b_iso=0.5, + adp_iso=0.5, ) structure.atom_sites.create( label='Cl', @@ -78,7 +78,7 @@ fract_y=0, fract_z=0.197, wyckoff_letter='c', - b_iso=0.5, + adp_iso=0.5, ) structure.atom_sites.create( label='H', @@ -87,7 +87,7 @@ fract_y=-0.13, fract_z=0.08, wyckoff_letter='h', - b_iso=0.5, + adp_iso=0.5, ) # %% [markdown] @@ -311,11 +311,11 @@ # Set more parameters to be refined. # %% -structure.atom_sites['Zn'].b_iso.free = True -structure.atom_sites['Cu'].b_iso.free = True -structure.atom_sites['O'].b_iso.free = True -structure.atom_sites['Cl'].b_iso.free = True -structure.atom_sites['H'].b_iso.free = True +structure.atom_sites['Zn'].adp_iso.free = True +structure.atom_sites['Cu'].adp_iso.free = True +structure.atom_sites['O'].adp_iso.free = True +structure.atom_sites['Cl'].adp_iso.free = True +structure.atom_sites['H'].adp_iso.free = True # %% [markdown] # Show free parameters after selection. @@ -332,6 +332,9 @@ # %% project.analysis.display.fit_results() +# %% +project.plotter.plot_param_correlations() + # %% [markdown] # #### Plot Measured vs Calculated diff --git a/docs/docs/tutorials/ed-7.ipynb b/docs/docs/tutorials/ed-7.ipynb index b80018e28..bc9a57ed7 100644 --- a/docs/docs/tutorials/ed-7.ipynb +++ b/docs/docs/tutorials/ed-7.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e195a39c", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Structure Refinement: Si, SEPD\n", @@ -33,7 +33,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -42,7 +42,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -54,7 +54,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Define Structure\n", @@ -68,7 +68,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -77,7 +77,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "#### Set Space Group" @@ -86,7 +86,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -96,7 +96,7 @@ }, { "cell_type": "markdown", - "id": "7", + "id": "8", "metadata": {}, "source": [ "#### Set Unit Cell" @@ -105,7 +105,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -114,7 +114,7 @@ }, { "cell_type": "markdown", - "id": "9", + "id": "10", "metadata": {}, "source": [ "#### Set Atom Sites" @@ -123,7 +123,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -133,13 +133,13 @@ " fract_x=0.125,\n", " fract_y=0.125,\n", " fract_z=0.125,\n", - " b_iso=0.5,\n", + " adp_iso=0.5,\n", ")" ] }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "## Define Experiment\n", @@ -153,7 +153,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -162,7 +162,7 @@ }, { "cell_type": "markdown", - "id": "13", + "id": "14", "metadata": {}, "source": [ "#### Create Experiment" @@ -171,7 +171,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -182,7 +182,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "16", "metadata": {}, "source": [ "#### Set Instrument" @@ -191,7 +191,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -203,7 +203,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "#### Set Peak Profile" @@ -212,41 +212,24 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ - "expt.peak_profile_type = 'pseudo-voigt * ikeda-carpenter'\n", + "expt.peak_profile_type = 'jorgensen'\n", "expt.peak.broad_gauss_sigma_0 = 3.0\n", "expt.peak.broad_gauss_sigma_1 = 40.0\n", "expt.peak.broad_gauss_sigma_2 = 2.0\n", - "expt.peak.broad_mix_beta_0 = 0.04221\n", - "expt.peak.broad_mix_beta_1 = 0.00946" + "expt.peak.exp_decay_beta_0 = 0.04221\n", + "expt.peak.exp_decay_beta_1 = 0.00946\n", + "expt.peak.exp_rise_alpha_0 = 0.0\n", + "expt.peak.exp_rise_alpha_1 = 0.5971" ] }, { "cell_type": "markdown", - "id": "19", - "metadata": {}, - "source": [ - "#### Set Peak Asymmetry" - ] - }, - { - "cell_type": "code", - "execution_count": null, "id": "20", "metadata": {}, - "outputs": [], - "source": [ - "expt.peak.asym_alpha_0 = 0.0\n", - "expt.peak.asym_alpha_1 = 0.5971" - ] - }, - { - "cell_type": "markdown", - "id": "21", - "metadata": {}, "source": [ "#### Set Background" ] @@ -254,7 +237,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -265,7 +248,7 @@ }, { "cell_type": "markdown", - "id": "23", + "id": "22", "metadata": {}, "source": [ "#### Set Linked Phases" @@ -274,7 +257,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -283,7 +266,7 @@ }, { "cell_type": "markdown", - "id": "25", + "id": "24", "metadata": {}, "source": [ "## Define Project\n", @@ -297,7 +280,7 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -306,7 +289,7 @@ }, { "cell_type": "markdown", - "id": "27", + "id": "26", "metadata": {}, "source": [ "#### Add Structure" @@ -315,7 +298,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -324,7 +307,7 @@ }, { "cell_type": "markdown", - "id": "29", + "id": "28", "metadata": {}, "source": [ "#### Add Experiment" @@ -333,7 +316,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -342,7 +325,7 @@ }, { "cell_type": "markdown", - "id": "31", + "id": "30", "metadata": {}, "source": [ "## Perform Analysis\n", @@ -356,7 +339,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -365,7 +348,7 @@ }, { "cell_type": "markdown", - "id": "33", + "id": "32", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -374,7 +357,7 @@ { "cell_type": "code", "execution_count": null, - "id": "34", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -384,7 +367,7 @@ }, { "cell_type": "markdown", - "id": "35", + "id": "34", "metadata": {}, "source": [ "### Perform Fit 1/5\n", @@ -395,7 +378,7 @@ { "cell_type": "code", "execution_count": null, - "id": "36", + "id": "35", "metadata": {}, "outputs": [], "source": [ @@ -407,7 +390,7 @@ }, { "cell_type": "markdown", - "id": "37", + "id": "36", "metadata": {}, "source": [ "Show free parameters after selection." @@ -416,7 +399,7 @@ { "cell_type": "code", "execution_count": null, - "id": "38", + "id": "37", "metadata": {}, "outputs": [], "source": [ @@ -425,7 +408,7 @@ }, { "cell_type": "markdown", - "id": "39", + "id": "38", "metadata": {}, "source": [ "#### Run Fitting" @@ -434,7 +417,7 @@ { "cell_type": "code", "execution_count": null, - "id": "40", + "id": "39", "metadata": {}, "outputs": [], "source": [ @@ -444,7 +427,7 @@ }, { "cell_type": "markdown", - "id": "41", + "id": "40", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -453,7 +436,7 @@ { "cell_type": "code", "execution_count": null, - "id": "42", + "id": "41", "metadata": {}, "outputs": [], "source": [ @@ -463,7 +446,7 @@ { "cell_type": "code", "execution_count": null, - "id": "43", + "id": "42", "metadata": {}, "outputs": [], "source": [ @@ -472,7 +455,7 @@ }, { "cell_type": "markdown", - "id": "44", + "id": "43", "metadata": {}, "source": [ "### Perform Fit 2/5\n", @@ -483,7 +466,7 @@ { "cell_type": "code", "execution_count": null, - "id": "45", + "id": "44", "metadata": {}, "outputs": [], "source": [ @@ -493,7 +476,7 @@ }, { "cell_type": "markdown", - "id": "46", + "id": "45", "metadata": {}, "source": [ "Show free parameters after selection." @@ -502,7 +485,7 @@ { "cell_type": "code", "execution_count": null, - "id": "47", + "id": "46", "metadata": {}, "outputs": [], "source": [ @@ -511,7 +494,7 @@ }, { "cell_type": "markdown", - "id": "48", + "id": "47", "metadata": {}, "source": [ "#### Run Fitting" @@ -520,7 +503,7 @@ { "cell_type": "code", "execution_count": null, - "id": "49", + "id": "48", "metadata": {}, "outputs": [], "source": [ @@ -530,7 +513,7 @@ }, { "cell_type": "markdown", - "id": "50", + "id": "49", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -539,7 +522,7 @@ { "cell_type": "code", "execution_count": null, - "id": "51", + "id": "50", "metadata": {}, "outputs": [], "source": [ @@ -549,7 +532,7 @@ { "cell_type": "code", "execution_count": null, - "id": "52", + "id": "51", "metadata": {}, "outputs": [], "source": [ @@ -558,7 +541,7 @@ }, { "cell_type": "markdown", - "id": "53", + "id": "52", "metadata": {}, "source": [ "### Perform Fit 3/5\n", @@ -569,7 +552,7 @@ { "cell_type": "code", "execution_count": null, - "id": "54", + "id": "53", "metadata": {}, "outputs": [], "source": [ @@ -579,7 +562,7 @@ }, { "cell_type": "markdown", - "id": "55", + "id": "54", "metadata": {}, "source": [ "Set more parameters to be refined." @@ -588,7 +571,7 @@ { "cell_type": "code", "execution_count": null, - "id": "56", + "id": "55", "metadata": {}, "outputs": [], "source": [ @@ -599,7 +582,7 @@ }, { "cell_type": "markdown", - "id": "57", + "id": "56", "metadata": {}, "source": [ "Show free parameters after selection." @@ -608,7 +591,7 @@ { "cell_type": "code", "execution_count": null, - "id": "58", + "id": "57", "metadata": {}, "outputs": [], "source": [ @@ -617,7 +600,7 @@ }, { "cell_type": "markdown", - "id": "59", + "id": "58", "metadata": {}, "source": [ "#### Run Fitting" @@ -626,7 +609,7 @@ { "cell_type": "code", "execution_count": null, - "id": "60", + "id": "59", "metadata": {}, "outputs": [], "source": [ @@ -636,7 +619,7 @@ }, { "cell_type": "markdown", - "id": "61", + "id": "60", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -645,7 +628,7 @@ { "cell_type": "code", "execution_count": null, - "id": "62", + "id": "61", "metadata": {}, "outputs": [], "source": [ @@ -655,7 +638,7 @@ { "cell_type": "code", "execution_count": null, - "id": "63", + "id": "62", "metadata": {}, "outputs": [], "source": [ @@ -664,7 +647,7 @@ }, { "cell_type": "markdown", - "id": "64", + "id": "63", "metadata": {}, "source": [ "### Perform Fit 4/5\n", @@ -675,16 +658,20 @@ { "cell_type": "code", "execution_count": null, - "id": "65", + "id": "64", "metadata": {}, "outputs": [], "source": [ - "structure.atom_sites['Si'].b_iso.free = True" + "structure.atom_sites['Si'].adp_iso.free = True\n", + "\n", + "expt.peak.exp_decay_beta_0.free = True\n", + "expt.peak.exp_decay_beta_1.free = True\n", + "expt.peak.exp_rise_alpha_1.free = True" ] }, { "cell_type": "markdown", - "id": "66", + "id": "65", "metadata": {}, "source": [ "Show free parameters after selection." @@ -693,7 +680,7 @@ { "cell_type": "code", "execution_count": null, - "id": "67", + "id": "66", "metadata": {}, "outputs": [], "source": [ @@ -702,7 +689,7 @@ }, { "cell_type": "markdown", - "id": "68", + "id": "67", "metadata": {}, "source": [ "#### Run Fitting" @@ -711,7 +698,7 @@ { "cell_type": "code", "execution_count": null, - "id": "69", + "id": "68", "metadata": {}, "outputs": [], "source": [ @@ -721,8 +708,26 @@ }, { "cell_type": "markdown", + "id": "69", + "metadata": {}, + "source": [ + "#### Show parameter correlations" + ] + }, + { + "cell_type": "code", + "execution_count": null, "id": "70", "metadata": {}, + "outputs": [], + "source": [ + "project.plotter.plot_param_correlations()" + ] + }, + { + "cell_type": "markdown", + "id": "71", + "metadata": {}, "source": [ "#### Plot Measured vs Calculated" ] @@ -730,7 +735,7 @@ { "cell_type": "code", "execution_count": null, - "id": "71", + "id": "72", "metadata": {}, "outputs": [], "source": [ @@ -740,12 +745,22 @@ { "cell_type": "code", "execution_count": null, - "id": "72", + "id": "73", "metadata": {}, "outputs": [], "source": [ "project.plotter.plot_meas_vs_calc(expt_name='sepd', x_min=23200, x_max=23700, show_residual=True)" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "74", + "metadata": {}, + "outputs": [], + "source": [ + "project.plotter.plot_meas_vs_calc(expt_name='sepd', x='d_spacing', show_residual=True)" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-7.py b/docs/docs/tutorials/ed-7.py index 8dc9415ab..9bc97488e 100644 --- a/docs/docs/tutorials/ed-7.py +++ b/docs/docs/tutorials/ed-7.py @@ -48,7 +48,7 @@ fract_x=0.125, fract_y=0.125, fract_z=0.125, - b_iso=0.5, + adp_iso=0.5, ) # %% [markdown] @@ -256,7 +256,7 @@ # Set more parameters to be refined. # %% -structure.atom_sites['Si'].b_iso.free = True +structure.atom_sites['Si'].adp_iso.free = True expt.peak.exp_decay_beta_0.free = True expt.peak.exp_decay_beta_1.free = True diff --git a/docs/docs/tutorials/ed-8.ipynb b/docs/docs/tutorials/ed-8.ipynb index 45a9f8381..e8b6006eb 100644 --- a/docs/docs/tutorials/ed-8.ipynb +++ b/docs/docs/tutorials/ed-8.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "68e98133", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Structure Refinement: NCAF, WISH\n", @@ -36,7 +36,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -45,7 +45,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -57,7 +57,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Define Structure\n", @@ -71,7 +71,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -80,7 +80,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "#### Set Space Group" @@ -89,7 +89,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -99,7 +99,7 @@ }, { "cell_type": "markdown", - "id": "7", + "id": "8", "metadata": {}, "source": [ "#### Set Unit Cell" @@ -108,7 +108,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -117,7 +117,7 @@ }, { "cell_type": "markdown", - "id": "9", + "id": "10", "metadata": {}, "source": [ "#### Set Atom Sites" @@ -126,7 +126,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -137,7 +137,7 @@ " fract_y=0.0,\n", " fract_z=0.25,\n", " wyckoff_letter='b',\n", - " b_iso=0.92,\n", + " adp_iso=0.92,\n", ")\n", "structure.atom_sites.create(\n", " label='Al',\n", @@ -146,7 +146,7 @@ " fract_y=0.2521,\n", " fract_z=0.2521,\n", " wyckoff_letter='a',\n", - " b_iso=0.73,\n", + " adp_iso=0.73,\n", ")\n", "structure.atom_sites.create(\n", " label='Na',\n", @@ -155,7 +155,7 @@ " fract_y=0.0851,\n", " fract_z=0.0851,\n", " wyckoff_letter='a',\n", - " b_iso=2.08,\n", + " adp_iso=2.08,\n", ")\n", "structure.atom_sites.create(\n", " label='F1',\n", @@ -164,7 +164,7 @@ " fract_y=0.3054,\n", " fract_z=0.1195,\n", " wyckoff_letter='c',\n", - " b_iso=0.90,\n", + " adp_iso=0.90,\n", ")\n", "structure.atom_sites.create(\n", " label='F2',\n", @@ -173,7 +173,7 @@ " fract_y=0.3633,\n", " fract_z=0.1867,\n", " wyckoff_letter='c',\n", - " b_iso=1.37,\n", + " adp_iso=1.37,\n", ")\n", "structure.atom_sites.create(\n", " label='F3',\n", @@ -182,13 +182,13 @@ " fract_y=0.4612,\n", " fract_z=0.4612,\n", " wyckoff_letter='a',\n", - " b_iso=0.88,\n", + " adp_iso=0.88,\n", ")" ] }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "## Define Experiment\n", @@ -202,7 +202,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -212,7 +212,7 @@ { "cell_type": "code", "execution_count": null, - "id": "13", + "id": "14", "metadata": {}, "outputs": [], "source": [ @@ -221,7 +221,7 @@ }, { "cell_type": "markdown", - "id": "14", + "id": "15", "metadata": {}, "source": [ "#### Create Experiment" @@ -230,7 +230,7 @@ { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -244,7 +244,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -257,7 +257,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "#### Set Instrument" @@ -266,7 +266,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -279,7 +279,7 @@ { "cell_type": "code", "execution_count": null, - "id": "19", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -291,7 +291,7 @@ }, { "cell_type": "markdown", - "id": "20", + "id": "21", "metadata": {}, "source": [ "#### Set Peak Profile" @@ -300,38 +300,38 @@ { "cell_type": "code", "execution_count": null, - "id": "21", + "id": "22", "metadata": {}, "outputs": [], "source": [ "expt56.peak.broad_gauss_sigma_0 = 0.0\n", "expt56.peak.broad_gauss_sigma_1 = 0.0\n", "expt56.peak.broad_gauss_sigma_2 = 15.5\n", - "expt56.peak.broad_mix_beta_0 = 0.007\n", - "expt56.peak.broad_mix_beta_1 = 0.01\n", - "expt56.peak.asym_alpha_0 = -0.0094\n", - "expt56.peak.asym_alpha_1 = 0.1" + "expt56.peak.exp_decay_beta_0 = 0.007\n", + "expt56.peak.exp_decay_beta_1 = 0.01\n", + "expt56.peak.exp_rise_alpha_0 = -0.0094\n", + "expt56.peak.exp_rise_alpha_1 = 0.1" ] }, { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ "expt47.peak.broad_gauss_sigma_0 = 0.0\n", "expt47.peak.broad_gauss_sigma_1 = 29.8\n", "expt47.peak.broad_gauss_sigma_2 = 18.0\n", - "expt47.peak.broad_mix_beta_0 = 0.006\n", - "expt47.peak.broad_mix_beta_1 = 0.015\n", - "expt47.peak.asym_alpha_0 = -0.0115\n", - "expt47.peak.asym_alpha_1 = 0.1" + "expt47.peak.exp_decay_beta_0 = 0.006\n", + "expt47.peak.exp_decay_beta_1 = 0.015\n", + "expt47.peak.exp_rise_alpha_0 = -0.0115\n", + "expt47.peak.exp_rise_alpha_1 = 0.1" ] }, { "cell_type": "markdown", - "id": "23", + "id": "24", "metadata": {}, "source": [ "#### Set Background" @@ -340,7 +340,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -384,7 +384,7 @@ { "cell_type": "code", "execution_count": null, - "id": "25", + "id": "26", "metadata": {}, "outputs": [], "source": [ @@ -426,7 +426,7 @@ }, { "cell_type": "markdown", - "id": "26", + "id": "27", "metadata": {}, "source": [ "#### Set Linked Phases" @@ -435,7 +435,7 @@ { "cell_type": "code", "execution_count": null, - "id": "27", + "id": "28", "metadata": {}, "outputs": [], "source": [ @@ -445,7 +445,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -454,7 +454,7 @@ }, { "cell_type": "markdown", - "id": "29", + "id": "30", "metadata": {}, "source": [ "#### Set Excluded Regions" @@ -463,7 +463,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -474,7 +474,7 @@ { "cell_type": "code", "execution_count": null, - "id": "31", + "id": "32", "metadata": {}, "outputs": [], "source": [ @@ -484,7 +484,7 @@ }, { "cell_type": "markdown", - "id": "32", + "id": "33", "metadata": {}, "source": [ "## Define Project\n", @@ -498,7 +498,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33", + "id": "34", "metadata": {}, "outputs": [], "source": [ @@ -507,7 +507,7 @@ }, { "cell_type": "markdown", - "id": "34", + "id": "35", "metadata": {}, "source": [ "#### Set Plotting Engine" @@ -516,7 +516,7 @@ { "cell_type": "code", "execution_count": null, - "id": "35", + "id": "36", "metadata": {}, "outputs": [], "source": [ @@ -527,7 +527,7 @@ }, { "cell_type": "markdown", - "id": "36", + "id": "37", "metadata": {}, "source": [ "#### Add Structure" @@ -536,7 +536,7 @@ { "cell_type": "code", "execution_count": null, - "id": "37", + "id": "38", "metadata": {}, "outputs": [], "source": [ @@ -545,7 +545,7 @@ }, { "cell_type": "markdown", - "id": "38", + "id": "39", "metadata": {}, "source": [ "#### Add Experiment" @@ -554,7 +554,7 @@ { "cell_type": "code", "execution_count": null, - "id": "39", + "id": "40", "metadata": {}, "outputs": [], "source": [ @@ -564,7 +564,7 @@ }, { "cell_type": "markdown", - "id": "40", + "id": "41", "metadata": {}, "source": [ "## Perform Analysis\n", @@ -578,7 +578,7 @@ { "cell_type": "code", "execution_count": null, - "id": "41", + "id": "42", "metadata": {}, "outputs": [], "source": [ @@ -587,7 +587,7 @@ }, { "cell_type": "markdown", - "id": "42", + "id": "43", "metadata": {}, "source": [ "#### Set Fit Mode" @@ -596,7 +596,7 @@ { "cell_type": "code", "execution_count": null, - "id": "43", + "id": "44", "metadata": {}, "outputs": [], "source": [ @@ -605,7 +605,7 @@ }, { "cell_type": "markdown", - "id": "44", + "id": "45", "metadata": {}, "source": [ "#### Set Free Parameters" @@ -614,22 +614,22 @@ { "cell_type": "code", "execution_count": null, - "id": "45", + "id": "46", "metadata": {}, "outputs": [], "source": [ - "structure.atom_sites['Ca'].b_iso.free = True\n", - "structure.atom_sites['Al'].b_iso.free = True\n", - "structure.atom_sites['Na'].b_iso.free = True\n", - "structure.atom_sites['F1'].b_iso.free = True\n", - "structure.atom_sites['F2'].b_iso.free = True\n", - "structure.atom_sites['F3'].b_iso.free = True" + "structure.atom_sites['Ca'].adp_iso.free = True\n", + "structure.atom_sites['Al'].adp_iso.free = True\n", + "structure.atom_sites['Na'].adp_iso.free = True\n", + "structure.atom_sites['F1'].adp_iso.free = True\n", + "structure.atom_sites['F2'].adp_iso.free = True\n", + "structure.atom_sites['F3'].adp_iso.free = True" ] }, { "cell_type": "code", "execution_count": null, - "id": "46", + "id": "47", "metadata": {}, "outputs": [], "source": [ @@ -637,22 +637,22 @@ "expt56.instrument.calib_d_to_tof_offset.free = True\n", "expt56.instrument.calib_d_to_tof_linear.free = True\n", "expt56.peak.broad_gauss_sigma_2.free = True\n", - "expt56.peak.broad_mix_beta_0.free = True\n", - "expt56.peak.broad_mix_beta_1.free = True\n", - "expt56.peak.asym_alpha_1.free = True\n", + "expt56.peak.exp_decay_beta_0.free = True\n", + "expt56.peak.exp_decay_beta_1.free = True\n", + "expt56.peak.exp_rise_alpha_1.free = True\n", "\n", "expt47.linked_phases['ncaf'].scale.free = True\n", "expt47.instrument.calib_d_to_tof_linear.free = True\n", "expt47.instrument.calib_d_to_tof_offset.free = True\n", "expt47.peak.broad_gauss_sigma_2.free = True\n", - "expt47.peak.broad_mix_beta_0.free = True\n", - "expt47.peak.broad_mix_beta_1.free = True\n", - "expt47.peak.asym_alpha_1.free = True" + "expt47.peak.exp_decay_beta_0.free = True\n", + "expt47.peak.exp_decay_beta_1.free = True\n", + "expt47.peak.exp_rise_alpha_1.free = True" ] }, { "cell_type": "markdown", - "id": "47", + "id": "48", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -661,7 +661,7 @@ { "cell_type": "code", "execution_count": null, - "id": "48", + "id": "49", "metadata": {}, "outputs": [], "source": [ @@ -671,7 +671,7 @@ { "cell_type": "code", "execution_count": null, - "id": "49", + "id": "50", "metadata": {}, "outputs": [], "source": [ @@ -680,7 +680,7 @@ }, { "cell_type": "markdown", - "id": "50", + "id": "51", "metadata": {}, "source": [ "#### Run Fitting" @@ -689,17 +689,18 @@ { "cell_type": "code", "execution_count": null, - "id": "51", + "id": "52", "metadata": {}, "outputs": [], "source": [ "project.analysis.fit()\n", - "project.analysis.display.fit_results()" + "project.analysis.display.fit_results()\n", + "project.plotter.plot_param_correlations()" ] }, { "cell_type": "markdown", - "id": "52", + "id": "53", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -708,7 +709,7 @@ { "cell_type": "code", "execution_count": null, - "id": "53", + "id": "54", "metadata": {}, "outputs": [], "source": [ @@ -718,7 +719,7 @@ { "cell_type": "code", "execution_count": null, - "id": "54", + "id": "55", "metadata": {}, "outputs": [], "source": [ @@ -727,7 +728,7 @@ }, { "cell_type": "markdown", - "id": "55", + "id": "56", "metadata": {}, "source": [ "## Summary\n", @@ -737,7 +738,7 @@ }, { "cell_type": "markdown", - "id": "56", + "id": "57", "metadata": {}, "source": [ "#### Show Project Summary" @@ -746,7 +747,7 @@ { "cell_type": "code", "execution_count": null, - "id": "57", + "id": "58", "metadata": {}, "outputs": [], "source": [ diff --git a/docs/docs/tutorials/ed-8.py b/docs/docs/tutorials/ed-8.py index 88c14698a..b933c27cd 100644 --- a/docs/docs/tutorials/ed-8.py +++ b/docs/docs/tutorials/ed-8.py @@ -52,7 +52,7 @@ fract_y=0.0, fract_z=0.25, wyckoff_letter='b', - b_iso=0.92, + adp_iso=0.92, ) structure.atom_sites.create( label='Al', @@ -61,7 +61,7 @@ fract_y=0.2521, fract_z=0.2521, wyckoff_letter='a', - b_iso=0.73, + adp_iso=0.73, ) structure.atom_sites.create( label='Na', @@ -70,7 +70,7 @@ fract_y=0.0851, fract_z=0.0851, wyckoff_letter='a', - b_iso=2.08, + adp_iso=2.08, ) structure.atom_sites.create( label='F1', @@ -79,7 +79,7 @@ fract_y=0.3054, fract_z=0.1195, wyckoff_letter='c', - b_iso=0.90, + adp_iso=0.90, ) structure.atom_sites.create( label='F2', @@ -88,7 +88,7 @@ fract_y=0.3633, fract_z=0.1867, wyckoff_letter='c', - b_iso=1.37, + adp_iso=1.37, ) structure.atom_sites.create( label='F3', @@ -97,7 +97,7 @@ fract_y=0.4612, fract_z=0.4612, wyckoff_letter='a', - b_iso=0.88, + adp_iso=0.88, ) # %% [markdown] @@ -316,12 +316,12 @@ # #### Set Free Parameters # %% -structure.atom_sites['Ca'].b_iso.free = True -structure.atom_sites['Al'].b_iso.free = True -structure.atom_sites['Na'].b_iso.free = True -structure.atom_sites['F1'].b_iso.free = True -structure.atom_sites['F2'].b_iso.free = True -structure.atom_sites['F3'].b_iso.free = True +structure.atom_sites['Ca'].adp_iso.free = True +structure.atom_sites['Al'].adp_iso.free = True +structure.atom_sites['Na'].adp_iso.free = True +structure.atom_sites['F1'].adp_iso.free = True +structure.atom_sites['F2'].adp_iso.free = True +structure.atom_sites['F3'].adp_iso.free = True # %% expt56.linked_phases['ncaf'].scale.free = True @@ -355,6 +355,7 @@ # %% project.analysis.fit() project.analysis.display.fit_results() +project.plotter.plot_param_correlations() # %% [markdown] # #### Plot Measured vs Calculated diff --git a/docs/docs/tutorials/ed-9.ipynb b/docs/docs/tutorials/ed-9.ipynb index 31579906e..be44e177c 100644 --- a/docs/docs/tutorials/ed-9.ipynb +++ b/docs/docs/tutorials/ed-9.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f854b55b", + "id": "0", "metadata": { "tags": [ "hide-in-docs" @@ -21,7 +21,7 @@ }, { "cell_type": "markdown", - "id": "0", + "id": "1", "metadata": {}, "source": [ "# Structure Refinement: LBCO+Si, McStas\n", @@ -33,7 +33,7 @@ }, { "cell_type": "markdown", - "id": "1", + "id": "2", "metadata": {}, "source": [ "## Import Library" @@ -42,7 +42,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2", + "id": "3", "metadata": {}, "outputs": [], "source": [ @@ -54,7 +54,7 @@ }, { "cell_type": "markdown", - "id": "3", + "id": "4", "metadata": {}, "source": [ "## Define Structures\n", @@ -68,7 +68,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4", + "id": "5", "metadata": {}, "outputs": [], "source": [ @@ -77,7 +77,7 @@ }, { "cell_type": "markdown", - "id": "5", + "id": "6", "metadata": {}, "source": [ "#### Set Space Group" @@ -86,7 +86,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -96,7 +96,7 @@ }, { "cell_type": "markdown", - "id": "7", + "id": "8", "metadata": {}, "source": [ "#### Set Unit Cell" @@ -105,7 +105,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -114,7 +114,7 @@ }, { "cell_type": "markdown", - "id": "9", + "id": "10", "metadata": {}, "source": [ "#### Set Atom Sites" @@ -123,7 +123,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -134,7 +134,7 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=0.2,\n", + " adp_iso=0.2,\n", " occupancy=0.5,\n", ")\n", "structure_1.atom_sites.create(\n", @@ -144,7 +144,7 @@ " fract_y=0,\n", " fract_z=0,\n", " wyckoff_letter='a',\n", - " b_iso=0.2,\n", + " adp_iso=0.2,\n", " occupancy=0.5,\n", ")\n", "structure_1.atom_sites.create(\n", @@ -154,7 +154,7 @@ " fract_y=0.5,\n", " fract_z=0.5,\n", " wyckoff_letter='b',\n", - " b_iso=0.2567,\n", + " adp_iso=0.2567,\n", ")\n", "structure_1.atom_sites.create(\n", " label='O',\n", @@ -163,13 +163,13 @@ " fract_y=0.5,\n", " fract_z=0.5,\n", " wyckoff_letter='c',\n", - " b_iso=1.4041,\n", + " adp_iso=1.4041,\n", ")" ] }, { "cell_type": "markdown", - "id": "11", + "id": "12", "metadata": {}, "source": [ "### Create Structure 2: Si" @@ -178,7 +178,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -187,7 +187,7 @@ }, { "cell_type": "markdown", - "id": "13", + "id": "14", "metadata": {}, "source": [ "#### Set Space Group" @@ -196,7 +196,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -206,7 +206,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "16", "metadata": {}, "source": [ "#### Set Unit Cell" @@ -215,7 +215,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -224,7 +224,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "#### Set Atom Sites" @@ -233,7 +233,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -244,13 +244,13 @@ " fract_y=0.0,\n", " fract_z=0.0,\n", " wyckoff_letter='a',\n", - " b_iso=0.0,\n", + " adp_iso=0.0,\n", ")" ] }, { "cell_type": "markdown", - "id": "19", + "id": "20", "metadata": {}, "source": [ "## Define Experiment\n", @@ -264,7 +264,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -273,7 +273,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "#### Create Experiment" @@ -282,7 +282,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -298,7 +298,7 @@ }, { "cell_type": "markdown", - "id": "23", + "id": "24", "metadata": {}, "source": [ "#### Set Instrument" @@ -307,7 +307,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -319,7 +319,7 @@ }, { "cell_type": "markdown", - "id": "25", + "id": "26", "metadata": {}, "source": [ "#### Set Peak Profile" @@ -328,23 +328,23 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "27", "metadata": {}, "outputs": [], "source": [ - "# experiment.peak_profile_type = 'pseudo-voigt * ikeda-carpenter'\n", + "# experiment.peak_profile_type = 'jorgensen'\n", "experiment.peak.broad_gauss_sigma_0 = 45137\n", "experiment.peak.broad_gauss_sigma_1 = -52394\n", "experiment.peak.broad_gauss_sigma_2 = 22998\n", - "experiment.peak.broad_mix_beta_0 = 0.0055\n", - "experiment.peak.broad_mix_beta_1 = 0.0041\n", - "experiment.peak.asym_alpha_0 = 0\n", - "experiment.peak.asym_alpha_1 = 0.0097" + "experiment.peak.exp_decay_beta_0 = 0.0055\n", + "experiment.peak.exp_decay_beta_1 = 0.0041\n", + "experiment.peak.exp_rise_alpha_0 = 0\n", + "experiment.peak.exp_rise_alpha_1 = 0.0097" ] }, { "cell_type": "markdown", - "id": "27", + "id": "28", "metadata": {}, "source": [ "#### Set Background" @@ -352,7 +352,7 @@ }, { "cell_type": "markdown", - "id": "28", + "id": "29", "metadata": {}, "source": [ "Select the background type." @@ -361,7 +361,7 @@ { "cell_type": "code", "execution_count": null, - "id": "29", + "id": "30", "metadata": {}, "outputs": [], "source": [ @@ -370,7 +370,7 @@ }, { "cell_type": "markdown", - "id": "30", + "id": "31", "metadata": {}, "source": [ "Add background points." @@ -379,7 +379,7 @@ { "cell_type": "code", "execution_count": null, - "id": "31", + "id": "32", "metadata": {}, "outputs": [], "source": [ @@ -400,7 +400,7 @@ }, { "cell_type": "markdown", - "id": "32", + "id": "33", "metadata": {}, "source": [ "#### Set Linked Phases" @@ -409,7 +409,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33", + "id": "34", "metadata": {}, "outputs": [], "source": [ @@ -419,7 +419,7 @@ }, { "cell_type": "markdown", - "id": "34", + "id": "35", "metadata": {}, "source": [ "## Define Project\n", @@ -433,7 +433,7 @@ { "cell_type": "code", "execution_count": null, - "id": "35", + "id": "36", "metadata": {}, "outputs": [], "source": [ @@ -442,7 +442,7 @@ }, { "cell_type": "markdown", - "id": "36", + "id": "37", "metadata": {}, "source": [ "#### Add Structures" @@ -451,7 +451,7 @@ { "cell_type": "code", "execution_count": null, - "id": "37", + "id": "38", "metadata": {}, "outputs": [], "source": [ @@ -461,7 +461,7 @@ }, { "cell_type": "markdown", - "id": "38", + "id": "39", "metadata": {}, "source": [ "#### Show Structures" @@ -470,7 +470,7 @@ { "cell_type": "code", "execution_count": null, - "id": "39", + "id": "40", "metadata": {}, "outputs": [], "source": [ @@ -479,7 +479,7 @@ }, { "cell_type": "markdown", - "id": "40", + "id": "41", "metadata": {}, "source": [ "#### Add Experiments" @@ -488,7 +488,7 @@ { "cell_type": "code", "execution_count": null, - "id": "41", + "id": "42", "metadata": {}, "outputs": [], "source": [ @@ -497,7 +497,7 @@ }, { "cell_type": "markdown", - "id": "42", + "id": "43", "metadata": {}, "source": [ "#### Set Excluded Regions\n", @@ -508,7 +508,7 @@ { "cell_type": "code", "execution_count": null, - "id": "43", + "id": "44", "metadata": {}, "outputs": [], "source": [ @@ -517,7 +517,7 @@ }, { "cell_type": "markdown", - "id": "44", + "id": "45", "metadata": {}, "source": [ "Add excluded regions." @@ -526,7 +526,7 @@ { "cell_type": "code", "execution_count": null, - "id": "45", + "id": "46", "metadata": {}, "outputs": [], "source": [ @@ -536,7 +536,7 @@ }, { "cell_type": "markdown", - "id": "46", + "id": "47", "metadata": {}, "source": [ "Show excluded regions." @@ -545,7 +545,7 @@ { "cell_type": "code", "execution_count": null, - "id": "47", + "id": "48", "metadata": {}, "outputs": [], "source": [ @@ -554,7 +554,7 @@ }, { "cell_type": "markdown", - "id": "48", + "id": "49", "metadata": {}, "source": [ "Show measured data after adding excluded regions." @@ -563,7 +563,7 @@ { "cell_type": "code", "execution_count": null, - "id": "49", + "id": "50", "metadata": {}, "outputs": [], "source": [ @@ -572,7 +572,7 @@ }, { "cell_type": "markdown", - "id": "50", + "id": "51", "metadata": {}, "source": [ "Show experiment as CIF." @@ -581,7 +581,7 @@ { "cell_type": "code", "execution_count": null, - "id": "51", + "id": "52", "metadata": {}, "outputs": [], "source": [ @@ -590,7 +590,7 @@ }, { "cell_type": "markdown", - "id": "52", + "id": "53", "metadata": {}, "source": [ "## Perform Analysis\n", @@ -604,7 +604,7 @@ { "cell_type": "code", "execution_count": null, - "id": "53", + "id": "54", "metadata": {}, "outputs": [], "source": [ @@ -613,7 +613,7 @@ }, { "cell_type": "markdown", - "id": "54", + "id": "55", "metadata": {}, "source": [ "#### Set Fitting Parameters\n", @@ -624,20 +624,20 @@ { "cell_type": "code", "execution_count": null, - "id": "55", + "id": "56", "metadata": {}, "outputs": [], "source": [ "structure_1.cell.length_a.free = True\n", - "structure_1.atom_sites['Co'].b_iso.free = True\n", - "structure_1.atom_sites['O'].b_iso.free = True\n", + "structure_1.atom_sites['Co'].adp_iso.free = True\n", + "structure_1.atom_sites['O'].adp_iso.free = True\n", "\n", "structure_2.cell.length_a.free = True" ] }, { "cell_type": "markdown", - "id": "56", + "id": "57", "metadata": {}, "source": [ "Set experiment parameters to be optimized." @@ -646,7 +646,7 @@ { "cell_type": "code", "execution_count": null, - "id": "57", + "id": "58", "metadata": {}, "outputs": [], "source": [ @@ -657,9 +657,9 @@ "experiment.peak.broad_gauss_sigma_1.free = True\n", "experiment.peak.broad_gauss_sigma_2.free = True\n", "\n", - "experiment.peak.asym_alpha_1.free = True\n", - "experiment.peak.broad_mix_beta_0.free = True\n", - "experiment.peak.broad_mix_beta_1.free = True\n", + "experiment.peak.exp_rise_alpha_1.free = True\n", + "experiment.peak.exp_decay_beta_0.free = True\n", + "experiment.peak.exp_decay_beta_1.free = True\n", "\n", "for point in experiment.background:\n", " point.y.free = True" @@ -667,7 +667,7 @@ }, { "cell_type": "markdown", - "id": "58", + "id": "59", "metadata": {}, "source": [ "#### Perform Fit" @@ -676,17 +676,18 @@ { "cell_type": "code", "execution_count": null, - "id": "59", + "id": "60", "metadata": {}, "outputs": [], "source": [ "project.analysis.fit()\n", - "project.analysis.display.fit_results()" + "project.analysis.display.fit_results()\n", + "project.plotter.plot_param_correlations()" ] }, { "cell_type": "markdown", - "id": "60", + "id": "61", "metadata": {}, "source": [ "#### Plot Measured vs Calculated" @@ -695,20 +696,12 @@ { "cell_type": "code", "execution_count": null, - "id": "61", + "id": "62", "metadata": {}, "outputs": [], "source": [ "project.plotter.plot_meas_vs_calc(expt_name='mcstas')" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "62", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-9.py b/docs/docs/tutorials/ed-9.py index c2cd4c157..92a024512 100644 --- a/docs/docs/tutorials/ed-9.py +++ b/docs/docs/tutorials/ed-9.py @@ -49,7 +49,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.2, + adp_iso=0.2, occupancy=0.5, ) structure_1.atom_sites.create( @@ -59,7 +59,7 @@ fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.2, + adp_iso=0.2, occupancy=0.5, ) structure_1.atom_sites.create( @@ -69,7 +69,7 @@ fract_y=0.5, fract_z=0.5, wyckoff_letter='b', - b_iso=0.2567, + adp_iso=0.2567, ) structure_1.atom_sites.create( label='O', @@ -78,7 +78,7 @@ fract_y=0.5, fract_z=0.5, wyckoff_letter='c', - b_iso=1.4041, + adp_iso=1.4041, ) # %% [markdown] @@ -111,7 +111,7 @@ fract_y=0.0, fract_z=0.0, wyckoff_letter='a', - b_iso=0.0, + adp_iso=0.0, ) # %% [markdown] @@ -275,8 +275,8 @@ # %% structure_1.cell.length_a.free = True -structure_1.atom_sites['Co'].b_iso.free = True -structure_1.atom_sites['O'].b_iso.free = True +structure_1.atom_sites['Co'].adp_iso.free = True +structure_1.atom_sites['O'].adp_iso.free = True structure_2.cell.length_a.free = True @@ -304,11 +304,10 @@ # %% project.analysis.fit() project.analysis.display.fit_results() +project.plotter.plot_param_correlations() # %% [markdown] # #### Plot Measured vs Calculated # %% project.plotter.plot_meas_vs_calc(expt_name='mcstas') - -# %% diff --git a/docs/docs/user-guide/analysis-workflow/analysis.md b/docs/docs/user-guide/analysis-workflow/analysis.md index 86dbaec79..7b1be89f9 100644 --- a/docs/docs/user-guide/analysis-workflow/analysis.md +++ b/docs/docs/user-guide/analysis-workflow/analysis.md @@ -273,11 +273,11 @@ An example of setting aliases for parameters in a structure: # Set aliases for the atomic displacement parameters project.analysis.aliases.create( label='biso_La', - param_uid=project.structures['lbco'].atom_sites['La'].b_iso.uid, + param_uid=project.structures['lbco'].atom_sites['La'].adp_iso.uid, ) project.analysis.aliases.create( label='biso_Ba', - param_uid=project.structures['lbco'].atom_sites['Ba'].b_iso.uid, + param_uid=project.structures['lbco'].atom_sites['Ba'].adp_iso.uid, ) # Set aliases for the occupancies of the atom sites diff --git a/docs/docs/user-guide/analysis-workflow/model.md b/docs/docs/user-guide/analysis-workflow/model.md index 95e309cdb..3227199d6 100644 --- a/docs/docs/user-guide/analysis-workflow/model.md +++ b/docs/docs/user-guide/analysis-workflow/model.md @@ -108,7 +108,7 @@ project.structures['nacl'].atom_sites.create( fract_y=0, fract_z=0, occupancy=1, - b_iso_or_equiv=0.5, + adp_iso=0.5, ) project.structures['nacl'].atom_sites.create( label='Cl', @@ -117,7 +117,7 @@ project.structures['nacl'].atom_sites.create( fract_y=0, fract_z=0.5, occupancy=1, - b_iso_or_equiv=0.5, + adp_iso=0.5, ) ``` diff --git a/docs/docs/user-guide/first-steps.md b/docs/docs/user-guide/first-steps.md index 2f443398f..82f1b9de1 100644 --- a/docs/docs/user-guide/first-steps.md +++ b/docs/docs/user-guide/first-steps.md @@ -143,16 +143,16 @@ their projects. An example of the output for the `project.analysis.display.how_to_access_parameters()` method is: -| | Code variable | Unique ID for CIF | -| --- | --------------------------------------------------- | -------------------------------- | -| 1 | project.structures['lbco'].atom_site['La'].adp_type | lbco.atom_site.La.ADP_type | -| 2 | project.structures['lbco'].atom_site['La'].b_iso | lbco.atom_site.La.B_iso_or_equiv | -| 3 | project.structures['lbco'].atom_site['La'].fract_x | lbco.atom_site.La.fract_x | -| 4 | project.structures['lbco'].atom_site['La'].fract_y | lbco.atom_site.La.fract_y | -| ... | ... | ... | -| 59 | project.experiments['hrpt'].peak.broad_gauss_u | hrpt.peak.broad_gauss_u | -| 60 | project.experiments['hrpt'].peak.broad_gauss_v | hrpt.peak.broad_gauss_v | -| 61 | project.experiments['hrpt'].peak.broad_gauss_w | hrpt.peak.broad_gauss_w | +| | Code variable | Unique ID for CIF | +| --- | --------------------------------------------------- | -------------------------- | +| 1 | project.structures['lbco'].atom_site['La'].adp_type | lbco.atom_site.La.ADP_type | +| 2 | project.structures['lbco'].atom_site['La'].adp_iso | lbco.atom_site.La.adp_iso | +| 3 | project.structures['lbco'].atom_site['La'].fract_x | lbco.atom_site.La.fract_x | +| 4 | project.structures['lbco'].atom_site['La'].fract_y | lbco.atom_site.La.fract_y | +| ... | ... | ... | +| 59 | project.experiments['hrpt'].peak.broad_gauss_u | hrpt.peak.broad_gauss_u | +| 60 | project.experiments['hrpt'].peak.broad_gauss_v | hrpt.peak.broad_gauss_v | +| 61 | project.experiments['hrpt'].peak.broad_gauss_w | hrpt.peak.broad_gauss_w | ### Supported plotters diff --git a/docs/docs/user-guide/parameters.md b/docs/docs/user-guide/parameters.md index 424619316..4b4da1016 100644 --- a/docs/docs/user-guide/parameters.md +++ b/docs/docs/user-guide/parameters.md @@ -13,9 +13,9 @@ reference, and it belongs to a specific category. of the CIF name to comply with Python naming conventions. For example, `name_H-M_alt` becomes `name_h_m`, replacing hyphens with underscores and using lowercase letters. -- In rare cases, the EasyDiffraction name is a bit shorter, like `b_iso` - instead of CIF `B_iso_or_equiv`, to make the code a bit more - user-friendly. +- In rare cases, the EasyDiffraction name is a bit shorter, like + `adp_iso` instead of CIF `B_iso_or_equiv` / `U_iso_or_equiv`, to make + the code a bit more user-friendly. - When there is no defined CIF name for a parameter, EasyDiffraction introduces its own name, which is used in the code as well as an equivalent CIF name to be placed in the custom CIF dictionary @@ -106,7 +106,7 @@ EasyDiffraction. | | :material-map-marker: [fract_z][atom_site] | atom_sites['ID'].fract_z | | | :material-format-color-fill: [occupancy][atom_site] | atom_sites['ID'].occupancy | | | :material-cursor-move: [adp_type][atom_site] | atom_sites['ID'].adp_type | - | | :material-cursor-move: [b_iso][atom_site] | atom_sites['ID'].b_iso | + | | :material-cursor-move: [adp_iso][atom_site] | atom_sites['ID'].adp_iso | | | :material-reflect-horizontal: [multiplicity][atom_site] | atom_sites['ID'].multiplicity | | | :material-reflect-horizontal: [wyckoff_letter][atom_site] | atom_sites['ID'].wyckoff_letter | @@ -129,7 +129,7 @@ EasyDiffraction. | | :material-map-marker: [fract_z][atom_site] | \_atom_site.fract_z | [coreCIF][1]{:.label-cif} | | | :material-format-color-fill: [occupancy][atom_site] | \_atom_site.occupancy | [coreCIF][1]{:.label-cif} | | | :material-cursor-move: [adp_type][atom_site] | \_atom_site.ADP_type | [coreCIF][1]{:.label-cif} | - | | :material-cursor-move: [b_iso][atom_site] | \_atom_site.B_iso_or_equiv | [coreCIF][1]{:.label-cif} | + | | :material-cursor-move: [adp_iso][atom_site] | \_atom_site.B_iso_or_equiv | [coreCIF][1]{:.label-cif} | | | :material-reflect-horizontal: [multiplicity][atom_site] | \_atom_site.site_symmetry_multiplicity | [coreCIF][1]{:.label-cif} | | | :material-reflect-horizontal: [wyckoff_letter][atom_site] | \_atom_site.Wyckoff_symbol | [coreCIF][1]{:.label-cif} | diff --git a/pixi.toml b/pixi.toml index 6706f3c9f..824f18508 100644 --- a/pixi.toml +++ b/pixi.toml @@ -187,8 +187,8 @@ notebook-exec = 'python -m pytest --nbmake docs/docs/tutorials/ --nbmake-timeout notebook-prepare = { depends-on = [ 'notebook-convert', - 'notebook-strip', 'notebook-tweak', + 'notebook-strip', ] } ######################## diff --git a/src/easydiffraction/analysis/calculators/crysfml.py b/src/easydiffraction/analysis/calculators/crysfml.py index 1fcc4087b..4255ee41a 100644 --- a/src/easydiffraction/analysis/calculators/crysfml.py +++ b/src/easydiffraction/analysis/calculators/crysfml.py @@ -198,8 +198,8 @@ def _convert_structure_to_dict( # noqa: PLR6301 '_fract_y': atom.fract_y.value, '_fract_z': atom.fract_z.value, '_occupancy': atom.occupancy.value, - '_adp_type': 'Biso', # Assuming Biso for simplicity - '_B_iso_or_equiv': atom.b_iso.value, + '_adp_type': atom.adp_type.value, + '_B_iso_or_equiv': atom.adp_iso_as_b, } structure_dict[structure.name]['_atom_site'].append(atom_site) @@ -222,9 +222,10 @@ def _convert_experiment_to_dict( # noqa: PLR6301 dict[str, Any] A dictionary representation of the experiment. """ - expt_type = getattr(experiment, 'type', None) - instrument = getattr(experiment, 'instrument', None) - peak = getattr(experiment, 'peak', None) + attrs = type(experiment)._public_attrs() + expt_type = experiment.type if 'type' in attrs else None + instrument = experiment.instrument if 'instrument' in attrs else None + peak = experiment.peak if 'peak' in attrs else None x_data = experiment.data.x twotheta_min = float(x_data.min()) diff --git a/src/easydiffraction/analysis/calculators/cryspy.py b/src/easydiffraction/analysis/calculators/cryspy.py index 83f9587a6..15eaf9da4 100644 --- a/src/easydiffraction/analysis/calculators/cryspy.py +++ b/src/easydiffraction/analysis/calculators/cryspy.py @@ -19,9 +19,54 @@ try: import cryspy + + # Patch cryspy bug: calc_power_dwf_aniso uses indices [0:9] of + # reduced_symm_elems for the rotation matrix, but the rotation + # actually starts at index 4 (layout: [b1,b2,b3,bd, R(3x3)]). + # This causes wrong Debye-Waller factors for all anisotropic atoms. + # Bug confirmed in cryspy 0.7.8, reported upstream. + from cryspy.A_functions_base import debye_waller_factor as _dwf_mod from cryspy.H_functions_global.function_1_cryspy_objects import str_to_globaln from cryspy.procedure_rhochi.rhochi_by_dictionary import rhochi_calc_chi_sq_by_dictionary + def _patched_calc_power_dwf_aniso( + index_hkl: np.ndarray, + beta: np.ndarray, + symm_elems_r: np.ndarray, + *, + flag_beta: bool = False, + ) -> tuple: + h, k, l = index_hkl[0], index_hkl[1], index_hkl[2] # noqa: E741 + r = symm_elems_r + h_s = h * r[4] + k * r[7] + l * r[10] + k_s = h * r[5] + k * r[8] + l * r[11] + l_s = h * r[6] + k * r[9] + l * r[12] + power = ( + beta[0] * np.square(h_s) + + beta[1] * np.square(k_s) + + beta[2] * np.square(l_s) + + 2.0 * beta[3] * h_s * k_s + + 2.0 * beta[4] * h_s * l_s + + 2.0 * beta[5] * k_s * l_s + ) + dder: dict = {} + if flag_beta: + ones_b = np.ones_like(beta[0]) + dder['beta'] = np.stack( + [ + ones_b * np.square(h_s), + ones_b * np.square(k_s), + ones_b * np.square(l_s), + ones_b * 2.0 * h_s * k_s, + ones_b * 2.0 * h_s * l_s, + ones_b * 2.0 * k_s * l_s, + ], + axis=0, + ) + return power, dder + + _dwf_mod.calc_power_dwf_aniso = _patched_calc_power_dwf_aniso + # TODO: Add the following print to debug mode # print("✅ 'cryspy' calculation engine is successfully imported.") except ImportError: @@ -55,22 +100,32 @@ def __init__(self) -> None: super().__init__() self._cryspy_dicts: dict[str, dict[str, Any]] = {} self._cached_peak_types: dict[str, str] = {} + self._cached_adp_types: dict[str, tuple[str, ...]] = {} def _invalidate_stale_cache( self, combined_name: str, experiment: ExperimentBase, + structure: Structure | None = None, ) -> None: """ - Drop cached dict when experiment peak profile type changed. + Drop cached dict when experiment or structure config changed. + + Checks both the peak profile type and the per-atom ADP types. + When either changes the cached dictionary is stale and must be + rebuilt from a fresh cryspy object. """ - peak = getattr(experiment, 'peak', None) - if peak is None: - return - current_type = peak.type_info.tag - if self._cached_peak_types.get(combined_name) != current_type: - self._cryspy_dicts.pop(combined_name, None) - self._cached_peak_types[combined_name] = current_type + if 'peak' in type(experiment)._public_attrs(): + current_type = experiment.peak.type_info.tag + if self._cached_peak_types.get(combined_name) != current_type: + self._cryspy_dicts.pop(combined_name, None) + self._cached_peak_types[combined_name] = current_type + + if structure is not None: + current_adp = tuple(atom.adp_type.value for atom in structure.atom_sites) + if self._cached_adp_types.get(combined_name) != current_adp: + self._cryspy_dicts.pop(combined_name, None) + self._cached_adp_types[combined_name] = current_adp def calculate_structure_factors( self, @@ -92,7 +147,7 @@ def calculate_structure_factors( Whether the calculation is called by a minimizer. """ combined_name = f'{structure.name}_{experiment.name}' - self._invalidate_stale_cache(combined_name, experiment) + self._invalidate_stale_cache(combined_name, experiment, structure) if called_by_minimizer: if self._cryspy_dicts and combined_name in self._cryspy_dicts: @@ -164,7 +219,7 @@ def calculate_pattern( list of floats. """ combined_name = f'{structure.name}_{experiment.name}' - self._invalidate_stale_cache(combined_name, experiment) + self._invalidate_stale_cache(combined_name, experiment, structure) if called_by_minimizer: if self._cryspy_dicts and combined_name in self._cryspy_dicts: @@ -280,10 +335,100 @@ def _update_structure_in_cryspy_dict( for idx, atom_site in enumerate(structure.atom_sites): cryspy_occ[idx] = atom_site.occupancy.value - # Atomic ADPs - Biso only for now + # Atomic ADPs - isotropic + # For anisotropic atoms the full ADP lives in the β tensor; + # setting b_iso to zero avoids double-counting in cryspy's DWF + # which sums both the isotropic and anisotropic contributions. + from easydiffraction.datablocks.structure.categories.atom_sites.enums import ( # noqa: PLC0415 + AdpTypeEnum, + ) + + aniso_types = {AdpTypeEnum.BANI.value, AdpTypeEnum.UANI.value} cryspy_biso = cryspy_model_dict['atom_b_iso'] for idx, atom_site in enumerate(structure.atom_sites): - cryspy_biso[idx] = atom_site.b_iso.value + if atom_site.adp_type.value in aniso_types: + cryspy_biso[idx] = 0.0 + else: + cryspy_biso[idx] = atom_site.adp_iso_as_b + + # Atomic ADPs - anisotropic (update β tensor when present) + if 'atom_beta' in cryspy_model_dict: + CryspyCalculator._update_aniso_beta( + cryspy_model_dict, + structure, + ) + + @staticmethod + def _update_aniso_beta( + cryspy_model_dict: dict[str, Any], + structure: Structure, + ) -> None: + """ + Update cryspy ``atom_beta`` from anisotropic ADP values. + + Converts B or U tensor components to cryspy's internal β + representation using β_ij = 2π²·U_ij·a*_i·a*_j. + + Parameters + ---------- + cryspy_model_dict : dict[str, Any] + The ``crystal_`` sub-dict. + structure : Structure + The source structure. + """ + from cryspy.A_functions_base.function_1_atomic_vibrations import ( # noqa: PLC0415 + calc_beta_by_u, + ) + from cryspy.A_functions_base.unit_cell import ( # noqa: PLC0415 + calc_reciprocal_by_unit_cell_parameters, + ) + + from easydiffraction.datablocks.structure.categories.atom_sites.enums import ( # noqa: PLC0415 + AdpTypeEnum, + ) + + aniso_index = cryspy_model_dict.get('atom_site_aniso_index') + if aniso_index is None: + return + + cryspy_beta = cryspy_model_dict['atom_beta'] + cell_params = cryspy_model_dict['unit_cell_parameters'] + + # Compute reciprocal lengths from cell parameters (with angles + # already in radians as stored by cryspy). + recip_params, _ = calc_reciprocal_by_unit_cell_parameters(cell_params) + + class _CellLike: + reciprocal_length_a = recip_params[0] + reciprocal_length_b = recip_params[1] + reciprocal_length_c = recip_params[2] + + cell_like = _CellLike() + factor = 8.0 * np.pi**2 + + for col, atom_idx in enumerate(aniso_index): + atom = list(structure.atom_sites)[atom_idx] + adp_enum = AdpTypeEnum(atom.adp_type.value) + if adp_enum not in {AdpTypeEnum.BANI, AdpTypeEnum.UANI}: + continue + + aniso = structure.atom_site_aniso[atom.label.value] + u_vals = [ + aniso.adp_11.value, + aniso.adp_22.value, + aniso.adp_33.value, + aniso.adp_12.value, + aniso.adp_13.value, + aniso.adp_23.value, + ] + + # Convert to U if stored as B + if adp_enum == AdpTypeEnum.BANI: + u_vals = [v / factor for v in u_vals] + + betas = calc_beta_by_u(u_vals, cell_like) + for k in range(6): + cryspy_beta[k][col] = betas[k] @staticmethod def _update_experiment_in_cryspy_dict( @@ -395,13 +540,17 @@ def _recreate_cryspy_obj( return cryspy_obj - def _convert_structure_to_cryspy_cif( # noqa: PLR6301 - self, - structure: Structure, - ) -> str: + def _convert_structure_to_cryspy_cif(self, structure: Structure) -> str: """ Convert a structure to a Cryspy CIF string. + CrysPy uses attribute names that match the CIF convention: + ``u_11`` for ``U_11``, ``b_11`` for ``B_11``, etc. Its + ``apply_space_group_constraint`` always accesses ``u_11`` + regardless of ``adp_type``. To avoid mismatches the CIF sent to + cryspy always uses **U** notation: ``Biso`` ⟶ ``Uiso``, ``Bani`` + ⟶ ``Uani``, values divided by 8π². + Parameters ---------- structure : Structure @@ -412,7 +561,117 @@ def _convert_structure_to_cryspy_cif( # noqa: PLR6301 str The Cryspy CIF string representation of the structure. """ - return structure.as_cif + saved = self._temporarily_convert_to_u_notation(structure) + + try: + cif = structure.as_cif + finally: + self._restore_from_u_notation(structure, saved) + + return cif + + @staticmethod + def _temporarily_convert_to_u_notation( + structure: Structure, + ) -> list[tuple]: + """ + Temporarily convert all B-convention atoms to U notation. + + Returns saved state for later restoration. + """ + from easydiffraction.datablocks.structure.categories.atom_sites.enums import ( # noqa: PLC0415 + AdpTypeEnum, + ) + + factor = 8.0 * np.pi**2 + suffixes = ('11', '22', '33', '12', '13', '23') + saved: list[tuple] = [] + + for atom in structure.atom_sites: + adp_enum = AdpTypeEnum(atom.adp_type.value) + is_b = adp_enum in {AdpTypeEnum.BISO, AdpTypeEnum.BANI} + if not is_b: + continue + + orig_adp_type = atom._adp_type._value + orig_iso_val = atom._adp_iso._value + orig_iso_names = list(atom._adp_iso._cif_handler._names) + + atom._adp_iso._value = orig_iso_val / factor + atom._adp_iso._cif_handler._names = [ + '_atom_site.U_iso_or_equiv', + '_atom_site.B_iso_or_equiv', + ] + + if adp_enum == AdpTypeEnum.BISO: + atom._adp_type._value = AdpTypeEnum.UISO.value + saved.append((atom, None, None, None, orig_adp_type, orig_iso_names, orig_iso_val)) + else: + atom._adp_type._value = AdpTypeEnum.UANI.value + lbl = atom.label.value + if lbl in structure.atom_site_aniso: + aniso = structure.atom_site_aniso[lbl] + else: + aniso = None + if aniso is not None: + orig_vals = [] + orig_names = [] + for s in suffixes: + param = getattr(aniso, f'_adp_{s}') + orig_vals.append(param._value) + orig_names.append(list(param._cif_handler._names)) + param._value /= factor + param._cif_handler._names = [ + f'_atom_site_aniso.U_{s}', + f'_atom_site_aniso.B_{s}', + ] + saved.append(( + atom, + aniso, + orig_vals, + orig_names, + orig_adp_type, + orig_iso_names, + orig_iso_val, + )) + else: + saved.append(( + atom, + None, + None, + None, + orig_adp_type, + orig_iso_names, + orig_iso_val, + )) + + return saved + + @staticmethod + def _restore_from_u_notation( + structure: Structure, # noqa: ARG004 + saved: list[tuple], + ) -> None: + """Restore original B-convention state after CIF generation.""" + suffixes = ('11', '22', '33', '12', '13', '23') + + for ( + atom, + aniso, + orig_vals, + orig_names, + orig_adp_type, + orig_iso_names, + orig_iso_val, + ) in saved: + atom._adp_type._value = orig_adp_type + atom._adp_iso._value = orig_iso_val + atom._adp_iso._cif_handler._names = orig_iso_names + if aniso is not None and orig_vals is not None: + for s, val, names in zip(suffixes, orig_vals, orig_names, strict=False): + param = getattr(aniso, f'_adp_{s}') + param._value = val + param._cif_handler._names = names def _convert_experiment_to_cryspy_cif( # noqa: PLR6301 self, @@ -434,10 +693,11 @@ def _convert_experiment_to_cryspy_cif( # noqa: PLR6301 str The Cryspy CIF string representation of the experiment. """ - expt_type = getattr(experiment, 'type', None) - instrument = getattr(experiment, 'instrument', None) - peak = getattr(experiment, 'peak', None) - extinction = getattr(experiment, 'extinction', None) + attrs = type(experiment)._public_attrs() + expt_type = experiment.type if 'type' in attrs else None + instrument = experiment.instrument if 'instrument' in attrs else None + peak = experiment.peak if 'peak' in attrs else None + extinction = experiment.extinction if 'extinction' in attrs else None cif_lines = [f'data_{experiment.name}'] diff --git a/src/easydiffraction/analysis/fitting.py b/src/easydiffraction/analysis/fitting.py index 2b6e11ecd..a29062037 100644 --- a/src/easydiffraction/analysis/fitting.py +++ b/src/easydiffraction/analysis/fitting.py @@ -65,6 +65,13 @@ def fit( spec for parameters whose ``fit_min``/``fit_max`` are unbounded. """ + # Enforce symmetry constraints (e.g. ADP) before collecting + # free parameters so that components fixed by site symmetry are + # excluded from the minimizer's parameter set. + for structure in structures: + structure._need_categories_update = True + structure._update_categories() + expt_free_params: list[Parameter] = [] for expt in experiments: expt_free_params.extend( diff --git a/src/easydiffraction/core/guard.py b/src/easydiffraction/core/guard.py index ff259d3fb..986b589b3 100644 --- a/src/easydiffraction/core/guard.py +++ b/src/easydiffraction/core/guard.py @@ -33,6 +33,10 @@ def __repr__(self) -> str: def __getattr__(self, key: str) -> None: """Raise a descriptive error for unknown attribute access.""" + # Private/dunder lookups should not trigger diagnostics — + # raise AttributeError so getattr(obj, '_foo', default) works. + if key.startswith('_'): + raise AttributeError(key) cls = type(self) allowed = cls._public_attrs() if key not in allowed: diff --git a/src/easydiffraction/core/singleton.py b/src/easydiffraction/core/singleton.py index 3cfb67d46..59ade7c38 100644 --- a/src/easydiffraction/core/singleton.py +++ b/src/easydiffraction/core/singleton.py @@ -62,7 +62,7 @@ def set_aliases(self, aliases: object) -> None: Set the alias map (name → alias wrapper). Called when user registers parameter aliases like: - alias='biso_La', param=model.atom_sites['La'].b_iso + alias='biso_La', param=model.atom_sites['La'].adp_iso """ self._alias_to_param = dict(aliases.items()) diff --git a/src/easydiffraction/crystallography/crystallography.py b/src/easydiffraction/crystallography/crystallography.py index 525ac99a9..141f059f7 100644 --- a/src/easydiffraction/crystallography/crystallography.py +++ b/src/easydiffraction/crystallography/crystallography.py @@ -1,8 +1,11 @@ # SPDX-FileCopyrightText: 2025 EasyScience contributors # SPDX-License-Identifier: BSD-3-Clause +from fractions import Fraction from typing import Any +import numpy as np +from cryspy.A_functions_base.function_1_atomic_vibrations import vibration_constraints from cryspy.A_functions_base.function_2_space_group import get_crystal_system_by_it_number from cryspy.A_functions_base.function_2_space_group import get_it_number_by_name_hm_short from sympy import Expr @@ -189,3 +192,312 @@ def apply_atom_site_symmetry_constraints( _apply_fract_constraints(atom_site, parsed_exprs) return atom_site + + +# ------------------------------------------------------------------ +# ADP symmetry constraints +# ------------------------------------------------------------------ + + +def _parse_rotation_matrix(expr_str: str) -> tuple[np.ndarray, np.ndarray]: + """ + Extract rotation and translation from a coordinate expression. + + Parses a symmetry-equivalent position string such as ``'(-x+1/2, y, + -z+1/2)'`` into a 3x3 rotation matrix and a translation vector. + + Parameters + ---------- + expr_str : str + A single symmetry-equivalent position, e.g. ``'(x,y,z)'``. + + Returns + ------- + tuple[np.ndarray, np.ndarray] + rotation : (3, 3) integer array. translation : (3,) float array + (fractional). + """ + inner = expr_str.strip().strip('()') + parts = [p.strip() for p in inner.split(',')] + + rot = np.zeros((3, 3), dtype=int) + trans = np.zeros(3) + + var_map = {'x': 0, 'y': 1, 'z': 2} + for row, part in enumerate(parts): + # Replace subtraction by addition of negative terms + normalized = part.replace('-', '+-') + tokens = [t for t in normalized.split('+') if t] + for token in tokens: + matched = False + for var, col in var_map.items(): + if var in token: + coeff_str = token.replace(var, '').strip() + if coeff_str in {'', '+'}: + coeff = 1 + elif coeff_str == '-': + coeff = -1 + else: + coeff = int(coeff_str) + rot[row, col] = coeff + matched = True + break + if not matched: + trans[row] = float(Fraction(token)) + + return rot, trans + + +def _get_general_position_ops( + it_number: int, + coord_code: str | None, +) -> list[tuple[np.ndarray, np.ndarray]] | None: + """ + Return rotation matrices and translations for the general position. + + Parameters + ---------- + it_number : int + International Tables space group number. + coord_code : str | None + IT coordinate system code. + + Returns + ------- + list[tuple[np.ndarray, np.ndarray]] | None + List of (rotation, translation) pairs, or ``None`` on failure. + """ + key = (it_number, coord_code) + if key not in SPACE_GROUPS: + log.error(f'Space group ({it_number}, {coord_code!r}) not found') + return None + + entry = SPACE_GROUPS[key] + wyckoff_positions = entry['Wyckoff_positions'] + # General position is the first key (highest multiplicity) + general_letter = next(iter(wyckoff_positions)) + general_coords = wyckoff_positions[general_letter]['coords_xyz'] + return [_parse_rotation_matrix(c) for c in general_coords] + + +def _site_stabilizer_rotations( + ops: list[tuple[np.ndarray, np.ndarray]], + site_coords: tuple[float, float, float], +) -> list[np.ndarray]: + """ + Return rotation matrices of operations that leave a site invariant. + + An operation (R, t) stabilises a site r when R·r + t ≡ r (mod 1). + + Parameters + ---------- + ops : list[tuple[np.ndarray, np.ndarray]] + All space group operations as (rotation, translation) pairs. + site_coords : tuple[float, float, float] + Fractional coordinates of the site. + + Returns + ------- + list[np.ndarray] + Rotation matrices of stabiliser operations. + """ + r = np.array(site_coords, dtype=float) + stabiliser = [] + for rot, trans in ops: + image = rot @ r + trans + diff = image - r + diff_mod = diff - np.round(diff) + if np.allclose(diff_mod, 0.0, atol=1e-6): + stabiliser.append(rot) + return stabiliser + + +def _calc_adp_constraint_number(stabiliser: list[np.ndarray]) -> int: + """ + Derive ADP constraint type via the Peterse-Palm probe technique. + + A set of coprime probe values is transformed by each site-stabiliser + rotation (Acta Cryst. 1966, 20, 147). The algebraic relationships + among the summed transformed components uniquely identify one of 19 + constraint types (0 = no constraint, 1-18 as defined in cryspy's + ``vibration_constraints``). + + Parameters + ---------- + stabiliser : list[np.ndarray] + Rotation matrices of the site-stabiliser group. + + Returns + ------- + int + Constraint type number (0-18). + """ + # Peterse-Palm probe values (coprime, pairwise distinct) + b_vals = np.array([107, 181, 41, 7, 19, 1], dtype=float) + b_matrix = np.array([ + [b_vals[0], b_vals[3], b_vals[4]], + [b_vals[3], b_vals[1], b_vals[5]], + [b_vals[4], b_vals[5], b_vals[2]], + ]) + + accumulated = np.zeros((3, 3)) + for rot in stabiliser: + accumulated += rot @ b_matrix @ rot.T + + r_11 = round(accumulated[0, 0]) + r_22 = round(accumulated[1, 1]) + r_33 = round(accumulated[2, 2]) + r_12 = round(accumulated[0, 1]) + r_13 = round(accumulated[0, 2]) + r_23 = round(accumulated[1, 2]) + + return _classify_constraint(r_11, r_22, r_33, r_12, r_13, r_23) + + +def _classify_constraint( + r_11: int, + r_22: int, + r_33: int, + r_12: int, + r_13: int, + r_23: int, +) -> int: + """ + Map Peterse-Palm probe sums to a constraint type number. + + Rule table follows cryspy (Peterse & Palm, Acta Cryst. 1966). + + Parameters + ---------- + r_11 : int + Accumulated probe-tensor component (1,1). + r_22 : int + Accumulated probe-tensor component (2,2). + r_33 : int + Accumulated probe-tensor component (3,3). + r_12 : int + Accumulated probe-tensor component (1,2). + r_13 : int + Accumulated probe-tensor component (1,3). + r_23 : int + Accumulated probe-tensor component (2,3). + + Returns + ------- + int + Constraint type (0-18). + """ + z13 = r_13 == 0 + z23 = r_23 == 0 + z12 = r_12 == 0 + eq_11_22 = r_11 == r_22 + eq_22_33 = r_22 == r_33 + eq_22_2x12 = r_22 == 2 * r_12 + eq_23_13 = r_23 == r_13 + eq_12_13 = r_12 == r_13 + neg_23_13 = r_23 == -r_13 + + # Ordered from most specific to least; first match wins. + rules = [ + (z13 and z23 and z12 and eq_11_22 and eq_22_33, 17), + (z13 and z23 and z12 and eq_11_22, 8), + (z13 and z23 and z12 and eq_22_33, 12), + (z13 and z23 and z12, 4), + (z13 and z23 and eq_11_22 and eq_22_2x12, 16), + (z13 and z23 and eq_11_22, 5), + (z13 and z23 and eq_22_2x12, 14), + (z13 and z23, 2), + (z13 and eq_22_33, 9), + (z13, 3), + (z23 and eq_22_2x12, 13), + (z23, 1), + (eq_23_13 and eq_22_33, 18), + (eq_23_13, 6), + (eq_12_13, 10), + (neg_23_13, 7), + (eq_22_33, 11), + (eq_22_2x12, 15), + ] + for condition, result in rules: + if condition: + return result + return 0 + + +def apply_atom_site_aniso_symmetry_constraints( + atom_site_aniso: dict[str, float], + name_hm: str, + coord_code: str | None, + _wyckoff_letter: str, + site_fract: tuple[float, float, float], +) -> tuple[dict[str, float], tuple[bool, ...]]: + """ + Apply symmetry constraints to anisotropic ADP tensor components. + + Uses the Peterse-Palm probe technique to determine which tensor + components are constrained by the site symmetry, then delegates to + cryspy's ``vibration_constraints`` to enforce them. + + Parameters + ---------- + atom_site_aniso : dict[str, float] + Dictionary with keys ``'adp_11'`` … ``'adp_23'``. Modified in + place. + name_hm : str + Hermann-Mauguin symbol of the space group. + coord_code : str | None + IT coordinate system code. + _wyckoff_letter : str + Wyckoff position letter (unused, reserved). + site_fract : tuple[float, float, float] + Fractional coordinates of the atom site. + + Returns + ------- + tuple[dict[str, float], tuple[bool, ...]] + The *atom_site_aniso* dictionary with constrained values, and a + 6-tuple of booleans indicating which components remain free for + refinement (``True`` = free, ``False`` = fixed by symmetry). + """ + all_free = (True, True, True, True, True, True) + + it_number = get_it_number_by_name_hm_short(name_hm) + if it_number is None: + log.error(f"Failed to get IT_number for name_H-M '{name_hm}'") + return atom_site_aniso, all_free + + ops = _get_general_position_ops(it_number, coord_code) + if ops is None: + return atom_site_aniso, all_free + + stabiliser = _site_stabilizer_rotations(ops, site_fract) + if len(stabiliser) <= 1: + # Identity only — no ADP constraints + return atom_site_aniso, all_free + + numb = _calc_adp_constraint_number(stabiliser) + if numb == 0: + return atom_site_aniso, all_free + + param_i = ( + atom_site_aniso['adp_11'], + atom_site_aniso['adp_22'], + atom_site_aniso['adp_33'], + atom_site_aniso['adp_12'], + atom_site_aniso['adp_13'], + atom_site_aniso['adp_23'], + ) + sigma_i = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + ref_i = (True, True, True, True, True, True) + + param_i, _sigma_i, ref_i, _constr_i = vibration_constraints( + numb, + param_i, + sigma_i, + ref_i, + ) + + keys = ('adp_11', 'adp_22', 'adp_33', 'adp_12', 'adp_13', 'adp_23') + atom_site_aniso.update(dict(zip(keys, param_i, strict=False))) + + return atom_site_aniso, ref_i diff --git a/src/easydiffraction/datablocks/structure/categories/atom_site_aniso/__init__.py b/src/easydiffraction/datablocks/structure/categories/atom_site_aniso/__init__.py new file mode 100644 index 000000000..fc8393f27 --- /dev/null +++ b/src/easydiffraction/datablocks/structure/categories/atom_site_aniso/__init__.py @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause + +from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import AtomSiteAniso +from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import ( + AtomSiteAnisoCollection, +) diff --git a/src/easydiffraction/datablocks/structure/categories/atom_site_aniso/default.py b/src/easydiffraction/datablocks/structure/categories/atom_site_aniso/default.py new file mode 100644 index 000000000..baa1dd675 --- /dev/null +++ b/src/easydiffraction/datablocks/structure/categories/atom_site_aniso/default.py @@ -0,0 +1,283 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +""" +Anisotropic ADP category. + +Defines :class:`AtomSiteAniso` items and +:class:`AtomSiteAnisoCollection` used alongside :class:`AtomSites` to +hold anisotropic displacement parameters. +""" + +from __future__ import annotations + +from easydiffraction.core.category import CategoryCollection +from easydiffraction.core.category import CategoryItem +from easydiffraction.core.metadata import TypeInfo +from easydiffraction.core.validation import AttributeSpec +from easydiffraction.core.validation import RangeValidator +from easydiffraction.core.variable import Parameter +from easydiffraction.core.variable import StringDescriptor +from easydiffraction.datablocks.structure.categories.atom_site_aniso.factory import ( + AtomSiteAnisoFactory, +) +from easydiffraction.io.cif.handler import CifHandler + + +class AtomSiteAniso(CategoryItem): + """ + Single atom site anisotropic ADP entry. + + Each entry mirrors an :class:`AtomSite` by label and holds six + tensor components whose physical meaning (B or U) is determined by + ``atom_site.adp_type``. + """ + + def __init__(self) -> None: + """Initialise with default zero-valued tensor components.""" + super().__init__() + + self._label = StringDescriptor( + name='label', + description='Atom-site label matching the parent atom_site entry.', + value_spec=AttributeSpec(default=''), + cif_handler=CifHandler(names=['_atom_site_aniso.label']), + ) + + self._adp_11 = Parameter( + name='adp_11', + description='Anisotropic ADP tensor component (1,1).', + units='Ų', + value_spec=AttributeSpec( + default=0.0, + validator=RangeValidator(), + ), + cif_handler=CifHandler( + names=[ + '_atom_site_aniso.B_11', + '_atom_site_aniso.U_11', + ] + ), + ) + self._adp_22 = Parameter( + name='adp_22', + description='Anisotropic ADP tensor component (2,2).', + units='Ų', + value_spec=AttributeSpec( + default=0.0, + validator=RangeValidator(), + ), + cif_handler=CifHandler( + names=[ + '_atom_site_aniso.B_22', + '_atom_site_aniso.U_22', + ] + ), + ) + self._adp_33 = Parameter( + name='adp_33', + description='Anisotropic ADP tensor component (3,3).', + units='Ų', + value_spec=AttributeSpec( + default=0.0, + validator=RangeValidator(), + ), + cif_handler=CifHandler( + names=[ + '_atom_site_aniso.B_33', + '_atom_site_aniso.U_33', + ] + ), + ) + self._adp_12 = Parameter( + name='adp_12', + description='Anisotropic ADP tensor component (1,2).', + units='Ų', + value_spec=AttributeSpec( + default=0.0, + validator=RangeValidator(), + ), + cif_handler=CifHandler( + names=[ + '_atom_site_aniso.B_12', + '_atom_site_aniso.U_12', + ] + ), + ) + self._adp_13 = Parameter( + name='adp_13', + description='Anisotropic ADP tensor component (1,3).', + units='Ų', + value_spec=AttributeSpec( + default=0.0, + validator=RangeValidator(), + ), + cif_handler=CifHandler( + names=[ + '_atom_site_aniso.B_13', + '_atom_site_aniso.U_13', + ] + ), + ) + self._adp_23 = Parameter( + name='adp_23', + description='Anisotropic ADP tensor component (2,3).', + units='Ų', + value_spec=AttributeSpec( + default=0.0, + validator=RangeValidator(), + ), + cif_handler=CifHandler( + names=[ + '_atom_site_aniso.B_23', + '_atom_site_aniso.U_23', + ] + ), + ) + + self._identity.category_code = 'atom_site_aniso' + self._identity.category_entry_name = lambda: str(self.label.value) + + # ------------------------------------------------------------------ + # Public properties + # ------------------------------------------------------------------ + + @property + def label(self) -> StringDescriptor: + """Label matching the parent atom_site entry.""" + return self._label + + @label.setter + def label(self, value: str) -> None: + self._label.value = value + + @property + def adp_11(self) -> Parameter: + """Anisotropic ADP tensor component (1,1) in Ų.""" + return self._adp_11 + + @adp_11.setter + def adp_11(self, value: float) -> None: + self._adp_11.value = value + + @property + def adp_22(self) -> Parameter: + """Anisotropic ADP tensor component (2,2) in Ų.""" + return self._adp_22 + + @adp_22.setter + def adp_22(self, value: float) -> None: + self._adp_22.value = value + + @property + def adp_33(self) -> Parameter: + """Anisotropic ADP tensor component (3,3) in Ų.""" + return self._adp_33 + + @adp_33.setter + def adp_33(self, value: float) -> None: + self._adp_33.value = value + + @property + def adp_12(self) -> Parameter: + """Anisotropic ADP tensor component (1,2) in Ų.""" + return self._adp_12 + + @adp_12.setter + def adp_12(self, value: float) -> None: + self._adp_12.value = value + + @property + def adp_13(self) -> Parameter: + """Anisotropic ADP tensor component (1,3) in Ų.""" + return self._adp_13 + + @adp_13.setter + def adp_13(self, value: float) -> None: + self._adp_13.value = value + + @property + def adp_23(self) -> Parameter: + """Anisotropic ADP tensor component (2,3) in Ų.""" + return self._adp_23 + + @adp_23.setter + def adp_23(self, value: float) -> None: + self._adp_23.value = value + + +@AtomSiteAnisoFactory.register +class AtomSiteAnisoCollection(CategoryCollection): + """Collection of :class:`AtomSiteAniso` instances.""" + + type_info = TypeInfo( + tag='default', + description='Anisotropic ADP collection', + ) + + def __init__(self) -> None: + """Initialise an empty aniso-ADP collection.""" + super().__init__(item_type=AtomSiteAniso) + + def _skip_cif_serialization(self) -> bool: + """ + Return ``True`` when no atoms use an anisotropic ADP type. + + Returns + ------- + bool + ``True`` if CIF output should be suppressed. + """ + structure = getattr(self, '_parent', None) + if structure is None: + return True + atom_sites = getattr(structure, '_atom_sites', None) + if atom_sites is None: + return True + from easydiffraction.datablocks.structure.categories.atom_sites.enums import ( # noqa: PLC0415 + AdpTypeEnum, + ) + + aniso_types = {AdpTypeEnum.BANI.value, AdpTypeEnum.UANI.value} + return not any(atom.adp_type.value in aniso_types for atom in atom_sites) + + def _iso_labels(self) -> set[str]: + """Return labels of atoms with isotropic ADP type.""" + structure = getattr(self, '_parent', None) + if structure is None: + return set() + atom_sites = getattr(structure, '_atom_sites', None) + if atom_sites is None: + return set() + from easydiffraction.datablocks.structure.categories.atom_sites.enums import ( # noqa: PLC0415 + AdpTypeEnum, + ) + + iso_types = {AdpTypeEnum.BISO.value, AdpTypeEnum.UISO.value} + return {atom.label.value for atom in atom_sites if atom.adp_type.value in iso_types} + + def _format_cif_row(self, item: object) -> list[str] | None: + """ + Return ``?`` markers for isotropic atoms, ``None`` otherwise. + + Used by :func:`category_collection_to_cif` as a per-row hook. + Atoms whose ADP type is isotropic get ``?`` for the six tensor + components so they are not mistaken for genuine zeros. + + Parameters + ---------- + item : object + An :class:`AtomSiteAniso` instance. + + Returns + ------- + list[str] | None + Formatted row when overridden, ``None`` for default output. + """ + if item.label.value not in self._iso_labels(): + return None + from easydiffraction.io.cif.serialize import format_param_value # noqa: PLC0415 + from easydiffraction.io.cif.serialize import format_value # noqa: PLC0415 + + row = [format_param_value(item._label)] + row.extend([format_value(None)] * 6) + return row diff --git a/src/easydiffraction/datablocks/structure/categories/atom_site_aniso/factory.py b/src/easydiffraction/datablocks/structure/categories/atom_site_aniso/factory.py new file mode 100644 index 000000000..394c3211f --- /dev/null +++ b/src/easydiffraction/datablocks/structure/categories/atom_site_aniso/factory.py @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Atom-site-aniso factory — delegates entirely to ``FactoryBase``.""" + +from __future__ import annotations + +from typing import ClassVar + +from easydiffraction.core.factory import FactoryBase + + +class AtomSiteAnisoFactory(FactoryBase): + """Create atom-site-aniso collections by tag.""" + + _default_rules: ClassVar[dict] = { + frozenset(): 'default', + } diff --git a/src/easydiffraction/datablocks/structure/categories/atom_sites/__init__.py b/src/easydiffraction/datablocks/structure/categories/atom_sites/__init__.py index 7bd7b9ad4..feb70b52b 100644 --- a/src/easydiffraction/datablocks/structure/categories/atom_sites/__init__.py +++ b/src/easydiffraction/datablocks/structure/categories/atom_sites/__init__.py @@ -3,3 +3,4 @@ from easydiffraction.datablocks.structure.categories.atom_sites.default import AtomSite from easydiffraction.datablocks.structure.categories.atom_sites.default import AtomSites +from easydiffraction.datablocks.structure.categories.atom_sites.enums import AdpTypeEnum diff --git a/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py b/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py index db528d968..7396e9538 100644 --- a/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py +++ b/src/easydiffraction/datablocks/structure/categories/atom_sites/default.py @@ -9,6 +9,8 @@ from __future__ import annotations +import math + from cryspy.A_functions_base.database import DATABASE from easydiffraction.core.category import CategoryCollection @@ -21,6 +23,7 @@ from easydiffraction.core.variable import Parameter from easydiffraction.core.variable import StringDescriptor from easydiffraction.crystallography import crystallography as ecr +from easydiffraction.datablocks.structure.categories.atom_sites.enums import AdpTypeEnum from easydiffraction.datablocks.structure.categories.atom_sites.factory import AtomSitesFactory from easydiffraction.io.cif.handler import CifHandler @@ -110,23 +113,28 @@ def __init__(self) -> None: ), cif_handler=CifHandler(names=['_atom_site.occupancy']), ) - self._b_iso = Parameter( - name='b_iso', + self._adp_iso = Parameter( + name='adp_iso', description='Isotropic atomic displacement parameter (ADP) for the atom site.', units='Ų', value_spec=AttributeSpec( default=0.0, validator=RangeValidator(ge=0.0, le=100.0), ), - cif_handler=CifHandler(names=['_atom_site.B_iso_or_equiv']), + cif_handler=CifHandler( + names=[ + '_atom_site.B_iso_or_equiv', + '_atom_site.U_iso_or_equiv', + ] + ), ) self._adp_type = StringDescriptor( name='adp_type', description='Type of atomic displacement parameter (ADP) ' 'used (e.g., Biso, Uiso, Uani, Bani).', value_spec=AttributeSpec( - default='Biso', - validator=MembershipValidator(allowed=['Biso']), + default=AdpTypeEnum.default(), + validator=MembershipValidator(allowed=[m.value for m in AdpTypeEnum]), ), cif_handler=CifHandler(names=['_atom_site.adp_type']), ) @@ -179,6 +187,156 @@ def _wyckoff_letter_default_value(self) -> str: # TODO: What to pass as default? return self._wyckoff_letter_allowed_values[0] + def _convert_adp_values(self, old_type: str, new_type: str) -> None: + """ + Convert ADP values when the type changes. + + Handles B ↔ U conversion using B = 8π²U and iso ↔ ani seeding. + + Parameters + ---------- + old_type : str + Previous ADP type value. + new_type : str + New ADP type value. + """ + old_enum = AdpTypeEnum(old_type) + new_enum = AdpTypeEnum(new_type) + factor = 8.0 * math.pi**2 + old_is_b = old_enum in {AdpTypeEnum.BISO, AdpTypeEnum.BANI} + new_is_u = new_enum in {AdpTypeEnum.UISO, AdpTypeEnum.UANI} + old_is_iso = old_enum in {AdpTypeEnum.BISO, AdpTypeEnum.UISO} + new_is_iso = new_enum in {AdpTypeEnum.BISO, AdpTypeEnum.UISO} + + # Ani → Iso: collapse tensor to scalar first (in old units) + if not old_is_iso and new_is_iso: + self._collapse_aniso_to_iso() + + # B ↔ U conversion for iso value + if old_is_b and new_is_u: + self._adp_iso.value /= factor + elif not old_is_b and not new_is_u: + self._adp_iso.value *= factor + + # Iso → Ani: seed diagonal from (already converted) adp_iso + if old_is_iso and not new_is_iso: + self._seed_aniso_from_iso() + elif not old_is_iso and not new_is_iso: + # Ani → Ani (e.g. Bani→Uani): apply B↔U to aniso values + aniso = self._get_aniso_entry() + if aniso is not None: + self._convert_aniso_values( + aniso, + old_is_b=old_is_b, + new_is_u=new_is_u, + factor=factor, + ) + + def _seed_aniso_from_iso(self) -> None: + """Seed aniso diagonal from current adp_iso value.""" + aniso = self._get_aniso_entry() + if aniso is None: + # Entry not yet created; force sync on parent + structure = getattr(self._parent, '_parent', None) + if structure is not None and hasattr(structure, '_sync_atom_site_aniso'): + structure._sync_atom_site_aniso() + aniso = self._get_aniso_entry() + if aniso is None: + return + iso_val = self._adp_iso.value + aniso.adp_11 = iso_val + aniso.adp_22 = iso_val + aniso.adp_33 = iso_val + aniso.adp_12 = 0.0 + aniso.adp_13 = 0.0 + aniso.adp_23 = 0.0 + + def _collapse_aniso_to_iso(self) -> None: + """ + Set adp_iso to the mean of the aniso diagonal. + + Writes directly to ``_value`` to bypass range validation, + because intermediate minimizer steps can produce negative + anisotropic components whose mean falls outside the nominal + ``[0, 100]`` range. + """ + aniso = self._get_aniso_entry() + if aniso is None: + return + self._adp_iso._value = (aniso.adp_11.value + aniso.adp_22.value + aniso.adp_33.value) / 3.0 + + def _get_aniso_entry(self) -> object | None: + """Return the matching AtomSiteAniso entry, or None.""" + # _parent is absent before the atom is added to a collection + if '_parent' not in self.__dict__: + return None + structure = getattr(self._parent, '_parent', None) + if structure is None: + return None + aniso_coll = getattr(structure, '_atom_site_aniso', None) + if aniso_coll is None: + return None + lbl = self._label.value + if lbl in aniso_coll: + return aniso_coll[lbl] + return None + + @staticmethod + def _convert_aniso_values( + aniso: object, + *, + old_is_b: bool, + new_is_u: bool, + factor: float, + ) -> None: + """Apply B↔U conversion to all six aniso tensor components.""" + if old_is_b and new_is_u: + for attr in ('adp_11', 'adp_22', 'adp_33', 'adp_12', 'adp_13', 'adp_23'): + p = getattr(aniso, attr) + p.value /= factor + elif not old_is_b and not new_is_u: + for attr in ('adp_11', 'adp_22', 'adp_33', 'adp_12', 'adp_13', 'adp_23'): + p = getattr(aniso, attr) + p.value *= factor + + def _reorder_adp_cif_names(self, new_type: str) -> None: + """ + Reorder CIF names on adp_iso and aniso params for serialisation. + + Parameters + ---------- + new_type : str + The new ADP type value. + """ + is_u = AdpTypeEnum(new_type) in {AdpTypeEnum.UISO, AdpTypeEnum.UANI} + if is_u: + self._adp_iso._cif_handler._names = [ + '_atom_site.U_iso_or_equiv', + '_atom_site.B_iso_or_equiv', + ] + else: + self._adp_iso._cif_handler._names = [ + '_atom_site.B_iso_or_equiv', + '_atom_site.U_iso_or_equiv', + ] + + # Reorder aniso CIF names + aniso = self._get_aniso_entry() + if aniso is None: + return + for suffix in ('11', '22', '33', '12', '13', '23'): + param = getattr(aniso, f'_adp_{suffix}') + if is_u: + param._cif_handler._names = [ + f'_atom_site_aniso.U_{suffix}', + f'_atom_site_aniso.B_{suffix}', + ] + else: + param._cif_handler._names = [ + f'_atom_site_aniso.B_{suffix}', + f'_atom_site_aniso.U_{suffix}', + ] + # ------------------------------------------------------------------ # Public properties # ------------------------------------------------------------------ @@ -226,7 +384,15 @@ def adp_type(self) -> StringDescriptor: @adp_type.setter def adp_type(self, value: str) -> None: + old_type = self._adp_type.value self._adp_type.value = value + new_type = self._adp_type.value + if old_type != new_type: + self._convert_adp_values(old_type, new_type) + self._reorder_adp_cif_names(new_type) + parent = getattr(self, '_parent', None) + if parent is not None: + parent._propagate_adp_convention(self) @property def wyckoff_letter(self) -> StringDescriptor: @@ -300,18 +466,36 @@ def occupancy(self, value: float) -> None: self._occupancy.value = value @property - def b_iso(self) -> Parameter: + def adp_iso(self) -> Parameter: """ Isotropic ADP for the atom site (Ų). Reading this property returns the underlying ``Parameter`` object. Assigning to it updates the parameter value. """ - return self._b_iso + return self._adp_iso + + @adp_iso.setter + def adp_iso(self, value: float) -> None: + self._adp_iso.value = value + + @property + def adp_iso_as_b(self) -> float: + """ + Return the isotropic ADP as a B-factor value. + + When ``adp_type`` is ``Uiso`` or ``Uani`` the stored U value is + converted to B via B = 8π²U. Otherwise the stored value is + returned unchanged. - @b_iso.setter - def b_iso(self, value: float) -> None: - self._b_iso.value = value + Returns + ------- + float + Equivalent B_iso value. + """ + if AdpTypeEnum(self._adp_type.value) in {AdpTypeEnum.UISO, AdpTypeEnum.UANI}: + return self._adp_iso.value * 8.0 * math.pi**2 + return self._adp_iso.value @AtomSitesFactory.register @@ -331,6 +515,39 @@ def __init__(self) -> None: # Private helper methods # ------------------------------------------------------------------ + def _propagate_adp_convention(self, source: AtomSite) -> None: + """ + Align all atoms to the B/U convention of *source*. + + When an atom switches between B and U convention, all siblings + are converted to the same convention so that CIF loop headers + remain consistent. + + Parameters + ---------- + source : AtomSite + The atom whose convention just changed. + """ + new_enum = AdpTypeEnum(source._adp_type.value) + target_is_u = new_enum in {AdpTypeEnum.UISO, AdpTypeEnum.UANI} + + for atom in self._items: + if atom is source: + continue + sib_enum = AdpTypeEnum(atom._adp_type.value) + sib_is_u = sib_enum in {AdpTypeEnum.UISO, AdpTypeEnum.UANI} + if sib_is_u == target_is_u: + continue + sib_is_iso = sib_enum in {AdpTypeEnum.BISO, AdpTypeEnum.UISO} + if target_is_u: + target = AdpTypeEnum.UISO if sib_is_iso else AdpTypeEnum.UANI + else: + target = AdpTypeEnum.BISO if sib_is_iso else AdpTypeEnum.BANI + old_sib = atom._adp_type.value + atom._adp_type._value = target.value + atom._convert_adp_values(old_sib, target.value) + atom._reorder_adp_cif_names(target.value) + def _apply_atomic_coordinates_symmetry_constraints(self) -> None: """ Apply symmetry rules to fractional coordinates of every site. @@ -362,6 +579,74 @@ def _apply_atomic_coordinates_symmetry_constraints(self) -> None: atom.fract_y.value = dummy_atom['fract_y'] atom.fract_z.value = dummy_atom['fract_z'] + def _apply_adp_symmetry_constraints(self) -> None: + """ + Apply symmetry rules to anisotropic ADP tensor components. + + For each atom with an anisotropic ADP type and a Wyckoff letter, + enforces the tensor constraints dictated by the site symmetry. + Also sets ``free = False`` on tensor components that are fixed + by symmetry and on ``adp_iso`` for all anisotropic atoms. + """ + structure = self._parent + aniso_types = {AdpTypeEnum.BANI.value, AdpTypeEnum.UANI.value} + space_group_name = structure.space_group.name_h_m.value + space_group_coord_code = structure.space_group.it_coordinate_system_code.value + aniso_collection = structure.atom_site_aniso + + for atom in self._items: + if atom.adp_type.value not in aniso_types: + continue + # Isotropic ADP is not refinable for aniso atoms + atom._adp_iso.free = False + wl = atom.wyckoff_letter.value + if not wl: + continue + lbl = atom.label.value + if lbl not in aniso_collection: + continue + aniso_entry = aniso_collection[lbl] + dummy = { + 'adp_11': aniso_entry.adp_11.value, + 'adp_22': aniso_entry.adp_22.value, + 'adp_33': aniso_entry.adp_33.value, + 'adp_12': aniso_entry.adp_12.value, + 'adp_13': aniso_entry.adp_13.value, + 'adp_23': aniso_entry.adp_23.value, + } + site_fract = ( + atom.fract_x.value, + atom.fract_y.value, + atom.fract_z.value, + ) + dummy, ref_i = ecr.apply_atom_site_aniso_symmetry_constraints( + atom_site_aniso=dummy, + name_hm=space_group_name, + coord_code=space_group_coord_code, + _wyckoff_letter=wl, + site_fract=site_fract, + ) + adp_keys = ('adp_11', 'adp_22', 'adp_33', 'adp_12', 'adp_13', 'adp_23') + for key, is_free in zip(adp_keys, ref_i, strict=False): + param = getattr(aniso_entry, key) + param.value = dummy[key] + if not is_free: + param.free = False + + def _sync_iso_from_aniso(self) -> None: + """ + Update ``adp_iso`` from the anisotropic tensor for aniso atoms. + + For every atom whose ADP type is anisotropic (Bani / Uani), sets + ``adp_iso`` to the mean of the three diagonal tensor components + so that the isotropic value stays consistent with the current + tensor state. + """ + aniso_types = {AdpTypeEnum.BANI.value, AdpTypeEnum.UANI.value} + for atom in self._items: + if atom.adp_type.value in aniso_types: + atom._collapse_aniso_to_iso() + def _update( self, *, @@ -379,3 +664,5 @@ def _update( del called_by_minimizer self._apply_atomic_coordinates_symmetry_constraints() + self._apply_adp_symmetry_constraints() + self._sync_iso_from_aniso() diff --git a/src/easydiffraction/datablocks/structure/categories/atom_sites/enums.py b/src/easydiffraction/datablocks/structure/categories/atom_sites/enums.py new file mode 100644 index 000000000..9ca3d3b57 --- /dev/null +++ b/src/easydiffraction/datablocks/structure/categories/atom_sites/enums.py @@ -0,0 +1,31 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Enumeration for ADP type values.""" + +from __future__ import annotations + +from enum import StrEnum + + +class AdpTypeEnum(StrEnum): + """Atomic displacement parameter type.""" + + BISO = 'Biso' + UISO = 'Uiso' + BANI = 'Bani' + UANI = 'Uani' + + @classmethod + def default(cls) -> AdpTypeEnum: + """Return the default ADP type (BISO).""" + return cls.BISO + + def description(self) -> str: + """Return a human-readable description of this ADP type.""" + descriptions = { + AdpTypeEnum.BISO: 'Isotropic B-factor (Debye-Waller)', + AdpTypeEnum.UISO: 'Isotropic mean-square displacement', + AdpTypeEnum.BANI: 'Anisotropic B-factor tensor', + AdpTypeEnum.UANI: 'Anisotropic mean-square displacement tensor', + } + return descriptions[self] diff --git a/src/easydiffraction/datablocks/structure/item/base.py b/src/easydiffraction/datablocks/structure/item/base.py index 633e0b22a..b9c9c7a5f 100644 --- a/src/easydiffraction/datablocks/structure/item/base.py +++ b/src/easydiffraction/datablocks/structure/item/base.py @@ -5,6 +5,11 @@ from typeguard import typechecked from easydiffraction.core.datablock import DatablockItem +from easydiffraction.datablocks.structure.categories.atom_site_aniso import AtomSiteAnisoCollection +from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import AtomSiteAniso +from easydiffraction.datablocks.structure.categories.atom_site_aniso.factory import ( + AtomSiteAnisoFactory, +) from easydiffraction.datablocks.structure.categories.atom_sites import AtomSites from easydiffraction.datablocks.structure.categories.atom_sites.factory import AtomSitesFactory from easydiffraction.datablocks.structure.categories.cell import Cell @@ -31,6 +36,8 @@ def __init__( self._space_group = SpaceGroupFactory.create(self._space_group_type) self._atom_sites_type: str = AtomSitesFactory.default_tag() self._atom_sites = AtomSitesFactory.create(self._atom_sites_type) + self._atom_site_aniso_type: str = AtomSiteAnisoFactory.default_tag() + self._atom_site_aniso = AtomSiteAnisoFactory.create(self._atom_site_aniso_type) self._identity.datablock_entry_name = lambda: self.name # ------------------------------------------------------------------ @@ -128,6 +135,79 @@ def atom_sites(self, new: AtomSites) -> None: """ self._atom_sites = new + # ------------------------------------------------------------------ + # Atom site aniso (read-only, single type) + # ------------------------------------------------------------------ + + @property + def atom_site_aniso(self) -> AtomSiteAnisoCollection: + """Anisotropic-ADP collection for this structure.""" + return self._atom_site_aniso + + @atom_site_aniso.setter + @typechecked + def atom_site_aniso(self, new: AtomSiteAnisoCollection) -> None: + """ + Replace the anisotropic-ADP collection for this structure. + + Parameters + ---------- + new : AtomSiteAnisoCollection + New aniso collection. + """ + self._atom_site_aniso = new + + # ------------------------------------------------------------------ + # Private methods + # ------------------------------------------------------------------ + + def _sync_atom_site_aniso(self) -> None: + """ + Reconcile ``atom_site_aniso`` with ``atom_sites``. + + Ensures every atom in ``atom_sites`` has a matching entry in + ``atom_site_aniso`` and removes stale entries whose label no + longer appears in ``atom_sites``. Reorders CIF names on aniso + parameters to match each atom's ``adp_type``. + """ + existing_labels = {a.label.value for a in self._atom_sites} + aniso_labels = {a.label.value for a in self._atom_site_aniso} + + # Add missing entries + for atom in self._atom_sites: + lbl = atom.label.value + if lbl not in aniso_labels: + entry = AtomSiteAniso() + entry.label = lbl + self._atom_site_aniso.add(entry) + + # Remove stale entries + stale = [ + a.label.value for a in self._atom_site_aniso if a.label.value not in existing_labels + ] + for lbl in stale: + self._atom_site_aniso.remove(lbl) + + # Reorder CIF names to match each atom's adp_type + for atom in self._atom_sites: + atom._reorder_adp_cif_names(atom.adp_type.value) + + def _update_categories( + self, + *, + called_by_minimizer: bool = False, + ) -> None: + """Update categories with atom_site_aniso sync.""" + if not called_by_minimizer and not self._need_categories_update: + return + + self._sync_atom_site_aniso() + + for category in self.categories: + category._update(called_by_minimizer=called_by_minimizer) + + self._need_categories_update = False + # ------------------------------------------------------------------ # Public methods # ------------------------------------------------------------------ diff --git a/src/easydiffraction/io/cif/serialize.py b/src/easydiffraction/io/cif/serialize.py index a55361a58..c6a00e2c9 100644 --- a/src/easydiffraction/io/cif/serialize.py +++ b/src/easydiffraction/io/cif/serialize.py @@ -36,7 +36,6 @@ def format_value(value: object) -> str: minimizer's finite-difference Jacobian probes (typically ~1e-8 relative) survive the float→string→float round-trip through CIF. """ - width = 12 precision = 8 # Converting @@ -58,10 +57,10 @@ def format_value(value: object) -> str: # Format floats with given precision if isinstance(value, float): - return f'{value:>{width}.{precision}f}' - # Format strings right-aligned + return f'{value:.{precision}f}' + # Format strings as-is if isinstance(value, str): - return f'{value:>{width}s}' + return value # Everything else: fallback return str(value) @@ -101,8 +100,10 @@ def format_param_value(param: object) -> str: str Formatted CIF value string. """ - is_free = getattr(param, 'free', False) - is_constrained = getattr(param, 'constrained', False) + from easydiffraction.core.variable import Parameter # noqa: PLC0415 + + is_free = param.free if isinstance(param, Parameter) else False + is_constrained = param.constrained if isinstance(param, Parameter) else False value = param.value # type: ignore[attr-defined] if not is_free or is_constrained or not isinstance(value, (int, float)): @@ -145,6 +146,46 @@ def category_item_to_cif(item: object) -> str: return '\n'.join(lines) +def _validate_loop_tags( + item: object, + header_tags: list[str], +) -> None: + """Log an error if any row tag disagrees with *header_tags*.""" + for col, p in enumerate(item.parameters): + tag = p._cif_handler.names[0] # type: ignore[attr-defined] + if tag != header_tags[col]: + log.error( + f'CIF tag mismatch in loop column {col}: ' + f"header expects '{header_tags[col]}', " + f"row has '{tag}'", + exc_type=ValueError, + ) + + +def _emit_loop_rows( + items: list, + row_fn: object, + header_tags: list[str], + max_display: int | None, +) -> list[str]: + """Build formatted rows, optionally truncated.""" + lines: list[str] = [] + if max_display is not None and len(items) > max_display: + half = max_display // 2 + for item in items[:half]: + _validate_loop_tags(item, header_tags) + lines.append(' '.join(row_fn(item))) + lines.append('...') + for item in items[-half:]: + _validate_loop_tags(item, header_tags) + lines.append(' '.join(row_fn(item))) + else: + for item in items: + _validate_loop_tags(item, header_tags) + lines.append(' '.join(row_fn(item))) + return lines + + def category_collection_to_cif( collection: object, max_display: int | None = None, @@ -171,33 +212,34 @@ def category_collection_to_cif( if not len(collection): return '' + # Allow collections to conditionally suppress CIF output + skip = getattr(collection, '_skip_cif_serialization', None) + if skip is not None and skip(): + return '' + lines: list[str] = [] - # Header + # Header — use first item's CIF tag names as the canonical columns first_item = next(iter(collection.values())) lines.append('loop_') + header_tags: list[str] = [] for p in first_item.parameters: tags = p._cif_handler.names # type: ignore[attr-defined] + header_tags.append(tags[0]) lines.append(tags[0]) - # Rows - # Limit number of displayed rows if requested - if max_display is not None and len(collection) > max_display: - half_display = max_display // 2 - for i in range(half_display): - item = list(collection.values())[i] - row_vals = [format_param_value(p) for p in item.parameters] - lines.append(' '.join(row_vals)) - lines.append('...') - for i in range(-half_display, 0): - item = list(collection.values())[i] - row_vals = [format_param_value(p) for p in item.parameters] - lines.append(' '.join(row_vals)) - # No limit - else: - for item in collection.values(): - row_vals = [format_param_value(p) for p in item.parameters] - lines.append(' '.join(row_vals)) + # Allow collections to customise per-item row formatting + row_hook = getattr(collection, '_format_cif_row', None) + + def _row(item: object) -> list[str]: + if row_hook is not None: + override = row_hook(item) + if override is not None: + return override + return [format_param_value(p) for p in item.parameters] + + items = list(collection.values()) + lines.extend(_emit_loop_rows(items, _row, header_tags, max_display)) return '\n'.join(lines) diff --git a/src/easydiffraction/summary/summary.py b/src/easydiffraction/summary/summary.py index ea46bc63e..dfe3cbcba 100644 --- a/src/easydiffraction/summary/summary.py +++ b/src/easydiffraction/summary/summary.py @@ -107,7 +107,7 @@ def show_crystallographic_data(self) -> None: f'{site.fract_y.value:.5f}', f'{site.fract_z.value:.5f}', f'{site.occupancy.value:.5f}', - f'{site.b_iso.value:.5f}', + f'{site.adp_iso.value:.5f}', ] for site in model.atom_sites ] diff --git a/src/easydiffraction/utils/utils.py b/src/easydiffraction/utils/utils.py index 39ec94438..838868b63 100644 --- a/src/easydiffraction/utils/utils.py +++ b/src/easydiffraction/utils/utils.py @@ -73,7 +73,7 @@ def _fetch_data_index() -> dict: _validate_url(index_url) # macOS: sha256sum index.json - index_hash = 'sha256:af64483b9e0941af56d582b9d50285b8404e3d10a103d8696cddf3850ee2b660' + index_hash = 'sha256:b73db869debfe56ee776920644bfd28704885e8287ec7edb556e6ad7335cfe36' destination_dirname = 'easydiffraction' destination_fname = 'data-index.json' cache_dir = pooch.os_cache(destination_dirname) diff --git a/tests/functional/test_adp_switching.py b/tests/functional/test_adp_switching.py new file mode 100644 index 000000000..5715219ed --- /dev/null +++ b/tests/functional/test_adp_switching.py @@ -0,0 +1,244 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Functional tests for ADP type switching workflows.""" + +from __future__ import annotations + +import math + +import pytest + +from easydiffraction import Project + +_FACTOR = 8.0 * math.pi**2 + + +def _make_project_with_structure(): + """Build a project with a simple cubic structure.""" + Project._loading = True + try: + project = Project() + finally: + Project._loading = False + project.structures.create(name='cubic') + s = project.structures['cubic'] + s.space_group.name_h_m = 'P m -3 m' + s.cell.length_a = 3.89 + s.atom_sites.create( + label='A', + type_symbol='La', + fract_x=0, + fract_y=0, + fract_z=0, + wyckoff_letter='a', + adp_iso=0.5, + ) + s.atom_sites.create( + label='B', + type_symbol='Co', + fract_x=0.5, + fract_y=0.5, + fract_z=0.5, + wyckoff_letter='b', + adp_iso=0.3, + ) + return project + + +# ------------------------------------------------------------------ +# ADP type switching: value correctness +# ------------------------------------------------------------------ + + +class TestAdpTypeSwitchingValues: + def test_biso_to_bani_preserves_value(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Bani' + aniso = s.atom_site_aniso['A'] + assert aniso.adp_11.value == pytest.approx(0.5) + assert aniso.adp_22.value == pytest.approx(0.5) + assert aniso.adp_33.value == pytest.approx(0.5) + assert aniso.adp_12.value == pytest.approx(0.0) + + def test_biso_to_uiso_converts(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Uiso' + expected = 0.5 / _FACTOR + assert s.atom_sites['A'].adp_iso.value == pytest.approx(expected) + + def test_biso_to_uani_converts_and_seeds(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Uani' + aniso = s.atom_site_aniso['A'] + expected = 0.5 / _FACTOR + assert aniso.adp_11.value == pytest.approx(expected) + assert aniso.adp_22.value == pytest.approx(expected) + assert aniso.adp_33.value == pytest.approx(expected) + + def test_uiso_to_biso_converts(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Uiso' + u_val = s.atom_sites['A'].adp_iso.value + s.atom_sites['A'].adp_type = 'Biso' + assert s.atom_sites['A'].adp_iso.value == pytest.approx(u_val * _FACTOR) + + def test_uani_to_bani_converts_tensor(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Uani' + u11 = s.atom_site_aniso['A'].adp_11.value + s.atom_sites['A'].adp_type = 'Bani' + b11 = s.atom_site_aniso['A'].adp_11.value + assert b11 == pytest.approx(u11 * _FACTOR) + + def test_bani_to_uani_converts_tensor(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Bani' + b11 = s.atom_site_aniso['A'].adp_11.value + s.atom_sites['A'].adp_type = 'Uani' + u11 = s.atom_site_aniso['A'].adp_11.value + assert u11 == pytest.approx(b11 / _FACTOR) + + +# ------------------------------------------------------------------ +# Round trips +# ------------------------------------------------------------------ + + +class TestAdpRoundTrips: + def test_biso_bani_biso(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Bani' + s.atom_sites['A'].adp_type = 'Biso' + assert s.atom_sites['A'].adp_iso.value == pytest.approx(0.5) + + def test_biso_uani_biso(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Uani' + s.atom_sites['A'].adp_type = 'Biso' + assert s.atom_sites['A'].adp_iso.value == pytest.approx(0.5) + + def test_uiso_uani_uiso(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Uiso' + u_val = s.atom_sites['A'].adp_iso.value + s.atom_sites['A'].adp_type = 'Uani' + s.atom_sites['A'].adp_type = 'Uiso' + assert s.atom_sites['A'].adp_iso.value == pytest.approx(u_val) + + def test_biso_uiso_biso(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Uiso' + s.atom_sites['A'].adp_type = 'Biso' + assert s.atom_sites['A'].adp_iso.value == pytest.approx(0.5) + + def test_full_cycle_biso_uiso_uani_bani_biso(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Uiso' + s.atom_sites['A'].adp_type = 'Uani' + s.atom_sites['A'].adp_type = 'Bani' + s.atom_sites['A'].adp_type = 'Biso' + assert s.atom_sites['A'].adp_iso.value == pytest.approx(0.5) + + +# ------------------------------------------------------------------ +# Mixed ADP types in the same structure +# ------------------------------------------------------------------ + + +class TestMixedAdpTypes: + def test_mixed_types_coexist(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Uani' # Auto-changed to Bani by next line + s.atom_sites['B'].adp_type = 'Biso' + assert s.atom_sites['A'].adp_type.value == 'Bani' + assert s.atom_sites['B'].adp_type.value == 'Biso' + + def test_mixed_cif_has_question_marks_for_iso(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Bani' + cif = s.atom_site_aniso.as_cif + # A is Bani → numerical values + # B is Biso → ? markers + lines = cif.strip().split('\n') + data_lines = [l for l in lines if not l.startswith(('loop_', '_atom_site_aniso'))] + b_line = next(l for l in data_lines if 'B ' in l or l.startswith('B ')) + assert '?' in b_line + + def test_all_iso_suppresses_aniso_cif(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + cif = s.atom_site_aniso.as_cif + assert cif == '' + + def test_adp_iso_syncs_from_aniso_on_update(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Bani' + # In P m -3 m, Wyckoff 'a' constrains U11=U22=U33, U12=U13=U23=0 + # so any set of diagonal values collapses to U11 after update + s.atom_site_aniso['A'].adp_11 = 0.3 + s.atom_site_aniso['A'].adp_22 = 0.6 + s.atom_site_aniso['A'].adp_33 = 0.9 + s._update_categories() + # After symmetry constraints: all diags = 0.3 (first value wins) + aniso = s.atom_site_aniso['A'] + assert aniso.adp_11.value == pytest.approx(aniso.adp_22.value) + assert aniso.adp_11.value == pytest.approx(aniso.adp_33.value) + # adp_iso should match the constrained diagonal mean + expected = (aniso.adp_11.value + aniso.adp_22.value + aniso.adp_33.value) / 3.0 + assert s.atom_sites['A'].adp_iso.value == pytest.approx(expected) + + def test_adp_iso_unchanged_for_iso_atom_on_update(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Bani' + s._update_categories() + # B stays Biso → its adp_iso should not change + assert s.atom_sites['B'].adp_iso.value == pytest.approx(0.3) + + +# ------------------------------------------------------------------ +# CIF name selection based on ADP type +# ------------------------------------------------------------------ + + +class TestCifNamesByAdpType: + def test_biso_uses_b_names(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + site = s.atom_sites['A'] + assert '_atom_site.B_iso_or_equiv' in site._adp_iso._cif_handler.names[0] + + def test_uiso_uses_u_names(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Uiso' + site = s.atom_sites['A'] + assert '_atom_site.U_iso_or_equiv' in site._adp_iso._cif_handler.names[0] + + def test_bani_uses_b_aniso_names(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Bani' + aniso = s.atom_site_aniso['A'] + assert aniso._adp_11._cif_handler.names[0] == '_atom_site_aniso.B_11' + + def test_uani_uses_u_aniso_names(self): + project = _make_project_with_structure() + s = project.structures['cubic'] + s.atom_sites['A'].adp_type = 'Uani' + aniso = s.atom_site_aniso['A'] + assert aniso._adp_11._cif_handler.names[0] == '_atom_site_aniso.U_11' diff --git a/tests/functional/test_experiment_workflow.py b/tests/functional/test_experiment_workflow.py index ffc3da25b..9fd1ef617 100644 --- a/tests/functional/test_experiment_workflow.py +++ b/tests/functional/test_experiment_workflow.py @@ -34,7 +34,7 @@ def _make_project_with_experiment(): fract_z=0, wyckoff_letter='a', occupancy=0.5, - b_iso=0.5, + adp_iso=0.5, ) # Add experiment from data file diff --git a/tests/functional/test_fitting_workflow.py b/tests/functional/test_fitting_workflow.py index 9250bd9d9..3fde95dde 100644 --- a/tests/functional/test_fitting_workflow.py +++ b/tests/functional/test_fitting_workflow.py @@ -35,7 +35,7 @@ def _make_fit_ready_project(): fract_z=0, wyckoff_letter='a', occupancy=0.5, - b_iso=0.5, + adp_iso=0.5, ) s.atom_sites.create( label='Ba', @@ -45,7 +45,7 @@ def _make_fit_ready_project(): fract_z=0, wyckoff_letter='a', occupancy=0.5, - b_iso=0.5, + adp_iso=0.5, ) s.atom_sites.create( label='Co', @@ -54,7 +54,7 @@ def _make_fit_ready_project(): fract_y=0.5, fract_z=0.5, wyckoff_letter='b', - b_iso=0.5, + adp_iso=0.5, ) s.atom_sites.create( label='O', @@ -63,7 +63,7 @@ def _make_fit_ready_project(): fract_y=0.5, fract_z=0.5, wyckoff_letter='c', - b_iso=0.5, + adp_iso=0.5, ) # Experiment @@ -100,7 +100,7 @@ def test_create_alias(self): s = project.structures['lbco'] project.analysis.aliases.create( label='biso_La', - param=s.atom_sites['La'].b_iso, + param=s.atom_sites['La'].adp_iso, ) assert len(project.analysis.aliases) == 1 @@ -109,11 +109,11 @@ def test_create_multiple_aliases(self): s = project.structures['lbco'] project.analysis.aliases.create( label='biso_La', - param=s.atom_sites['La'].b_iso, + param=s.atom_sites['La'].adp_iso, ) project.analysis.aliases.create( label='biso_Ba', - param=s.atom_sites['Ba'].b_iso, + param=s.atom_sites['Ba'].adp_iso, ) assert len(project.analysis.aliases) == 2 @@ -124,11 +124,11 @@ def test_create_constraint(self): s = project.structures['lbco'] project.analysis.aliases.create( label='biso_La', - param=s.atom_sites['La'].b_iso, + param=s.atom_sites['La'].adp_iso, ) project.analysis.aliases.create( label='biso_Ba', - param=s.atom_sites['Ba'].b_iso, + param=s.atom_sites['Ba'].adp_iso, ) project.analysis.constraints.create( expression='biso_Ba = biso_La', @@ -162,16 +162,16 @@ def test_fit_updates_parameter_values(self): def test_fit_with_constraints(self): project = _make_fit_ready_project() s = project.structures['lbco'] - s.atom_sites['La'].b_iso.free = True - s.atom_sites['Ba'].b_iso.free = True + s.atom_sites['La'].adp_iso.free = True + s.atom_sites['Ba'].adp_iso.free = True project.analysis.aliases.create( label='biso_La', - param=s.atom_sites['La'].b_iso, + param=s.atom_sites['La'].adp_iso, ) project.analysis.aliases.create( label='biso_Ba', - param=s.atom_sites['Ba'].b_iso, + param=s.atom_sites['Ba'].adp_iso, ) project.analysis.constraints.create( expression='biso_Ba = biso_La', @@ -180,6 +180,6 @@ def test_fit_with_constraints(self): project.analysis.fit(verbosity='silent') assert project.analysis.fit_results.success is True # Constrained params should be equal after fitting - la_biso = s.atom_sites['La'].b_iso.value - ba_biso = s.atom_sites['Ba'].b_iso.value + la_biso = s.atom_sites['La'].adp_iso.value + ba_biso = s.atom_sites['Ba'].adp_iso.value assert la_biso == pytest.approx(ba_biso, rel=1e-3) diff --git a/tests/functional/test_structure_workflow.py b/tests/functional/test_structure_workflow.py index 4ed2da3f6..23ac232e6 100644 --- a/tests/functional/test_structure_workflow.py +++ b/tests/functional/test_structure_workflow.py @@ -77,7 +77,7 @@ def test_create_atom_site(self): fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.5, + adp_iso=0.5, ) assert len(s.atom_sites) == 1 @@ -92,11 +92,11 @@ def test_access_atom_site_by_label(self): fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.5, + adp_iso=0.5, ) atom = s.atom_sites['La'] assert atom.fract_x.value == pytest.approx(0) - assert atom.b_iso.value == pytest.approx(0.5) + assert atom.adp_iso.value == pytest.approx(0.5) def test_atom_site_fract_is_fittable(self): project = _make_project() @@ -109,7 +109,7 @@ def test_atom_site_fract_is_fittable(self): fract_y=0.2, fract_z=0.3, wyckoff_letter='a', - b_iso=0.5, + adp_iso=0.5, ) s.atom_sites['La'].fract_x.free = True assert s.atom_sites['La'].fract_x.free is True @@ -125,7 +125,7 @@ def test_multiple_atom_sites(self): fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.5, + adp_iso=0.5, ) s.atom_sites.create( label='O', @@ -134,6 +134,6 @@ def test_multiple_atom_sites(self): fract_y=0.5, fract_z=0, wyckoff_letter='c', - b_iso=0.3, + adp_iso=0.3, ) assert len(s.atom_sites) == 2 diff --git a/tests/integration/fitting/conftest.py b/tests/integration/fitting/conftest.py index 83be2e17d..851576140 100644 --- a/tests/integration/fitting/conftest.py +++ b/tests/integration/fitting/conftest.py @@ -29,7 +29,7 @@ def lbco_fitted_project(): fract_z=0, wyckoff_letter='a', occupancy=0.5, - b_iso=0.1, + adp_iso=0.1, ) model.atom_sites.create( label='Ba', @@ -39,7 +39,7 @@ def lbco_fitted_project(): fract_z=0, wyckoff_letter='a', occupancy=0.5, - b_iso=0.1, + adp_iso=0.1, ) model.atom_sites.create( label='Co', @@ -48,7 +48,7 @@ def lbco_fitted_project(): fract_y=0.5, fract_z=0.5, wyckoff_letter='b', - b_iso=0.1, + adp_iso=0.1, ) model.atom_sites.create( label='O', @@ -57,7 +57,7 @@ def lbco_fitted_project(): fract_y=0.5, fract_z=0.5, wyckoff_letter='c', - b_iso=0.1, + adp_iso=0.1, ) data_path = download_data(id=3, destination=TEMP_DIR) diff --git a/tests/integration/fitting/test_aniso_adp_fitting.py b/tests/integration/fitting/test_aniso_adp_fitting.py new file mode 100644 index 000000000..8daa6350a --- /dev/null +++ b/tests/integration/fitting/test_aniso_adp_fitting.py @@ -0,0 +1,106 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Integration tests for anisotropic ADP fitting (Tb2Ti2O7, HEiDi).""" + +import tempfile + +import pytest + +import easydiffraction as ed + +TEMP_DIR = tempfile.gettempdir() + + +def _setup_tbti_project(): + """Create a Tb2Ti2O7 single-crystal project ready for fitting.""" + project = ed.Project() + + model_path = ed.download_data(id=20, destination=TEMP_DIR) + project.structures.add_from_cif_path(model_path) + + data_path = ed.download_data(id=19, destination=TEMP_DIR) + project.experiments.add_from_data_path( + name='heidi', + data_path=data_path, + sample_form='single crystal', + beam_mode='constant wavelength', + radiation_probe='neutron', + ) + experiment = project.experiments['heidi'] + experiment.linked_crystal.id = 'tbti' + experiment.linked_crystal.scale = 1.0 + experiment.instrument.setup_wavelength = 0.793 + experiment.extinction.mosaicity = 35000 + experiment.extinction.radius = 10 + + return project + + +@pytest.mark.fast +def test_iso_then_aniso_fit() -> None: + """Fit Uiso first, then switch to Uani and fit again.""" + project = _setup_tbti_project() + s = project.structures['tbti'] + e = project.experiments['heidi'] + + # Step 1: Set all atoms to Uiso with zero starting values + for name in ('Tb', 'Ti', 'O1', 'O2'): + s.atom_sites[name].adp_type = 'Uiso' + s.atom_sites[name].adp_iso = 0.0 + + # Free parameters for isotropic fit + s.atom_sites['O1'].fract_x.free = True + s.atom_sites['Ti'].occupancy.free = True + s.atom_sites['O1'].occupancy.free = True + s.atom_sites['O2'].occupancy.free = True + for name in ('Tb', 'Ti', 'O1', 'O2'): + s.atom_sites[name].adp_iso.free = True + e.linked_crystal.scale.free = True + e.extinction.radius.free = True + + # Fit isotropic + project.analysis.fit(verbosity='silent') + chi2_iso = project.analysis.fit_results.reduced_chi_square + assert chi2_iso < 20.0 + + # Record iso values + u_iso_tb = s.atom_sites['Tb'].adp_iso.value + assert u_iso_tb > 0.0 + + # Step 2: Switch Tb, Ti, O1 to Uani (O2 stays Uiso) + for name in ('Tb', 'Ti', 'O1'): + s.atom_sites[name].adp_type = 'Uani' + + # Free anisotropic parameters + s.atom_site_aniso['Tb'].adp_11.free = True + s.atom_site_aniso['Tb'].adp_12.free = True + s.atom_site_aniso['Ti'].adp_11.free = True + s.atom_site_aniso['Ti'].adp_12.free = True + s.atom_site_aniso['O1'].adp_11.free = True + s.atom_site_aniso['O1'].adp_22.free = True + s.atom_site_aniso['O1'].adp_23.free = True + + # Fit anisotropic + project.analysis.fit(verbosity='silent') + chi2_aniso = project.analysis.fit_results.reduced_chi_square + + # Anisotropic fit should improve (or at least match) chi2 + assert chi2_aniso < chi2_iso + 1.0 + assert chi2_aniso < 10.0 + + # Aniso tensor should have non-zero off-diagonal for Tb + assert abs(s.atom_site_aniso['Tb'].adp_12.value) > 0.0001 + + # O2 should still be Uiso + assert s.atom_sites['O2'].adp_type.value == 'Uiso' + + # CIF should show ? for O2 in aniso loop + cif = s.atom_site_aniso.as_cif + lines = cif.strip().split('\n') + o2_lines = [l for l in lines if l.strip().startswith('O2')] + assert len(o2_lines) == 1 + assert '?' in o2_lines[0] + + +if __name__ == '__main__': + test_iso_then_aniso_fit() diff --git a/tests/integration/fitting/test_cif_round_trip.py b/tests/integration/fitting/test_cif_round_trip.py index 4ff5c02d1..17a5bff81 100644 --- a/tests/integration/fitting/test_cif_round_trip.py +++ b/tests/integration/fitting/test_cif_round_trip.py @@ -265,7 +265,7 @@ def test_structure_cif_round_trip_preserves_parameters() -> None: fract_z=0, wyckoff_letter='a', occupancy=0.5, - b_iso=0.5, + adp_iso=0.5, ) original.atom_sites.create( label='Co', @@ -274,7 +274,7 @@ def test_structure_cif_round_trip_preserves_parameters() -> None: fract_y=0.5, fract_z=0.5, wyckoff_letter='b', - b_iso=0.5, + adp_iso=0.5, ) original.atom_sites.create( label='O', @@ -283,7 +283,7 @@ def test_structure_cif_round_trip_preserves_parameters() -> None: fract_y=0.5, fract_z=0.5, wyckoff_letter='c', - b_iso=0.5, + adp_iso=0.5, ) # Apply symmetry constraints before serialisation original._update_categories() @@ -315,8 +315,8 @@ def test_structure_cif_round_trip_preserves_parameters() -> None: err_msg=f'fract_x mismatch for {label}', ) assert_almost_equal( - loaded_site.b_iso.value, - orig_site.b_iso.value, + loaded_site.adp_iso.value, + orig_site.adp_iso.value, decimal=4, - err_msg=f'b_iso mismatch for {label}', + err_msg=f'adp_iso mismatch for {label}', ) diff --git a/tests/integration/fitting/test_multi.py b/tests/integration/fitting/test_multi.py index f33d0bc4f..b25840f50 100644 --- a/tests/integration/fitting/test_multi.py +++ b/tests/integration/fitting/test_multi.py @@ -27,7 +27,7 @@ def test_single_fit_neutron_pd_tof_mcstas_lbco_si() -> None: fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.2, + adp_iso=0.2, occupancy=0.5, ) model_1.atom_sites.create( @@ -37,7 +37,7 @@ def test_single_fit_neutron_pd_tof_mcstas_lbco_si() -> None: fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.2, + adp_iso=0.2, occupancy=0.5, ) model_1.atom_sites.create( @@ -47,7 +47,7 @@ def test_single_fit_neutron_pd_tof_mcstas_lbco_si() -> None: fract_y=0.5, fract_z=0.5, wyckoff_letter='b', - b_iso=0.2567, + adp_iso=0.2567, ) model_1.atom_sites.create( label='O', @@ -56,7 +56,7 @@ def test_single_fit_neutron_pd_tof_mcstas_lbco_si() -> None: fract_y=0.5, fract_z=0.5, wyckoff_letter='c', - b_iso=1.4041, + adp_iso=1.4041, ) model_2 = StructureFactory.from_scratch(name='si') @@ -70,7 +70,7 @@ def test_single_fit_neutron_pd_tof_mcstas_lbco_si() -> None: fract_y=0.0, fract_z=0.0, wyckoff_letter='a', - b_iso=0.0, + adp_iso=0.0, ) # Set experiment @@ -111,12 +111,12 @@ def test_single_fit_neutron_pd_tof_mcstas_lbco_si() -> None: # Select fitting parameters model_1.cell.length_a.free = True - model_1.atom_sites['La'].b_iso.free = True - model_1.atom_sites['Ba'].b_iso.free = True - model_1.atom_sites['Co'].b_iso.free = True - model_1.atom_sites['O'].b_iso.free = True + model_1.atom_sites['La'].adp_iso.free = True + model_1.atom_sites['Ba'].adp_iso.free = True + model_1.atom_sites['Co'].adp_iso.free = True + model_1.atom_sites['O'].adp_iso.free = True model_2.cell.length_a.free = True - model_2.atom_sites['Si'].b_iso.free = True + model_2.atom_sites['Si'].adp_iso.free = True expt.linked_phases['lbco'].scale.free = True expt.linked_phases['si'].scale.free = True expt.peak.broad_gauss_sigma_0.free = True @@ -151,7 +151,7 @@ def _test_joint_fit_bragg_pdf_neutron_pd_tof_si() -> None: fract_x=0.125, fract_y=0.125, fract_z=0.125, - b_iso=0.5, + adp_iso=0.5, ) # Set Bragg experiment (SEPD, TOF) @@ -205,7 +205,7 @@ def _test_joint_fit_bragg_pdf_neutron_pd_tof_si() -> None: # Select fitting parameters — shared structure model.cell.length_a.free = True - model.atom_sites['Si'].b_iso.free = True + model.atom_sites['Si'].adp_iso.free = True # Select fitting parameters — Bragg experiment bragg_expt.linked_phases['si'].scale.free = True diff --git a/tests/integration/fitting/test_pair-distribution-function.py b/tests/integration/fitting/test_pair-distribution-function.py index 066e727e5..3d3c4b97e 100644 --- a/tests/integration/fitting/test_pair-distribution-function.py +++ b/tests/integration/fitting/test_pair-distribution-function.py @@ -27,7 +27,7 @@ def test_single_fit_pdf_xray_pd_cw_nacl() -> None: fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=1.1053, + adp_iso=1.1053, ) structure.atom_sites.create( label='Cl', @@ -36,7 +36,7 @@ def test_single_fit_pdf_xray_pd_cw_nacl() -> None: fract_y=0.5, fract_z=0.5, wyckoff_letter='b', - b_iso=0.5708, + adp_iso=0.5708, ) # Set experiment @@ -61,8 +61,8 @@ def test_single_fit_pdf_xray_pd_cw_nacl() -> None: # Select fitting parameters structure.cell.length_a.free = True - structure.atom_sites['Na'].b_iso.free = True - structure.atom_sites['Cl'].b_iso.free = True + structure.atom_sites['Na'].adp_iso.free = True + structure.atom_sites['Cl'].adp_iso.free = True experiment.linked_phases['nacl'].scale.free = True experiment.peak.damp_q.free = True experiment.peak.sharp_delta_2.free = True @@ -92,7 +92,7 @@ def test_single_fit_pdf_neutron_pd_cw_ni(): fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.4281, + adp_iso=0.4281, ) # Set experiment @@ -116,7 +116,7 @@ def test_single_fit_pdf_neutron_pd_cw_ni(): # Select fitting parameters structure.cell.length_a.free = True - structure.atom_sites['Ni'].b_iso.free = True + structure.atom_sites['Ni'].adp_iso.free = True experiment.linked_phases['ni'].scale.free = True experiment.peak.broad_q.free = True experiment.peak.sharp_delta_2.free = True @@ -145,7 +145,7 @@ def test_single_fit_pdf_neutron_pd_tof_si(): fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=0.717, + adp_iso=0.717, ) # Set experiment @@ -169,7 +169,7 @@ def test_single_fit_pdf_neutron_pd_tof_si(): # Select fitting parameters project.structures['si'].cell.length_a.free = True - project.structures['si'].atom_sites['Si'].b_iso.free = True + project.structures['si'].atom_sites['Si'].adp_iso.free = True experiment.linked_phases['si'].scale.free = True experiment.peak.damp_q.free = True experiment.peak.broad_q.free = True diff --git a/tests/integration/fitting/test_powder-diffraction_constant-wavelength.py b/tests/integration/fitting/test_powder-diffraction_constant-wavelength.py index f81d1b756..a00e63b08 100644 --- a/tests/integration/fitting/test_powder-diffraction_constant-wavelength.py +++ b/tests/integration/fitting/test_powder-diffraction_constant-wavelength.py @@ -27,7 +27,7 @@ def test_single_fit_neutron_pd_cwl_lbco() -> None: fract_z=0, wyckoff_letter='a', occupancy=0.5, - b_iso=0.1, + adp_iso=0.1, ) model.atom_sites.create( label='Ba', @@ -37,7 +37,7 @@ def test_single_fit_neutron_pd_cwl_lbco() -> None: fract_z=0, wyckoff_letter='a', occupancy=0.5, - b_iso=0.1, + adp_iso=0.1, ) model.atom_sites.create( label='Co', @@ -46,7 +46,7 @@ def test_single_fit_neutron_pd_cwl_lbco() -> None: fract_y=0.5, fract_z=0.5, wyckoff_letter='b', - b_iso=0.1, + adp_iso=0.1, ) model.atom_sites.create( label='O', @@ -55,7 +55,7 @@ def test_single_fit_neutron_pd_cwl_lbco() -> None: fract_y=0.5, fract_z=0.5, wyckoff_letter='c', - b_iso=0.1, + adp_iso=0.1, ) # Set experiment @@ -128,10 +128,10 @@ def test_single_fit_neutron_pd_cwl_lbco() -> None: # ------------ 3rd fitting ------------ # Select fitting parameters - model.atom_sites['La'].b_iso.free = True - model.atom_sites['Ba'].b_iso.free = True - model.atom_sites['Co'].b_iso.free = True - model.atom_sites['O'].b_iso.free = True + model.atom_sites['La'].adp_iso.free = True + model.atom_sites['Ba'].adp_iso.free = True + model.atom_sites['Co'].adp_iso.free = True + model.atom_sites['O'].adp_iso.free = True # Perform fit project.analysis.fit() @@ -163,7 +163,7 @@ def test_single_fit_neutron_pd_cwl_lbco_with_constraints() -> None: fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=1.0, + adp_iso=1.0, occupancy=0.5, ) atom_sites.create( @@ -173,7 +173,7 @@ def test_single_fit_neutron_pd_cwl_lbco_with_constraints() -> None: fract_y=0, fract_z=0, wyckoff_letter='a', - b_iso=1.0, + adp_iso=1.0, occupancy=0.5, ) atom_sites.create( @@ -183,7 +183,7 @@ def test_single_fit_neutron_pd_cwl_lbco_with_constraints() -> None: fract_y=0.5, fract_z=0.5, wyckoff_letter='b', - b_iso=1.0, + adp_iso=1.0, ) atom_sites.create( label='O', @@ -192,7 +192,7 @@ def test_single_fit_neutron_pd_cwl_lbco_with_constraints() -> None: fract_y=0.5, fract_z=0.5, wyckoff_letter='c', - b_iso=1.0, + adp_iso=1.0, ) # Set experiment @@ -241,16 +241,16 @@ def test_single_fit_neutron_pd_cwl_lbco_with_constraints() -> None: # Select fitting parameters atom_sites['La'].occupancy.free = True atom_sites['Ba'].occupancy.free = True - atom_sites['La'].b_iso.free = True - atom_sites['Ba'].b_iso.free = True - atom_sites['Co'].b_iso.free = True - atom_sites['O'].b_iso.free = True + atom_sites['La'].adp_iso.free = True + atom_sites['Ba'].adp_iso.free = True + atom_sites['Co'].adp_iso.free = True + atom_sites['O'].adp_iso.free = True # Compare parameter values before fit - assert_almost_equal(atom_sites['La'].b_iso.value, 1.0, decimal=2) - assert_almost_equal(atom_sites['Ba'].b_iso.value, 1.0, decimal=2) - assert_almost_equal(atom_sites['Co'].b_iso.value, 1.0, decimal=2) - assert_almost_equal(atom_sites['O'].b_iso.value, 1.0, decimal=2) + assert_almost_equal(atom_sites['La'].adp_iso.value, 1.0, decimal=2) + assert_almost_equal(atom_sites['Ba'].adp_iso.value, 1.0, decimal=2) + assert_almost_equal(atom_sites['Co'].adp_iso.value, 1.0, decimal=2) + assert_almost_equal(atom_sites['O'].adp_iso.value, 1.0, decimal=2) assert_almost_equal(atom_sites['La'].occupancy.value, 0.5, decimal=2) assert_almost_equal(atom_sites['Ba'].occupancy.value, 0.5, decimal=2) @@ -258,10 +258,10 @@ def test_single_fit_neutron_pd_cwl_lbco_with_constraints() -> None: project.analysis.fit() # Compare parameter values after fit - assert_almost_equal(atom_sites['La'].b_iso.value, desired=15.0945, decimal=2) - assert_almost_equal(atom_sites['Ba'].b_iso.value, desired=0.5226, decimal=2) - assert_almost_equal(atom_sites['Co'].b_iso.value, desired=0.2398, decimal=2) - assert_almost_equal(atom_sites['O'].b_iso.value, desired=1.4049, decimal=2) + assert_almost_equal(atom_sites['La'].adp_iso.value, desired=15.0945, decimal=2) + assert_almost_equal(atom_sites['Ba'].adp_iso.value, desired=0.5226, decimal=2) + assert_almost_equal(atom_sites['Co'].adp_iso.value, desired=0.2398, decimal=2) + assert_almost_equal(atom_sites['O'].adp_iso.value, desired=1.4049, decimal=2) assert_almost_equal(atom_sites['La'].occupancy.value, desired=0.011, decimal=2) assert_almost_equal(atom_sites['Ba'].occupancy.value, desired=1.3206, decimal=2) @@ -277,11 +277,11 @@ def test_single_fit_neutron_pd_cwl_lbco_with_constraints() -> None: # Set aliases for parameters project.analysis.aliases.create( label='biso_La', - param=atom_sites['La'].b_iso, + param=atom_sites['La'].adp_iso, ) project.analysis.aliases.create( label='biso_Ba', - param=atom_sites['Ba'].b_iso, + param=atom_sites['Ba'].adp_iso, ) project.analysis.aliases.create( label='occ_La', @@ -300,10 +300,10 @@ def test_single_fit_neutron_pd_cwl_lbco_with_constraints() -> None: project.analysis.fit() # Compare parameter values after fit - assert_almost_equal(atom_sites['La'].b_iso.value, desired=0.5443, decimal=2) - assert_almost_equal(atom_sites['Ba'].b_iso.value, desired=0.5443, decimal=2) - assert_almost_equal(atom_sites['Co'].b_iso.value, desired=0.2335, decimal=2) - assert_almost_equal(atom_sites['O'].b_iso.value, desired=1.4056, decimal=2) + assert_almost_equal(atom_sites['La'].adp_iso.value, desired=0.5443, decimal=2) + assert_almost_equal(atom_sites['Ba'].adp_iso.value, desired=0.5443, decimal=2) + assert_almost_equal(atom_sites['Co'].adp_iso.value, desired=0.2335, decimal=2) + assert_almost_equal(atom_sites['O'].adp_iso.value, desired=1.4056, decimal=2) assert_almost_equal(atom_sites['La'].occupancy.value, desired=0.5274, decimal=2) assert_almost_equal(atom_sites['Ba'].occupancy.value, desired=0.4726, decimal=2) @@ -329,7 +329,7 @@ def test_fit_neutron_pd_cwl_hs() -> None: fract_y=0, fract_z=0.5, wyckoff_letter='b', - b_iso=0.1, + adp_iso=0.1, ) model.atom_sites.create( label='Cu', @@ -338,7 +338,7 @@ def test_fit_neutron_pd_cwl_hs() -> None: fract_y=0, fract_z=0, wyckoff_letter='e', - b_iso=1.2, + adp_iso=1.2, ) model.atom_sites.create( label='O', @@ -347,7 +347,7 @@ def test_fit_neutron_pd_cwl_hs() -> None: fract_y=-0.206, fract_z=0.061, wyckoff_letter='h', - b_iso=0.7, + adp_iso=0.7, ) model.atom_sites.create( label='Cl', @@ -356,7 +356,7 @@ def test_fit_neutron_pd_cwl_hs() -> None: fract_y=0, fract_z=0.197, wyckoff_letter='c', - b_iso=1.1, + adp_iso=1.1, ) model.atom_sites.create( label='H', @@ -365,7 +365,7 @@ def test_fit_neutron_pd_cwl_hs() -> None: fract_y=-0.132, fract_z=0.09, wyckoff_letter='h', - b_iso=2.3, + adp_iso=2.3, ) # Set experiment @@ -462,11 +462,11 @@ def test_fit_neutron_pd_cwl_hs() -> None: # ------------ 3rd fitting ------------ # Select fitting parameters - model.atom_sites['Zn'].b_iso.free = True - model.atom_sites['Cu'].b_iso.free = True - model.atom_sites['O'].b_iso.free = True - model.atom_sites['Cl'].b_iso.free = True - model.atom_sites['H'].b_iso.free = True + model.atom_sites['Zn'].adp_iso.free = True + model.atom_sites['Cu'].adp_iso.free = True + model.atom_sites['O'].adp_iso.free = True + model.atom_sites['Cl'].adp_iso.free = True + model.atom_sites['H'].adp_iso.free = True # Perform fit project.analysis.fit() @@ -490,11 +490,11 @@ def test_single_fit_neutron_pd_cwl_lbco_with_constraints_from_project(tmp_path) # Set constraints project.analysis.aliases.create( label='biso_La', - param=project.structures['lbco'].atom_sites['La'].b_iso, + param=project.structures['lbco'].atom_sites['La'].adp_iso, ) project.analysis.aliases.create( label='biso_Ba', - param=project.structures['lbco'].atom_sites['Ba'].b_iso, + param=project.structures['lbco'].atom_sites['Ba'].adp_iso, ) project.analysis.aliases.create( diff --git a/tests/integration/fitting/test_powder-diffraction_joint-fit.py b/tests/integration/fitting/test_powder-diffraction_joint-fit.py index fb94a8ff0..9bf55f79e 100644 --- a/tests/integration/fitting/test_powder-diffraction_joint-fit.py +++ b/tests/integration/fitting/test_powder-diffraction_joint-fit.py @@ -29,7 +29,7 @@ def test_joint_fit_split_dataset_neutron_pd_cwl_pbso4() -> None: fract_y=0.25, fract_z=0.167, wyckoff_letter='c', - b_iso=1.37, + adp_iso=1.37, ) model.atom_sites.create( label='S', @@ -38,7 +38,7 @@ def test_joint_fit_split_dataset_neutron_pd_cwl_pbso4() -> None: fract_y=0.25, fract_z=0.684, wyckoff_letter='c', - b_iso=0.3777, + adp_iso=0.3777, ) model.atom_sites.create( label='O1', @@ -47,7 +47,7 @@ def test_joint_fit_split_dataset_neutron_pd_cwl_pbso4() -> None: fract_y=0.25, fract_z=0.5954, wyckoff_letter='c', - b_iso=1.9764, + adp_iso=1.9764, ) model.atom_sites.create( label='O2', @@ -56,7 +56,7 @@ def test_joint_fit_split_dataset_neutron_pd_cwl_pbso4() -> None: fract_y=0.25, fract_z=0.5432, wyckoff_letter='c', - b_iso=1.4456, + adp_iso=1.4456, ) model.atom_sites.create( label='O3', @@ -65,7 +65,7 @@ def test_joint_fit_split_dataset_neutron_pd_cwl_pbso4() -> None: fract_y=0.0272, fract_z=0.8086, wyckoff_letter='d', - b_iso=1.2822, + adp_iso=1.2822, ) # Set experiments @@ -156,7 +156,7 @@ def test_joint_fit_neutron_xray_pd_cwl_pbso4() -> None: fract_y=0.25, fract_z=0.167, wyckoff_letter='c', - b_iso=1.37, + adp_iso=1.37, ) model.atom_sites.create( label='S', @@ -165,7 +165,7 @@ def test_joint_fit_neutron_xray_pd_cwl_pbso4() -> None: fract_y=0.25, fract_z=0.684, wyckoff_letter='c', - b_iso=0.3777, + adp_iso=0.3777, ) model.atom_sites.create( label='O1', @@ -174,7 +174,7 @@ def test_joint_fit_neutron_xray_pd_cwl_pbso4() -> None: fract_y=0.25, fract_z=0.5954, wyckoff_letter='c', - b_iso=1.9764, + adp_iso=1.9764, ) model.atom_sites.create( label='O2', @@ -183,7 +183,7 @@ def test_joint_fit_neutron_xray_pd_cwl_pbso4() -> None: fract_y=0.25, fract_z=0.5432, wyckoff_letter='c', - b_iso=1.4456, + adp_iso=1.4456, ) model.atom_sites.create( label='O3', @@ -192,7 +192,7 @@ def test_joint_fit_neutron_xray_pd_cwl_pbso4() -> None: fract_y=0.0272, fract_z=0.8086, wyckoff_letter='d', - b_iso=1.2822, + adp_iso=1.2822, ) # Set experiments diff --git a/tests/integration/fitting/test_powder-diffraction_time-of-flight.py b/tests/integration/fitting/test_powder-diffraction_time-of-flight.py index c867e3fd8..c5dac22f0 100644 --- a/tests/integration/fitting/test_powder-diffraction_time-of-flight.py +++ b/tests/integration/fitting/test_powder-diffraction_time-of-flight.py @@ -26,7 +26,7 @@ def test_single_fit_neutron_pd_tof_si() -> None: fract_y=0.125, fract_z=0.125, wyckoff_letter='a', - b_iso=0.529, + adp_iso=0.529, ) # Set experiment @@ -62,7 +62,7 @@ def test_single_fit_neutron_pd_tof_si() -> None: # Select fitting parameters model.cell.length_a.free = True - model.atom_sites['Si'].b_iso.free = True + model.atom_sites['Si'].adp_iso.free = True expt.linked_phases['si'].scale.free = True expt.instrument.calib_d_to_tof_offset.free = True for point in expt.background: @@ -92,7 +92,7 @@ def test_single_fit_neutron_pd_tof_ncaf() -> None: fract_y=0.0, fract_z=0.25, wyckoff_letter='b', - b_iso=0.9, + adp_iso=0.9, ) model.atom_sites.create( label='Al', @@ -101,7 +101,7 @@ def test_single_fit_neutron_pd_tof_ncaf() -> None: fract_y=0.25171, fract_z=0.25171, wyckoff_letter='a', - b_iso=0.66, + adp_iso=0.66, ) model.atom_sites.create( label='Na', @@ -110,7 +110,7 @@ def test_single_fit_neutron_pd_tof_ncaf() -> None: fract_y=0.08481, fract_z=0.08481, wyckoff_letter='a', - b_iso=1.9, + adp_iso=1.9, ) model.atom_sites.create( label='F1', @@ -119,7 +119,7 @@ def test_single_fit_neutron_pd_tof_ncaf() -> None: fract_y=0.3053, fract_z=0.1195, wyckoff_letter='c', - b_iso=0.9, + adp_iso=0.9, ) model.atom_sites.create( label='F2', @@ -128,7 +128,7 @@ def test_single_fit_neutron_pd_tof_ncaf() -> None: fract_y=0.3634, fract_z=0.1867, wyckoff_letter='c', - b_iso=1.28, + adp_iso=1.28, ) model.atom_sites.create( label='F3', @@ -137,7 +137,7 @@ def test_single_fit_neutron_pd_tof_ncaf() -> None: fract_y=0.4612, fract_z=0.4612, wyckoff_letter='a', - b_iso=0.79, + adp_iso=0.79, ) # Set experiment diff --git a/tests/integration/fitting/test_project_load.py b/tests/integration/fitting/test_project_load.py index 53d8643f3..a7610956a 100644 --- a/tests/integration/fitting/test_project_load.py +++ b/tests/integration/fitting/test_project_load.py @@ -41,7 +41,7 @@ def _create_lbco_project() -> Project: fract_z=0, wyckoff_letter='a', occupancy=0.5, - b_iso=0.5, + adp_iso=0.5, ) model.atom_sites.create( label='Ba', @@ -51,7 +51,7 @@ def _create_lbco_project() -> Project: fract_z=0, wyckoff_letter='a', occupancy=0.5, - b_iso=0.5, + adp_iso=0.5, ) model.atom_sites.create( label='Co', @@ -60,7 +60,7 @@ def _create_lbco_project() -> Project: fract_y=0.5, fract_z=0.5, wyckoff_letter='b', - b_iso=0.5, + adp_iso=0.5, ) model.atom_sites.create( label='O', @@ -69,7 +69,7 @@ def _create_lbco_project() -> Project: fract_y=0.5, fract_z=0.5, wyckoff_letter='c', - b_iso=0.5, + adp_iso=0.5, ) # Experiment @@ -104,11 +104,11 @@ def _create_lbco_project() -> Project: # Aliases and constraints project.analysis.aliases.create( label='biso_La', - param=model.atom_sites['La'].b_iso, + param=model.atom_sites['La'].adp_iso, ) project.analysis.aliases.create( label='biso_Ba', - param=model.atom_sites['Ba'].b_iso, + param=model.atom_sites['Ba'].adp_iso, ) project.analysis.constraints.create(expression='biso_Ba = biso_La') diff --git a/tests/integration/fitting/test_sequential.py b/tests/integration/fitting/test_sequential.py index 4fb80209b..2583b9e10 100644 --- a/tests/integration/fitting/test_sequential.py +++ b/tests/integration/fitting/test_sequential.py @@ -39,7 +39,7 @@ def _create_sequential_project(tmp_path: Path) -> tuple[Project, str]: fract_z=0, wyckoff_letter='a', occupancy=0.5, - b_iso=0.5, + adp_iso=0.5, ) model.atom_sites.create( label='Ba', @@ -49,7 +49,7 @@ def _create_sequential_project(tmp_path: Path) -> tuple[Project, str]: fract_z=0, wyckoff_letter='a', occupancy=0.5, - b_iso=0.5, + adp_iso=0.5, ) model.atom_sites.create( label='Co', @@ -58,7 +58,7 @@ def _create_sequential_project(tmp_path: Path) -> tuple[Project, str]: fract_y=0.5, fract_z=0.5, wyckoff_letter='b', - b_iso=0.5, + adp_iso=0.5, ) model.atom_sites.create( label='O', @@ -67,7 +67,7 @@ def _create_sequential_project(tmp_path: Path) -> tuple[Project, str]: fract_y=0.5, fract_z=0.5, wyckoff_letter='c', - b_iso=0.5, + adp_iso=0.5, ) # Experiment (template) diff --git a/tests/integration/fitting/test_switch-calculator.py b/tests/integration/fitting/test_switch-calculator.py index a195ac183..bd9a31956 100644 --- a/tests/integration/fitting/test_switch-calculator.py +++ b/tests/integration/fitting/test_switch-calculator.py @@ -21,11 +21,11 @@ def test_neutron_pd_cwl_lbco_crysfml(tmp_path) -> None: # Set constraints project.analysis.aliases.create( label='biso_La', - param=project.structures['lbco'].atom_sites['La'].b_iso, + param=project.structures['lbco'].atom_sites['La'].adp_iso, ) project.analysis.aliases.create( label='biso_Ba', - param=project.structures['lbco'].atom_sites['Ba'].b_iso, + param=project.structures['lbco'].atom_sites['Ba'].adp_iso, ) project.analysis.aliases.create( diff --git a/tests/integration/scipp-analysis/dream/test_analyze_reduced_data.py b/tests/integration/scipp-analysis/dream/test_analyze_reduced_data.py index 31496c4b2..f44695c95 100644 --- a/tests/integration/scipp-analysis/dream/test_analyze_reduced_data.py +++ b/tests/integration/scipp-analysis/dream/test_analyze_reduced_data.py @@ -84,7 +84,7 @@ def project_with_data( fract_y=0.125, fract_z=0.125, wyckoff_letter='c', - b_iso=1.1, + adp_iso=1.1, ) # Step 3: Add experiment from modified CIF file @@ -144,7 +144,7 @@ def fitted_project( # Step 5: Select parameters to be fitted # Set free parameters for structure - structure.atom_sites['C'].b_iso.free = True + structure.atom_sites['C'].adp_iso.free = True # Set free parameters for experiment experiment.linked_phases['diamond'].scale.free = True diff --git a/tests/unit/easydiffraction/analysis/calculators/test_cryspy.py b/tests/unit/easydiffraction/analysis/calculators/test_cryspy.py index 8593bfe0e..407577c19 100644 --- a/tests/unit/easydiffraction/analysis/calculators/test_cryspy.py +++ b/tests/unit/easydiffraction/analysis/calculators/test_cryspy.py @@ -18,6 +18,8 @@ def test_cryspy_calculator_engine_flag_and_converters(): # Converters should just delegate/format without external deps class DummySample: + atom_sites = [] + @property def as_cif(self): return 'data_x' diff --git a/tests/unit/easydiffraction/analysis/categories/test_aliases.py b/tests/unit/easydiffraction/analysis/categories/test_aliases.py index 5efd265cf..81a936e53 100644 --- a/tests/unit/easydiffraction/analysis/categories/test_aliases.py +++ b/tests/unit/easydiffraction/analysis/categories/test_aliases.py @@ -10,9 +10,9 @@ def test_alias_creation_and_collection(): p1 = Parameter( - name='b_iso', + name='adp_iso', value_spec=AttributeSpec(default=0.5), - cif_handler=CifHandler(names=['_atom_site.b_iso']), + cif_handler=CifHandler(names=['_atom_site.adp_iso']), ) a = Alias() a.label = 'x' diff --git a/tests/unit/easydiffraction/analysis/test_fitting.py b/tests/unit/easydiffraction/analysis/test_fitting.py index f63788c07..0f7ef88b1 100644 --- a/tests/unit/easydiffraction/analysis/test_fitting.py +++ b/tests/unit/easydiffraction/analysis/test_fitting.py @@ -13,9 +13,18 @@ def test_module_import(): def test_fitter_early_exit_when_no_params(capsys, monkeypatch): from easydiffraction.analysis.fitting import Fitter + class DummyStructure: + _need_categories_update = False + + def _update_categories(self): + pass + class DummyStructures: free_parameters = [] + def __iter__(self): + return iter([DummyStructure()]) + class DummyExperiment: parameters = [] @@ -46,9 +55,18 @@ class DummyParam: value = 1.0 _fit_start_value = None + class DummyStructure: + _need_categories_update = False + + def _update_categories(self): + pass + class DummyStructures: free_parameters = [DummyParam()] + def __iter__(self): + return iter([DummyStructure()]) + class DummyExperiment: parameters = [] diff --git a/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_site_aniso.py b/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_site_aniso.py new file mode 100644 index 000000000..831158e7e --- /dev/null +++ b/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_site_aniso.py @@ -0,0 +1,537 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Tests for atom_site_aniso category (default and factory).""" + +import math + + +# ------------------------------------------------------------------ +# Module import +# ------------------------------------------------------------------ + + +def test_module_import(): + import easydiffraction.datablocks.structure.categories.atom_site_aniso as MUT + + expected_module_name = 'easydiffraction.datablocks.structure.categories.atom_site_aniso' + actual_module_name = MUT.__name__ + assert expected_module_name == actual_module_name + + +# ------------------------------------------------------------------ +# Factory +# ------------------------------------------------------------------ + + +class TestAtomSiteAnisoFactory: + def test_supported_tags(self): + from easydiffraction.datablocks.structure.categories.atom_site_aniso.factory import ( + AtomSiteAnisoFactory, + ) + + tags = AtomSiteAnisoFactory.supported_tags() + assert 'default' in tags + + def test_default_tag(self): + from easydiffraction.datablocks.structure.categories.atom_site_aniso.factory import ( + AtomSiteAnisoFactory, + ) + + assert AtomSiteAnisoFactory.default_tag() == 'default' + + def test_create(self): + from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import ( + AtomSiteAnisoCollection, + ) + from easydiffraction.datablocks.structure.categories.atom_site_aniso.factory import ( + AtomSiteAnisoFactory, + ) + + obj = AtomSiteAnisoFactory.create('default') + assert isinstance(obj, AtomSiteAnisoCollection) + + +# ------------------------------------------------------------------ +# AtomSiteAniso item +# ------------------------------------------------------------------ + + +class TestAtomSiteAniso: + def test_instantiation(self): + from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import ( + AtomSiteAniso, + ) + + entry = AtomSiteAniso() + assert entry is not None + + def test_identity_category_code(self): + from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import ( + AtomSiteAniso, + ) + + entry = AtomSiteAniso() + assert entry._identity.category_code == 'atom_site_aniso' + + def test_defaults(self): + from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import ( + AtomSiteAniso, + ) + + entry = AtomSiteAniso() + assert entry.label.value == '' + assert entry.adp_11.value == 0.0 + assert entry.adp_22.value == 0.0 + assert entry.adp_33.value == 0.0 + assert entry.adp_12.value == 0.0 + assert entry.adp_13.value == 0.0 + assert entry.adp_23.value == 0.0 + + def test_label_setter(self): + from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import ( + AtomSiteAniso, + ) + + entry = AtomSiteAniso() + entry.label = 'Si' + assert entry.label.value == 'Si' + + def test_tensor_setters(self): + from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import ( + AtomSiteAniso, + ) + + entry = AtomSiteAniso() + entry.adp_11 = 0.01 + entry.adp_22 = 0.02 + entry.adp_33 = 0.03 + entry.adp_12 = 0.04 + entry.adp_13 = 0.05 + entry.adp_23 = 0.06 + assert entry.adp_11.value == 0.01 + assert entry.adp_22.value == 0.02 + assert entry.adp_33.value == 0.03 + assert entry.adp_12.value == 0.04 + assert entry.adp_13.value == 0.05 + assert entry.adp_23.value == 0.06 + + def test_dual_cif_names(self): + from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import ( + AtomSiteAniso, + ) + + entry = AtomSiteAniso() + # Default order: B first + assert entry._adp_11._cif_handler.names[0] == '_atom_site_aniso.B_11' + assert entry._adp_11._cif_handler.names[1] == '_atom_site_aniso.U_11' + + def test_identity_entry_name_follows_label(self): + from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import ( + AtomSiteAniso, + ) + + entry = AtomSiteAniso() + entry.label = 'Fe1' + assert entry._identity.category_entry_name == 'Fe1' + + +# ------------------------------------------------------------------ +# AtomSiteAnisoCollection +# ------------------------------------------------------------------ + + +class TestAtomSiteAnisoCollection: + def test_type_info(self): + from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import ( + AtomSiteAnisoCollection, + ) + + assert AtomSiteAnisoCollection.type_info.tag == 'default' + + def test_instantiation(self): + from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import ( + AtomSiteAnisoCollection, + ) + + coll = AtomSiteAnisoCollection() + assert coll is not None + assert len(coll) == 0 + + def test_skip_cif_serialization_no_parent(self): + from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import ( + AtomSiteAnisoCollection, + ) + + coll = AtomSiteAnisoCollection() + # No parent → should skip + assert coll._skip_cif_serialization() is True + + def test_skip_cif_serialization_isotropic(self): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create(label='Si', type_symbol='Si', adp_type='Biso', adp_iso=0.5) + structure._sync_atom_site_aniso() + assert structure.atom_site_aniso._skip_cif_serialization() is True + + def test_skip_cif_serialization_anisotropic(self): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create(label='Si', type_symbol='Si', adp_type='Biso', adp_iso=0.5) + structure._sync_atom_site_aniso() + structure.atom_sites['Si'].adp_type = 'Bani' + assert structure.atom_site_aniso._skip_cif_serialization() is False + + +# ------------------------------------------------------------------ +# Structure ↔ aniso sync +# ------------------------------------------------------------------ + + +class TestStructureAnisoSync: + def test_sync_adds_missing_entries(self): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create(label='Si', type_symbol='Si') + structure._sync_atom_site_aniso() + assert 'Si' in structure.atom_site_aniso + assert structure.atom_site_aniso['Si'].label.value == 'Si' + + def test_sync_removes_stale_entries(self): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create(label='Si', type_symbol='Si') + structure.atom_sites.create(label='O', type_symbol='O') + structure._sync_atom_site_aniso() + assert len(structure.atom_site_aniso) == 2 + + structure.atom_sites.remove('O') + structure._sync_atom_site_aniso() + assert len(structure.atom_site_aniso) == 1 + assert 'Si' in structure.atom_site_aniso + + def test_sync_multiple_atoms(self): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create(label='La', type_symbol='La') + structure.atom_sites.create(label='Ba', type_symbol='Ba') + structure.atom_sites.create(label='Co', type_symbol='Co') + structure._sync_atom_site_aniso() + assert len(structure.atom_site_aniso) == 3 + for lbl in ('La', 'Ba', 'Co'): + assert lbl in structure.atom_site_aniso + + +# ------------------------------------------------------------------ +# ADP type conversion (iso ↔ ani) +# ------------------------------------------------------------------ + + +class TestAdpTypeConversion: + def _make_structure_with_atom(self, adp_type='Biso', adp_iso=0.5): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create( + label='Si', + type_symbol='Si', + adp_type=adp_type, + adp_iso=adp_iso, + ) + structure._sync_atom_site_aniso() + return structure + + def test_biso_to_bani_seeds_diagonal(self): + structure = self._make_structure_with_atom(adp_type='Biso', adp_iso=0.5) + structure.atom_sites['Si'].adp_type = 'Bani' + aniso = structure.atom_site_aniso['Si'] + assert aniso.adp_11.value == 0.5 + assert aniso.adp_22.value == 0.5 + assert aniso.adp_33.value == 0.5 + assert aniso.adp_12.value == 0.0 + assert aniso.adp_13.value == 0.0 + assert aniso.adp_23.value == 0.0 + + def test_biso_to_uani_seeds_converted_diagonal(self): + factor = 8.0 * math.pi**2 + structure = self._make_structure_with_atom(adp_type='Biso', adp_iso=0.5) + structure.atom_sites['Si'].adp_type = 'Uani' + aniso = structure.atom_site_aniso['Si'] + expected_u = 0.5 / factor + assert math.isclose(aniso.adp_11.value, expected_u, rel_tol=1e-10) + assert math.isclose(aniso.adp_22.value, expected_u, rel_tol=1e-10) + assert math.isclose(aniso.adp_33.value, expected_u, rel_tol=1e-10) + + def test_bani_to_biso_collapses_diagonal(self): + structure = self._make_structure_with_atom(adp_type='Biso', adp_iso=0.5) + structure.atom_sites['Si'].adp_type = 'Bani' + # Modify diagonal + aniso = structure.atom_site_aniso['Si'] + aniso.adp_11 = 0.3 + aniso.adp_22 = 0.6 + aniso.adp_33 = 0.9 + structure.atom_sites['Si'].adp_type = 'Biso' + expected = (0.3 + 0.6 + 0.9) / 3.0 + assert math.isclose(structure.atom_sites['Si'].adp_iso.value, expected, rel_tol=1e-10) + + def test_uiso_to_uani_seeds_diagonal(self): + structure = self._make_structure_with_atom(adp_type='Uiso', adp_iso=0.05) + structure.atom_sites['Si'].adp_type = 'Uani' + aniso = structure.atom_site_aniso['Si'] + assert math.isclose(aniso.adp_11.value, 0.05, rel_tol=1e-10) + + def test_bani_to_uani_converts_values(self): + factor = 8.0 * math.pi**2 + structure = self._make_structure_with_atom(adp_type='Biso', adp_iso=0.5) + structure.atom_sites['Si'].adp_type = 'Bani' + # Now ani values are B=0.5 + structure.atom_sites['Si'].adp_type = 'Uani' + aniso = structure.atom_site_aniso['Si'] + expected_u = 0.5 / factor + assert math.isclose(aniso.adp_11.value, expected_u, rel_tol=1e-10) + + def test_round_trip_biso_uani_biso(self): + structure = self._make_structure_with_atom(adp_type='Biso', adp_iso=0.5) + structure.atom_sites['Si'].adp_type = 'Uani' + structure.atom_sites['Si'].adp_type = 'Biso' + assert math.isclose(structure.atom_sites['Si'].adp_iso.value, 0.5, rel_tol=1e-10) + + +# ------------------------------------------------------------------ +# CIF name reordering +# ------------------------------------------------------------------ + + +class TestCifNameReordering: + def test_biso_cif_names_default_order(self): + from easydiffraction.datablocks.structure.categories.atom_sites.default import AtomSite + + site = AtomSite() + assert site._adp_iso._cif_handler.names[0] == '_atom_site.B_iso_or_equiv' + + def test_uiso_reorders_iso_cif_names(self): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create(label='Si', type_symbol='Si', adp_type='Biso', adp_iso=0.5) + structure._sync_atom_site_aniso() + structure.atom_sites['Si'].adp_type = 'Uiso' + assert ( + structure.atom_sites['Si']._adp_iso._cif_handler.names[0] + == '_atom_site.U_iso_or_equiv' + ) + + def test_bani_reorders_aniso_cif_names(self): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create(label='Si', type_symbol='Si', adp_type='Biso', adp_iso=0.5) + structure._sync_atom_site_aniso() + structure.atom_sites['Si'].adp_type = 'Bani' + aniso = structure.atom_site_aniso['Si'] + assert aniso._adp_11._cif_handler.names[0] == '_atom_site_aniso.B_11' + + def test_uani_reorders_aniso_cif_names(self): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create(label='Si', type_symbol='Si', adp_type='Biso', adp_iso=0.5) + structure._sync_atom_site_aniso() + structure.atom_sites['Si'].adp_type = 'Uani' + aniso = structure.atom_site_aniso['Si'] + assert aniso._adp_11._cif_handler.names[0] == '_atom_site_aniso.U_11' + + +# ------------------------------------------------------------------ +# _iso_labels helper +# ------------------------------------------------------------------ + + +class TestIsoLabels: + def test_all_iso_returns_all_labels(self): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create(label='A', type_symbol='Si', adp_type='Biso', adp_iso=0.5) + structure.atom_sites.create(label='B', type_symbol='O', adp_type='Uiso', adp_iso=0.01) + structure._sync_atom_site_aniso() + labels = structure.atom_site_aniso._iso_labels() + assert labels == {'A', 'B'} + + def test_all_aniso_returns_empty(self): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create(label='A', type_symbol='Si', adp_type='Biso', adp_iso=0.5) + structure._sync_atom_site_aniso() + structure.atom_sites['A'].adp_type = 'Bani' + labels = structure.atom_site_aniso._iso_labels() + assert labels == set() + + def test_mixed_returns_only_iso(self): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create(label='A', type_symbol='Si', adp_type='Biso', adp_iso=0.5) + structure.atom_sites.create(label='B', type_symbol='O', adp_type='Biso', adp_iso=0.3) + structure._sync_atom_site_aniso() + structure.atom_sites['A'].adp_type = 'Bani' + labels = structure.atom_site_aniso._iso_labels() + assert labels == {'B'} + + def test_no_parent_returns_empty(self): + from easydiffraction.datablocks.structure.categories.atom_site_aniso.default import ( + AtomSiteAnisoCollection, + ) + + coll = AtomSiteAnisoCollection() + assert coll._iso_labels() == set() + + +# ------------------------------------------------------------------ +# _format_cif_row (? for iso atoms) +# ------------------------------------------------------------------ + + +class TestFormatCifRow: + def _make_structure(self): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create(label='A', type_symbol='Si', adp_type='Biso', adp_iso=0.5) + structure.atom_sites.create(label='B', type_symbol='O', adp_type='Biso', adp_iso=0.3) + structure._sync_atom_site_aniso() + return structure + + def test_iso_atom_gets_question_marks(self): + structure = self._make_structure() + structure.atom_sites['A'].adp_type = 'Bani' + aniso_coll = structure.atom_site_aniso + row = aniso_coll._format_cif_row(aniso_coll['B']) + assert row is not None + assert len(row) == 7 + assert row[0] == 'B' + assert all(v == '?' for v in row[1:]) + + def test_aniso_atom_returns_none(self): + structure = self._make_structure() + structure.atom_sites['A'].adp_type = 'Bani' + aniso_coll = structure.atom_site_aniso + row = aniso_coll._format_cif_row(aniso_coll['A']) + assert row is None + + def test_cif_output_has_question_marks_for_iso(self): + structure = self._make_structure() + structure.atom_sites['A'].adp_type = 'Bani' + cif = structure.atom_site_aniso.as_cif + lines = cif.strip().split('\n') + data_lines = [l for l in lines if not l.startswith(('loop_', '_atom_site_aniso'))] + # B is iso → should have ? + b_line = next(l for l in data_lines if l.strip().startswith('B')) + assert '?' in b_line + # A is aniso → should not have ? + a_line = next(l for l in data_lines if l.strip().startswith('A')) + assert '?' not in a_line + + def test_all_aniso_no_question_marks(self): + structure = self._make_structure() + structure.atom_sites['A'].adp_type = 'Bani' + structure.atom_sites['B'].adp_type = 'Bani' + cif = structure.atom_site_aniso.as_cif + assert '?' not in cif + + def test_all_iso_cif_suppressed(self): + structure = self._make_structure() + cif = structure.atom_site_aniso.as_cif + assert cif == '' + + +# ------------------------------------------------------------------ +# Additional ADP type switching paths +# ------------------------------------------------------------------ + + +class TestAdpTypeSwitchingPaths: + def _make_structure(self, adp_type='Biso', adp_iso=0.5): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create( + label='Si', + type_symbol='Si', + adp_type=adp_type, + adp_iso=adp_iso, + ) + structure._sync_atom_site_aniso() + return structure + + def test_uani_to_uiso_collapses(self): + structure = self._make_structure(adp_type='Uiso', adp_iso=0.05) + structure.atom_sites['Si'].adp_type = 'Uani' + aniso = structure.atom_site_aniso['Si'] + aniso.adp_11 = 0.01 + aniso.adp_22 = 0.02 + aniso.adp_33 = 0.03 + structure.atom_sites['Si'].adp_type = 'Uiso' + expected = (0.01 + 0.02 + 0.03) / 3.0 + assert math.isclose(structure.atom_sites['Si'].adp_iso.value, expected, rel_tol=1e-10) + + def test_uani_to_biso_converts_and_collapses(self): + factor = 8.0 * math.pi**2 + structure = self._make_structure(adp_type='Uiso', adp_iso=0.05) + structure.atom_sites['Si'].adp_type = 'Uani' + aniso = structure.atom_site_aniso['Si'] + aniso.adp_11 = 0.01 + aniso.adp_22 = 0.02 + aniso.adp_33 = 0.03 + structure.atom_sites['Si'].adp_type = 'Biso' + expected_b = (0.01 + 0.02 + 0.03) / 3.0 * factor + assert math.isclose(structure.atom_sites['Si'].adp_iso.value, expected_b, rel_tol=1e-10) + + def test_uani_to_bani_converts_values(self): + factor = 8.0 * math.pi**2 + structure = self._make_structure(adp_type='Uiso', adp_iso=0.05) + structure.atom_sites['Si'].adp_type = 'Uani' + structure.atom_sites['Si'].adp_type = 'Bani' + aniso = structure.atom_site_aniso['Si'] + expected_b = 0.05 * factor + assert math.isclose(aniso.adp_11.value, expected_b, rel_tol=1e-10) + + def test_biso_to_uiso_converts(self): + factor = 8.0 * math.pi**2 + structure = self._make_structure(adp_type='Biso', adp_iso=0.5) + structure.atom_sites['Si'].adp_type = 'Uiso' + expected_u = 0.5 / factor + assert math.isclose(structure.atom_sites['Si'].adp_iso.value, expected_u, rel_tol=1e-10) + + def test_uiso_to_biso_converts(self): + factor = 8.0 * math.pi**2 + u_val = 0.005 + structure = self._make_structure(adp_type='Uiso', adp_iso=u_val) + structure.atom_sites['Si'].adp_type = 'Biso' + expected_b = u_val * factor + assert math.isclose(structure.atom_sites['Si'].adp_iso.value, expected_b, rel_tol=1e-10) + + def test_round_trip_uiso_bani_uiso(self): + structure = self._make_structure(adp_type='Uiso', adp_iso=0.05) + structure.atom_sites['Si'].adp_type = 'Bani' + structure.atom_sites['Si'].adp_type = 'Uiso' + assert math.isclose(structure.atom_sites['Si'].adp_iso.value, 0.05, rel_tol=1e-10) + + def test_round_trip_biso_bani_biso(self): + structure = self._make_structure(adp_type='Biso', adp_iso=0.5) + structure.atom_sites['Si'].adp_type = 'Bani' + structure.atom_sites['Si'].adp_type = 'Biso' + assert math.isclose(structure.atom_sites['Si'].adp_iso.value, 0.5, rel_tol=1e-10) + + def test_adp_iso_not_free_when_aniso(self): + structure = self._make_structure(adp_type='Biso', adp_iso=0.5) + structure.space_group.name_h_m = 'P m -3 m' + structure.atom_sites['Si'].adp_iso.free = True + structure.atom_sites['Si'].adp_type = 'Bani' + structure.atom_sites._update() + assert structure.atom_sites['Si'].adp_iso.free is False diff --git a/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py b/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py index e47cd084f..60a74a683 100644 --- a/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py +++ b/tests/unit/easydiffraction/datablocks/structure/categories/test_atom_sites.py @@ -60,7 +60,7 @@ def test_defaults(self): assert site.fract_y.value == 0.0 assert site.fract_z.value == 0.0 assert site.occupancy.value == 1.0 - assert site.b_iso.value == 0.0 + assert site.adp_iso.value == 0.0 assert site.adp_type.value == 'Biso' def test_label_setter(self): @@ -95,12 +95,12 @@ def test_occupancy_setter(self): site.occupancy = 0.5 assert site.occupancy.value == 0.5 - def test_b_iso_setter(self): + def test_adp_iso_setter(self): from easydiffraction.datablocks.structure.categories.atom_sites.default import AtomSite site = AtomSite() - site.b_iso = 1.5 - assert site.b_iso.value == 1.5 + site.adp_iso = 1.5 + assert site.adp_iso.value == 1.5 def test_type_symbol_allowed_values(self): from easydiffraction.datablocks.structure.categories.atom_sites.default import AtomSite @@ -130,3 +130,120 @@ def test_instantiation(self): sites = AtomSites() assert sites is not None + + +# ------------------------------------------------------------------ +# _sync_iso_from_aniso +# ------------------------------------------------------------------ + + +class TestSyncIsoFromAniso: + def _make_structure(self, adp_type='Biso', adp_iso=0.5): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create( + label='Si', + type_symbol='Si', + adp_type=adp_type, + adp_iso=adp_iso, + ) + structure._sync_atom_site_aniso() + return structure + + def test_sync_updates_iso_for_bani_atom(self): + import math + + structure = self._make_structure(adp_type='Biso', adp_iso=0.5) + structure.atom_sites['Si'].adp_type = 'Bani' + aniso = structure.atom_site_aniso['Si'] + aniso.adp_11 = 0.3 + aniso.adp_22 = 0.6 + aniso.adp_33 = 0.9 + structure.atom_sites._sync_iso_from_aniso() + expected = (0.3 + 0.6 + 0.9) / 3.0 + assert math.isclose(structure.atom_sites['Si'].adp_iso.value, expected, rel_tol=1e-10) + + def test_sync_updates_iso_for_uani_atom(self): + import math + + structure = self._make_structure(adp_type='Uiso', adp_iso=0.05) + structure.atom_sites['Si'].adp_type = 'Uani' + aniso = structure.atom_site_aniso['Si'] + aniso.adp_11 = 0.01 + aniso.adp_22 = 0.02 + aniso.adp_33 = 0.03 + structure.atom_sites._sync_iso_from_aniso() + expected = (0.01 + 0.02 + 0.03) / 3.0 + assert math.isclose(structure.atom_sites['Si'].adp_iso.value, expected, rel_tol=1e-10) + + def test_sync_skips_iso_atoms(self): + structure = self._make_structure(adp_type='Biso', adp_iso=0.5) + structure.atom_sites._sync_iso_from_aniso() + assert structure.atom_sites['Si'].adp_iso.value == 0.5 + + def test_update_calls_sync(self): + """Verify _update() triggers _sync_iso_from_aniso(). + + In P m -3 m Wyckoff a, symmetry forces U11=U22=U33. + We set all diags to 0.3 (satisfying the constraint), then + manually overwrite adp_iso to a wrong value. After _update(), + adp_iso must be resynced from the (still-equal) diags. + """ + structure = self._make_structure(adp_type='Biso', adp_iso=0.5) + structure.space_group.name_h_m = 'P m -3 m' + structure.atom_sites['Si'].adp_type = 'Bani' + aniso = structure.atom_site_aniso['Si'] + aniso.adp_11 = 0.3 + aniso.adp_22 = 0.3 + aniso.adp_33 = 0.3 + # Force adp_iso to a wrong value so we can confirm _update resyncs it + structure.atom_sites['Si'].adp_iso = 0.99 + structure.atom_sites._update() + assert structure.atom_sites['Si'].adp_iso.value == 0.3 + + +# ------------------------------------------------------------------ +# adp_iso_as_b property +# ------------------------------------------------------------------ + + +class TestAdpIsoAsB: + def _make_structure(self, adp_type='Biso', adp_iso=0.5): + from easydiffraction.datablocks.structure.item.base import Structure + + structure = Structure(name='test') + structure.atom_sites.create( + label='Si', + type_symbol='Si', + adp_type=adp_type, + adp_iso=adp_iso, + ) + structure._sync_atom_site_aniso() + return structure + + def test_biso_as_b_returns_same_value(self): + structure = self._make_structure(adp_type='Biso', adp_iso=0.5) + assert structure.atom_sites['Si'].adp_iso_as_b == 0.5 + + def test_uiso_as_b_converts(self): + import math + + u_val = 0.005 + structure = self._make_structure(adp_type='Uiso', adp_iso=u_val) + expected_b = u_val * 8.0 * math.pi**2 + assert math.isclose(structure.atom_sites['Si'].adp_iso_as_b, expected_b, rel_tol=1e-10) + + def test_bani_as_b_returns_iso_value(self): + structure = self._make_structure(adp_type='Biso', adp_iso=0.5) + structure.atom_sites['Si'].adp_type = 'Bani' + assert structure.atom_sites['Si'].adp_iso_as_b == 0.5 + + def test_uani_as_b_converts(self): + import math + + u_val = 0.005 + structure = self._make_structure(adp_type='Uiso', adp_iso=u_val) + structure.atom_sites['Si'].adp_type = 'Uani' + expected_b = u_val * 8.0 * math.pi**2 + assert math.isclose(structure.atom_sites['Si'].adp_iso_as_b, expected_b, rel_tol=1e-10) diff --git a/tests/unit/easydiffraction/io/cif/test_serialize.py b/tests/unit/easydiffraction/io/cif/test_serialize.py index e79d0d972..fc8f1fa2f 100644 --- a/tests/unit/easydiffraction/io/cif/test_serialize.py +++ b/tests/unit/easydiffraction/io/cif/test_serialize.py @@ -13,8 +13,8 @@ def test_module_import(): def test_format_value_quotes_whitespace_strings(): import easydiffraction.io.cif.serialize as MUT - assert MUT.format_value('a b') == ' "a b"' - assert MUT.format_value('ab') == ' ab' + assert MUT.format_value('a b') == '"a b"' + assert MUT.format_value('ab') == 'ab' def test_param_to_cif_minimal(): @@ -27,7 +27,7 @@ def __init__(self): self.value = 3 p = P() - assert MUT.param_to_cif(p) == '_x.y 3.00000000' + assert MUT.param_to_cif(p) == '_x.y 3.00000000' def test_category_collection_to_cif_empty_and_one_row(): diff --git a/tests/unit/easydiffraction/io/cif/test_serialize_more.py b/tests/unit/easydiffraction/io/cif/test_serialize_more.py index 8be11b204..f8e5dfd25 100644 --- a/tests/unit/easydiffraction/io/cif/test_serialize_more.py +++ b/tests/unit/easydiffraction/io/cif/test_serialize_more.py @@ -34,7 +34,7 @@ def __init__(self): out = MUT.datablock_item_to_cif(DB()) assert out.startswith('data_block1') - assert '_aa 42.0000' in out + assert '_aa 42.0000' in out assert 'loop_' in out assert '_aa' in out assert '7' in out diff --git a/tests/unit/easydiffraction/project/test_project_load.py b/tests/unit/easydiffraction/project/test_project_load.py index 807cb580b..bea053200 100644 --- a/tests/unit/easydiffraction/project/test_project_load.py +++ b/tests/unit/easydiffraction/project/test_project_load.py @@ -46,7 +46,7 @@ def test_round_trips_structure(self, tmp_path): fract_x=0.0, fract_y=0.0, fract_z=0.0, - b_iso=0.5, + adp_iso=0.5, ) original.save_as(str(tmp_path / 'proj')) @@ -58,7 +58,7 @@ def test_round_trips_structure(self, tmp_path): assert abs(ls.cell.length_a.value - 3.88) < 1e-6 assert len(ls.atom_sites) == 1 assert ls.atom_sites['Co'].type_symbol.value == 'Co' - assert abs(ls.atom_sites['Co'].b_iso.value - 0.5) < 1e-6 + assert abs(ls.atom_sites['Co'].adp_iso.value - 0.5) < 1e-6 class TestLoadAnalysis: diff --git a/tests/unit/easydiffraction/summary/test_summary_details.py b/tests/unit/easydiffraction/summary/test_summary_details.py index 2ada0f573..98dcc1027 100644 --- a/tests/unit/easydiffraction/summary/test_summary_details.py +++ b/tests/unit/easydiffraction/summary/test_summary_details.py @@ -32,7 +32,7 @@ def __init__(self, label, typ, x, y, z, occ, biso): self.fract_y = _Val(y) self.fract_z = _Val(z) self.occupancy = _Val(occ) - self.b_iso = _Val(biso) + self.adp_iso = _Val(biso) class _Model: