qthermo 0.6.0__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.
- qthermo-0.6.0/LICENSE +7 -0
- qthermo-0.6.0/PKG-INFO +487 -0
- qthermo-0.6.0/README.md +455 -0
- qthermo-0.6.0/pyproject.toml +42 -0
- qthermo-0.6.0/qthermo/__init__.py +179 -0
- qthermo-0.6.0/qthermo/_benchmark_suite.py +537 -0
- qthermo-0.6.0/qthermo/analysis.py +353 -0
- qthermo-0.6.0/qthermo/audit.py +317 -0
- qthermo-0.6.0/qthermo/baths.py +494 -0
- qthermo-0.6.0/qthermo/batteries.py +314 -0
- qthermo-0.6.0/qthermo/benchmarks.py +157 -0
- qthermo-0.6.0/qthermo/channels.py +78 -0
- qthermo-0.6.0/qthermo/core.py +155 -0
- qthermo-0.6.0/qthermo/counting.py +240 -0
- qthermo-0.6.0/qthermo/cycle.py +319 -0
- qthermo-0.6.0/qthermo/engines.py +273 -0
- qthermo-0.6.0/qthermo/explorer.py +312 -0
- qthermo-0.6.0/qthermo/export.py +126 -0
- qthermo-0.6.0/qthermo/floquet.py +242 -0
- qthermo-0.6.0/qthermo/fluctuations.py +305 -0
- qthermo-0.6.0/qthermo/geometry.py +172 -0
- qthermo-0.6.0/qthermo/information.py +383 -0
- qthermo-0.6.0/qthermo/models.py +462 -0
- qthermo-0.6.0/qthermo/modes.py +78 -0
- qthermo-0.6.0/qthermo/network.py +354 -0
- qthermo-0.6.0/qthermo/papers.py +225 -0
- qthermo-0.6.0/qthermo/plotting.py +629 -0
- qthermo-0.6.0/qthermo/report.py +145 -0
- qthermo-0.6.0/qthermo/response.py +154 -0
- qthermo-0.6.0/qthermo/solver.py +134 -0
- qthermo-0.6.0/qthermo/steady.py +653 -0
- qthermo-0.6.0/qthermo/stochastic.py +361 -0
- qthermo-0.6.0/qthermo/strong_coupling.py +211 -0
- qthermo-0.6.0/qthermo/subsystems.py +385 -0
- qthermo-0.6.0/qthermo/transient.py +137 -0
- qthermo-0.6.0/qthermo/units.py +88 -0
- qthermo-0.6.0/qthermo/validation.py +106 -0
- qthermo-0.6.0/qthermo.egg-info/PKG-INFO +487 -0
- qthermo-0.6.0/qthermo.egg-info/SOURCES.txt +66 -0
- qthermo-0.6.0/qthermo.egg-info/dependency_links.txt +1 -0
- qthermo-0.6.0/qthermo.egg-info/requires.txt +12 -0
- qthermo-0.6.0/qthermo.egg-info/top_level.txt +1 -0
- qthermo-0.6.0/setup.cfg +4 -0
- qthermo-0.6.0/tests/test_audit.py +59 -0
- qthermo-0.6.0/tests/test_batteries.py +91 -0
- qthermo-0.6.0/tests/test_counting.py +94 -0
- qthermo-0.6.0/tests/test_docs.py +23 -0
- qthermo-0.6.0/tests/test_engines.py +138 -0
- qthermo-0.6.0/tests/test_explorer.py +28 -0
- qthermo-0.6.0/tests/test_export.py +41 -0
- qthermo-0.6.0/tests/test_floquet.py +80 -0
- qthermo-0.6.0/tests/test_fluctuations.py +126 -0
- qthermo-0.6.0/tests/test_geometry.py +60 -0
- qthermo-0.6.0/tests/test_information.py +145 -0
- qthermo-0.6.0/tests/test_invariants.py +138 -0
- qthermo-0.6.0/tests/test_modes.py +63 -0
- qthermo-0.6.0/tests/test_network.py +143 -0
- qthermo-0.6.0/tests/test_papers.py +65 -0
- qthermo-0.6.0/tests/test_physics.py +284 -0
- qthermo-0.6.0/tests/test_qutip.py +45 -0
- qthermo-0.6.0/tests/test_readme.py +28 -0
- qthermo-0.6.0/tests/test_report.py +21 -0
- qthermo-0.6.0/tests/test_response.py +45 -0
- qthermo-0.6.0/tests/test_steady.py +269 -0
- qthermo-0.6.0/tests/test_strong_coupling.py +81 -0
- qthermo-0.6.0/tests/test_subsystems.py +263 -0
- qthermo-0.6.0/tests/test_transient.py +46 -0
- qthermo-0.6.0/tests/test_units.py +33 -0
qthermo-0.6.0/LICENSE
ADDED
qthermo-0.6.0/PKG-INFO
ADDED
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: qthermo
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: Heat, work and entropy for open quantum systems, with the modelling traps checked and published results reproduced
|
|
5
|
+
Author: Vivek Khanna
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/VivekKhanna0/Qthermo
|
|
8
|
+
Project-URL: Documentation, https://github.com/VivekKhanna0/Qthermo/blob/main/docs/api.md
|
|
9
|
+
Project-URL: Changelog, https://github.com/VivekKhanna0/Qthermo/blob/main/CHANGELOG.md
|
|
10
|
+
Project-URL: Issues, https://github.com/VivekKhanna0/Qthermo/issues
|
|
11
|
+
Keywords: quantum thermodynamics,open quantum systems,master equation,Lindblad,heat engines,quantum refrigerators,physics
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: numpy>=1.23
|
|
23
|
+
Requires-Dist: scipy>=1.9
|
|
24
|
+
Provides-Extra: qutip
|
|
25
|
+
Requires-Dist: qutip>=4.7; extra == "qutip"
|
|
26
|
+
Provides-Extra: plot
|
|
27
|
+
Requires-Dist: matplotlib>=3.5; extra == "plot"
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
30
|
+
Requires-Dist: matplotlib>=3.5; extra == "dev"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# qthermo
|
|
34
|
+
|
|
35
|
+
Thermodynamic bookkeeping for open quantum systems — heat, work, entropy
|
|
36
|
+
production, currents and their fluctuations — with the modelling traps checked
|
|
37
|
+
for you.
|
|
38
|
+
|
|
39
|
+
You write down a Hamiltonian and the baths. `qthermo` gives you per-bath heat
|
|
40
|
+
currents, entropy production, efficiencies against their Carnot bounds,
|
|
41
|
+
site-resolved energy flows, exact current fluctuations and uncertainty-relation
|
|
42
|
+
ratios, for stroke machines and continuous machines, from one qubit to a few
|
|
43
|
+
hundred levels. It also tells you when the model you wrote down cannot mean
|
|
44
|
+
what you think it means.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install "qthermo[plot]" # numpy, scipy, matplotlib
|
|
48
|
+
python -m qthermo.benchmarks # 44 checks against published results, ~40 s
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For the latest version, `pip install "qthermo[plot] @ git+https://github.com/VivekKhanna0/Qthermo"`.
|
|
52
|
+
To run the examples and tests, `git clone` the repository and
|
|
53
|
+
`pip install -e ".[dev]"`.
|
|
54
|
+
|
|
55
|
+
**Highlights**, each reproduced by the package and checked in CI:
|
|
56
|
+
|
|
57
|
+
- Local master equations can make heat flow from cold to hot. `qthermo`
|
|
58
|
+
detects it and runs the same machine under global baths in one call.
|
|
59
|
+
- The three-qubit absorption fridge hits COP = ω_c/ω_h to 1e-15, and its
|
|
60
|
+
target qubit transiently cools *below* its steady state.
|
|
61
|
+
- The coherently driven maser beats the classical thermodynamic uncertainty
|
|
62
|
+
relation (exact current noise, no sampling).
|
|
63
|
+
- Optimal finite-time protocols for *any* drive: simulations land on the
|
|
64
|
+
predicted minimum L²/τ to 0.2%.
|
|
65
|
+
- A quantum Szilard engine attains the Sagawa–Ueda bound exactly, and a
|
|
66
|
+
zz-coupled transistor amplifies heat currents 4.8×.
|
|
67
|
+
- Which master equation is right? For coupled oscillators, where the exact
|
|
68
|
+
answer is known, the global equation is off by 25× at weak coupling and the
|
|
69
|
+
local one by 10% when detuned. The Redfield bath matches exact to 0.1% in
|
|
70
|
+
both regimes.
|
|
71
|
+
- Agrees with QuTiP to 1e-16 (steady states) and 1e-10 (dynamics).
|
|
72
|
+
|
|
73
|
+
**New here?** [`examples/tutorial.ipynb`](https://github.com/VivekKhanna0/Qthermo/blob/main/examples/tutorial.ipynb) takes one
|
|
74
|
+
research question (a two-qubit thermal diode) from a Hamiltonian to publishable
|
|
75
|
+
numbers, including the checks a referee would ask about. It renders on GitHub
|
|
76
|
+
with all outputs.
|
|
77
|
+
|
|
78
|
+
**Docs:** [physics definitions](https://github.com/VivekKhanna0/Qthermo/blob/main/docs/physics.md) · [API reference](https://github.com/VivekKhanna0/Qthermo/blob/main/docs/api.md) ·
|
|
79
|
+
[figure gallery](https://github.com/VivekKhanna0/Qthermo/blob/main/docs/gallery.md) · [examples](https://github.com/VivekKhanna0/Qthermo/blob/main/examples/README.md) ·
|
|
80
|
+
[changelog](https://github.com/VivekKhanna0/Qthermo/blob/main/CHANGELOG.md)
|
|
81
|
+
|
|
82
|
+
## Reproduce a paper in 10 lines
|
|
83
|
+
|
|
84
|
+
A question papers in this field argue about: the *local* and *global* master
|
|
85
|
+
equations give different heat currents, so which one is right? For two
|
|
86
|
+
coupled oscillators the exact answer is known, so each can be graded:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
import qthermo as qt
|
|
90
|
+
|
|
91
|
+
r = qt.papers.local_vs_global(detuning=0.1) # Hofer et al., NJP 19, 123037 (2017)
|
|
92
|
+
print(r.report())
|
|
93
|
+
r.plot()
|
|
94
|
+
```
|
|
95
|
+
```
|
|
96
|
+
local: worst error 10.3%
|
|
97
|
+
global: worst error 4.0%
|
|
98
|
+
redfield: worst error 0.0%
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
<img src="https://raw.githubusercontent.com/VivekKhanna0/Qthermo/main/examples/figures/local_vs_global_exact.png" width="720" alt="local, global and Redfield heat currents against the exact result">
|
|
102
|
+
|
|
103
|
+
Each standard approximation fails somewhere (top: global, for resonant
|
|
104
|
+
oscillators at weak coupling; bottom: local, for detuned ones). The Redfield
|
|
105
|
+
bath (`qt.redfield_bath`) is right in both cases. The same three baths work on
|
|
106
|
+
any Hamiltonian you write down, so you can run this check on your own model:
|
|
107
|
+
see [Your own model](#your-own-model). The script that draws this figure is
|
|
108
|
+
[`examples/reproduce_local_vs_global.py`](https://github.com/VivekKhanna0/Qthermo/blob/main/examples/reproduce_local_vs_global.py).
|
|
109
|
+
|
|
110
|
+
## Thirty seconds
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
import qthermo as qt
|
|
114
|
+
|
|
115
|
+
fridge = qt.models.absorption_refrigerator(T_c=1.0, T_h=6.0, T_r=1.5)
|
|
116
|
+
steady = fridge.analyze()
|
|
117
|
+
print(steady.report())
|
|
118
|
+
```
|
|
119
|
+
```
|
|
120
|
+
bath T J (into system) -J/T
|
|
121
|
+
-------------------------------------------------------
|
|
122
|
+
cold 1 6.963227e-04 -6.9632e-04
|
|
123
|
+
hot 6 2.088968e-03 -3.4816e-04
|
|
124
|
+
room 1.5 -2.785291e-03 1.8569e-03
|
|
125
|
+
-------------------------------------------------------
|
|
126
|
+
sum 1.301e-18 8.1238e-04
|
|
127
|
+
entropy production rate: 8.1238e-04
|
|
128
|
+
note: local baths -- valid only for inter-site coupling << bath rates; compare with global baths
|
|
129
|
+
```
|
|
130
|
+
```python
|
|
131
|
+
steady.cop("cold", "hot") # 0.3333 = w_c / w_h exactly
|
|
132
|
+
steady.absorption_carnot_cop("cold", "hot", "room") # 1.5
|
|
133
|
+
print(fridge.compare().report()) # would "you used a local master equation" change anything?
|
|
134
|
+
```
|
|
135
|
+
```
|
|
136
|
+
bath J local J global rel. diff
|
|
137
|
+
------------------------------------------------------
|
|
138
|
+
cold 6.96323e-04 7.53796e-04 7.62%
|
|
139
|
+
hot 2.08897e-03 2.27304e-03 8.10%
|
|
140
|
+
room -2.78529e-03 -3.02684e-03 7.98%
|
|
141
|
+
------------------------------------------------------
|
|
142
|
+
entropy production rate: local 8.1238e-04, global 8.8526e-04
|
|
143
|
+
steady-state trace distance: 1.040e-02
|
|
144
|
+
```
|
|
145
|
+
```python
|
|
146
|
+
qt.plot_machine(steady) # the figure below
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
<img src="https://raw.githubusercontent.com/VivekKhanna0/Qthermo/main/examples/figures/absorption_fridge.png" width="620" alt="heat-flow network of the absorption refrigerator">
|
|
150
|
+
|
|
151
|
+
Baths (squares) and qubits (circles) share one temperature colour scale; each
|
|
152
|
+
qubit is coloured by its **virtual temperature**. The cold qubit is colder
|
|
153
|
+
than every bath, which nothing passive can do. Arrow widths are heat
|
|
154
|
+
currents, and the internal balances close to ~1e-17.
|
|
155
|
+
|
|
156
|
+
## Your own model
|
|
157
|
+
|
|
158
|
+
Nothing above is special-cased. Describe the sites, the couplings and which
|
|
159
|
+
bath touches which site:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
machine = qt.build_model(
|
|
163
|
+
local_H=[qt.qubit_hamiltonian(1.0), qt.qubit_hamiltonian(0.6)],
|
|
164
|
+
interactions={(0, 1): (0.3 * qt.sigma_x, qt.sigma_x)}, # 0.3 sx (x) sx
|
|
165
|
+
baths=[dict(name="hot", site=0, coupling=qt.sigma_x, T=2.0, gamma=0.1),
|
|
166
|
+
dict(name="cold", site=1, coupling=qt.sigma_x, T=1.0, gamma=0.1)],
|
|
167
|
+
master_equation="global")
|
|
168
|
+
|
|
169
|
+
steady = machine.analyze() # exact steady state, per-bath currents
|
|
170
|
+
print(qt.audit(machine)) # every consistency check
|
|
171
|
+
machine.compare() # the same machine under local baths
|
|
172
|
+
qt.current_statistics(machine, "hot") # exact noise, TUR / KUR ratios
|
|
173
|
+
qt.plot_machine(steady) # heat-flow network, virtual temperatures
|
|
174
|
+
qt.report(machine, "machine.html") # all of it in one shareable page
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Sites can have any dimension, and interactions can be given as full matrices.
|
|
178
|
+
For full control, build the baths yourself:
|
|
179
|
+
`qt.davies_bath(H, coupling, T)` gives the *global* (secular,
|
|
180
|
+
detailed-balance) bath for any Hamiltonian, coupled, degenerate or many-body,
|
|
181
|
+
and `qt.local_bath` gives the local one. `qt.analyze(H, baths)` takes any list
|
|
182
|
+
of them. QuTiP `Qobj`s are accepted anywhere an array is.
|
|
183
|
+
|
|
184
|
+
## I want to...
|
|
185
|
+
|
|
186
|
+
| ...do this | call |
|
|
187
|
+
|---|---|
|
|
188
|
+
| get currents, entropy production, COP/efficiency of a continuous machine | `qt.analyze(H, baths)` or `model.analyze()` |
|
|
189
|
+
| check my model for known modelling mistakes | `qt.audit(model)` or `qt.audit(H, baths)` |
|
|
190
|
+
| describe my own machine once and get every tool | `qt.build_model(local_H, interactions, baths)` |
|
|
191
|
+
| check which master equation is right for my model | `model.rebuild("redfield").analyze()` against `model.compare()`; see `qt.papers.local_vs_global()` |
|
|
192
|
+
| build baths for a coupled / many-body system | `qt.davies_bath` (global), `qt.local_bath` (local) |
|
|
193
|
+
| know whether local vs global master equations matter | `model.compare()` |
|
|
194
|
+
| see where heat flows inside a multi-qubit machine | `qt.heat_flow_map(steady)`, `qt.plot_machine(steady)` |
|
|
195
|
+
| follow each qubit (energy, T*, entanglement) through a cycle | `qt.site_dynamics(result, dims, local_H)`, `qt.plot_site_dynamics` |
|
|
196
|
+
| get the noise of a current and the TUR/KUR ratios | `qt.current_statistics(model, "bath")` |
|
|
197
|
+
| simulate a stroke cycle and its limit cycle | `qt.Cycle([qt.Stroke(...), ...]).limit_cycle(rho0)` |
|
|
198
|
+
| know the quasi-static limit of an interacting Otto engine | `qt.ideal_otto(H_c, H_h, T_c, T_h)` |
|
|
199
|
+
| get the exact heat distribution of one cycle | `qt.cycle_counting(cycle, {"stroke": "quanta"})` |
|
|
200
|
+
| map engine / fridge / heater / accelerator regions | `qt.mode_map(build, xs, ys)`, `qt.plot_mode_map` |
|
|
201
|
+
| scan any machine over parameters | `qt.sweep`, `qt.scan_2d`, `qt.pareto_front` |
|
|
202
|
+
| go beyond weak coupling | `qt.reaction_coordinate_model`, `qt.rc_convergence` |
|
|
203
|
+
| cost of erasure and the optimal protocol | `qt.landauer_erasure`, `qt.geodesic_schedule` |
|
|
204
|
+
| work from information (measurement + feedback) | `qt.szilard_engine(T, error=..., tau=...)` |
|
|
205
|
+
| the least-dissipative schedule for *my* drive | `qt.optimal_schedule(H_of, baths_of, T, path)` |
|
|
206
|
+
| a machine powered by a periodic drive | `qt.floquet_analyze(H_of_t, period, [qt.DrivenBath(...)])` |
|
|
207
|
+
| what happens after switching a machine on | `qt.transient(model, rho0, duration)` |
|
|
208
|
+
| conductance matrix, Onsager check, transistor gain | `qt.response(build, {bath: T})` |
|
|
209
|
+
| analyse a quantum battery | `qt.batteries.ergotropy_split`, `locked_ergotropy`, `dicke_battery` |
|
|
210
|
+
| use lab numbers (GHz, mK, µs, W) | `lab = qt.LabUnits(5.0)`; `lab.temperature(20)`, `lab.rate(1/T1)`, `lab.to_watts(J)` |
|
|
211
|
+
| save results with provenance | `qt.save(result, "file.json")` |
|
|
212
|
+
| send a colleague the result *and* the checks | `qt.report(model, "machine.html")`, a single self-contained page |
|
|
213
|
+
| an interactive page with a parameter slider | `qt.explorer(build, values, path="x.html")` |
|
|
214
|
+
| confirm the package is right | `python -m qthermo.benchmarks` |
|
|
215
|
+
|
|
216
|
+
## What it catches
|
|
217
|
+
|
|
218
|
+
Most of the value is here. Each of these is a mistake that produces a plausible
|
|
219
|
+
number with no error message, and each is detected and explained. `qt.audit`
|
|
220
|
+
runs every check in one call:
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
print(qt.audit(qt.models.two_qubit_heat_valve(master_equation="local")))
|
|
224
|
+
```
|
|
225
|
+
```
|
|
226
|
+
[ERROR] local vs global: the two master equations disagree on the direction of heat flow for hot, cold
|
|
227
|
+
Inter-site coupling is too strong for the local approximation. Use the
|
|
228
|
+
global model.
|
|
229
|
+
[info] relaxation time: 2.72 (populations)
|
|
230
|
+
[ok] steady state: unique
|
|
231
|
+
[ok] second law: entropy production rate 1.937e-02 >= 0
|
|
232
|
+
[ok] internal currents: site energy balances close to 3.5e-17
|
|
233
|
+
[ok] uncertainty relation: 'hot': TUR ratio 9.626 >= 2
|
|
234
|
+
[ok] uncertainty relation: 'cold': TUR ratio 5.117 >= 2
|
|
235
|
+
------------------------------------------------------------
|
|
236
|
+
1 error(s), 0 warning(s), 6 other checks
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
| Trap | What happens | What `qthermo` does |
|
|
240
|
+
|---|---|---|
|
|
241
|
+
| Local master equation on coupled sites | Heat can flow cold → hot; σ < 0 (Levy & Kosloff 2014) | Warns on σ < 0; `model.compare()` runs local vs global side by side; bare-Hamiltonian accounting with explicit boundary work (De Chiara et al. 2018) |
|
|
242
|
+
| Non-unique steady state | Identical qubits on one bath, dark states, conserved quantities: "the" steady state doesn't exist | Detected from the conditioning of the linear solve; raises unless you give an initial state, then returns the state it actually relaxes to |
|
|
243
|
+
| Baths that respect a symmetry of H | e.g. σx couplings on an Ising medium conserve parity; isochores never thermalise and the "efficiency" describes a different machine | `otto_cycle` refuses and says which symmetry-breaking coupling to use |
|
|
244
|
+
| Level crossings in an interacting Otto engine | Energy-rank pairing of levels gives the wrong quasi-static cycle | `ideal_otto` follows adiabatic continuation along the actual drive |
|
|
245
|
+
| Degenerate levels + flat spectral density | The zero-frequency channel has an undefined rate; thermalisation silently takes 1000× longer | Warns; `relaxation_time()` exposes the time scale; `otto_cycle` checks τ_iso against it |
|
|
246
|
+
| Global ME and local currents | The secular steady state is diagonal in H, so every bond current i⟨[V,h_i]⟩ is identically zero | `heat_flow_map` says so instead of printing zeros |
|
|
247
|
+
| Reaction-coordinate truncation | Strong coupling displaces the RC; too few levels gives unconverged currents | `rc_convergence()` reports the change between truncations |
|
|
248
|
+
| Temperature inconsistent with the channel | σ < 0 from a mislabelled bath | Warning naming the likely cause |
|
|
249
|
+
| Bath temperature inconsistent with its rates | A bath labelled T=2 whose jump rates encode T=3 gives a meaningless σ | `audit` infers the detailed-balance temperature from the jump operators and compares |
|
|
250
|
+
| Invalid input | Non-Hermitian H, unnormalised ρ, wrong dimensions | `QThermoError` naming the violated requirement, never a LinAlg traceback |
|
|
251
|
+
|
|
252
|
+
## What it does
|
|
253
|
+
|
|
254
|
+
| Area | Entry points | Validated against |
|
|
255
|
+
|---|---|---|
|
|
256
|
+
| **Stroke machines** (Otto, arbitrary cycles) | `Stroke`, `Cycle`, `limit_cycle` | Otto COP/efficiency limits; first law to 1e-16 by construction |
|
|
257
|
+
| **Interacting working media** | `ideal_otto`, `otto_cycle`, `resolve_stroke` | Exact quasi-static limit (simulation agrees to 1e-8); coupling-enhanced efficiency (Thomas & Johal 2011) |
|
|
258
|
+
| **Continuous machines** | `analyze`, `steady_state`, `models.*` | LPS fridge COP = ω_c/ω_h exactly; SSDB maser η = 1 − ω_c/ω_h; Carnot bounds |
|
|
259
|
+
| **Bath models** | `davies_bath`, `local_bath`, `instantaneous_bath` | Gibbs fixed point for random H to 1e-16; Levy–Kosloff violation reproduced and resolved |
|
|
260
|
+
| **Where the heat goes** | `heat_flow_map`, `plot_machine`, virtual temperatures, concurrence, negativity | Site balances close to 1e-17; Werner-state entanglement threshold |
|
|
261
|
+
| **Fluctuations** | `current_statistics`, `scaled_cgf` | Exact vs tilted-generator vs independent classical FCS (1e-10); Gallavotti–Cohen symmetry to 1e-15; TUR holds for all classical machines, violated by the maser as published |
|
|
262
|
+
| **Strong coupling** | `reaction_coordinate_model`, `mean_force_state` | O(λ²) weak-coupling limit; Cresser–Anders ultrastrong limit; heat-current turnover |
|
|
263
|
+
| **Information** | `landauer_erasure`, `geodesic_schedule`, `thermodynamic_length`, `szilard_engine` | Erasure → T ln 2; excess ∝ 1/τ matching slow-driving theory to <1%; geodesic attains L²/τ. Szilard engine attains the Sagawa–Ueda bound T·I exactly, including with measurement errors |
|
|
264
|
+
| **Periodically driven machines** | `floquet_analyze`, `DrivenBath`, `window_spectrum` | Undriven limit = static Davies (1e-14); Bessel sideband weights; tight-coupling efficiency and COP of the modulated-qubit machine to 1e-7; σ ≥ 0 for random drives |
|
|
265
|
+
| **Linear response** | `response` → conductance, Onsager matrix, coupling `q`, `amplification` | Onsager reciprocity to 1e-9; tight coupling \|q\| = 1 for the local fridge; thermal-transistor gain 4.8 |
|
|
266
|
+
| **Transients** | `transient`, `product_thermal_state` | Long-time limit = steady state; cumulative heat balances ΔE; single-shot cooling below steady state |
|
|
267
|
+
| **Optimal protocols** (any H(λ), any thermalising bath) | `friction`, `optimal_schedule`, `excess_work` | Friction metric reproduces the erasure closed form to 1e-11; non-commuting drive: simulated excess within 0.2% of L²/τ, 34% below a linear ramp |
|
|
268
|
+
| **Quantum batteries** | `batteries.ergotropy_split`, `locked_ergotropy`, `asymptotic_ergotropy`, `dicke_battery`, `collective_advantage` | Dicke √N power advantage (exponent 0.499); locked ergotropy of a Bell pair; activation of passive states |
|
|
269
|
+
| **Per-cycle statistics** | `cycle_counting` (exact), `unravel` (sampled) | Exact P(n) vs independent classical telegraph model (1e-12); vs trajectories; Jarzynski to 1e-16 |
|
|
270
|
+
| **Operation modes** | `classify`, `mode_map`, `plot_mode_map`, `.mode()` on every result | Quasi-static qubit Otto boundary ω_c/ω_h = T_c/T_h reproduced exactly |
|
|
271
|
+
| **Optimisation** | `sweep`, `scan_2d`, `pareto_front` (cycles *and* continuous models) | Interior optimum located; sequential vs joint tuning |
|
|
272
|
+
|
|
273
|
+
## Figures
|
|
274
|
+
|
|
275
|
+
<table>
|
|
276
|
+
<tr>
|
|
277
|
+
<td width="50%"><img src="https://raw.githubusercontent.com/VivekKhanna0/Qthermo/main/examples/figures/local_vs_global.png" alt="local vs global master equation"></td>
|
|
278
|
+
<td width="50%"><img src="https://raw.githubusercontent.com/VivekKhanna0/Qthermo/main/examples/figures/tur.png" alt="TUR violation in the maser"></td>
|
|
279
|
+
</tr>
|
|
280
|
+
<tr>
|
|
281
|
+
<td><b>When the local master equation breaks.</b> Past g ≈ 0.55 it moves heat
|
|
282
|
+
from cold to hot. The global model never does.</td>
|
|
283
|
+
<td><b>Beyond any classical machine.</b> The maser's power output is more
|
|
284
|
+
precise than the thermodynamic uncertainty relation allows a classical
|
|
285
|
+
process. Computed exactly, with no sampling.</td>
|
|
286
|
+
</tr>
|
|
287
|
+
<tr>
|
|
288
|
+
<td width="50%"><img src="https://raw.githubusercontent.com/VivekKhanna0/Qthermo/main/examples/figures/thermal_transistor.png" alt="quantum thermal transistor"></td>
|
|
289
|
+
<td width="50%"><img src="https://raw.githubusercontent.com/VivekKhanna0/Qthermo/main/examples/figures/szilard_engine.png" alt="quantum Szilard engine"></td>
|
|
290
|
+
</tr>
|
|
291
|
+
<tr>
|
|
292
|
+
<td><b>A quantum thermal transistor.</b> The base heat current steers up to
|
|
293
|
+
4.8× as much collector current. The conductance matrix is checked for Onsager
|
|
294
|
+
symmetry.</td>
|
|
295
|
+
<td><b>Information into work.</b> Optimal feedback attains the Sagawa–Ueda
|
|
296
|
+
bound T·I exactly, even with measurement errors. In finite time it falls
|
|
297
|
+
short by ~1/τ.</td>
|
|
298
|
+
</tr>
|
|
299
|
+
</table>
|
|
300
|
+
|
|
301
|
+
**[The full gallery: 16 figures, with what each shows →](https://github.com/VivekKhanna0/Qthermo/blob/main/docs/gallery.md)**, covering
|
|
302
|
+
strong coupling, Landauer erasure, optimal protocols, interacting Otto
|
|
303
|
+
engines, entanglement inside a two-qubit engine cycle, operation-mode maps,
|
|
304
|
+
periodically driven machines, transient cooling, transport scaling and
|
|
305
|
+
quantum batteries.
|
|
306
|
+
|
|
307
|
+
## Verification
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
python -m qthermo.benchmarks # computed value next to the published / analytic one
|
|
311
|
+
python -m pytest # ~270 tests, ~95 s
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Every benchmark is a number fixed independently of this code: a closed-form
|
|
315
|
+
limit, an exact identity, or a published bound or violation. A failure means
|
|
316
|
+
the physics is wrong, not that an interface changed. The test suite adds
|
|
317
|
+
randomised property tests. They draw random Hamiltonians, couplings, baths and
|
|
318
|
+
temperatures (qubits, qutrits, mixed dimensions, degenerate spectra) and
|
|
319
|
+
assert what must always hold:
|
|
320
|
+
|
|
321
|
+
- the steady state is a valid, stationary density matrix;
|
|
322
|
+
- energy is conserved and σ ≥ 0;
|
|
323
|
+
- a single bath gives the Gibbs state;
|
|
324
|
+
- counting statistics reproduce the currents;
|
|
325
|
+
- site flows close;
|
|
326
|
+
- ergotropy is non-negative and zero for passive states.
|
|
327
|
+
|
|
328
|
+
It is also cross-checked against QuTiP. CI runs all of this, and every
|
|
329
|
+
example, on every push.
|
|
330
|
+
|
|
331
|
+
```
|
|
332
|
+
[continuous machines]
|
|
333
|
+
ok 3-qubit absorption fridge COP (local ME, tight coupling) 0.333333 0.333333 ==
|
|
334
|
+
w_c/w_h; Linden, Popescu & Skrzypczyk, PRL 105, 130401 (2010)
|
|
335
|
+
ok three-level maser efficiency 0.666667 0.666667 ==
|
|
336
|
+
1 - w_c/w_h; Scovil & Schulz-DuBois, PRL 2, 262 (1959)
|
|
337
|
+
ok local ME, detuned XX qubits: heat current from hot bath -0.00044776 0 <=
|
|
338
|
+
< 0, i.e. cold -> hot; Levy & Kosloff, EPL 107, 20004 (2014)
|
|
339
|
+
[fluctuations]
|
|
340
|
+
ok TUR ratio, three-level maser power (coherent drive) 1.96697 2 <=
|
|
341
|
+
< 2 possible; Kalaee, Wacker & Potts, PRE 104, L012103 (2021)
|
|
342
|
+
ok Gallavotti-Cohen symmetry of heat FCS, 3-qubit chain 1.84228e-15 0 ==
|
|
343
|
+
[information]
|
|
344
|
+
ok geodesic erasure protocol: excess heat x tau 0.890737 0.886534 ==
|
|
345
|
+
= L^2 (thermodynamic length); Scandi & Perarnau-Llobet, Quantum 3, 197 (2019)
|
|
346
|
+
...
|
|
347
|
+
44/44 passed in 39.3 s
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
The exact definitions of every computed quantity (sign conventions, which
|
|
351
|
+
energy operator defines heat under local baths, rate conventions of the
|
|
352
|
+
spectral densities, the FCS formulas) are in [docs/physics.md](https://github.com/VivekKhanna0/Qthermo/blob/main/docs/physics.md).
|
|
353
|
+
|
|
354
|
+
## Stroke machines and trajectories
|
|
355
|
+
|
|
356
|
+
The original core is still here and unchanged: a cycle is a list of strokes,
|
|
357
|
+
and whether it is a fridge or an engine follows from the parameters.
|
|
358
|
+
|
|
359
|
+
```python
|
|
360
|
+
H_cold, H_hot = qt.qubit_hamiltonian(1.0), qt.qubit_hamiltonian(1.5)
|
|
361
|
+
ramp = lambda a, b, tau: (lambda t: qt.qubit_hamiltonian(a + (t/tau)*(b-a)))
|
|
362
|
+
|
|
363
|
+
cycle = qt.Cycle([
|
|
364
|
+
qt.Stroke("cold_iso", H_cold, 12.0, qt.thermal_bath(1.0, 1.0, 1.0), temperature=1.0),
|
|
365
|
+
qt.Stroke("compress", ramp(1.0, 1.5, 0.02), 0.02),
|
|
366
|
+
qt.Stroke("hot_iso", H_hot, 12.0, qt.thermal_bath(1.0, 1.5, 1.3), temperature=1.3),
|
|
367
|
+
qt.Stroke("expand", ramp(1.5, 1.0, 0.02), 0.02),
|
|
368
|
+
])
|
|
369
|
+
result, passes, converged = cycle.limit_cycle(qt.thermal_state(H_cold, 1.0))
|
|
370
|
+
result.cop(("cold_iso",))
|
|
371
|
+
|
|
372
|
+
counts = qt.cycle_counting(cycle, {"cold_iso": "quanta"}) # exact, no sampling
|
|
373
|
+
counts.probability(lambda n: n <= 0) # 0.7955: 80% of cycles extract nothing
|
|
374
|
+
print(counts.report())
|
|
375
|
+
|
|
376
|
+
ensemble = qt.unravel(cycle, result.strokes[-1].rho_final, trajectories=6000)
|
|
377
|
+
ensemble.probability_of("cold_iso", lambda q: q <= 0) # ~0.79, sampled
|
|
378
|
+
```
|
|
379
|
+
```
|
|
380
|
+
net quanta exchanged per cycle, counting cold_iso (quanta)
|
|
381
|
+
n P(n), one cycle
|
|
382
|
+
-1 0.175299 #######
|
|
383
|
+
0 0.620249 #########################
|
|
384
|
+
1 0.204453 ########
|
|
385
|
+
one cycle: mean +0.029154, P(n <= 0) = 0.795547
|
|
386
|
+
long run: mean +0.029154 per cycle, variance 0.378901, Fano 12.9965
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
On average this refrigerator cools. In 80% of individual cycles it draws
|
|
390
|
+
nothing from the cold bath, a number the master equation cannot give.
|
|
391
|
+
`cycle_counting` computes the single-cycle distribution *exactly*, by
|
|
392
|
+
propagating the counting-field master equation through the strokes, and the
|
|
393
|
+
long-run noise from its dominant eigenvalue. `unravel` samples the same thing
|
|
394
|
+
with quantum-jump trajectories. (Earlier versions of this README said "about
|
|
395
|
+
half": that was floating-point round-off in the sampled heats misclassifying
|
|
396
|
+
zero-heat trajectories, found by comparing against the exact result, and now
|
|
397
|
+
fixed.)
|
|
398
|
+
|
|
399
|
+
Heat and work use the midpoint Alicki split, which satisfies `dU = Q + W` to
|
|
400
|
+
machine precision at every step. That makes the first-law residual a test of
|
|
401
|
+
the solver rather than of the discretisation. Strokes also accept `Bath`
|
|
402
|
+
objects, including several at once and baths that follow a driven Hamiltonian
|
|
403
|
+
(`instantaneous_bath`), and then report heat per bath. See
|
|
404
|
+
`examples/full_demo.py` for sweeps, joint scans, Pareto fronts and trajectory
|
|
405
|
+
distributions.
|
|
406
|
+
|
|
407
|
+
## Scope and limitations
|
|
408
|
+
|
|
409
|
+
- **Markovian** master equations (Lindblad form). Non-Markovian and
|
|
410
|
+
strong-coupling effects enter through the reaction-coordinate mapping, which
|
|
411
|
+
is exact for a single-peaked (Brownian) spectral density and approximate
|
|
412
|
+
otherwise. No HEOM. `redfield_bath` (not of Lindblad form, so positivity is
|
|
413
|
+
not guaranteed) works for steady states only, not for trajectories,
|
|
414
|
+
fluctuations or cycles.
|
|
415
|
+
- **Lamb shifts are neglected** in the Davies construction.
|
|
416
|
+
- **Size:** dense or sparse matrices, no tensor networks.
|
|
417
|
+
- Global-bath steady states run to a few hundred levels; the 200-level RC
|
|
418
|
+
model takes about 20 s.
|
|
419
|
+
- Local-bath chains take seconds up to 7 qubits and about 25 s at 8 qubits
|
|
420
|
+
(0.6 GB), using ILU-preconditioned GMRES above 128 levels. 9 qubits takes
|
|
421
|
+
minutes.
|
|
422
|
+
- Current fluctuations use dense superoperators and suit a few dozen levels.
|
|
423
|
+
- **Periodically driven machines** use the full-secular Floquet–Markov
|
|
424
|
+
equation. It is valid when quasienergy differences are resolved on the scale
|
|
425
|
+
of the bath rates, and warns when they are not.
|
|
426
|
+
- Simulation only. Nothing here has been checked against hardware data.
|
|
427
|
+
|
|
428
|
+
## Feedback wanted
|
|
429
|
+
|
|
430
|
+
This is being shared with researchers in quantum thermodynamics to find out
|
|
431
|
+
what is actually useful. The most valuable replies are specific: *"I would
|
|
432
|
+
use this if it did X"*, *"this number disagrees with Ref. Y"*, *"the local/global
|
|
433
|
+
check would have saved me a week"*. Please open an issue.
|
|
434
|
+
|
|
435
|
+
Some concrete open questions where input from people who work on these
|
|
436
|
+
problems would help:
|
|
437
|
+
|
|
438
|
+
- **The regime between local and global.** With J ≈ γ, neither master
|
|
439
|
+
equation is controlled; the tutorial's thermal diode even changes direction
|
|
440
|
+
between them. A naive "unified" (partially secular) construction was
|
|
441
|
+
prototyped and gave erratic currents, so it was not shipped. `redfield_bath`
|
|
442
|
+
now matches the exact oscillator current in both limits. Is Redfield what
|
|
443
|
+
you would trust for coupled *qubits* too, or is there a benchmark where it
|
|
444
|
+
fails that should be added?
|
|
445
|
+
- **Collective baths.** N qubits coupled to one bath through their total
|
|
446
|
+
spin carry more heat per qubit than N independent ones. At the temperatures
|
|
447
|
+
tried, the gain saturates near 2.6× instead of growing with N. Is there a
|
|
448
|
+
published benchmark for superradiant heat transport to validate against
|
|
449
|
+
before this becomes a feature?
|
|
450
|
+
- **Strong coupling beyond one reaction coordinate.** Is the RC mapping
|
|
451
|
+
enough for the systems you study, or is a HEOM or TEMPO backend the
|
|
452
|
+
missing piece?
|
|
453
|
+
- **Hardware.** Which experimental platform (superconducting circuits,
|
|
454
|
+
trapped ions, NV centres, quantum dots) should the models and `LabUnits`
|
|
455
|
+
presets target first?
|
|
456
|
+
|
|
457
|
+
## Units and conventions
|
|
458
|
+
|
|
459
|
+
`ħ = k_B = 1`, with an energy unit of your choice; `qt.LabUnits(f0_GHz)`
|
|
460
|
+
converts to and from GHz, mK, seconds and watts for the unit `E0 = h f0`.
|
|
461
|
+
`Q > 0` and `J > 0` mean energy flowing **into** the system;
|
|
462
|
+
`W > 0` means work done **on** it. `qubit_hamiltonian(ω) = −(ω/2)σ_z`, so
|
|
463
|
+
|1⟩ is the excited state.
|
|
464
|
+
|
|
465
|
+
## References
|
|
466
|
+
|
|
467
|
+
Implemented quantities are standard; the package does not introduce new
|
|
468
|
+
physics. Each benchmark cites its source (run `python -m qthermo.benchmarks`).
|
|
469
|
+
Main ones: Alicki (1979) heat/work split; Spohn (1978) entropy production;
|
|
470
|
+
Davies (1974) weak-coupling generator; Levy & Kosloff, EPL 107, 20004 (2014);
|
|
471
|
+
De Chiara et al., NJP 20, 113024 (2018); Linden, Popescu & Skrzypczyk, PRL 105,
|
|
472
|
+
130401 (2010); Brunner et al., PRE 85, 051117 (2012); Scovil & Schulz-DuBois,
|
|
473
|
+
PRL 2, 262 (1959); Barato & Seifert, PRL 114, 158101 (2015); Kalaee, Wacker &
|
|
474
|
+
Potts, PRE 104, L012103 (2021); Landi et al., PRX Quantum 5, 020201 (2024);
|
|
475
|
+
Strasberg et al., NJP 18, 073007 (2016); Cresser & Anders, PRL 127, 250601
|
|
476
|
+
(2021); Scandi & Perarnau-Llobet, Quantum 3, 197 (2019); Thomas & Johal, PRE
|
|
477
|
+
83, 031135 (2011); Jarzynski, PRL 78, 2690 (1997).
|
|
478
|
+
|
|
479
|
+
## Citing
|
|
480
|
+
|
|
481
|
+
See [`CITATION.cff`](https://github.com/VivekKhanna0/Qthermo/blob/main/CITATION.cff) (GitHub shows a "Cite this repository"
|
|
482
|
+
button). Please also cite the original papers for the physics you use; each
|
|
483
|
+
benchmark names its source.
|
|
484
|
+
|
|
485
|
+
## License
|
|
486
|
+
|
|
487
|
+
MIT
|