axionbloch 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- axionbloch-0.2.3/LICENSE +19 -0
- axionbloch-0.2.3/MANIFEST.in +3 -0
- axionbloch-0.2.3/PKG-INFO +74 -0
- axionbloch-0.2.3/README.md +44 -0
- axionbloch-0.2.3/axionbloch/Apparatus.py +221 -0
- axionbloch-0.2.3/axionbloch/EarthBoundAxionHalo.py +763 -0
- axionbloch-0.2.3/axionbloch/FineGrainedAxionStream.py +306 -0
- axionbloch-0.2.3/axionbloch/GravBoundAxionHalo.py +1234 -0
- axionbloch-0.2.3/axionbloch/MilkyWay.py +1017 -0
- axionbloch-0.2.3/axionbloch/MilkyWayAxionHalo.py +494 -0
- axionbloch-0.2.3/axionbloch/Sample.py +215 -0
- axionbloch-0.2.3/axionbloch/SimuTools.py +1990 -0
- axionbloch-0.2.3/axionbloch/SimuTypes.py +108 -0
- axionbloch-0.2.3/axionbloch/Station.py +314 -0
- axionbloch-0.2.3/axionbloch/__init__.py +35 -0
- axionbloch-0.2.3/axionbloch/constants.py +32 -0
- axionbloch-0.2.3/axionbloch/data/Earth_Models/PREM.md +41 -0
- axionbloch-0.2.3/axionbloch/data/Earth_Models/PREM_data.txt +752 -0
- axionbloch-0.2.3/axionbloch/dependency.py +67 -0
- axionbloch-0.2.3/axionbloch/kits/CASPEr_G_HF.py +0 -0
- axionbloch-0.2.3/axionbloch/kits/CASPEr_G_LF.py +0 -0
- axionbloch-0.2.3/axionbloch/kits/DataAnalysis.py +7930 -0
- axionbloch-0.2.3/axionbloch/kits/LockInAmp.py +0 -0
- axionbloch-0.2.3/axionbloch/kits/Simu_Signal.py +137 -0
- axionbloch-0.2.3/axionbloch/kits/__init__.py +0 -0
- axionbloch-0.2.3/axionbloch/kits/utils.py +3383 -0
- axionbloch-0.2.3/axionbloch/utils.py +3067 -0
- axionbloch-0.2.3/axionbloch.egg-info/PKG-INFO +74 -0
- axionbloch-0.2.3/axionbloch.egg-info/SOURCES.txt +49 -0
- axionbloch-0.2.3/axionbloch.egg-info/dependency_links.txt +1 -0
- axionbloch-0.2.3/axionbloch.egg-info/not-zip-safe +1 -0
- axionbloch-0.2.3/axionbloch.egg-info/requires.txt +20 -0
- axionbloch-0.2.3/axionbloch.egg-info/top_level.txt +1 -0
- axionbloch-0.2.3/blochSimulation_ext/bloch.cpp +327 -0
- axionbloch-0.2.3/blochSimulation_ext/bloch.h +90 -0
- axionbloch-0.2.3/blochSimulation_ext/bloch_wrapper.cpp +195 -0
- axionbloch-0.2.3/pyproject.toml +67 -0
- axionbloch-0.2.3/setup.cfg +4 -0
- axionbloch-0.2.3/setup.py +50 -0
- axionbloch-0.2.3/tests/test_EarthBoundAxionHalo.py +59 -0
- axionbloch-0.2.3/tests/test_Magnet.py +48 -0
- axionbloch-0.2.3/tests/test_MilkyWay.py +347 -0
- axionbloch-0.2.3/tests/test_MilkyWayAxionHalo.py +440 -0
- axionbloch-0.2.3/tests/test_Sample.py +156 -0
- axionbloch-0.2.3/tests/test_calibrations_cw_nmr.py +435 -0
- axionbloch-0.2.3/tests/test_calibrations_free_decay.py +337 -0
- axionbloch-0.2.3/tests/test_calibrations_t1_hyperpolarized.py +337 -0
- axionbloch-0.2.3/tests/test_calibrations_t1_relaxation.py +324 -0
- axionbloch-0.2.3/tests/test_constants.py +28 -0
- axionbloch-0.2.3/tests/test_findGradients_EarthLocation.py +95 -0
- axionbloch-0.2.3/tests/test_numpy_unit_performance.py +243 -0
axionbloch-0.2.3/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yuzhe Zhang
|
|
4
|
+
|
|
5
|
+
You are free to:
|
|
6
|
+
|
|
7
|
+
- Share — copy and redistribute the material in any medium or format
|
|
8
|
+
- Adapt — remix, transform, and build upon the material
|
|
9
|
+
|
|
10
|
+
Under the following terms:
|
|
11
|
+
|
|
12
|
+
- Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made.
|
|
13
|
+
- NonCommercial — You may not use the material for commercial purposes.
|
|
14
|
+
|
|
15
|
+
No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
Full license text: https://creativecommons.org/licenses/by-nc/4.0/legalcode
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: axionbloch
|
|
3
|
+
Version: 0.2.3
|
|
4
|
+
Summary: Simulation tool for axion-induced spin dynamics.
|
|
5
|
+
Author-email: Yuzhe Zhang <yuhzhang@uni-mainz.de>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Documentation, https://axionbloch.readthedocs.io/en/latest/
|
|
8
|
+
Project-URL: Source, https://github.com/Yuzhe98/AxionBloch
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: numpy
|
|
13
|
+
Requires-Dist: matplotlib
|
|
14
|
+
Requires-Dist: astropy
|
|
15
|
+
Requires-Dist: scipy
|
|
16
|
+
Requires-Dist: h5py
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
19
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
20
|
+
Requires-Dist: black>=23.0; extra == "dev"
|
|
21
|
+
Requires-Dist: ruff>=0.1; extra == "dev"
|
|
22
|
+
Provides-Extra: docs
|
|
23
|
+
Requires-Dist: sphinx>=5.0; extra == "docs"
|
|
24
|
+
Requires-Dist: sphinx-rtd-theme>=1.0; extra == "docs"
|
|
25
|
+
Requires-Dist: sphinx-autodoc-typehints>=1.0; extra == "docs"
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
28
|
+
Requires-Dist: pytest-cov>=4.0; extra == "test"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# AxionBloch
|
|
32
|
+
A package for simulating **axion**-induced spin dynamics based on **Bloch equations**, implemented in **Python** and **C++**.
|
|
33
|
+
|
|
34
|
+
Yuzhe Zhang - GSI HIM & Uni Mainz - yuhzhang@uni-mainz.de
|
|
35
|
+
|
|
36
|
+
📖 Documentation: [axionbloch.readthedocs.io](https://axionbloch.readthedocs.io/en/latest/)
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
In AxionBloch, the axion (including axionlike-particle or ALP) field acts like a **pseudomagnetic field** coupling to (nuclear) spins.
|
|
41
|
+
|
|
42
|
+
The package provides a **numerical platform** to study these subtle effects using Bloch-equation-based simulations.
|
|
43
|
+
|
|
44
|
+
## Requirements
|
|
45
|
+
|
|
46
|
+
- Python >= 3.10
|
|
47
|
+
|
|
48
|
+
### Dependencies
|
|
49
|
+
|
|
50
|
+
- **numpy** — Numerical computing
|
|
51
|
+
- **scipy** — Scientific computing and numerical integration
|
|
52
|
+
- **matplotlib** — Plotting and visualization
|
|
53
|
+
- **astropy** — Astronomical utilities
|
|
54
|
+
- **h5py** — HDF5 file I/O
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
Install from [PyPI](https://pypi.org/project/axionbloch/):
|
|
59
|
+
```bash
|
|
60
|
+
pip install axionbloch
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Or build and install from source (requires a C++17 compiler for the simulation extension):
|
|
64
|
+
```bash
|
|
65
|
+
git clone https://github.com/Yuzhe98/AxionBloch.git
|
|
66
|
+
cd AxionBloch
|
|
67
|
+
pip install .
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Quick Start
|
|
71
|
+
Examples can be found in the examples/.
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# AxionBloch
|
|
2
|
+
A package for simulating **axion**-induced spin dynamics based on **Bloch equations**, implemented in **Python** and **C++**.
|
|
3
|
+
|
|
4
|
+
Yuzhe Zhang - GSI HIM & Uni Mainz - yuhzhang@uni-mainz.de
|
|
5
|
+
|
|
6
|
+
📖 Documentation: [axionbloch.readthedocs.io](https://axionbloch.readthedocs.io/en/latest/)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
In AxionBloch, the axion (including axionlike-particle or ALP) field acts like a **pseudomagnetic field** coupling to (nuclear) spins.
|
|
11
|
+
|
|
12
|
+
The package provides a **numerical platform** to study these subtle effects using Bloch-equation-based simulations.
|
|
13
|
+
|
|
14
|
+
## Requirements
|
|
15
|
+
|
|
16
|
+
- Python >= 3.10
|
|
17
|
+
|
|
18
|
+
### Dependencies
|
|
19
|
+
|
|
20
|
+
- **numpy** — Numerical computing
|
|
21
|
+
- **scipy** — Scientific computing and numerical integration
|
|
22
|
+
- **matplotlib** — Plotting and visualization
|
|
23
|
+
- **astropy** — Astronomical utilities
|
|
24
|
+
- **h5py** — HDF5 file I/O
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
Install from [PyPI](https://pypi.org/project/axionbloch/):
|
|
29
|
+
```bash
|
|
30
|
+
pip install axionbloch
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or build and install from source (requires a C++17 compiler for the simulation extension):
|
|
34
|
+
```bash
|
|
35
|
+
git clone https://github.com/Yuzhe98/AxionBloch.git
|
|
36
|
+
cd AxionBloch
|
|
37
|
+
pip install .
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
Examples can be found in the examples/.
|
|
42
|
+
|
|
43
|
+
## License
|
|
44
|
+
Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
from functools import partial
|
|
2
|
+
|
|
3
|
+
from axionbloch.dependency import *
|
|
4
|
+
from axionbloch.utils import Lorentzian_0edge
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Magnet:
|
|
8
|
+
"""DC magnetic field apparatus.
|
|
9
|
+
|
|
10
|
+
Models a static polarising magnet whose field may be spatially inhomogeneous.
|
|
11
|
+
Inhomogeneity is characterised by a Lorentzian lineshape with a given FWHM,
|
|
12
|
+
and the field distribution is discretised into ``numPt`` spin packets for
|
|
13
|
+
simulation.
|
|
14
|
+
|
|
15
|
+
Attributes
|
|
16
|
+
----------
|
|
17
|
+
name : str
|
|
18
|
+
B0 : astropy Quantity
|
|
19
|
+
Nominal field strength.
|
|
20
|
+
direction : list or None
|
|
21
|
+
Unit vector along B0 (laboratory frame).
|
|
22
|
+
FWHM : astropy Quantity
|
|
23
|
+
Fractional field inhomogeneity (dimensionless, e.g. ppm).
|
|
24
|
+
B_spread : ndarray
|
|
25
|
+
Sampled B0 values for each spin packet.
|
|
26
|
+
ratios : ndarray
|
|
27
|
+
Fractional weight of each spin packet (sums to 1).
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
name: str
|
|
31
|
+
B0: Quantity | None = None
|
|
32
|
+
direction: list | None = None
|
|
33
|
+
FWHM: Quantity | None = None
|
|
34
|
+
numPt: float = 1
|
|
35
|
+
nFWHM: float = 10.0
|
|
36
|
+
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
name="magnet",
|
|
40
|
+
B0: Quantity[unit.T] | None = None,
|
|
41
|
+
direction: list | None = None,
|
|
42
|
+
FWHM: Quantity[ppm] | None = None,
|
|
43
|
+
numPt: float = 1,
|
|
44
|
+
nFWHM: float = 10.0,
|
|
45
|
+
verbose: bool = False,
|
|
46
|
+
):
|
|
47
|
+
"""
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
name : str
|
|
51
|
+
Human-readable label for this magnet.
|
|
52
|
+
B0 : Quantity
|
|
53
|
+
Nominal DC field strength (e.g. ``0.1 * unit.T``).
|
|
54
|
+
direction : list, optional
|
|
55
|
+
Unit vector specifying the field orientation in the lab frame.
|
|
56
|
+
FWHM : Quantity
|
|
57
|
+
Fractional full-width at half-maximum of the field inhomogeneity
|
|
58
|
+
(dimensionless, e.g. ``1e-6 * unit.one`` for 1 ppm).
|
|
59
|
+
numPt : int
|
|
60
|
+
Number of discrete spin packets used to model field inhomogeneity.
|
|
61
|
+
``numPt=1`` treats the field as perfectly homogeneous.
|
|
62
|
+
nFWHM : float
|
|
63
|
+
Half-range of the field spread expressed in units of FWHM.
|
|
64
|
+
verbose : bool
|
|
65
|
+
Print diagnostic information.
|
|
66
|
+
"""
|
|
67
|
+
logPrefix = f"[{self.__class__.__name__}.{self.__init__.__name__}]"
|
|
68
|
+
self.name = name
|
|
69
|
+
assert nFWHM >= 0
|
|
70
|
+
self.nFWHM = nFWHM
|
|
71
|
+
if B0 is None or FWHM is None:
|
|
72
|
+
raise ValueError(logPrefix + " B0 and FWHM must be provided")
|
|
73
|
+
|
|
74
|
+
self.B0 = B0
|
|
75
|
+
self.direction = direction
|
|
76
|
+
self.FWHM = FWHM
|
|
77
|
+
self.B0_nW = self.nFWHM * self.FWHM * self.B0
|
|
78
|
+
self.numPt = numPt
|
|
79
|
+
self.FWHM_B0 = (self.B0 * self.FWHM).to(unit.T)
|
|
80
|
+
self.B_spread = np.ones(1) * self.B0
|
|
81
|
+
self.ratios = np.ones(1)
|
|
82
|
+
self.setHomogeneity(verbose=verbose)
|
|
83
|
+
|
|
84
|
+
def setHomogeneity(
|
|
85
|
+
self,
|
|
86
|
+
# lineshape:str = "Lorentizan",
|
|
87
|
+
numPt: int | float = None,
|
|
88
|
+
showPlot: bool = False,
|
|
89
|
+
verbose: bool = False,
|
|
90
|
+
):
|
|
91
|
+
"""Set the spin-packet sampling of the field inhomogeneity.
|
|
92
|
+
|
|
93
|
+
Discretises a Lorentzian field distribution into ``numPt`` spin packets
|
|
94
|
+
using a non-uniform sampling scheme (density proportional to
|
|
95
|
+
``|x|^(1/2)`` in normalized coordinates) to oversample the peak region.
|
|
96
|
+
Each packet is assigned a weight ``ratio`` equal to its fraction of the
|
|
97
|
+
total Lorentzian area so that weighted averages reproduce the continuous
|
|
98
|
+
lineshape.
|
|
99
|
+
|
|
100
|
+
For ``numPt == 1`` or zero FWHM the field is treated as homogeneous and
|
|
101
|
+
a single packet at ``B0`` with weight 1 is used.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
numPt : int or float, optional
|
|
106
|
+
Override the stored ``self.numPt``.
|
|
107
|
+
showPlot : bool
|
|
108
|
+
Display diagnostic histograms of the sampled B values and weights.
|
|
109
|
+
verbose : bool
|
|
110
|
+
Print diagnostic information.
|
|
111
|
+
"""
|
|
112
|
+
logPrefix = f"[{self.__class__.__name__}.{self.setHomogeneity.__name__}]"
|
|
113
|
+
# update self.numPt if it is None
|
|
114
|
+
if numPt is not None:
|
|
115
|
+
self.numPt = max(1, int(numPt))
|
|
116
|
+
elif self.numPt is None:
|
|
117
|
+
self.numPt = 1
|
|
118
|
+
if verbose:
|
|
119
|
+
print(logPrefix, f"numPt = {numPt}")
|
|
120
|
+
print(logPrefix, f"self.numPt = {self.numPt}")
|
|
121
|
+
# homogeneous field
|
|
122
|
+
if self.numPt == 1 or self.FWHM_B0 == 0.0 or self.nFWHM == 0:
|
|
123
|
+
self.B_spread = np.ones(1) * self.B0
|
|
124
|
+
self.ratios = np.ones(1)
|
|
125
|
+
# inhomogeneous field
|
|
126
|
+
else:
|
|
127
|
+
pdf = partial(
|
|
128
|
+
Lorentzian_0edge,
|
|
129
|
+
center=self.B0,
|
|
130
|
+
FWHM=self.FWHM_B0,
|
|
131
|
+
area=1,
|
|
132
|
+
offset=0,
|
|
133
|
+
)
|
|
134
|
+
if verbose:
|
|
135
|
+
print(logPrefix, f"inhomogeneous field. self.numPt = {self.numPt}")
|
|
136
|
+
# uniform sampling over [-1, 1]
|
|
137
|
+
uni_samp = np.linspace(start=-1, stop=1, num=self.numPt, endpoint=True)
|
|
138
|
+
# transform uniform sampling to the desired distribution
|
|
139
|
+
self.B_spread = (
|
|
140
|
+
self.nFWHM * np.sign(uni_samp) * np.abs(uni_samp) ** 2
|
|
141
|
+
) * self.FWHM_B0 + self.B0
|
|
142
|
+
if verbose:
|
|
143
|
+
print(logPrefix, f"B_spread.shape = {self.B_spread.shape}")
|
|
144
|
+
print(
|
|
145
|
+
f"{logPrefix} B_spread: {len(self.B_spread)} points "
|
|
146
|
+
f"range=[{self.B_spread.min():.6g}, {self.B_spread.max():.6g}]"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
if showPlot:
|
|
150
|
+
fig = plt.figure(
|
|
151
|
+
figsize=(8.5 / 2.54, 6.5 / 2.54), dpi=300
|
|
152
|
+
) # initialize a figure
|
|
153
|
+
gs = gridspec.GridSpec(
|
|
154
|
+
nrows=1, ncols=1
|
|
155
|
+
) # create grid for multiple figures
|
|
156
|
+
ax = fig.add_subplot(gs[0, 0])
|
|
157
|
+
hist, bin_edges = np.histogram(self.B_spread, bins=30)
|
|
158
|
+
ax.plot(
|
|
159
|
+
(bin_edges[1:] - self.B0) / self.FWHM_B0,
|
|
160
|
+
hist,
|
|
161
|
+
label="",
|
|
162
|
+
marker="o",
|
|
163
|
+
color="goldenrod",
|
|
164
|
+
markeredgecolor="darkgoldenrod",
|
|
165
|
+
)
|
|
166
|
+
ax.set_xlabel("Magnetic field - $B_0$ (FWHM)")
|
|
167
|
+
ax.set_ylabel("Number of sampling points")
|
|
168
|
+
ax.set_title(
|
|
169
|
+
"Histogram of number of sampling \nover magnetic field spread"
|
|
170
|
+
)
|
|
171
|
+
plt.tight_layout()
|
|
172
|
+
# plt.savefig('example figure - one-column.png', transparent=False)
|
|
173
|
+
plt.show()
|
|
174
|
+
|
|
175
|
+
# Define interval edges
|
|
176
|
+
edges = np.zeros(len(self.B_spread) + 1) * self.B_spread[0].unit
|
|
177
|
+
edges[1:-1] = (self.B_spread[:-1] + self.B_spread[1:]) / 2
|
|
178
|
+
edges[0] = self.B_spread[0] - abs(edges[2] - edges[1]) / 2
|
|
179
|
+
edges[-1] = self.B_spread[-1] + abs(edges[-2] - edges[-3]) / 2
|
|
180
|
+
|
|
181
|
+
self.ratios = np.zeros(self.B_spread.shape)
|
|
182
|
+
for i in range(len(self.B_spread)):
|
|
183
|
+
a, b = edges[i], edges[i + 1]
|
|
184
|
+
x = np.linspace(a, b, 32)
|
|
185
|
+
self.ratios[i] = np.trapezoid(pdf(x), x)
|
|
186
|
+
# high-frequency spins can create wiggles in the magnetization signal
|
|
187
|
+
# to suppress wiggles, add hamming window to decrease the ratio of high-frequency spins
|
|
188
|
+
# this is not ideal or physical. However, in simulations, we cannot use extremely large nFWHM
|
|
189
|
+
# to account for the real magnetic field distribution. We truncate at edges, instead.
|
|
190
|
+
self.ratios *= np.hamming(len(self.ratios)) ** 2
|
|
191
|
+
# normalize ratios to sum to 1
|
|
192
|
+
self.ratios /= np.sum(self.ratios)
|
|
193
|
+
|
|
194
|
+
if verbose:
|
|
195
|
+
print(
|
|
196
|
+
f"{logPrefix} ratios computed sum={self.ratios.sum():.6g} "
|
|
197
|
+
f"min={self.ratios.min():.4g} max={self.ratios.max():.4g}"
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
if showPlot:
|
|
201
|
+
fig = plt.figure(figsize=(8.5 / 2.54, 6.5 / 2.54), dpi=300)
|
|
202
|
+
gs = gridspec.GridSpec(
|
|
203
|
+
nrows=1, ncols=1
|
|
204
|
+
) # create grid for multiple figures
|
|
205
|
+
ax = fig.add_subplot(gs[0, 0])
|
|
206
|
+
ax.plot(
|
|
207
|
+
(self.B_spread - self.B0) / self.FWHM_B0,
|
|
208
|
+
self.ratios,
|
|
209
|
+
label="",
|
|
210
|
+
marker="o",
|
|
211
|
+
)
|
|
212
|
+
ax.set_xlabel("Magnetic field - $B_0$ (FWHM)")
|
|
213
|
+
ax.set_ylabel("")
|
|
214
|
+
ax.set_title(
|
|
215
|
+
"Histogram of spin packet ratio over magnetic field spread"
|
|
216
|
+
)
|
|
217
|
+
plt.tight_layout()
|
|
218
|
+
plt.show()
|
|
219
|
+
|
|
220
|
+
if verbose:
|
|
221
|
+
print(logPrefix, f"self.ratios normalized sum={self.ratios.sum():g}")
|