wavepacket 0.4.0__tar.gz → 0.5__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.
- {wavepacket-0.4.0 → wavepacket-0.5}/CHANGELOG.rst +49 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/LICENSE +1 -1
- {wavepacket-0.4.0 → wavepacket-0.5}/PKG-INFO +4 -5
- {wavepacket-0.4.0 → wavepacket-0.5}/README.rst +3 -2
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/advanced/ode_solvers.md +3 -5
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/advanced/pendular_states.md +2 -2
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/advanced/plane_wave_grid.md +2 -2
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/advanced/polynomial_solvers.md +9 -8
- wavepacket-0.5/doc/advanced/reduced_density.md +259 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/advanced/thermal_states.md +7 -6
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/architecture.rst +1 -1
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/conf.py +1 -1
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/index.rst +2 -0
- wavepacket-0.5/doc/tutorials/channels.md +266 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/tutorials/chebychev_solvers.md +9 -9
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/tutorials/eigenstates.md +2 -1
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/tutorials/plotting.md +11 -12
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/tutorials/relaxation.md +1 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/tutorials/schroedinger_cat.md +9 -5
- {wavepacket-0.4.0 → wavepacket-0.5}/pyproject.toml +8 -3
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/__init__.py +1 -1
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/builder/density.py +4 -4
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/builder/wave_function.py +40 -14
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/exceptions.py +1 -1
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/expression/liouvillian.py +1 -1
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/expression/schroedingerequation.py +1 -1
- wavepacket-0.5/src/wavepacket/grid/__init__.py +27 -0
- wavepacket-0.5/src/wavepacket/grid/channel_dof.py +112 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/grid/dofbase.py +1 -1
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/grid/grid.py +23 -2
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/grid/planewavedof.py +3 -5
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/grid/spherical_harmonics_dof.py +2 -2
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/grid/state.py +3 -3
- wavepacket-0.5/src/wavepacket/grid/transformation.py +237 -0
- wavepacket-0.5/src/wavepacket/logging.py +74 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/operator/__init__.py +3 -0
- wavepacket-0.5/src/wavepacket/operator/channel_operators.py +141 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/operator/misc_operators.py +2 -2
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/operator/time_dependent_operators.py +1 -1
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/operator_utils.py +4 -4
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/plot/plot_1d.py +77 -15
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/plot/plot_2d.py +67 -30
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/solver/chebychev.py +4 -3
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/solver/odesolver.py +1 -1
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/special/generators.py +2 -2
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/special/pulse_shapes.py +1 -1
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/state_utilities.py +10 -9
- {wavepacket-0.4.0 → wavepacket-0.5}/test/builder/test_product_wave_function.py +34 -0
- wavepacket-0.5/test/grid/test_channel_dof.py +78 -0
- wavepacket-0.5/test/grid/test_channel_projection_transformation.py +80 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/grid/test_grid.py +13 -0
- wavepacket-0.5/test/grid/test_partialtracetransformation.py +93 -0
- wavepacket-0.5/test/operator/test_channel_operators.py +144 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/special/test_pulse_shapes.py +2 -2
- {wavepacket-0.4.0 → wavepacket-0.5}/test/test_state_utilities.py +8 -2
- wavepacket-0.5/test_acceptance/readme +7 -0
- wavepacket-0.5/test_acceptance/test_1d_absorbing_boundaries.txt +75 -0
- wavepacket-0.5/test_acceptance/test_2d_harmonic_oscillator.txt +65 -0
- wavepacket-0.5/test_acceptance/test_electronic_plotting.py +57 -0
- wavepacket-0.5/test_acceptance/test_laser_pulse_with_density_operator.txt +161 -0
- wavepacket-0.5/test_acceptance/test_relaxation.txt +37 -0
- wavepacket-0.5/test_acceptance/test_tise.txt +49 -0
- wavepacket-0.5/test_acceptance/test_tracing_out.txt +118 -0
- wavepacket-0.4.0/src/wavepacket/grid/__init__.py +0 -11
- wavepacket-0.4.0/src/wavepacket/logging.py +0 -39
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/Makefile +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/license.rst +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/license.txt +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/make.bat +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/representations.rst +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/doc/requirements.txt +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/builder/__init__.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/expression/__init__.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/expression/expressionbase.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/grid/_utils.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/operator/_clipping.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/operator/fbroperators.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/operator/operatorbase.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/operator/potentials.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/plot/__init__.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/plot/_utilities.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/py.typed +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/solver/__init__.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/solver/solverbase.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/special/__init__.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/testing/__init__.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/testing/assertions.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/testing/dummydof.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/testing/dummyoperator.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/testing/random.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/typing/__init__.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/src/wavepacket/typing/data_types.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/builder/test_density.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/builder/test_wave_function.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/conftest.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/expression/test_expression_sum.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/expression/test_liouvillian.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/expression/test_schroedingerequation.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/grid/test_dofbase.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/grid/test_planewavedof_basics.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/grid/test_planewavedof_transformations.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/grid/test_sphericalharmonicsdof_basics.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/grid/test_sphericalharmonicsdof_transformations.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/grid/test_state.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/operator/test_clipping.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/operator/test_fbroperators.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/operator/test_misc_operators.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/operator/test_operator_arithmetic.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/operator/test_operatorbase.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/operator/test_planewavefbroperator.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/operator/test_potential1d.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/operator/test_time_dependent_operators.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/solver/test_chebychev.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/solver/test_odesolver.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/solver/test_solverbase.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/special/test_generators.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/test_base_exports.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/test_logging.py +0 -0
- {wavepacket-0.4.0 → wavepacket-0.5}/test/test_operator_utilities.py +0 -0
|
@@ -2,6 +2,55 @@
|
|
|
2
2
|
ChangeLog
|
|
3
3
|
=========
|
|
4
4
|
|
|
5
|
+
0.5
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Breaking changes:
|
|
9
|
+
|
|
10
|
+
Major changes:
|
|
11
|
+
|
|
12
|
+
- (#39) Added a PartialTraceTransformation to trace out all but one degree of freedom
|
|
13
|
+
|
|
14
|
+
- (#25) Added coupled channels consisting of a degree of freedom, a transformation,
|
|
15
|
+
two operators and a few convenience functions.
|
|
16
|
+
|
|
17
|
+
New documentation / examples:
|
|
18
|
+
|
|
19
|
+
- (#39) Effect of an environment on system states (decoherence) for a simple example
|
|
20
|
+
- (#25) Introduction and usage of coupled channels
|
|
21
|
+
|
|
22
|
+
Minor changes:
|
|
23
|
+
|
|
24
|
+
- documented use of atomic units in the code
|
|
25
|
+
|
|
26
|
+
Bug fixes:
|
|
27
|
+
|
|
28
|
+
- (#63) removed some warnings due to incorrect formula escaping
|
|
29
|
+
- fixed a type error with recent scipy versions when using a SphericalHarmonicsDof
|
|
30
|
+
- (#41) fixed broken references in the documentation
|
|
31
|
+
|
|
32
|
+
0.4.1
|
|
33
|
+
-----
|
|
34
|
+
|
|
35
|
+
Minor changes:
|
|
36
|
+
|
|
37
|
+
- (#56) Added acceptance / regression tests, also for CI
|
|
38
|
+
|
|
39
|
+
Bug fixes:
|
|
40
|
+
|
|
41
|
+
- The SinSquare function had an incorrect implementation without the "square" part
|
|
42
|
+
|
|
43
|
+
- population() could return complex values for density operators.
|
|
44
|
+
The imaginary part was negligible, but the type was still wrong.
|
|
45
|
+
The return values are also no longer (negligible) negative values.
|
|
46
|
+
|
|
47
|
+
- log() calculated <x> only for the first degree of freedom,
|
|
48
|
+
and reported it for all other degrees of freedom as well.
|
|
49
|
+
Also, fixed a typo in the output.
|
|
50
|
+
|
|
51
|
+
- Stacked1DPlot threw an exception if you exceeded the number of plots.
|
|
52
|
+
It now overwrites the last plot as it is documented.
|
|
53
|
+
|
|
5
54
|
0.4
|
|
6
55
|
---
|
|
7
56
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wavepacket
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5
|
|
4
4
|
Summary: A package for solving Schrödinger and Liouville von Neumann equations.
|
|
5
5
|
Keywords: wave packet,quantum simulation,quantum system,DVR,Schroedinger equation,Liouville von Neumann equation,open systems,wave function,density operator,Liouvillian
|
|
6
6
|
Author: Ulf Lorenz
|
|
@@ -22,13 +22,11 @@ License-File: LICENSE
|
|
|
22
22
|
Requires-Dist: numpy >= 2.1.3
|
|
23
23
|
Requires-Dist: scipy >= 1.14.1
|
|
24
24
|
Requires-Dist: matplotlib >= 3.10
|
|
25
|
-
Requires-Dist: coverage >= 7 ; extra == "coverage"
|
|
26
25
|
Requires-Dist: black == 26.* ; extra == "formatting"
|
|
27
26
|
Requires-Dist: pytest >= 8.3 ; extra == "test"
|
|
28
27
|
Project-URL: Homepage, https://wavepacket.readthedocs.io
|
|
29
28
|
Project-URL: Issues, https://github.com/ulflor/wavepacket/issues
|
|
30
29
|
Project-URL: Source, https://github.com/ulflor/wavepacket
|
|
31
|
-
Provides-Extra: coverage
|
|
32
30
|
Provides-Extra: formatting
|
|
33
31
|
Provides-Extra: test
|
|
34
32
|
|
|
@@ -49,6 +47,7 @@ Wavepacket focuses on a particular niche:
|
|
|
49
47
|
- Direct solution of Schrödinger / Liouville von Neumann equations.
|
|
50
48
|
No electronic structure, no MCTDH, no semiclassics, at least for now.
|
|
51
49
|
- Grid-based representation of operators (DVR approximation).
|
|
50
|
+
Atomic units to simplify equations.
|
|
52
51
|
- Accessibility is an overriding goal. Wavepacket should be directly usable in teaching.
|
|
53
52
|
We try to provide good tutorials / docs, but also goodies like simple plotting.
|
|
54
53
|
- Exotic use cases should be as frictionless as possible.
|
|
@@ -74,7 +73,7 @@ Support
|
|
|
74
73
|
|
|
75
74
|
There are three different avenues for feedback and support:
|
|
76
75
|
|
|
77
|
-
- The
|
|
76
|
+
- The preferred option is through the mailing list wavepacket@python.org.
|
|
78
77
|
You may want to subscribe at https://mail.python.org/mailman3/lists/wavepacket.python.org/
|
|
79
78
|
to ensure you receive all answers.
|
|
80
79
|
- You can use the Forum on github: https://github.com/ulflor/wavepacket/discussions
|
|
@@ -94,7 +93,7 @@ I currently lack a formal procedure for new contributors, but you are
|
|
|
94
93
|
very welcome to contribute to the project. If you do not know what to do,
|
|
95
94
|
use one of the support channels from the previous section ; there is enough
|
|
96
95
|
work for multiple developers, also for non-coding skills (there is never enough
|
|
97
|
-
documentation).
|
|
96
|
+
documentation, for example).
|
|
98
97
|
|
|
99
98
|
|
|
100
99
|
History
|
|
@@ -15,6 +15,7 @@ Wavepacket focuses on a particular niche:
|
|
|
15
15
|
- Direct solution of Schrödinger / Liouville von Neumann equations.
|
|
16
16
|
No electronic structure, no MCTDH, no semiclassics, at least for now.
|
|
17
17
|
- Grid-based representation of operators (DVR approximation).
|
|
18
|
+
Atomic units to simplify equations.
|
|
18
19
|
- Accessibility is an overriding goal. Wavepacket should be directly usable in teaching.
|
|
19
20
|
We try to provide good tutorials / docs, but also goodies like simple plotting.
|
|
20
21
|
- Exotic use cases should be as frictionless as possible.
|
|
@@ -40,7 +41,7 @@ Support
|
|
|
40
41
|
|
|
41
42
|
There are three different avenues for feedback and support:
|
|
42
43
|
|
|
43
|
-
- The
|
|
44
|
+
- The preferred option is through the mailing list wavepacket@python.org.
|
|
44
45
|
You may want to subscribe at https://mail.python.org/mailman3/lists/wavepacket.python.org/
|
|
45
46
|
to ensure you receive all answers.
|
|
46
47
|
- You can use the Forum on github: https://github.com/ulflor/wavepacket/discussions
|
|
@@ -60,7 +61,7 @@ I currently lack a formal procedure for new contributors, but you are
|
|
|
60
61
|
very welcome to contribute to the project. If you do not know what to do,
|
|
61
62
|
use one of the support channels from the previous section ; there is enough
|
|
62
63
|
work for multiple developers, also for non-coding skills (there is never enough
|
|
63
|
-
documentation).
|
|
64
|
+
documentation, for example).
|
|
64
65
|
|
|
65
66
|
|
|
66
67
|
History
|
|
@@ -25,7 +25,7 @@ For the impatient, the main results of the following treatise are:
|
|
|
25
25
|
|
|
26
26
|
### ODE solvers theory
|
|
27
27
|
|
|
28
|
-
We start from the Schrödinger equation
|
|
28
|
+
We start from the Schrödinger equation (we use atomic units throughout the text)
|
|
29
29
|
|
|
30
30
|
$$
|
|
31
31
|
\imath \dot \psi(t) = \hat H(t) \psi(t)
|
|
@@ -245,15 +245,13 @@ To answer this question, we can look at the projection of the truncated result o
|
|
|
245
245
|
any deviation from one can serve as a figure of merit of the additional error.
|
|
246
246
|
|
|
247
247
|
```{code-cell}
|
|
248
|
-
import math
|
|
249
|
-
|
|
250
248
|
truncated_hamiltonian = (wp.operator.CartesianKineticEnergy(grid, 0, 1.0, cutoff=50)
|
|
251
249
|
+ wp.operator.Potential1D(grid, 0, lambda x: 0.5 * x ** 2, cutoff=50))
|
|
252
250
|
truncated_equation = wp.expression.SchroedingerEquation(truncated_hamiltonian)
|
|
253
|
-
truncated_solver = wp.solver.OdeSolver(truncated_equation,
|
|
251
|
+
truncated_solver = wp.solver.OdeSolver(truncated_equation, np.pi / 2)
|
|
254
252
|
truncated_result = truncated_solver.step(psi0, 0)
|
|
255
253
|
|
|
256
|
-
solver = wp.solver.OdeSolver(equation,
|
|
254
|
+
solver = wp.solver.OdeSolver(equation, np.pi/2)
|
|
257
255
|
result = solver.step(psi0, 0)
|
|
258
256
|
|
|
259
257
|
print(f"Overlap after pi/2: {wp.population(truncated_result, result)}")
|
|
@@ -17,6 +17,7 @@ how to extract non-trivial data with minimal fuss and plot it.
|
|
|
17
17
|
|
|
18
18
|
If a molecule interacts with a non-resonant laser field, the electronic ground state is shifted in energy.
|
|
19
19
|
We can calculate the shift with standard perturbation theory and cavity-dressed states as
|
|
20
|
+
(we use atomic units throughout the text)
|
|
20
21
|
|
|
21
22
|
$$
|
|
22
23
|
\Delta E \propto - \sum_n \frac{|\langle \Phi_0 | \hat{\vec{\mu}} \vec E |\Phi_n \rangle|^2}{E_n - E_0 - \omega}
|
|
@@ -73,7 +74,6 @@ Note that at certain points in time, the rotor exhibits alignment recurrence eve
|
|
|
73
74
|
This field-free alignment is used in practice because the molecule is aligned, yet undisturbed by external fields.
|
|
74
75
|
|
|
75
76
|
```{code-cell}
|
|
76
|
-
import math
|
|
77
77
|
import matplotlib.pyplot as plt
|
|
78
78
|
import numpy as np
|
|
79
79
|
|
|
@@ -91,7 +91,7 @@ def calculate_alignment(Delta, sigma, l0=0, m=0):
|
|
|
91
91
|
kinetic = wp.operator.RotationalKineticEnergy(grid, 0, 0.5)
|
|
92
92
|
cos2 = wp.operator.Potential1D(grid, 0, lambda theta: np.cos(theta)**2)
|
|
93
93
|
laser = wp.operator.TimeDependentOperator(grid,
|
|
94
|
-
lambda t: Delta *
|
|
94
|
+
lambda t: Delta * np.exp(-(t-delay)**2/sigma**2))
|
|
95
95
|
|
|
96
96
|
hamiltonian = kinetic - 0.5 * cos2 * laser
|
|
97
97
|
equation = wp.expression.SchroedingerEquation(hamiltonian)
|
|
@@ -143,9 +143,9 @@ There are, however, two major drawbacks:
|
|
|
143
143
|
and you may need to converge this as well.
|
|
144
144
|
* With the NIP term, the Hamiltonian is no longer self-adjoint.
|
|
145
145
|
Some efficient solvers like the ChebychevSolver only work for self-adjoint Hamiltonians.
|
|
146
|
-
|
|
146
|
+
A possible workaround here is to move the NIP out of the Hamiltonian,
|
|
147
147
|
and absorb the wave packet after every propagation step.
|
|
148
|
-
As of Wavepacket 0.4, this is
|
|
148
|
+
As of Wavepacket 0.4, this is not implemented conveniently, though.
|
|
149
149
|
|
|
150
150
|
Let us demonstrate the first point by adding a steep NIP to the Morse oscillator example:
|
|
151
151
|
|
|
@@ -25,6 +25,7 @@ was introduced by Huisinga et al. [^faber], but we omit this discussion for simp
|
|
|
25
25
|
## Basic theory
|
|
26
26
|
|
|
27
27
|
For a time-independent, closed system, the time evolution operator is defined by
|
|
28
|
+
(we use atomic units throughout the text)
|
|
28
29
|
|
|
29
30
|
$$
|
|
30
31
|
\psi(t+\Delta t) = \hat U(\Delta t) \psi(t) = \mathrm{e}^{-\imath \hat H \Delta t} \psi(t).
|
|
@@ -96,10 +97,10 @@ We get for a normalized state
|
|
|
96
97
|
We do not care about the exact value of the error, just note two properties of the expression:
|
|
97
98
|
|
|
98
99
|
1. There is an upper bound for the error independent of the initial state. That is, the convergence is continuous,
|
|
99
|
-
there are no
|
|
100
|
+
there are no singular states for which the series does not converge.
|
|
100
101
|
2. For large enough N, the right-hand side decreases exponentially with increasing N.
|
|
101
102
|
|
|
102
|
-
|
|
103
|
+
For simplicity, we do not target a specific value of the (upper bound of the) propagation error,
|
|
103
104
|
but simply truncate the series as soon as the Bessel function has reached a certain cutoff.
|
|
104
105
|
This cutoff can still be considered a proxy for the order of magnitude of the error,
|
|
105
106
|
but is not a rigorous quantity.
|
|
@@ -117,7 +118,7 @@ The size of the time step, that is, the gain, however, is proportional to the al
|
|
|
117
118
|
argument of said Bessel function.
|
|
118
119
|
|
|
119
120
|
So we can rephrase the question: At which value of alpha do we get most gain per cost?
|
|
120
|
-
Let us plot the
|
|
121
|
+
Let us plot the behavior of the Bessel functions for different values of alpha
|
|
121
122
|
|
|
122
123
|
```{code-cell}
|
|
123
124
|
import matplotlib.pyplot as plt
|
|
@@ -149,7 +150,7 @@ Hence, the proposition of using an alpha value of at least 40 to avoid inefficie
|
|
|
149
150
|
of increasing alpha beyond, say, 100.
|
|
150
151
|
Both values are not exact numbers, however, just crude rules of thumb.
|
|
151
152
|
|
|
152
|
-
However, very large orders of expansion may lead to
|
|
153
|
+
However, very large orders of expansion may lead to artifacts.
|
|
153
154
|
For example the values of the Bessel functions may become inaccurate, depending on the implementation details.
|
|
154
155
|
Therefore, we would recommend not increasing alpha beyond something like 100, but that is also not a hard value.
|
|
155
156
|
For example, we encountered a Matlab version around 2010
|
|
@@ -166,7 +167,7 @@ so let us back this up with numbers.
|
|
|
166
167
|
We choose the truncated harmonic oscillator example from {doc}`/tutorials/chebychev_solvers`.
|
|
167
168
|
|
|
168
169
|
```{code-cell}
|
|
169
|
-
import
|
|
170
|
+
import numpy as np
|
|
170
171
|
import wavepacket as wp
|
|
171
172
|
|
|
172
173
|
grid = wp.grid.Grid(wp.grid.PlaneWaveDof(-10, 10, 128))
|
|
@@ -200,17 +201,17 @@ Then we only wrap our (truncated) expression and propagate for a common time.
|
|
|
200
201
|
```{code-cell}
|
|
201
202
|
counting_equation = CountingExpression(equation)
|
|
202
203
|
|
|
203
|
-
solver_chebychev = wp.solver.ChebychevSolver(counting_equation,
|
|
204
|
+
solver_chebychev = wp.solver.ChebychevSolver(counting_equation, np.pi/2, (0, 70))
|
|
204
205
|
solver_chebychev.step(psi0, t=0)
|
|
205
206
|
print(f"Chebychev solver: count={counting_equation.count}, alpha={solver_chebychev.alpha:.4}")
|
|
206
207
|
|
|
207
208
|
counting_equation.count = 0
|
|
208
|
-
solver_rk45 = wp.solver.OdeSolver(counting_equation,
|
|
209
|
+
solver_rk45 = wp.solver.OdeSolver(counting_equation, np.pi/2)
|
|
209
210
|
solver_rk45.step(psi0, t=0)
|
|
210
211
|
print(f"Runge-Kutta 4/5 solver: count={counting_equation.count}")
|
|
211
212
|
|
|
212
213
|
counting_equation.count = 0
|
|
213
|
-
solver_rk45_precise = wp.solver.OdeSolver(counting_equation,
|
|
214
|
+
solver_rk45_precise = wp.solver.OdeSolver(counting_equation, np.pi/2, rtol=1e-9, atol=1e-9)
|
|
214
215
|
solver_rk45_precise.step(psi0, t=0)
|
|
215
216
|
print(f"High-precision Runge-Kutta 4/5 solver: count={counting_equation.count}")
|
|
216
217
|
```
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
---
|
|
2
|
+
file_format: mystnb
|
|
3
|
+
kernelspec:
|
|
4
|
+
name: python3
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Background theory: Reduced density operators
|
|
8
|
+
|
|
9
|
+
This web page can be downloaded as notebook: {nb-download}`reduced_density.ipynb` (Jupyter)
|
|
10
|
+
or {download}`reduced_density.md` (Markdown)
|
|
11
|
+
|
|
12
|
+
In this notebook, we investigate a toy problem that qualitatively demonstrates the effect of
|
|
13
|
+
an environment on a quantum measurement.
|
|
14
|
+
Basically, we discuss the mechanism behind coherent and incoherent superpositions,
|
|
15
|
+
that is shown in {doc}`/tutorials/schroedinger_cat`.
|
|
16
|
+
|
|
17
|
+
## Theory: Partial trace
|
|
18
|
+
|
|
19
|
+
Let us consider an excerpt of the universe whose state can be described by a wave function.
|
|
20
|
+
At some point, we want to make a measurement, so we calculate an expectation value of the corresponding operator.
|
|
21
|
+
By inserting a summation over an orthonormal basis {math}`\phi`, we can rewrite this as a trace over
|
|
22
|
+
a (pure) density operator,
|
|
23
|
+
|
|
24
|
+
\begin{align*}
|
|
25
|
+
\langle \hat A \rangle &= \langle \psi | \hat A | \psi \rangle\\
|
|
26
|
+
&= \langle \psi | \hat A \sum_n|\phi_n\rangle \langle \phi_n | \psi \rangle\\
|
|
27
|
+
&= \sum_n \langle \phi_n | \psi \rangle \langle \psi | \hat A |\phi_n\rangle\\
|
|
28
|
+
&= \mathrm{Tr}(|\psi\rangle\langle\psi | \hat A) = \mathrm{Tr} (\hat \rho \hat A)
|
|
29
|
+
.
|
|
30
|
+
\end{align*}
|
|
31
|
+
|
|
32
|
+
Now we decompose our small universe into system and environment degrees of freedom, $\mathcal{H} = S \otimes E$
|
|
33
|
+
with respective orthonormal basis $\varphi, \eta$.
|
|
34
|
+
As "system", we denote those degrees of freedom along which our operator(s) act,
|
|
35
|
+
the rest we call "environment" or "bath".
|
|
36
|
+
By definition, the operator can be rewritten as $\hat A = \hat A_S \otimes \hat 1_E$,
|
|
37
|
+
where the subscripts denote action or integration over the system or environment part.
|
|
38
|
+
The trace now becomes
|
|
39
|
+
|
|
40
|
+
\begin{align*}
|
|
41
|
+
\langle \hat A \rangle &= \sum_{k,l} \Bigl(\langle \varphi_k | \otimes \langle \eta_l|\Bigr) \ \hat \rho
|
|
42
|
+
\hat A_S \otimes \hat 1_E \ \Bigl(|\varphi_k\rangle_S \otimes |\eta_l \rangle_E\Bigr)\\
|
|
43
|
+
&= \sum_k \langle \varphi_k | \ \Bigl( \sum_l \langle \eta_l | \hat \rho |\eta_l\rangle_E \Bigr)
|
|
44
|
+
\ \hat A_S |\varphi_k\rangle_S \\
|
|
45
|
+
&= \sum_k \langle \varphi_k | \hat \rho_\mathrm{red} \hat A_S | \varphi_k \rangle \\
|
|
46
|
+
&= \mathrm{Tr}_S ( \hat \varrho_\mathrm{red} \hat A_S) \qquad \qquad
|
|
47
|
+
\mathrm{with} \qquad \hat \varrho_\mathrm{red} = \mathrm{Tr}_E \hat \rho
|
|
48
|
+
\end{align*}
|
|
49
|
+
|
|
50
|
+
Even though our original state is pure and can be described by a wave function,
|
|
51
|
+
the reduced density may be impure/mixed and describe a statistical ensemble.
|
|
52
|
+
It can easily be checked that
|
|
53
|
+
|
|
54
|
+
\begin{align*}
|
|
55
|
+
\psi = (\varphi_0 + \varphi_1) \otimes \eta_0 \quad &\rightarrow \quad
|
|
56
|
+
\varrho_\mathrm{red} = |\varphi_0+\varphi_1\rangle\langle\varphi_0+\varphi_1|\\
|
|
57
|
+
\psi = \varphi_0 \otimes \eta_0 + \varphi_1 \otimes \eta_1 \quad &\rightarrow \quad
|
|
58
|
+
\varrho_\mathrm{red} = |\varphi_0\rangle\langle\varphi_0| + |\varphi_1\langle\rangle \varphi_1|
|
|
59
|
+
\end{align*}
|
|
60
|
+
|
|
61
|
+
That is, we get a pure reduced density if $\psi$ is a product state,
|
|
62
|
+
and a mixed reduced density if $\psi$ contains correlations between the system and environment.
|
|
63
|
+
|
|
64
|
+
## The system under study
|
|
65
|
+
|
|
66
|
+
With the basic theory result spelled out, let us look at a toy example, where we can observe these effects,
|
|
67
|
+
yet still understand the full dynamics.
|
|
68
|
+
We use one-dimensional harmonic oscillators for the system and environment, respectively.
|
|
69
|
+
Let us start with the grid definitions:
|
|
70
|
+
|
|
71
|
+
```{code-cell}
|
|
72
|
+
import wavepacket as wp
|
|
73
|
+
|
|
74
|
+
system_dof = wp.grid.PlaneWaveDof(-10, 10, 96)
|
|
75
|
+
environment_dof = wp.grid.PlaneWaveDof(-5, 5, 96)
|
|
76
|
+
full_grid = wp.grid.Grid([system_dof, environment_dof])
|
|
77
|
+
|
|
78
|
+
trafo = wp.grid.PartialTraceTransformation(full_grid, 0)
|
|
79
|
+
system_grid = trafo.target_grid
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
We exploit here that the transformation object creates a one-dimensional "target grid"
|
|
83
|
+
containing only the first (/system) degree of freedom during setup.
|
|
84
|
+
We will use this transformation later to calculate the reduced density operator
|
|
85
|
+
from a state defined on the system+environment grid.
|
|
86
|
+
|
|
87
|
+
For system and environment, we define different harmonic oscillators
|
|
88
|
+
|
|
89
|
+
```{code-cell}
|
|
90
|
+
kinetic_sys = wp.operator.CartesianKineticEnergy(system_grid, 0, mass=1, cutoff=40)
|
|
91
|
+
potential_sys = wp.operator.Potential1D(system_grid, 0, lambda x: 0.5 * x**2, cutoff=40)
|
|
92
|
+
|
|
93
|
+
kinetic_full = (wp.operator.CartesianKineticEnergy(full_grid, 0, mass=1, cutoff=40)
|
|
94
|
+
+ wp.operator.CartesianKineticEnergy(full_grid, 1, mass=1, cutoff=40))
|
|
95
|
+
potential_full = (wp.operator.Potential1D(full_grid, 0, lambda x: 0.5 * x**2, cutoff=40)
|
|
96
|
+
+ wp.operator.Potential1D(full_grid, 1, lambda x: 0.5 * (2*x)**2, cutoff=40))
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Dynamics with and without environment
|
|
100
|
+
|
|
101
|
+
### Product state without coupling
|
|
102
|
+
|
|
103
|
+
To demonstrate the theoretical results, we start with an environment not coupled to the system,
|
|
104
|
+
and with a product state.
|
|
105
|
+
For the initial system states, we choose a squeezed and shifted Gaussian that oscillates in the system potential.
|
|
106
|
+
For the environment state, we choose some Gaussian centered around the potential minimum.
|
|
107
|
+
|
|
108
|
+
```{code-cell}
|
|
109
|
+
import math
|
|
110
|
+
|
|
111
|
+
left_gauss = wp.special.Gaussian(-5, 0, rms=0.5)
|
|
112
|
+
right_gauss = wp.special.Gaussian(5, 0, rms=0.5)
|
|
113
|
+
env_gauss = wp.special.Gaussian(0, 0, rms=0.5)
|
|
114
|
+
|
|
115
|
+
psi0_sys = math.sqrt(0.5) * (
|
|
116
|
+
wp.builder.product_wave_function(system_grid, left_gauss)
|
|
117
|
+
+ wp.builder.product_wave_function(system_grid, right_gauss)
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
psi0_full = math.sqrt(0.5) * (
|
|
121
|
+
wp.builder.product_wave_function(full_grid, [left_gauss, env_gauss])
|
|
122
|
+
+ wp.builder.product_wave_function(full_grid, [right_gauss, env_gauss])
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
As reference, we start with a simulation of only the system degree of freedom.
|
|
127
|
+
|
|
128
|
+
```{code-cell}
|
|
129
|
+
equation_sys = wp.expression.SchroedingerEquation(kinetic_sys + potential_sys)
|
|
130
|
+
|
|
131
|
+
solver = wp.solver.ChebychevSolver(equation_sys, math.pi/6, (0, 80))
|
|
132
|
+
plotter = wp.plot.StackedPlot1D(4, psi0_sys, potential_sys, kinetic_sys + potential_sys)
|
|
133
|
+
for t, psi in solver.propagate(psi0_sys, 0.0, 3):
|
|
134
|
+
plotter.plot(t, psi);
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The two Gaussians breathe and oscillate in the potential and show interference when they cross paths.
|
|
138
|
+
This is just textbook quantum mechanics, no surprises so far.
|
|
139
|
+
|
|
140
|
+
Now what happens if we add an environment degree of freedom?
|
|
141
|
+
We start with a product state, and because of the missing system-environment coupling,
|
|
142
|
+
our solution remains a product state.
|
|
143
|
+
Hence, we expect a pure reduced density matrix that just replicates the
|
|
144
|
+
system-only result including interferences.
|
|
145
|
+
|
|
146
|
+
```{code-cell}
|
|
147
|
+
equation_uncoupled = wp.expression.SchroedingerEquation(kinetic_full + potential_full)
|
|
148
|
+
|
|
149
|
+
solver = wp.solver.ChebychevSolver(equation_uncoupled, math.pi/6, (0, 160))
|
|
150
|
+
plotter = wp.plot.StackedPlot1D(4, psi0_sys, potential_sys, kinetic_sys + potential_sys)
|
|
151
|
+
for t, psi in solver.propagate(psi0_full, 0.0, 3):
|
|
152
|
+
reduced_density = trafo.transform(psi)
|
|
153
|
+
plotter.plot(t, reduced_density);
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This result also makes sense for philosophical reasons.
|
|
157
|
+
If the addition of an arbitrary, uninteresting degree of freedom would change the results,
|
|
158
|
+
we could modify any calculation results by, say, adding the phase of the moon
|
|
159
|
+
which is an obviously silly proposition.
|
|
160
|
+
|
|
161
|
+
### Couplings and correlations
|
|
162
|
+
|
|
163
|
+
For the environment to have an effect on the system dynamics, we need to introduce a coupling.
|
|
164
|
+
To understand what happens now, let us first have a look at the two-dimensional dynamics.
|
|
165
|
+
|
|
166
|
+
```{code-cell}
|
|
167
|
+
coupling = -0.5 * (wp.operator.Potential1D(full_grid, 0, lambda x: x)
|
|
168
|
+
* wp.operator.Potential1D(full_grid, 1, lambda x: x))
|
|
169
|
+
equation_coupled = wp.expression.SchroedingerEquation(kinetic_full + potential_full + coupling)
|
|
170
|
+
|
|
171
|
+
# store the results, we iterate twice over them, but want to calculate only once.
|
|
172
|
+
solver = wp.solver.ChebychevSolver(equation_coupled, math.pi/6, (0, 210))
|
|
173
|
+
results = [(t, psi) for t, psi in solver.propagate(psi0_full, 0.0, 3)]
|
|
174
|
+
|
|
175
|
+
plotter = wp.plot.StackedContourPlot2D(2, 2, psi0_full, potential_full + coupling)
|
|
176
|
+
plotter.contours /= 2
|
|
177
|
+
for t, psi in results:
|
|
178
|
+
plotter.plot(t, psi)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Adding a bilinear coupling to a harmonic oscillator results in a harmonic oscillator
|
|
182
|
+
with different frequencies, and rotated normal modes.
|
|
183
|
+
For the parameters here, we see that the new normal modes are roughly
|
|
184
|
+
$n_0 \approx x_s + 0.5 x_e$ and $n_1 \approx x_s - 0.5 x_e$.
|
|
185
|
+
|
|
186
|
+
The two Gaussians that form our initial state move along these new normal modes, and now it gets interesting.
|
|
187
|
+
From a purely formal perspective, we get correlations between the system and environment.
|
|
188
|
+
That is, the total wave function is clearly no longer a direct product of a system and an environment wave function.
|
|
189
|
+
As discussed in the theory section, we expect a mixed density operator and a suppression of interferences.
|
|
190
|
+
|
|
191
|
+
We can also look at the situation from a different angle.
|
|
192
|
+
Because the two Gaussians move along the new normal modes, they mostly miss each other,
|
|
193
|
+
and barely overlap / interfere in the system-environment space.
|
|
194
|
+
The operation of tracing out the environment just projects this situation onto the system axis;
|
|
195
|
+
basically as if you "looked onto a projection of the plot while standing on the system axis".
|
|
196
|
+
|
|
197
|
+
```{code-cell}
|
|
198
|
+
plotter = wp.plot.StackedPlot1D(4, psi0_sys, potential_sys, kinetic_sys + potential_sys)
|
|
199
|
+
for t, psi in results:
|
|
200
|
+
reduced_density = trafo.transform(psi)
|
|
201
|
+
plotter.plot(t, reduced_density);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
In a "real" system, we define observables for a few degrees of freedom at most,
|
|
205
|
+
while the environment around the system has a gazillion degrees of freedom.
|
|
206
|
+
There is then much more "space" for different parts of the total wave function to avoid each other.
|
|
207
|
+
After a while (the "decoherence time"), the likelihood of different parts of
|
|
208
|
+
the wave function overlapping in the system+environment space is negligible,
|
|
209
|
+
and interferences vanish.
|
|
210
|
+
|
|
211
|
+
Note, however, that we introduced a pretty strong system-environment coupling to force visible effects.
|
|
212
|
+
In practical systems, such couplings may be weak, giving significant experimental time scales during which you
|
|
213
|
+
can safely ignore environment effects.
|
|
214
|
+
|
|
215
|
+
But even the weakest coupling affects the initial state.
|
|
216
|
+
Typically, at the start of an experiment, the system has spent plenty of time interacting with the environment;
|
|
217
|
+
it is "thermalized".
|
|
218
|
+
And this interaction has introduced correlations between the system and the environment into the initial state,
|
|
219
|
+
whose reduced density matrix is therefore no longer pure.
|
|
220
|
+
Let us set up such a prototypical situation here again: We use a correlated initial state,
|
|
221
|
+
and ignore coupling between system and environment.
|
|
222
|
+
|
|
223
|
+
```{code-cell}
|
|
224
|
+
psi0_correlated = math.sqrt(0.5) * (
|
|
225
|
+
wp.builder.product_wave_function(full_grid, [left_gauss, wp.special.Gaussian(-1.5, 0, rms=0.5)])
|
|
226
|
+
+ wp.builder.product_wave_function(full_grid, [right_gauss, env_gauss])
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
# store the results, we iterate twice over them, but want to calculate only once.
|
|
231
|
+
solver = wp.solver.ChebychevSolver(equation_uncoupled, math.pi/6, (0, 180))
|
|
232
|
+
results = [(t, psi) for t, psi in solver.propagate(psi0_correlated, 0.0, 3)]
|
|
233
|
+
|
|
234
|
+
plotter = wp.plot.StackedContourPlot2D(2, 2, psi0_correlated, potential_full)
|
|
235
|
+
plotter.contours /= 2
|
|
236
|
+
for t, psi in results:
|
|
237
|
+
plotter.plot(t, psi)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
The "right" Gaussian oscillates only along the system degree of freedom,
|
|
241
|
+
while the "left" Gaussian follows a trajectory from the "bottom left" to the "center top".
|
|
242
|
+
As a consequence, these two wave packets again miss each other, and the interference pattern is suppressed.
|
|
243
|
+
If we look at the system degree of freedom again, we find exactly this pattern:
|
|
244
|
+
|
|
245
|
+
```{code-cell}
|
|
246
|
+
plotter = wp.plot.StackedPlot1D(4, psi0_sys, potential_sys, kinetic_sys + potential_sys)
|
|
247
|
+
for t, psi in results:
|
|
248
|
+
reduced_density = trafo.transform(psi)
|
|
249
|
+
plotter.plot(t, reduced_density);
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
While interference patterns _within_ each Gaussian are retained during the simulation (no coupling),
|
|
253
|
+
there is no interference _between_ the two Gaussians.
|
|
254
|
+
Or in other words, even though we can ignore the environment during the simulation, we need to
|
|
255
|
+
take it into account in the initial state.
|
|
256
|
+
Following this thread of thought much further eventually leads to the
|
|
257
|
+
expression of thermal states with mixed density operators,
|
|
258
|
+
without interference terms between the system Hamiltonian's eigentstates,
|
|
259
|
+
but that goes well beyond such a small Jupyter notebook.
|
|
@@ -14,6 +14,7 @@ or {download}`thermal_states.md` (Markdown)
|
|
|
14
14
|
Sometimes, we wish to study systems at finite temperatures.
|
|
15
15
|
To describe such systems, we need either a density operator or an ensemble of wave functions.
|
|
16
16
|
The textbook expression for a thermal state is a density operator
|
|
17
|
+
(we use atomic units throughout the text)
|
|
17
18
|
|
|
18
19
|
$$
|
|
19
20
|
\hat \varrho_\mathrm{th} = \frac{1}{Z} \ \mathrm{e}^{- \beta \hat H}
|
|
@@ -49,7 +50,7 @@ but the path to more complex setups should be readily apparent from the formulas
|
|
|
49
50
|
As example system, we calculate the temperature-dependent energy of a Morse oscillator,
|
|
50
51
|
with parameters chosen for an OH radical.
|
|
51
52
|
The system is simple, but not entirely trivial.
|
|
52
|
-
Because we are going to use the {py:class}`RelaxationSolver`,
|
|
53
|
+
Because we are going to use the {py:class}`wavepacket.solver.RelaxationSolver`,
|
|
53
54
|
we truncate the operators at energies well beyond the dissociation energy.
|
|
54
55
|
This has the side effect of providing us bounds for the spectrum of the Hamiltonian that we can use later.
|
|
55
56
|
|
|
@@ -211,7 +212,7 @@ explicit solver.
|
|
|
211
212
|
|
|
212
213
|
### Implementation
|
|
213
214
|
|
|
214
|
-
For simplicity, we choose to obtain the eigenstates here from
|
|
215
|
+
For simplicity, we choose to obtain the eigenstates here from diagonalizing the Hamiltonian matrix.
|
|
215
216
|
This is not a good choice performance-wise, but keeps the example focused.
|
|
216
217
|
|
|
217
218
|
Conceptually, we need two passes.
|
|
@@ -276,7 +277,7 @@ complexity.
|
|
|
276
277
|
One solution is the use of imaginary-time relaxation to get the lowest few eigenstates.
|
|
277
278
|
This method is discussed in {doc}`/tutorials/relaxation`.
|
|
278
279
|
Curiously, the relaxation limitation to few excited eigenstates aligns naturally
|
|
279
|
-
with
|
|
280
|
+
with this method's limitation to few excited eigenstates.
|
|
280
281
|
|
|
281
282
|
If relaxation is difficult, you can simply choose a different basis.
|
|
282
283
|
After all, we do not need energy eigenstates, we need to cover the relevant low-energy subspace.
|
|
@@ -326,7 +327,7 @@ $$
|
|
|
326
327
|
Random wave functions are only useful for certain manipulations, such as replacing a unit operator.
|
|
327
328
|
You must not confuse them with ordinary wave functions,
|
|
328
329
|
as not all operations are well-defined.
|
|
329
|
-
For example, it is easy to check that they
|
|
330
|
+
For example, it is easy to check that they are not normalized.
|
|
330
331
|
```
|
|
331
332
|
|
|
332
333
|
We now take again [the response expression](#eq_response), split the exponential,
|
|
@@ -361,7 +362,7 @@ On first view, this method may look like a slightly deranged variant of the prev
|
|
|
361
362
|
So how, and especially why and when does it work?
|
|
362
363
|
The hand-waving answer is that this is almost method II, but
|
|
363
364
|
the ensemble of random wave functions (i) is not orthogonal (bad),
|
|
364
|
-
and (ii) covers the "typical" Hilbert space
|
|
365
|
+
and (ii) covers the "typical" Hilbert space with few wave functions already (good).
|
|
365
366
|
|
|
366
367
|
Non-orthogonality is uniformly bad; it means for example that you may count contributions twice,
|
|
367
368
|
and this problem only averages out over large samples.
|
|
@@ -383,7 +384,7 @@ where the phase is drawn uniformly from the interval $\phi \in [-\pi, \pi]$.
|
|
|
383
384
|
The overall implementation is similar to that of method II with three differences.
|
|
384
385
|
|
|
385
386
|
1. Instead of calculating eigenstates, we generate random wave functions using
|
|
386
|
-
{py:func}`
|
|
387
|
+
{py:func}`wavepacket.builder.random_wave_function`.
|
|
387
388
|
2. We need to explicitly relax the states.
|
|
388
389
|
3. We do not sum the individual contributions, but average.
|
|
389
390
|
|
|
@@ -27,7 +27,7 @@ To get there, the code ended up with a few common concepts.
|
|
|
27
27
|
and we did not cover every potential pitfall. Avoid breaking this guarantee, however,
|
|
28
28
|
because doing so can corrupt object consistency (and therefore results) in
|
|
29
29
|
subtle ways. In particular, if you create a :py:class:`wavepacket.grid.State`
|
|
30
|
-
directly from a numpy array (very advanced use case),
|
|
30
|
+
directly from a numpy array (very advanced use case), forget about this array and
|
|
31
31
|
do not modify it afterwards.
|
|
32
32
|
|
|
33
33
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
project = "Wavepacket"
|
|
10
10
|
copyright = "2024-%Y, Ulf Lorenz"
|
|
11
11
|
author = "Ulf Lorenz"
|
|
12
|
-
release = "0.
|
|
12
|
+
release = "0.5"
|
|
13
13
|
|
|
14
14
|
# -- General configuration ---------------------------------------------------
|
|
15
15
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
|
@@ -19,6 +19,7 @@ Wavepacket documentation
|
|
|
19
19
|
tutorials/schroedinger_cat
|
|
20
20
|
tutorials/eigenstates
|
|
21
21
|
tutorials/plotting
|
|
22
|
+
tutorials/channels
|
|
22
23
|
tutorials/chebychev_solvers
|
|
23
24
|
tutorials/relaxation
|
|
24
25
|
|
|
@@ -28,6 +29,7 @@ Wavepacket documentation
|
|
|
28
29
|
|
|
29
30
|
advanced/pendular_states
|
|
30
31
|
advanced/thermal_states
|
|
32
|
+
advanced/reduced_density
|
|
31
33
|
advanced/plane_wave_grid
|
|
32
34
|
advanced/ode_solvers
|
|
33
35
|
advanced/polynomial_solvers
|