From f890e64d837a948bf931cabbcde87c0b0b7a802b Mon Sep 17 00:00:00 2001 From: Guillaume Bouvignies Date: Wed, 25 Sep 2024 15:57:37 +0200 Subject: [PATCH] Add the `cs_evolution_prior` flag to CEST and CPMG experiments (#281) The `cs_evolution_prior` flag allows for simulations where the CEST or CPMG block occurs after chemical shift evolution. When this flag is set to true in the `[experiment]` section of the `experiment.toml` file, the initial magnetization is populated only for the observed state (`observed_state`), while all other terms are set to zero. This modification ensures accurate boundary conditions by reflecting the magnetization distribution prior to the exchange block. --- chemex/configuration/experiment.py | 19 ++++- chemex/experiments/catalog/cest_13c.py | 10 ++- chemex/experiments/catalog/cest_15n.py | 10 ++- chemex/experiments/catalog/cest_15n_cw.py | 11 ++- chemex/experiments/catalog/cest_15n_tr.py | 28 ++++---- chemex/experiments/catalog/cest_1hn_ap.py | 13 ++-- chemex/experiments/catalog/coscest_13c.py | 12 ++-- .../experiments/catalog/coscest_1hn_ip_ap.py | 5 +- chemex/experiments/catalog/cpmg_13c_ip.py | 11 ++- chemex/experiments/catalog/cpmg_13co_ap.py | 13 ++-- chemex/experiments/catalog/cpmg_15n_ip.py | 11 ++- .../experiments/catalog/cpmg_15n_ip_0013.py | 14 ++-- chemex/experiments/catalog/cpmg_15n_tr.py | 9 ++- .../experiments/catalog/cpmg_15n_tr_0013.py | 28 ++++---- chemex/experiments/catalog/cpmg_1hn_ap.py | 14 ++-- .../experiments/catalog/cpmg_1hn_ap_0013.py | 15 ++-- .../experiments/catalog/cpmg_ch3_13c_h2c.py | 18 ++--- chemex/experiments/catalog/cpmg_ch3_1h_dq.py | 12 +++- chemex/experiments/catalog/cpmg_ch3_1h_sq.py | 11 ++- chemex/experiments/catalog/cpmg_ch3_1h_tq.py | 10 ++- .../catalog/cpmg_ch3_1h_tq_diff.py | 14 ++-- chemex/experiments/catalog/cpmg_ch3_mq.py | 9 ++- chemex/experiments/catalog/cpmg_chd2_1h_ap.py | 17 +++-- chemex/experiments/catalog/cpmg_hn_dq_zq.py | 14 ++-- chemex/experiments/catalog/dcest_13c.py | 20 +++--- chemex/experiments/catalog/dcest_15n.py | 22 +++--- chemex/experiments/catalog/relaxation_hznz.py | 13 ++-- chemex/experiments/catalog/relaxation_nz.py | 13 ++-- chemex/nmr/liouvillian.py | 72 ++++++++++++------- .../Parameters/parameters.toml | 2 +- 30 files changed, 298 insertions(+), 172 deletions(-) diff --git a/chemex/configuration/experiment.py b/chemex/configuration/experiment.py index a1d41e90..7bcc870e 100644 --- a/chemex/configuration/experiment.py +++ b/chemex/configuration/experiment.py @@ -1,6 +1,7 @@ from __future__ import annotations import math +from functools import cached_property from typing import Literal, TypeVar from pydantic import BaseModel, ConfigDict, model_validator @@ -18,13 +19,25 @@ class ExperimentSettings(BaseModel): _key_to_lower = model_validator(mode="before")(key_to_lower) -class CpmgSettings(ExperimentSettings): +class RelaxationSettings(ExperimentSettings): + cs_evolution_prior: bool = False + + @cached_property + def suffix(self) -> str: + return f"_{self.observed_state}" if self.cs_evolution_prior else "" + + +class CpmgSettings(RelaxationSettings): even_ncycs: bool = False -class CpmgSettingsEvenNcycs(ExperimentSettings): +class CpmgSettingsEvenNcycs(RelaxationSettings): even_ncycs: bool = True -class CestSettings(ExperimentSettings): +class CestSettings(RelaxationSettings): sw: float = math.inf + + +class MFCestSettings(RelaxationSettings): + sw: float diff --git a/chemex/experiments/catalog/cest_13c.py b/chemex/experiments/catalog/cest_13c.py index a32127c4..d8a4d9d8 100644 --- a/chemex/experiments/catalog/cest_13c.py +++ b/chemex/experiments/catalog/cest_13c.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -33,9 +34,12 @@ class Cest13CSettings(CestSettings): b1_frq: float b1_inh_scale: float = 0.1 b1_inh_res: int = 11 - observed_state: Literal["a", "b", "c", "d"] = "a" - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"iz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[iz_{self.observed_state}]" @@ -88,7 +92,7 @@ def is_reference(metadata: ArrayFloat) -> ArrayBool: def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata - start = spectrometer.get_equilibrium() + start = spectrometer.get_start_magnetization(self.settings.start_terms) intensities: dict[float, ArrayFloat] = {} diff --git a/chemex/experiments/catalog/cest_15n.py b/chemex/experiments/catalog/cest_15n.py index ff036e6e..4a789e12 100644 --- a/chemex/experiments/catalog/cest_15n.py +++ b/chemex/experiments/catalog/cest_15n.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -34,9 +35,12 @@ class Cest15NSettings(CestSettings): b1_frq: float b1_inh_scale: float = 0.1 b1_inh_res: int = 11 - observed_state: Literal["a", "b", "c", "d"] = "a" - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"iz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[iz_{self.observed_state}]" @@ -87,7 +91,7 @@ def is_reference(metadata: ArrayFloat) -> ArrayBool: def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata - start = spectrometer.get_equilibrium() + start = spectrometer.get_start_magnetization(self.settings.start_terms) intensities: dict[float, ArrayFloat] = {} diff --git a/chemex/experiments/catalog/cest_15n_cw.py b/chemex/experiments/catalog/cest_15n_cw.py index 56267e4c..df3c20c7 100644 --- a/chemex/experiments/catalog/cest_15n_cw.py +++ b/chemex/experiments/catalog/cest_15n_cw.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -37,7 +38,11 @@ class Cest15NCwSettings(CestSettings): b1_inh_scale: float = 0.1 b1_inh_res: int = 11 - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"iz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[iz_{self.observed_state}]" @@ -101,7 +106,9 @@ def is_reference(metadata: ArrayFloat) -> ArrayBool: def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata - start = spectrometer.get_start_magnetization(terms=["iz"], atom="n") + start = spectrometer.get_start_magnetization( + terms=self.settings.start_terms, atom="n" + ) intensities: dict[float, ArrayFloat] = {} diff --git a/chemex/experiments/catalog/cest_15n_tr.py b/chemex/experiments/catalog/cest_15n_tr.py index 8dc9d387..c1765536 100644 --- a/chemex/experiments/catalog/cest_15n_tr.py +++ b/chemex/experiments/catalog/cest_15n_tr.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -36,7 +37,19 @@ class Cest15NTrSettings(CestSettings): b1_inh_res: int = 11 antitrosy: bool = False - @property + @cached_property + def start_terms(self) -> list[str]: + """Start from the TROSY or ANTI-TROSY component. + + TROSY: (2IzSz + Iz) / 2 + ANTITROSY: (2IzSz - Iz) / 2. + """ + if not self.antitrosy: + return [f"2izsz{self.suffix}", f"-iz{self.suffix}"] + + return [f"2izsz{self.suffix}", f"iz{self.suffix}"] + + @cached_property def detection(self) -> str: if self.antitrosy: return f"[2izsz_{self.observed_state}] + [iz_{self.observed_state}]" @@ -95,21 +108,10 @@ class Cest15NTrSequence: def is_reference(metadata: ArrayFloat) -> ArrayBool: return np.abs(metadata) > OFFSET_REF - def _get_start(self, spectrometer: Spectrometer) -> ArrayFloat: - """Start from the TROSY or ANTI-TROSY component. - - TROSY: (2IzSz - Iz) / 2 - ANTITROSY: (2IzSz + Iz) / 2. - """ - start = 0.5 * spectrometer.get_start_magnetization(["2izsz", "iz"]) - if not self.settings.antitrosy: - start -= spectrometer.get_start_magnetization(["iz"]) - return start - def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata - start = self._get_start(spectrometer) + start = spectrometer.get_start_magnetization(self.settings.start_terms) intensities: dict[float, ArrayFloat] = {} diff --git a/chemex/experiments/catalog/cest_1hn_ap.py b/chemex/experiments/catalog/cest_1hn_ap.py index 53a180cb..479273e5 100644 --- a/chemex/experiments/catalog/cest_1hn_ap.py +++ b/chemex/experiments/catalog/cest_1hn_ap.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -33,13 +34,13 @@ class Cest1HnApSettings(CestSettings): b1_frq: float b1_inh_scale: float = 0.1 b1_inh_res: int = 11 - observed_state: Literal["a", "b", "c", "d"] = "a" + cs_evolution_prior: bool = True - @property - def start(self) -> list[str]: - return [f"2izsz_{self.observed_state}"] + @cached_property + def start_terms(self) -> list[str]: + return [f"2izsz{self.suffix}"] - @property + @cached_property def detection(self) -> str: return f"[2izsz_{self.observed_state}]" @@ -90,7 +91,7 @@ def is_reference(metadata: ArrayFloat) -> ArrayBool: def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata - start = spectrometer.get_start_magnetization(terms=self.settings.start) + start = spectrometer.get_start_magnetization(self.settings.start_terms) intensities: dict[float, ArrayFloat] = {} diff --git a/chemex/experiments/catalog/coscest_13c.py b/chemex/experiments/catalog/coscest_13c.py index 3562e895..e3243698 100644 --- a/chemex/experiments/catalog/coscest_13c.py +++ b/chemex/experiments/catalog/coscest_13c.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -9,7 +10,7 @@ from chemex.configuration.base import ExperimentConfiguration, ToBeFitted from chemex.configuration.conditions import ConditionsWithValidations from chemex.configuration.data import CestDataSettings -from chemex.configuration.experiment import CestSettings +from chemex.configuration.experiment import MFCestSettings from chemex.containers.data import Data from chemex.containers.dataset import load_relaxation_dataset from chemex.experiments.factories import Creators, factories @@ -28,19 +29,22 @@ OFFSET_REF = 1e4 -class CosCest13CSettings(CestSettings): +class CosCest13CSettings(MFCestSettings): name: Literal["coscest_13c"] time_t1: float time_equil: float = 0.0 carrier: float - sw: float cos_n: int cos_res: int = 10 b1_frq: float b1_inh_scale: float = 0.1 b1_inh_res: int = 11 - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"iz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[iz_{self.observed_state}]" diff --git a/chemex/experiments/catalog/coscest_1hn_ip_ap.py b/chemex/experiments/catalog/coscest_1hn_ip_ap.py index 9ee2e24f..d01b592a 100644 --- a/chemex/experiments/catalog/coscest_1hn_ip_ap.py +++ b/chemex/experiments/catalog/coscest_1hn_ip_ap.py @@ -9,7 +9,7 @@ from chemex.configuration.base import ExperimentConfiguration, ToBeFitted from chemex.configuration.conditions import ConditionsWithValidations from chemex.configuration.data import CestDataSettingsNoRef -from chemex.configuration.experiment import CestSettings +from chemex.configuration.experiment import MFCestSettings from chemex.containers.data import Data from chemex.containers.dataset import load_relaxation_dataset from chemex.experiments.factories import Creators, factories @@ -27,11 +27,10 @@ OFFSET_REF = 1e4 -class CosCest1HnIpApSettings(CestSettings): +class CosCest1HnIpApSettings(MFCestSettings): name: Literal["coscest_1hn_ip_ap"] time_t1: float carrier: float - sw: float cos_n: int cos_res: int = 10 d1: float diff --git a/chemex/experiments/catalog/cpmg_13c_ip.py b/chemex/experiments/catalog/cpmg_13c_ip.py index 68b93e6e..83865113 100644 --- a/chemex/experiments/catalog/cpmg_13c_ip.py +++ b/chemex/experiments/catalog/cpmg_13c_ip.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -32,11 +33,15 @@ class Cpmg13CIpSettings(CpmgSettings): pw90: float time_equil: float = 0.0 - @property + @cached_property def t_neg(self) -> float: return -2.0 * self.pw90 / np.pi - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"iz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[iz_{self.observed_state}]" @@ -104,7 +109,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: p180pmx = 0.5 * (p180[0] + p180[2]) # +/- phase cycling # Getting the starting magnetization - start = spectrometer.get_equilibrium() + start = spectrometer.get_start_magnetization(self.settings.start_terms) # Calculating the instensities as a function of ncyc part1 = d_neg @ p90[0] @ start diff --git a/chemex/experiments/catalog/cpmg_13co_ap.py b/chemex/experiments/catalog/cpmg_13co_ap.py index 802dc390..e0a8dc68 100644 --- a/chemex/experiments/catalog/cpmg_13co_ap.py +++ b/chemex/experiments/catalog/cpmg_13co_ap.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -34,15 +35,19 @@ class Cpmg13CoApSettings(CpmgSettings): refocusing: bool = False taucc: float = 9.09e-3 - @property + @cached_property def t_neg(self) -> float: return -2.0 * self.pw90 / np.pi - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"2izsz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[2izsz_{self.observed_state}]" - @property + @cached_property def even_ncycs(self) -> bool: return self.refocusing @@ -114,7 +119,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: perfect180x = spectrometer.perfect180_i[0] # Getting the starting magnetization - start = spectrometer.get_start_magnetization(["2izsz"]) + start = spectrometer.get_start_magnetization(self.settings.start_terms) # Calculate the flip block if self.settings.refocusing: diff --git a/chemex/experiments/catalog/cpmg_15n_ip.py b/chemex/experiments/catalog/cpmg_15n_ip.py index 0cd4ee9b..84abd0f2 100644 --- a/chemex/experiments/catalog/cpmg_15n_ip.py +++ b/chemex/experiments/catalog/cpmg_15n_ip.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -32,11 +33,15 @@ class Cpmg15NIpSettings(CpmgSettings): pw90: float time_equil: float = 0.0 - @property + @cached_property def t_neg(self) -> float: return -2.0 * self.pw90 / np.pi - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"iz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[iz_{self.observed_state}]" @@ -104,7 +109,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: p180pmx = 0.5 * (p180[0] + p180[2]) # +/- phase cycling # Getting the starting magnetization - start = spectrometer.get_equilibrium() + start = spectrometer.get_start_magnetization(self.settings.start_terms) # Calculating the instensities as a function of ncyc part1 = d_neg @ p90[0] @ start diff --git a/chemex/experiments/catalog/cpmg_15n_ip_0013.py b/chemex/experiments/catalog/cpmg_15n_ip_0013.py index b8f43d87..f31f2307 100644 --- a/chemex/experiments/catalog/cpmg_15n_ip_0013.py +++ b/chemex/experiments/catalog/cpmg_15n_ip_0013.py @@ -1,7 +1,7 @@ from __future__ import annotations from dataclasses import dataclass -from functools import reduce +from functools import cached_property, reduce from typing import Literal import numpy as np @@ -36,15 +36,19 @@ class Cpmg15N0013IpSettings(CpmgSettings): time_equil: float = 0.0 ncyc_max: int - @property + @cached_property def t_neg(self) -> float: return -2.0 * self.pw90 / np.pi - @property + @cached_property def t_pos(self) -> float: return 4.0 * self.pw90 / np.pi - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"iz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[iz_{self.observed_state}]" @@ -133,7 +137,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: p180 = spectrometer.p180_i # Getting the starting magnetization - start = spectrometer.get_equilibrium() + start = spectrometer.get_start_magnetization(self.settings.start_terms) # Calculating the instensities as a function of ncyc intensities = { diff --git a/chemex/experiments/catalog/cpmg_15n_tr.py b/chemex/experiments/catalog/cpmg_15n_tr.py index dba6baf6..df8d8b6f 100644 --- a/chemex/experiments/catalog/cpmg_15n_tr.py +++ b/chemex/experiments/catalog/cpmg_15n_tr.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -34,7 +35,7 @@ class Cpmg15NTrSettings(CpmgSettings): taub: float = 2.68e-3 antitrosy: bool = False - @property + @cached_property def t_neg(self) -> float: return -2.0 * self.pw90 / np.pi @@ -42,6 +43,10 @@ def t_neg(self) -> float: def taub_eff(self) -> float: return self.taub - 2.0 * self.pw90 - 2.0 * self.pw90 / np.pi + @cached_property + def start_terms(self) -> list[str]: + return [f"2izsz{self.suffix}"] + @property def detection(self) -> str: if self.antitrosy: @@ -122,7 +127,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: p180_sx = spectrometer.perfect180_s[0] # Getting the starting magnetization - start = spectrometer.get_start_magnetization(["2izsz"]) + start = spectrometer.get_start_magnetization(self.settings.start_terms) # Calculating the p-element p1, p2 = (2, 1) if self.settings.antitrosy else (1, 0) diff --git a/chemex/experiments/catalog/cpmg_15n_tr_0013.py b/chemex/experiments/catalog/cpmg_15n_tr_0013.py index 4d92d904..46baff9d 100644 --- a/chemex/experiments/catalog/cpmg_15n_tr_0013.py +++ b/chemex/experiments/catalog/cpmg_15n_tr_0013.py @@ -1,7 +1,7 @@ from __future__ import annotations from dataclasses import dataclass -from functools import reduce +from functools import cached_property, reduce from typing import Literal import numpy as np @@ -39,15 +39,23 @@ class Cpmg15NTr0013Settings(CpmgSettings): antitrosy: bool = False s3e: bool = True - @property + @cached_property def t_neg(self) -> float: return -2.0 * self.pw90 / np.pi - @property + @cached_property def taub_eff(self) -> float: return self.taub - 2.0 * self.pw90 - 2.0 * self.pw90 / np.pi - @property + @cached_property + def start_terms(self) -> list[str]: + if self.s3e: + if self.antitrosy: + return [f"2izsz{self.suffix}", f"iz{self.suffix}"] + return [f"2izsz{self.suffix}", f"-iz{self.suffix}"] + return [f"2izsz{self.suffix}"] + + @cached_property def detection(self) -> str: if self.antitrosy: return f"[2izsz_{self.observed_state}] + [iz_{self.observed_state}]" @@ -134,16 +142,6 @@ def _get_phases(self, ncyc: float) -> tuple[ArrayInt, ArrayInt]: phases2 = np.take(cp_phases2, indexes, mode="wrap", axis=1) return phases1, phases2 - def _get_start(self, spectrometer: Spectrometer) -> ArrayFloat: - start = spectrometer.get_start_magnetization(["2izsz"]) - if self.settings.s3e: - if self.settings.antitrosy: - start += spectrometer.get_start_magnetization(["iz"]) - else: - start -= spectrometer.get_start_magnetization(["iz"]) - start *= 0.5 - return start - def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata @@ -162,7 +160,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: p180_sx = spectrometer.perfect180_s[0] # Getting the starting magnetization - start = self._get_start(spectrometer) + start = spectrometer.get_start_magnetization(self.settings.start_terms) # Calculating the p-element if self.settings.antitrosy: diff --git a/chemex/experiments/catalog/cpmg_1hn_ap.py b/chemex/experiments/catalog/cpmg_1hn_ap.py index cd41a2d2..62dc1dc5 100644 --- a/chemex/experiments/catalog/cpmg_1hn_ap.py +++ b/chemex/experiments/catalog/cpmg_1hn_ap.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -32,16 +33,17 @@ class Cpmg1HnApSettings(CpmgSettings): pw90: float time_equil_1: float = 0.0 time_equil_2: float = 0.0 + cs_evolution_prior: bool = True - @property + @cached_property def t_neg(self) -> float: return -2.0 * self.pw90 / np.pi - @property - def start(self) -> list[str]: - return [f"2izsz_{self.observed_state}"] + @cached_property + def start_terms(self) -> list[str]: + return [f"2izsz{self.suffix}"] - @property + @cached_property def detection(self) -> str: return f"[2izsz_{self.observed_state}]" @@ -115,7 +117,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: p180pmx = 0.5 * (p180[0] + p180[2]) # +/- phase cycling # Getting the starting magnetization - start = spectrometer.get_start_magnetization(terms=self.settings.start) + start = spectrometer.get_start_magnetization(terms=self.settings.start_terms) # Calculating the instensities as a function of ncyc part1 = d_neg @ p90[0] @ d_eq_1 @ start diff --git a/chemex/experiments/catalog/cpmg_1hn_ap_0013.py b/chemex/experiments/catalog/cpmg_1hn_ap_0013.py index 6d990fcd..4f9d9516 100644 --- a/chemex/experiments/catalog/cpmg_1hn_ap_0013.py +++ b/chemex/experiments/catalog/cpmg_1hn_ap_0013.py @@ -1,7 +1,7 @@ from __future__ import annotations from dataclasses import dataclass -from functools import reduce +from functools import cached_property, reduce from typing import Literal import numpy as np @@ -39,16 +39,17 @@ class Cpmg1HnAp0013Settings(CpmgSettings): pw_reburp: float = 1.52e-3 time_equil_1: float = 0.0 time_equil_2: float = 0.0 + cs_evolution_prior: bool = True - @property + @cached_property def t_neg(self) -> float: return -2.0 * self.pw90 / np.pi - @property - def start(self) -> list[str]: - return [f"2izsz_{self.observed_state}"] + @cached_property + def start_terms(self) -> list[str]: + return [f"2izsz{self.suffix}"] - @property + @cached_property def detection(self) -> str: return f"[iz_{self.observed_state}]" @@ -158,7 +159,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: zfilter = spectrometer.zfilter # Getting the starting magnetization - start = spectrometer.get_start_magnetization(terms=self.settings.start) + start = spectrometer.get_start_magnetization(terms=self.settings.start_terms) # Calculating the central refocusing block if self.settings.eburp_flg: diff --git a/chemex/experiments/catalog/cpmg_ch3_13c_h2c.py b/chemex/experiments/catalog/cpmg_ch3_13c_h2c.py index 4912024b..4f12a02c 100644 --- a/chemex/experiments/catalog/cpmg_ch3_13c_h2c.py +++ b/chemex/experiments/catalog/cpmg_ch3_13c_h2c.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -9,9 +10,7 @@ from chemex.configuration.base import ExperimentConfiguration, ToBeFitted from chemex.configuration.conditions import ConditionsWithValidations from chemex.configuration.data import RelaxationDataSettings -from chemex.configuration.experiment import ( - CpmgSettingsEvenNcycs, -) +from chemex.configuration.experiment import CpmgSettingsEvenNcycs from chemex.containers.data import Data from chemex.containers.dataset import load_relaxation_dataset from chemex.experiments.factories import Creators, factories @@ -34,16 +33,17 @@ class CpmgCh313CH2cSettings(CpmgSettingsEvenNcycs): pw90: float taub: float = 2.0e-3 time_equil: float = 0.0 + cs_evolution_prior: bool = True - @property + @cached_property def t_neg(self) -> float: return -2.0 * self.pw90 / np.pi - @property - def start(self) -> list[str]: - return [f"2izsz_{self.observed_state}"] + @cached_property + def start_terms(self) -> list[str]: + return [f"2izsz{self.suffix}"] - @property + @cached_property def detection(self) -> str: return f"[iz_{self.observed_state}]" @@ -114,7 +114,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: p180_sx = spectrometer.perfect180_s[0] # Getting the starting magnetization - start = spectrometer.get_start_magnetization(terms=self.settings.start) + start = spectrometer.get_start_magnetization(terms=self.settings.start_terms) # Calculating the p-element palmer = d_taub @ p90[0] @ p180_sx @ p90[0] @ d_taub diff --git a/chemex/experiments/catalog/cpmg_ch3_1h_dq.py b/chemex/experiments/catalog/cpmg_ch3_1h_dq.py index 424eb160..53262ee4 100644 --- a/chemex/experiments/catalog/cpmg_ch3_1h_dq.py +++ b/chemex/experiments/catalog/cpmg_ch3_1h_dq.py @@ -1,7 +1,7 @@ from __future__ import annotations from dataclasses import dataclass -from functools import reduce +from functools import cached_property, reduce from typing import Literal import numpy as np @@ -34,7 +34,11 @@ class CpmgCh31HDqSettings(CpmgSettings): comp180_flg: bool = True ipap_flg: bool = False - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"2ixsz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[2ixsz_{self.observed_state}]" @@ -103,7 +107,9 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Getting the starting magnetization - start = spectrometer.get_start_magnetization(["2ixsz"], atom="h") + start = spectrometer.get_start_magnetization( + self.settings.start_terms, atom="h" + ) # Calculation of the spectrometers corresponding to all the delays tau_cps, all_delays = self._get_delays(ncycs) diff --git a/chemex/experiments/catalog/cpmg_ch3_1h_sq.py b/chemex/experiments/catalog/cpmg_ch3_1h_sq.py index 6f6e8ab2..94f46bd4 100644 --- a/chemex/experiments/catalog/cpmg_ch3_1h_sq.py +++ b/chemex/experiments/catalog/cpmg_ch3_1h_sq.py @@ -1,7 +1,7 @@ from __future__ import annotations from dataclasses import dataclass -from functools import reduce +from functools import cached_property, reduce from typing import Literal import numpy as np @@ -34,8 +34,13 @@ class CpmgCh31HSqSettings(CpmgSettings): taua: float = 2.0e-3 comp180_flg: bool = True ipap_flg: bool = False + cs_evolution_prior: bool = True - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"2ixsz{self.suffix}", f"2iysz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[iy_{self.observed_state}]" @@ -128,7 +133,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: # Getting the starting magnetization start = spectrometer.get_start_magnetization(terms=["iy"]) start = perfect180y @ d_taua @ d_taua @ start - start = spectrometer.keep(start, ["2ixsz_a", "2iysz_a"]) + start = spectrometer.keep(start, self.settings.start_terms) # Calculating the intensities as a function of ncyc if self.settings.ipap_flg: diff --git a/chemex/experiments/catalog/cpmg_ch3_1h_tq.py b/chemex/experiments/catalog/cpmg_ch3_1h_tq.py index dcd15a0e..f086de42 100644 --- a/chemex/experiments/catalog/cpmg_ch3_1h_tq.py +++ b/chemex/experiments/catalog/cpmg_ch3_1h_tq.py @@ -1,7 +1,7 @@ from __future__ import annotations from dataclasses import dataclass -from functools import reduce +from functools import cached_property, reduce from typing import Literal import numpy as np @@ -34,6 +34,10 @@ class CpmgCh31HTqSettings(CpmgSettings): comp180_flg: bool = True ipap_flg: bool = False + @cached_property + def start_terms(self) -> list[str]: + return [f"2ixsz{self.suffix}"] + @property def detection(self) -> str: return f"[2ixsz_{self.observed_state}]" @@ -103,7 +107,9 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Getting the starting magnetization - start = spectrometer.get_start_magnetization(["2ixsz"], atom="h") + start = spectrometer.get_start_magnetization( + self.settings.start_terms, atom="h" + ) # Calculation of the spectrometers corresponding to all the delays tau_cps, all_delays = self._get_delays(ncycs) diff --git a/chemex/experiments/catalog/cpmg_ch3_1h_tq_diff.py b/chemex/experiments/catalog/cpmg_ch3_1h_tq_diff.py index db4dff5b..a11b1803 100644 --- a/chemex/experiments/catalog/cpmg_ch3_1h_tq_diff.py +++ b/chemex/experiments/catalog/cpmg_ch3_1h_tq_diff.py @@ -1,7 +1,7 @@ from __future__ import annotations from dataclasses import dataclass -from functools import reduce +from functools import cached_property, reduce from typing import Literal import numpy as np @@ -38,11 +38,15 @@ class CpmgCh31HTqDiffSettings(CpmgSettings): comp180_flg: bool = True ipap_flg: bool = False - @property + @cached_property def k2_factor(self) -> float: return (3.0 * GAMMA["h"] * self.gradient * self.delta) ** 2 - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"2ixsz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[2ixsz_{self.observed_state}]" @@ -114,7 +118,9 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: ncycs = data.metadata # Getting the starting magnetization - start = spectrometer.get_start_magnetization(["2ixsz"], atom="h") + start = spectrometer.get_start_magnetization( + self.settings.start_terms, atom="h" + ) # Calculation of the spectrometers with gradient 0 spectrometer.gradient_dephasing = 0.0 diff --git a/chemex/experiments/catalog/cpmg_ch3_mq.py b/chemex/experiments/catalog/cpmg_ch3_mq.py index 7449ef09..10951f54 100644 --- a/chemex/experiments/catalog/cpmg_ch3_mq.py +++ b/chemex/experiments/catalog/cpmg_ch3_mq.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -31,7 +32,11 @@ class CpmgCh3MqSettings(CpmgSettings): t_zeta: float = 1.0 / (8.0 * 125.3) small_protein: bool = False - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"2iysx{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[2iysx_{self.observed_state}]" @@ -90,7 +95,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: p180_iy = spectrometer.perfect180_i[1] # Getting the starting magnetization - start = spectrometer.get_start_magnetization(terms=["2iysx"]) + start = spectrometer.get_start_magnetization(self.settings.start_terms) # Calculating the instensities as a function of ncyc part1 = start diff --git a/chemex/experiments/catalog/cpmg_chd2_1h_ap.py b/chemex/experiments/catalog/cpmg_chd2_1h_ap.py index 3cb376ec..9c20e53e 100644 --- a/chemex/experiments/catalog/cpmg_chd2_1h_ap.py +++ b/chemex/experiments/catalog/cpmg_chd2_1h_ap.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -32,21 +33,23 @@ class CpmgChd21HApSettings(CpmgSettings): pw90: float time_equil: float = 0.0 - @property + @cached_property def t_neg(self) -> float: return -2.0 * self.pw90 / np.pi - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"2izsz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[2izsz_{self.observed_state}]" class CpmgChd21HApConfig( ExperimentConfiguration[ - CpmgChd21HApSettings, - ConditionsWithValidations, - RelaxationDataSettings, - ], + CpmgChd21HApSettings, ConditionsWithValidations, RelaxationDataSettings + ] ): @property def to_be_fitted(self) -> ToBeFitted: @@ -104,7 +107,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: p180pmx = 0.5 * (p180[0] + p180[2]) # +/- phase cycling # Getting the starting magnetization - start = spectrometer.get_start_magnetization(terms=["2izsz"]) + start = spectrometer.get_start_magnetization(self.settings.start_terms) # Calculating the instensities as a function of ncyc part1 = d_neg @ p90[0] @ start diff --git a/chemex/experiments/catalog/cpmg_hn_dq_zq.py b/chemex/experiments/catalog/cpmg_hn_dq_zq.py index f0aca1b2..fc05fdaf 100644 --- a/chemex/experiments/catalog/cpmg_hn_dq_zq.py +++ b/chemex/experiments/catalog/cpmg_hn_dq_zq.py @@ -1,7 +1,7 @@ from __future__ import annotations from dataclasses import dataclass -from functools import reduce +from functools import cached_property, reduce from typing import Literal import numpy as np @@ -39,7 +39,11 @@ class CpmgHNDqZqSettings(CpmgSettingsEvenNcycs): pw90_n: float dq_flg: bool - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"2ixsx{self.suffix}"] + + @cached_property def detection(self) -> str: if self.dq_flg: return f"[2ixsx_{self.observed_state}] - [2iysy_{self.observed_state}]" @@ -48,9 +52,7 @@ def detection(self) -> str: class CpmgHNDqZqConfig( ExperimentConfiguration[ - CpmgHNDqZqSettings, - ConditionsWithValidations, - RelaxationDataSettings, + CpmgHNDqZqSettings, ConditionsWithValidations, RelaxationDataSettings ], ): @property @@ -126,7 +128,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: p9024090_2 = spectrometer.p9024090_nh_2[[0, 1], [0, 1]] # Getting the starting magnetization - start = spectrometer.get_start_magnetization(["2ixsx"]) + start = spectrometer.get_start_magnetization(self.settings.start_terms) # Calculating the cpmg trains intensities = {0.0: spectrometer.detect(start)} diff --git a/chemex/experiments/catalog/dcest_13c.py b/chemex/experiments/catalog/dcest_13c.py index 989426e4..bd472d83 100644 --- a/chemex/experiments/catalog/dcest_13c.py +++ b/chemex/experiments/catalog/dcest_13c.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -9,7 +10,7 @@ from chemex.configuration.base import ExperimentConfiguration, ToBeFitted from chemex.configuration.conditions import ConditionsWithValidations from chemex.configuration.data import CestDataSettings -from chemex.configuration.experiment import CestSettings +from chemex.configuration.experiment import MFCestSettings from chemex.containers.data import Data from chemex.containers.dataset import load_relaxation_dataset from chemex.experiments.factories import Creators, factories @@ -28,30 +29,33 @@ OFFSET_REF = 1e4 -class DCest13CSettings(CestSettings): +class DCest13CSettings(MFCestSettings): name: Literal["dcest_13c"] time_t1: float time_equil: float = 0.0 carrier: float pw90: float - sw: float b1_frq: float b1_inh_scale: float = 0.1 b1_inh_res: int = 11 - @property + @cached_property def pw_dante(self) -> float: return 4.0 * self.pw90 * self.b1_frq / self.sw - @property + @cached_property def tau_dante(self) -> float: return 1.0 / self.sw - self.pw_dante - @property + @cached_property def ncyc_dante(self) -> int: return int(self.time_t1 * self.sw + 0.1) - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"iz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[iz_{self.observed_state}]" @@ -103,7 +107,7 @@ def is_reference(metadata: ArrayFloat) -> ArrayBool: def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata - start = spectrometer.get_equilibrium() + start = spectrometer.get_start_magnetization(terms=self.settings.start_terms) d_eq = ( spectrometer.delays(self.settings.time_equil) diff --git a/chemex/experiments/catalog/dcest_15n.py b/chemex/experiments/catalog/dcest_15n.py index 89d8c17c..0d26d3c9 100644 --- a/chemex/experiments/catalog/dcest_15n.py +++ b/chemex/experiments/catalog/dcest_15n.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -9,7 +10,7 @@ from chemex.configuration.base import ExperimentConfiguration, ToBeFitted from chemex.configuration.conditions import ConditionsWithValidations from chemex.configuration.data import CestDataSettings -from chemex.configuration.experiment import CestSettings +from chemex.configuration.experiment import MFCestSettings from chemex.containers.data import Data from chemex.containers.dataset import load_relaxation_dataset from chemex.experiments.factories import Creators, factories @@ -31,35 +32,34 @@ OFFSET_REF = 1e4 -class DCest15NSettings(CestSettings): +class DCest15NSettings(MFCestSettings): name: Literal["dcest_15n"] time_t1: float time_equil: float = 0.0 carrier: float pw90: float - sw: float b1_frq: float b1_inh_scale: float = 0.1 b1_inh_res: int = 11 - @property + @cached_property def pw_dante(self) -> float: return 4.0 * self.pw90 * self.b1_frq / self.sw - @property + @cached_property def tau_dante(self) -> float: return 1.0 / self.sw - self.pw_dante - @property + @cached_property def ncyc_dante(self) -> int: return int(self.time_t1 * self.sw + 0.1) - @property - def start(self) -> list[str]: + @cached_property + def start_terms(self) -> list[str]: starts = {"2st_hd": ["iz_a"], "4st_hd": ["iz_a", "iz_b"]} - return starts.get(model.name, ["iz"]) + return starts.get(model.name, [f"iz{self.suffix}"]) - @property + @cached_property def detection(self) -> str: return f"[iz_{self.observed_state}]" @@ -111,7 +111,7 @@ def is_reference(metadata: ArrayFloat) -> ArrayBool: def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: offsets = data.metadata - start = spectrometer.get_start_magnetization(self.settings.start, "n") + start = spectrometer.get_start_magnetization(self.settings.start_terms, "n") d_eq = ( spectrometer.delays(self.settings.time_equil) diff --git a/chemex/experiments/catalog/relaxation_hznz.py b/chemex/experiments/catalog/relaxation_hznz.py index f8e53ec6..216d39aa 100644 --- a/chemex/experiments/catalog/relaxation_hznz.py +++ b/chemex/experiments/catalog/relaxation_hznz.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -8,7 +9,7 @@ from chemex.configuration.base import ExperimentConfiguration, ToBeFitted from chemex.configuration.conditions import ConditionsWithValidations from chemex.configuration.data import RelaxationDataSettings -from chemex.configuration.experiment import ExperimentSettings +from chemex.configuration.experiment import RelaxationSettings from chemex.containers.data import Data from chemex.containers.dataset import load_relaxation_dataset from chemex.experiments.factories import Creators, factories @@ -24,10 +25,14 @@ EXPERIMENT_NAME = "relaxation_hznz" -class RelaxationHzNzSettings(ExperimentSettings): +class RelaxationHzNzSettings(RelaxationSettings): name: Literal["relaxation_hznz"] - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"2izsz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[2izsz_{self.observed_state}]" @@ -72,7 +77,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: times = data.metadata # Getting the starting magnetization - start = spectrometer.get_start_magnetization(["2izsz"]) + start = spectrometer.get_start_magnetization(self.settings.start_terms) # Return profile delays = spectrometer.delays(0.25 * np.array(times)) diff --git a/chemex/experiments/catalog/relaxation_nz.py b/chemex/experiments/catalog/relaxation_nz.py index b9511f53..363a0b99 100644 --- a/chemex/experiments/catalog/relaxation_nz.py +++ b/chemex/experiments/catalog/relaxation_nz.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from functools import cached_property from typing import Literal import numpy as np @@ -8,7 +9,7 @@ from chemex.configuration.base import ExperimentConfiguration, ToBeFitted from chemex.configuration.conditions import ConditionsWithValidations from chemex.configuration.data import RelaxationDataSettings -from chemex.configuration.experiment import ExperimentSettings +from chemex.configuration.experiment import RelaxationSettings from chemex.containers.data import Data from chemex.containers.dataset import load_relaxation_dataset from chemex.experiments.factories import Creators, factories @@ -24,10 +25,14 @@ EXPERIMENT_NAME = "relaxation_nz" -class RelaxationNzSettings(ExperimentSettings): +class RelaxationNzSettings(RelaxationSettings): name: Literal["relaxation_nz"] - @property + @cached_property + def start_terms(self) -> list[str]: + return [f"iz{self.suffix}"] + + @cached_property def detection(self) -> str: return f"[iz_{self.observed_state}]" @@ -72,7 +77,7 @@ def calculate(self, spectrometer: Spectrometer, data: Data) -> ArrayFloat: times = data.metadata # Getting the starting magnetization - start = spectrometer.get_equilibrium() + start = spectrometer.get_start_magnetization(self.settings.start_terms) # Return profile delays = spectrometer.delays(times) diff --git a/chemex/nmr/liouvillian.py b/chemex/nmr/liouvillian.py index 2315bc8a..2e5f34ff 100644 --- a/chemex/nmr/liouvillian.py +++ b/chemex/nmr/liouvillian.py @@ -34,20 +34,22 @@ SMALL_VALUE = 1e-6 -def _make_gaussian( +def _generate_gaussian_distribution( value: float, scale: float, res: int, ) -> tuple[ArrayFloat, ArrayFloat]: if scale not in (0.0, np.inf) and res > 1: grid = np.linspace(-2.0, 2.0, res) - dist = grid * scale + 1.0 + distribution = grid * scale + 1.0 else: grid = np.array([0.0]) - dist = np.array([1.0]) + distribution = np.array([1.0]) + weights = stats.norm.pdf(grid) weights /= weights.sum() - return dist * value, weights + + return distribution * value, weights class LiouvillianIS: @@ -187,7 +189,7 @@ def b1_i(self) -> float: @b1_i.setter def b1_i(self, value: float) -> None: self._b1_i = value - self._b1_i_dist, self._b1_i_weights = _make_gaussian( + self._b1_i_dist, self._b1_i_weights = _generate_gaussian_distribution( self.b1_i, self.b1_i_inh_scale, self.b1_i_inh_res, @@ -250,6 +252,11 @@ def weights(self) -> ArrayFloat: def detection(self) -> str: return self._detection + def _collapse(self, magnetization: ArrayFloat) -> float: + shape = -1, *magnetization.shape[-2:] + magnetization_weighted = self.weights * magnetization + return magnetization_weighted.reshape(shape).sum(axis=0) + @detection.setter def detection(self, value: str) -> None: self._detection = value @@ -258,14 +265,22 @@ def detection(self, value: str) -> None: self._detect_vector = vector.transpose() def detect(self, magnetization: ArrayFloat) -> float: - shape = -1, *magnetization.shape[-2:] - mag_weighted = self.weights * magnetization - mag = mag_weighted.reshape(shape).sum(axis=0) - detected = self._detect_vector @ mag + collapsed_magnetization = self._collapse(magnetization) + detected = self._detect_vector @ collapsed_magnetization if np.iscomplexobj(detected): detected = np.sign(detected.real) * np.abs(detected) return float(detected) + # def detect_spectrum(self, magnetization: ArrayFloat) -> ArrayFloat: + # collapsed_magnetization = self._collapse(magnetization) + # i_minus = self.vectors.get("ix", 0.0) - 1j * self.vectors.get("iy", 0.0) + # eigen_values, eigen_vectors = np.linalg.eig(self._l_base) + # relaxations = eigen_values.real + # frequencies = eigen_values.imag + + # detected = self._detect_vector @ collapsed_magnetization + # return detected + def get_equilibrium(self) -> ArrayFloat: mag = np.zeros((self.size, 1)) for state, (name, atom) in product(model.states, self.basis.atoms.items()): @@ -274,6 +289,27 @@ def get_equilibrium(self) -> ArrayFloat: mag += self.vectors.get(f"{name}z_{state}", 0.0) * scale return mag + def get_start_magnetization( + self, terms: Iterable[str], atom: str = "h" + ) -> ArrayFloat: + ratio = XI_RATIO.get(atom, 1.0) + terms_set = set(terms) + mag = np.zeros((self.size, 1)) + + for component, vector in self.vectors.items(): + state_specific = "_" in component + if not state_specific: + continue + state = component[-1] + for term in terms_set: + match = component.startswith(term.strip("+-")) + if match: + sign = -1.0 if term.startswith("-") else 1.0 + population = self.par_values.get(f"p{state}", 0.0) + mag += sign * population * ratio * vector + + return mag + def tilt_mag_along_weff_i( self, magnetization: ArrayFloat, *, back: bool = False ) -> ArrayFloat: @@ -305,22 +341,6 @@ def tilt_mag_along_weff_i( return magnetization - def get_start_magnetization( - self, - terms: Iterable[str], - atom: str = "h", - ) -> ArrayFloat: - ratio = XI_RATIO.get(atom, 1.0) - mag = np.zeros((self.size, 1)) - for term, state, (comp, vector) in product( - terms, - model.states, - self.vectors.items(), - ): - if comp.startswith(term) and comp.endswith(f"_{state}"): - mag += self.par_values[f"p{state}"] * ratio * vector - return mag - def keep(self, magnetization: ArrayFloat, components: Iterable[str]) -> ArrayFloat: keep = sum( (self.vectors[name] for name in components), @@ -340,4 +360,4 @@ def calculate_r1rho(self) -> float: liouv = liouv.reshape((self.size, self.size)) eigenvalues = np.linalg.eigvals(liouv) real_eigenvalues = eigenvalues[abs(eigenvalues.imag) < SMALL_VALUE].real - return -np.max(real_eigenvalues) + return -float(np.max(real_eigenvalues)) diff --git a/examples/Experiments/CEST_13C_LABEL_CN/Parameters/parameters.toml b/examples/Experiments/CEST_13C_LABEL_CN/Parameters/parameters.toml index 6a0920b4..909b9253 100644 --- a/examples/Experiments/CEST_13C_LABEL_CN/Parameters/parameters.toml +++ b/examples/Experiments/CEST_13C_LABEL_CN/Parameters/parameters.toml @@ -24,7 +24,7 @@ I28CD1 = 10.63040 [DW_AB] L18CA = 1.0 L18CB = -2.5 -L18CG = 0.01 +L18CG = 0.05 L18CD1 = 0.01 L18CD2 = -2.0 K25CA = 1.5