wavepacket 0.1.0__tar.gz → 0.2.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.
- wavepacket-0.2.0/.github/workflows/ci_testing.yml +30 -0
- wavepacket-0.2.0/.gitignore +67 -0
- wavepacket-0.2.0/.readthedocs.yaml +18 -0
- wavepacket-0.2.0/CHANGELOG.rst +41 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/PKG-INFO +3 -12
- wavepacket-0.2.0/doc/Makefile +20 -0
- wavepacket-0.2.0/doc/architecture.rst +67 -0
- wavepacket-0.2.0/doc/conf.py +53 -0
- wavepacket-0.2.0/doc/demos/pendular_states.md +170 -0
- wavepacket-0.2.0/doc/getting-started.rst +55 -0
- wavepacket-0.2.0/doc/index.rst +64 -0
- wavepacket-0.2.0/doc/make.bat +35 -0
- wavepacket-0.2.0/doc/representations.rst +130 -0
- wavepacket-0.2.0/doc/requirements.txt +248 -0
- wavepacket-0.2.0/doc/tutorials/plotting.md +197 -0
- wavepacket-0.2.0/doc/tutorials/schroedinger_cat.md +96 -0
- wavepacket-0.2.0/pyproject.toml +64 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/__init__.py +10 -8
- wavepacket-0.2.0/src/wavepacket/builder/__init__.py +9 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/builder/density.py +27 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/builder/wave_function.py +54 -0
- wavepacket-0.2.0/src/wavepacket/functions.py +90 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/generators.py +45 -1
- wavepacket-0.2.0/src/wavepacket/grid/__init__.py +13 -0
- wavepacket-0.2.0/src/wavepacket/grid/_utils.py +23 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/grid/grid.py +4 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/grid/planewavedof.py +8 -14
- wavepacket-0.2.0/src/wavepacket/grid/spherical_harmonics_dof.py +161 -0
- wavepacket-0.2.0/src/wavepacket/grid/state_utilities.py +250 -0
- wavepacket-0.2.0/src/wavepacket/operator/__init__.py +14 -0
- wavepacket-0.2.0/src/wavepacket/operator/fbroperators.py +184 -0
- wavepacket-0.2.0/src/wavepacket/operator/misc_operators.py +109 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/operator/operatorbase.py +75 -6
- wavepacket-0.2.0/src/wavepacket/operator/time_dependent_operators.py +70 -0
- wavepacket-0.2.0/src/wavepacket/plot/__init__.py +3 -0
- wavepacket-0.2.0/src/wavepacket/plot/plot_1d.py +221 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/typing/data_types.py +1 -1
- wavepacket-0.2.0/test/builder/test_density.py +78 -0
- wavepacket-0.2.0/test/builder/test_product_wave_function.py +42 -0
- wavepacket-0.2.0/test/builder/test_wave_function.py +60 -0
- wavepacket-0.2.0/test/conftest.py +14 -0
- wavepacket-0.2.0/test/expression/test_commutatorliouvillian.py +49 -0
- wavepacket-0.2.0/test/expression/test_schroedingerequation.py +32 -0
- wavepacket-0.2.0/test/grid/test_dofbase.py +51 -0
- wavepacket-0.2.0/test/grid/test_grid.py +105 -0
- wavepacket-0.2.0/test/grid/test_planewavedof_basics.py +60 -0
- wavepacket-0.2.0/test/grid/test_planewavedof_transformations.py +125 -0
- wavepacket-0.2.0/test/grid/test_sphericalharmonicsdof_basics.py +50 -0
- wavepacket-0.2.0/test/grid/test_sphericalharmonicsdof_transformations.py +110 -0
- wavepacket-0.2.0/test/grid/test_state.py +103 -0
- wavepacket-0.2.0/test/grid/test_state_utilities.py +177 -0
- wavepacket-0.2.0/test/operator/test_fbroperator.py +75 -0
- wavepacket-0.2.0/test/operator/test_misc_operators.py +112 -0
- wavepacket-0.2.0/test/operator/test_operator_arithmetic.py +113 -0
- wavepacket-0.2.0/test/operator/test_operatorbase.py +41 -0
- wavepacket-0.2.0/test/operator/test_operatorutils.py +40 -0
- wavepacket-0.2.0/test/operator/test_planewavefbroperator.py +72 -0
- wavepacket-0.2.0/test/operator/test_potential1d.py +57 -0
- wavepacket-0.2.0/test/operator/test_time_dependent_operators.py +35 -0
- wavepacket-0.2.0/test/solver/test_odesolver.py +46 -0
- wavepacket-0.2.0/test/solver/test_solverbase.py +57 -0
- wavepacket-0.2.0/test/test_base_exports.py +5 -0
- wavepacket-0.2.0/test/test_functions.py +56 -0
- wavepacket-0.2.0/test/test_generators.py +71 -0
- wavepacket-0.2.0/test/test_logging.py +8 -0
- wavepacket-0.1.0/pyproject.toml +0 -41
- wavepacket-0.1.0/src/wavepacket/builder/__init__.py +0 -8
- wavepacket-0.1.0/src/wavepacket/grid/__init__.py +0 -12
- wavepacket-0.1.0/src/wavepacket/grid/state_utilities.py +0 -89
- wavepacket-0.1.0/src/wavepacket/operator/__init__.py +0 -12
- wavepacket-0.1.0/src/wavepacket/operator/fbroperators.py +0 -94
- {wavepacket-0.1.0 → wavepacket-0.2.0}/LICENSE +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/README.rst +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/exceptions.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/expression/__init__.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/expression/expressionbase.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/expression/liouvillian.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/expression/schroedingerequation.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/grid/dofbase.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/grid/state.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/logging.py +0 -0
- /wavepacket-0.1.0/src/wavepacket/operator/operatorutils.py → /wavepacket-0.2.0/src/wavepacket/operator/operator_utils.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/operator/potentials.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/solver/__init__.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/solver/odesolver.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/solver/solverbase.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/testing/__init__.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/testing/assertions.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/testing/dummydof.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/testing/dummyoperator.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/testing/random.py +0 -0
- {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/typing/__init__.py +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Wavepacket CI
|
|
2
|
+
run-name: Testing ${{ github.ref_name }} with ref ${{ github.ref }}
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
push
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
Run-all-tests:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- uses: actions/setup-python@v6
|
|
13
|
+
id: cp311
|
|
14
|
+
with:
|
|
15
|
+
python-version: '3.11'
|
|
16
|
+
- uses: actions/setup-python@v6
|
|
17
|
+
id: cp312
|
|
18
|
+
with:
|
|
19
|
+
python-version: '3.12'
|
|
20
|
+
- uses: actions/setup-python@v6
|
|
21
|
+
id: cp313
|
|
22
|
+
with:
|
|
23
|
+
python-version: '3.13'
|
|
24
|
+
- uses: actions/setup-python@v6
|
|
25
|
+
id: cp314
|
|
26
|
+
with:
|
|
27
|
+
python-version: '3.14'
|
|
28
|
+
- run: ${{ steps.cp313.outputs.python-path }} -m venv ~/venv
|
|
29
|
+
- run: ~/venv/bin/python -m pip install tox
|
|
30
|
+
- run: cd $GITHUB_WORKSPACE && ~/venv/bin/tox
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
.Python
|
|
8
|
+
build/
|
|
9
|
+
develop-eggs/
|
|
10
|
+
dist/
|
|
11
|
+
downloads/
|
|
12
|
+
eggs/
|
|
13
|
+
.eggs/
|
|
14
|
+
lib/
|
|
15
|
+
lib64/
|
|
16
|
+
parts/
|
|
17
|
+
sdist/
|
|
18
|
+
var/
|
|
19
|
+
wheels/
|
|
20
|
+
share/python-wheels/
|
|
21
|
+
*.egg-info/
|
|
22
|
+
.installed.cfg
|
|
23
|
+
*.egg
|
|
24
|
+
MANIFEST
|
|
25
|
+
|
|
26
|
+
# Installer logs
|
|
27
|
+
pip-log.txt
|
|
28
|
+
pip-delete-this-directory.txt
|
|
29
|
+
|
|
30
|
+
# Unit test / coverage reports
|
|
31
|
+
htmlcov/
|
|
32
|
+
.tox/
|
|
33
|
+
.nox/
|
|
34
|
+
.coverage
|
|
35
|
+
.coverage.*
|
|
36
|
+
.cache
|
|
37
|
+
nosetests.xml
|
|
38
|
+
coverage.xml
|
|
39
|
+
*.cover
|
|
40
|
+
*.py,cover
|
|
41
|
+
.hypothesis/
|
|
42
|
+
.pytest_cache/
|
|
43
|
+
cover/
|
|
44
|
+
|
|
45
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
46
|
+
__pypackages__/
|
|
47
|
+
|
|
48
|
+
# mkdocs documentation
|
|
49
|
+
/site
|
|
50
|
+
|
|
51
|
+
# mypy
|
|
52
|
+
.mypy_cache/
|
|
53
|
+
.dmypy.json
|
|
54
|
+
dmypy.json
|
|
55
|
+
|
|
56
|
+
# Pyre type checker
|
|
57
|
+
.pyre/
|
|
58
|
+
|
|
59
|
+
# pytype static type analyzer
|
|
60
|
+
.pytype/
|
|
61
|
+
|
|
62
|
+
# PyCharm
|
|
63
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
64
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
65
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
66
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
67
|
+
.idea/
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
|
|
3
|
+
build:
|
|
4
|
+
os: ubuntu-22.04
|
|
5
|
+
tools:
|
|
6
|
+
python: "3.13"
|
|
7
|
+
apt_packages:
|
|
8
|
+
- dvipng
|
|
9
|
+
- texlive-binaries
|
|
10
|
+
formats:
|
|
11
|
+
- htmlzip
|
|
12
|
+
sphinx:
|
|
13
|
+
configuration: doc/conf.py
|
|
14
|
+
python:
|
|
15
|
+
install:
|
|
16
|
+
- requirements: doc/requirements.txt
|
|
17
|
+
- method: pip
|
|
18
|
+
path: .
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
=========
|
|
2
|
+
ChangeLog
|
|
3
|
+
=========
|
|
4
|
+
|
|
5
|
+
0.2
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
- (#18) added spherical harmonics expansion:
|
|
9
|
+
degree of freedom, operator, generator
|
|
10
|
+
|
|
11
|
+
- (#19) added time-dependent functions and laser fields as operators,
|
|
12
|
+
including helper functions for sin**2 and rectangular pulses with soft turn-on
|
|
13
|
+
|
|
14
|
+
- (#20) added functionality related to projections
|
|
15
|
+
- projection operator for projecting onto a state or subspace
|
|
16
|
+
- population() function to easily calculate populations of target states
|
|
17
|
+
- Gram-Schmidt orthogonalization and normalization
|
|
18
|
+
|
|
19
|
+
- (#21) added more initial states
|
|
20
|
+
random wave functions, zero densities and wave functions, unit density
|
|
21
|
+
- (#21) added function grid.fbr_density() to calculate density in FBR
|
|
22
|
+
|
|
23
|
+
- (#22) 1D plotting helpers
|
|
24
|
+
- added plotting classes StackedPlot1D and SimplePlot1D
|
|
25
|
+
- added a tutorial on plotting
|
|
26
|
+
|
|
27
|
+
- (#23) Added a notebook with the PendularStates demos converted from the older versions
|
|
28
|
+
|
|
29
|
+
- (#15) added CI build using tox for different Python versions
|
|
30
|
+
Wavepacket now supports every Python >= 3.11
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
0.1
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
Initial release.
|
|
37
|
+
|
|
38
|
+
Scope is the simulation of a harmonic oscillator with an ordinary ODE solver,
|
|
39
|
+
plus a bit of introductory documentation and a demo.
|
|
40
|
+
|
|
41
|
+
That is, infrastructure, not so much content.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wavepacket
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A package for the propagation of quantum-mechanical wave functions.
|
|
5
5
|
Author: Ulf Lorenz
|
|
6
|
-
Requires-Python: >=3.
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
7
|
Description-Content-Type: text/x-rst
|
|
8
8
|
Classifier: License :: OSI Approved :: MIT License
|
|
9
9
|
Classifier: Development Status :: 3 - Alpha
|
|
@@ -13,17 +13,8 @@ Classifier: Topic :: Scientific/Engineering :: Physics
|
|
|
13
13
|
License-File: LICENSE
|
|
14
14
|
Requires-Dist: numpy >= 2.1.3
|
|
15
15
|
Requires-Dist: scipy >= 1.14.1
|
|
16
|
-
Requires-Dist: matplotlib >= 3.10
|
|
17
|
-
Requires-Dist: sphinx >= 8.1.3 ; extra == "doc"
|
|
18
|
-
Requires-Dist: sphinx-autoapi >= 3.4.0 ; extra == "doc"
|
|
19
|
-
Requires-Dist: numpydoc >= 1.8.0 ; extra == "doc"
|
|
20
|
-
Requires-Dist: myst-nb >= 1.2 ; extra == "doc"
|
|
21
|
-
Requires-Dist: sphinx-rtd-theme >= 3.0.2 ; extra == "doc"
|
|
22
|
-
Requires-Dist: pytest >= 8.3 ; extra == "test"
|
|
16
|
+
Requires-Dist: matplotlib >= 3.10
|
|
23
17
|
Project-URL: Home, https://github.com/ulflor/wavepacket
|
|
24
|
-
Provides-Extra: demos
|
|
25
|
-
Provides-Extra: doc
|
|
26
|
-
Provides-Extra: test
|
|
27
18
|
|
|
28
19
|
Description
|
|
29
20
|
-----------
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Minimal makefile for Sphinx documentation
|
|
2
|
+
#
|
|
3
|
+
|
|
4
|
+
# You can set these variables from the command line, and also
|
|
5
|
+
# from the environment for the first two.
|
|
6
|
+
SPHINXOPTS ?=
|
|
7
|
+
SPHINXBUILD ?= sphinx-build
|
|
8
|
+
SOURCEDIR = .
|
|
9
|
+
BUILDDIR = _build
|
|
10
|
+
|
|
11
|
+
# Put it first so that "make" without argument is like "make help".
|
|
12
|
+
help:
|
|
13
|
+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
14
|
+
|
|
15
|
+
.PHONY: help Makefile
|
|
16
|
+
|
|
17
|
+
# Catch-all target: route all unknown targets to Sphinx using the new
|
|
18
|
+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
|
19
|
+
%: Makefile
|
|
20
|
+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
Architecture overview
|
|
2
|
+
=====================
|
|
3
|
+
|
|
4
|
+
Common concepts
|
|
5
|
+
---------------
|
|
6
|
+
|
|
7
|
+
The focus of Wavepacket is on flexible setups of simple quantum systems.
|
|
8
|
+
To get there, the code ended up with a few common concepts.
|
|
9
|
+
|
|
10
|
+
* To abstract away the difference between wave functions and density operators,
|
|
11
|
+
a class :py:class:`wavepacket.grid.State` has been introduced.
|
|
12
|
+
* Most utility functions and classes can operate on wave functions as well as
|
|
13
|
+
density operators, wherever this is possible and sensible.
|
|
14
|
+
|
|
15
|
+
Where the difference can lead to confusion and errors, functionality may not be offered.
|
|
16
|
+
For example, the wave function norm is the square root of the
|
|
17
|
+
of the corresponding density operator (trace) norm. This has been extremely confusing
|
|
18
|
+
when switching between the two objects, so Wavepacket does not offer a `norm()`
|
|
19
|
+
function, it offers :py:func:`wavepacket.grid.trace` instead,
|
|
20
|
+
* Classes in Wavepacket normally use the Value Pattern, and are immutable after
|
|
21
|
+
creation. This allows you to recycle objects without side effects; for example,
|
|
22
|
+
when you have set up a Hamiltonian for the field-free case, you can trivially use it
|
|
23
|
+
also as a component for a system interacting with a laser field.
|
|
24
|
+
Also, all classes and packages follow a strict hierarchy as described in the
|
|
25
|
+
subsequent section.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
Packages
|
|
29
|
+
--------
|
|
30
|
+
|
|
31
|
+
Wavepacket is split into several subpackages with hierarchical dependencies.
|
|
32
|
+
From lowest to highest layer, these are:
|
|
33
|
+
|
|
34
|
+
:py:mod:`wavepacket.grid`
|
|
35
|
+
Contains all classes that describe the representation of a state (the grid),
|
|
36
|
+
and all functionality that operates only on this representation. These include
|
|
37
|
+
degrees of freedom, :py:class:`wavepacket.grid.Grid` itself, the class
|
|
38
|
+
:py:class:`wavepacket.grid.State`, as well as supporting functions and classes.
|
|
39
|
+
|
|
40
|
+
:py:mod:`wavepacket.builder`
|
|
41
|
+
Contains utility functions to create an initial wave function or density operator.
|
|
42
|
+
These functions require a grid on which to create the state.
|
|
43
|
+
|
|
44
|
+
:py:mod:`wavepacket.operator`
|
|
45
|
+
Contains operator classes. Operators are always defined on a specific grid,
|
|
46
|
+
hence this module requires the grid module. The module also contains some utility
|
|
47
|
+
functions related to operators, such as :py:func:`wavepacket.operator.expectation_value`
|
|
48
|
+
|
|
49
|
+
:py:mod:`wavepacket.expression`
|
|
50
|
+
This module contains classes that wrap an operator for a differential
|
|
51
|
+
equation. These can be a Schroedinger equation or various Liouvillians.
|
|
52
|
+
As these entities wrap an operator, this module requires the operator module.
|
|
53
|
+
|
|
54
|
+
:py:mod:`wavepacket.solver`
|
|
55
|
+
Here, you can find actual Solvers for the differential equations.
|
|
56
|
+
Hence, this module requires knowledge of the expression module.
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
Two other modules stand apart from this hierarchy:
|
|
60
|
+
|
|
61
|
+
* :py:mod:`wavepacket.typing` contains definitions for type hinting.
|
|
62
|
+
* :py:mod:`wavepacket.testing` contains some test helpers,
|
|
63
|
+
for example :py:func:`wavepacket.testing.assert_close` to compare two states with each other.
|
|
64
|
+
* A few grid-independent utilities are found in the top-level namespace, such as
|
|
65
|
+
callables, exceptions, logging functions etc.
|
|
66
|
+
|
|
67
|
+
With these concepts in mind, most functionality should be readily findable.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Configuration file for the Sphinx documentation builder.
|
|
2
|
+
#
|
|
3
|
+
# For the full list of built-in configuration values, see the documentation:
|
|
4
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
|
5
|
+
|
|
6
|
+
# -- Project information -----------------------------------------------------
|
|
7
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
|
8
|
+
|
|
9
|
+
project = 'Wavepacket'
|
|
10
|
+
copyright = '2025, Ulf Lorenz'
|
|
11
|
+
author = 'Ulf Lorenz'
|
|
12
|
+
release = '0.2'
|
|
13
|
+
|
|
14
|
+
# -- General configuration ---------------------------------------------------
|
|
15
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
|
16
|
+
|
|
17
|
+
extensions = [
|
|
18
|
+
"sphinx.ext.autodoc",
|
|
19
|
+
"sphinx.ext.imgmath",
|
|
20
|
+
"sphinx.ext.inheritance_diagram",
|
|
21
|
+
"autoapi.extension",
|
|
22
|
+
"numpydoc",
|
|
23
|
+
"myst_nb"
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
templates_path = ['_templates']
|
|
27
|
+
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
|
28
|
+
|
|
29
|
+
# ------ AutoApi configuration
|
|
30
|
+
autoapi_dirs = ["../src/wavepacket"]
|
|
31
|
+
|
|
32
|
+
autoapi_options = ['members', 'undoc-members', 'imported-members',
|
|
33
|
+
'show-inheritance', 'show-module-summary']
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# Unless we prefix _every_ module by "_", we get every symbol twice: Once in the
|
|
37
|
+
# exposing package, once in the defining module. This here skips all module docs.
|
|
38
|
+
def skip_modules(app, what, name, obj, skip, options):
|
|
39
|
+
if what == "module":
|
|
40
|
+
skip = True
|
|
41
|
+
|
|
42
|
+
return skip
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def setup(sphinx):
|
|
46
|
+
sphinx.connect("autoapi-skip-member", skip_modules)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# -- Options for HTML output -------------------------------------------------
|
|
50
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
|
51
|
+
|
|
52
|
+
html_theme = 'sphinx_rtd_theme'
|
|
53
|
+
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
---
|
|
2
|
+
file_format: mystnb
|
|
3
|
+
kernelspec:
|
|
4
|
+
name: python3
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
(demo-pendular-states)=
|
|
8
|
+
|
|
9
|
+
# Pendular states
|
|
10
|
+
|
|
11
|
+
The goal of this demo is the partial reproduction of some results of a paper by Oritgoso et al.[^ref-paper]
|
|
12
|
+
Besides discussing pretty cool physics, it aims to demonstrate
|
|
13
|
+
how to extract non-trivial data with minimal fuss and plot it.
|
|
14
|
+
|
|
15
|
+
## Alignment of molecules, some theory
|
|
16
|
+
|
|
17
|
+
If a molecule interacts with a non-resonant laser field, the ground state is shifted in energy.
|
|
18
|
+
We can calculate the shift with standard perturbation theory and cavity-dressed states as
|
|
19
|
+
|
|
20
|
+
```{math}
|
|
21
|
+
\Delta E \propto - \sum_n \frac{|\langle \Phi_0 | \hat{\vec{\mu}} \vec E |\Phi_n \rangle|^2}{E_n - E_i - \omega}
|
|
22
|
+
= - \frac{1}{2} \alpha(\omega) E^2 \cos^2 \theta
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
in terms of the dipole operator {math}`\mu`, the electric field with strength {math}`E` and frequency {math}`\omega`,
|
|
26
|
+
and where the summation includes all excited states {math}`\Phi_n` with energies {math}`E_n`.
|
|
27
|
+
Calculating the energy shift is difficult, but that is not our goal here.
|
|
28
|
+
Instead, we absorb all these calculations in a material-specific dynamic polarizability {math}`\alpha(\omega)`.
|
|
29
|
+
Then only a dependency on the angle {math}`\theta` between the effective dipole moment and the laser
|
|
30
|
+
polarization axis remains.
|
|
31
|
+
|
|
32
|
+
If we plug this energy shift into the formula of a rigid linear rotor, we arrive at the Hamiltonian
|
|
33
|
+
|
|
34
|
+
```{math}
|
|
35
|
+
\hat H = \frac{\hat{L}^2}{2I} - \frac{1}{2} \ \alpha E^2 \cos^2\theta.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This Hamiltonian describes a linear rotor (first term) trapped in a cosine-shaped potential that draws the
|
|
39
|
+
rotor towards the laser polarization axis ({math}`\alpha > 0`) or away from it ({math}`\alpha < 0`).
|
|
40
|
+
In the following, we only consider the former case of a positive polarizability.
|
|
41
|
+
As the final step, we introduce three further manipulations:
|
|
42
|
+
|
|
43
|
+
1. We assume that the electric field changes slowly over time. Effectively, this adds a time-dependent shape function
|
|
44
|
+
to the second term in the Hamiltonian. We will follow the reference and assume a Gaussian shape.
|
|
45
|
+
2. Because only the product of electric field strength and polarizability matters, we replace it by a
|
|
46
|
+
single parameter.
|
|
47
|
+
3. To get rid of the moment of inertia, we rescale the time such that we can set {math}`I=1`.
|
|
48
|
+
|
|
49
|
+
With these manipulations, we arrive at the final formulation of a scaled model Hamiltonian
|
|
50
|
+
|
|
51
|
+
```{math}
|
|
52
|
+
\hat H = \frac{\hat{L}^2}{2} - \frac{\Delta}{2} \ \cos^2\theta \ \mathrm{e}^{- (t - \delta)^2 / \sigma^2}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
In the following, we will follow ref.[^ref-paper] further by studying the dynamics of this Hamiltonian
|
|
56
|
+
in different parameter regimes.
|
|
57
|
+
|
|
58
|
+
## Non-adiabatic alignment
|
|
59
|
+
|
|
60
|
+
The natural timescales of the scaled Hamiltonian are determined by the energy levels of the free rotor.
|
|
61
|
+
For low-lying rotational states, these time scales are somewhere on the order of 0.1 ... 1.
|
|
62
|
+
If the laser pulse is shorter than this timescale, the laser effectively "kicks" the rotor,
|
|
63
|
+
after which it starts to tumble.
|
|
64
|
+
|
|
65
|
+
As alignment measure, we usually employ the expectation value of the squared cosine.
|
|
66
|
+
In the dynamics shown below, we can clearly see the out of equilibrium dynamics after the laser pulse at t = 0.15.
|
|
67
|
+
This plot corresponds to the first graph of figure 1 of ref.[^ref-paper].
|
|
68
|
+
The stronger the laser field the faster the subsequent dynamics of the rotor.
|
|
69
|
+
|
|
70
|
+
Note that at certain points in time, the rotor exhibits alignment recurrence even after the laser field has passed.
|
|
71
|
+
This field-free alignment is useful because the molecule is aligned, yet undisturbed by external fields.
|
|
72
|
+
|
|
73
|
+
```{code-cell}
|
|
74
|
+
import math
|
|
75
|
+
import matplotlib.pyplot as plt
|
|
76
|
+
import numpy as np
|
|
77
|
+
|
|
78
|
+
import wavepacket as wp
|
|
79
|
+
|
|
80
|
+
def calculate_alignment(Delta, sigma, l0=0, m=0):
|
|
81
|
+
delay = 3 * sigma
|
|
82
|
+
|
|
83
|
+
# tiny optimization: smaller grids are faster
|
|
84
|
+
thetaDof = wp.grid.SphericalHarmonicsDof(25+l0, m)
|
|
85
|
+
grid = wp.grid.Grid(thetaDof)
|
|
86
|
+
|
|
87
|
+
psi0 = wp.builder.product_wave_function(grid, wp.SphericalHarmonic(l0, m))
|
|
88
|
+
|
|
89
|
+
kinetic = wp.operator.RotationalKineticEnergy(grid, 0, 0.5)
|
|
90
|
+
cos2 = wp.operator.Potential1D(grid, 0, lambda theta: np.cos(theta)**2)
|
|
91
|
+
laser = wp.operator.TimeDependentOperator(grid,
|
|
92
|
+
lambda t: Delta * math.exp(-(t-delay)**2/sigma**2))
|
|
93
|
+
|
|
94
|
+
hamiltonian = kinetic - 0.5 * cos2 * laser
|
|
95
|
+
equation = wp.expression.SchroedingerEquation(hamiltonian)
|
|
96
|
+
solver = wp.solver.OdeSolver(equation, dt=sigma / 50)
|
|
97
|
+
|
|
98
|
+
results = [(t, wp.operator.expectation_value(cos2, psi))
|
|
99
|
+
for (t, psi) in solver.propagate(psi0, 0, 500)]
|
|
100
|
+
times = np.array([t for (t, _) in results])
|
|
101
|
+
expectation_values = np.array([abs(val) for (_, val) in results])
|
|
102
|
+
|
|
103
|
+
return times, expectation_values
|
|
104
|
+
|
|
105
|
+
times, expectation_values_100 = calculate_alignment(Delta=100, sigma=0.05)
|
|
106
|
+
_, expectation_values_400 = calculate_alignment(Delta=400, sigma=0.05)
|
|
107
|
+
_, expectation_values_900 = calculate_alignment(Delta=900, sigma=0.05)
|
|
108
|
+
plt.plot(times, expectation_values_100, '-k',
|
|
109
|
+
times, expectation_values_400, '--k',
|
|
110
|
+
times, expectation_values_900, ':k');
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Note that the actual work is encapsulated in a function with only a few parameters.
|
|
114
|
+
This was a deliberate choice to make the code reusable over this whole demo,
|
|
115
|
+
hence the parameters "l0" (initial angular momentum) and "m" (magnetic quantum number), which will only be
|
|
116
|
+
used further below.
|
|
117
|
+
When changing the laser field parameters, you would otherwise have to retype quite some boilerplate
|
|
118
|
+
code to eventually recreate the solver.
|
|
119
|
+
Encapsulation saves us some noise here, plus it guarantees a homogenous setup.
|
|
120
|
+
|
|
121
|
+
## Adiabatic alignment
|
|
122
|
+
|
|
123
|
+
If the laser pulse is much longer than the relevant rotational time scales, we are in the adiabatic limit.
|
|
124
|
+
The rotor aligns with the laser pulse when it is turned on and largely regresses to the field-free rotation
|
|
125
|
+
as the laser is turned off.
|
|
126
|
+
This plot corresponds to the third graph of figure 1 of ref[^ref-paper].
|
|
127
|
+
|
|
128
|
+
```{code-cell}
|
|
129
|
+
times, expectation_values_100 = calculate_alignment(Delta=100, sigma=5)
|
|
130
|
+
_, expectation_values_400 = calculate_alignment(Delta=400, sigma=5)
|
|
131
|
+
_, expectation_values_900 = calculate_alignment(Delta=900, sigma=5)
|
|
132
|
+
plt.plot(times, expectation_values_100, '-k',
|
|
133
|
+
times, expectation_values_400, '--k',
|
|
134
|
+
times, expectation_values_900, ':k');
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Stronger laser fields correspond to a higher degree of alignment, although this converges for large field strengths.
|
|
138
|
+
The alignment is much stronger than in the non-adiabatic case, but at the cost of an external alignment field
|
|
139
|
+
that may perturb molecular dynamics.
|
|
140
|
+
|
|
141
|
+
## Alignment of an excited rotational state
|
|
142
|
+
|
|
143
|
+
Finally, we can also study the alignment of rotationally excited states.
|
|
144
|
+
A new feature in this case is that the magnetic quantum number "m" no longer needs to be zero.
|
|
145
|
+
Let us reproduce figure 3 of ref.[^ref-paper].
|
|
146
|
+
|
|
147
|
+
```{code-cell}
|
|
148
|
+
data = [calculate_alignment(Delta=400, sigma=0.05, l0=5, m=m) for m in range(6)]
|
|
149
|
+
|
|
150
|
+
times = data[0][0]
|
|
151
|
+
results = [vals for (t, vals) in data]
|
|
152
|
+
|
|
153
|
+
average = results[0]
|
|
154
|
+
for m in range(1,6):
|
|
155
|
+
average = average + 2 * results[m]
|
|
156
|
+
average /= 11
|
|
157
|
+
|
|
158
|
+
plt.plot(times, average, '-k',
|
|
159
|
+
times, results[0], '-.k',
|
|
160
|
+
times, results[2], '--k',
|
|
161
|
+
times, results[4], ':k');
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The plot shows the average over all magnetic quantum numbers (solid line), and the individual results for
|
|
165
|
+
m = 0, 2, 4 (dot-dashed, dashed, dotted line).
|
|
166
|
+
While an increasing magnetic quantum number results in less field-free alignment, the total alignment is
|
|
167
|
+
similar for all even values of m.
|
|
168
|
+
The averaged alignment, however, is significantly damped, and smaller due to the lower alignment of odd values of m.
|
|
169
|
+
|
|
170
|
+
[^ref-paper]: Oritgoso et al. https://dx.doi.org/10.1063/1.478241
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
Getting started
|
|
2
|
+
===============
|
|
3
|
+
|
|
4
|
+
To demonstrate the usage of Wavepacket, let us dive right into
|
|
5
|
+
a simulation of a one-dimensional free particle.
|
|
6
|
+
|
|
7
|
+
.. code-block:: python
|
|
8
|
+
|
|
9
|
+
import math
|
|
10
|
+
import wavepacket as wp
|
|
11
|
+
|
|
12
|
+
dof = wp.grid.PlaneWaveDof(-20, 20, 128)
|
|
13
|
+
grid = wp.grid.Grid(dof)
|
|
14
|
+
|
|
15
|
+
hamiltonian = wp.operator.CartesianKineticEnergy(grid, 0, mass=1.0)
|
|
16
|
+
equation = wp.expression.SchroedingerEquation(hamiltonian)
|
|
17
|
+
|
|
18
|
+
psi0 = wp.builder.product_wave_function(grid,
|
|
19
|
+
wp.Gaussian(x=0, p=0, fwhm=1))
|
|
20
|
+
|
|
21
|
+
solver = wp.solver.OdeSolver(equation, dt=math.pi/5)
|
|
22
|
+
for t, psi in solver.propagate(psi0, t0=0, num_steps=20):
|
|
23
|
+
# do something with the solution psi
|
|
24
|
+
|
|
25
|
+
This program already highlights the basic structure of a Wavepacket simulation:
|
|
26
|
+
|
|
27
|
+
1. You first need to set up a grid / basis expansion for your system.
|
|
28
|
+
For that, you need to define the grid along each degree of freedom,
|
|
29
|
+
and then form the multidimensional grid as the direct product of the
|
|
30
|
+
one-dimensional grids. Note that Wavepacket uses exclusively the DVR / pseudo-spectral method,
|
|
31
|
+
see :doc:`representations` or [#dvr]_.
|
|
32
|
+
2. Given a grid, you can define your equations of motion.
|
|
33
|
+
Again, this step consists of two parts: First, you define all relevant
|
|
34
|
+
operators, for example the Hamiltonian, then you wrap these operators
|
|
35
|
+
into components for your equation of motion. For Wavepacket dynamics,
|
|
36
|
+
you usually want to setup a Schroedinger equation, but for density operators,
|
|
37
|
+
you may compose your equation from various commutators, anticommutators,
|
|
38
|
+
Lindblad Liouvillians etc.
|
|
39
|
+
3. Next you specify your initial state that you want to evolve in time.
|
|
40
|
+
4. Finally, you set up the solver for your equations of motion, and propagate
|
|
41
|
+
your initial state in time [#solvers]_.
|
|
42
|
+
|
|
43
|
+
This programmatic approach is rather complex and verbose when compared to more rigid programs.
|
|
44
|
+
For example, Matlab Wavepacket only requires you to set the various parameters, which makes the scripts
|
|
45
|
+
shorter and simpler.
|
|
46
|
+
However, the Python version allows more flexibility when you use more complex setups.
|
|
47
|
+
For example, you can almost seamlessly switch between density operator and wavepacket descriptions,
|
|
48
|
+
see the :ref:`tutorial-schroedinger-cat` demo, or you can propagate an ensemble of random thermal
|
|
49
|
+
wave functions to replicate a thermal system (TODO: translate demo).
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
.. [#dvr] See the explanation of the DVR method in the
|
|
53
|
+
`Wavepacket wiki <https://sourceforge.net/p/wavepacket/wiki/Numerics.DVR>`_.
|
|
54
|
+
.. [#solvers] See the
|
|
55
|
+
`discussion of ODE solvers <https://sourceforge.net/p/wavepacket/cpp/blog/2021/04/convergence-2/>`_.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
Wavepacket documentation
|
|
2
|
+
========================
|
|
3
|
+
|
|
4
|
+
Wavepacket allows you to easily set up and simulate smaller quantum
|
|
5
|
+
systems. It is particularly well suited for small molecule molecular dynamics
|
|
6
|
+
or for teaching.
|
|
7
|
+
|
|
8
|
+
The current Python package is the offspring of a longer history of
|
|
9
|
+
development, there is also a maintained Matlab implementation and a
|
|
10
|
+
superseded C++ implementation.
|
|
11
|
+
|
|
12
|
+
Features
|
|
13
|
+
--------
|
|
14
|
+
|
|
15
|
+
- Uses the DVR approximation, which allows you to define
|
|
16
|
+
potentials directly as functions in real space.
|
|
17
|
+
See :doc:`representations` for more information.
|
|
18
|
+
- Directly solves the differential equations numerically.
|
|
19
|
+
This is slower than clever methods like MCTDH, but easier to use.
|
|
20
|
+
- Most functions accept wave functions as well as density operators,
|
|
21
|
+
allowing you to move between closed and open quantum systems with
|
|
22
|
+
few code changes.
|
|
23
|
+
- You can easily define complex setups: Want to use an ensemble of
|
|
24
|
+
random thermal wave functions? Can be easily done.
|
|
25
|
+
Summing over all magnetic quantum numbers m for a given initial
|
|
26
|
+
angular momentum? No problem.
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
Bugs / Requests
|
|
30
|
+
---------------
|
|
31
|
+
|
|
32
|
+
If you find a bug, have a feature request, or even need support, feel
|
|
33
|
+
free to use the `issue tracker <https://github.com/ulflor/wavepacket/features>`_.
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
.. toctree::
|
|
37
|
+
:caption: Introduction
|
|
38
|
+
|
|
39
|
+
getting-started
|
|
40
|
+
architecture
|
|
41
|
+
representations
|
|
42
|
+
|
|
43
|
+
.. toctree::
|
|
44
|
+
:caption: Tutorials for typical usages
|
|
45
|
+
|
|
46
|
+
tutorials/schroedinger_cat
|
|
47
|
+
tutorials/plotting
|
|
48
|
+
|
|
49
|
+
.. toctree::
|
|
50
|
+
:caption: Demos
|
|
51
|
+
|
|
52
|
+
demos/pendular_states
|
|
53
|
+
|
|
54
|
+
.. toctree::
|
|
55
|
+
:caption: Other links
|
|
56
|
+
|
|
57
|
+
Project homepage <https://github.com/ulflor/wavepacket>
|
|
58
|
+
Wavepacket wiki <https://sourceforge.net/p/wavepacket/wiki>
|
|
59
|
+
|
|
60
|
+
.. toctree::
|
|
61
|
+
:caption: API
|
|
62
|
+
:maxdepth: 4
|
|
63
|
+
|
|
64
|
+
autoapi/index
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
@ECHO OFF
|
|
2
|
+
|
|
3
|
+
pushd %~dp0
|
|
4
|
+
|
|
5
|
+
REM Command file for Sphinx documentation
|
|
6
|
+
|
|
7
|
+
if "%SPHINXBUILD%" == "" (
|
|
8
|
+
set SPHINXBUILD=sphinx-build
|
|
9
|
+
)
|
|
10
|
+
set SOURCEDIR=.
|
|
11
|
+
set BUILDDIR=_build
|
|
12
|
+
|
|
13
|
+
%SPHINXBUILD% >NUL 2>NUL
|
|
14
|
+
if errorlevel 9009 (
|
|
15
|
+
echo.
|
|
16
|
+
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
|
17
|
+
echo.installed, then set the SPHINXBUILD environment variable to point
|
|
18
|
+
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
|
19
|
+
echo.may add the Sphinx directory to PATH.
|
|
20
|
+
echo.
|
|
21
|
+
echo.If you don't have Sphinx installed, grab it from
|
|
22
|
+
echo.https://www.sphinx-doc.org/
|
|
23
|
+
exit /b 1
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
if "%1" == "" goto help
|
|
27
|
+
|
|
28
|
+
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
|
29
|
+
goto end
|
|
30
|
+
|
|
31
|
+
:help
|
|
32
|
+
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
|
33
|
+
|
|
34
|
+
:end
|
|
35
|
+
popd
|