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.
Files changed (92) hide show
  1. wavepacket-0.2.0/.github/workflows/ci_testing.yml +30 -0
  2. wavepacket-0.2.0/.gitignore +67 -0
  3. wavepacket-0.2.0/.readthedocs.yaml +18 -0
  4. wavepacket-0.2.0/CHANGELOG.rst +41 -0
  5. {wavepacket-0.1.0 → wavepacket-0.2.0}/PKG-INFO +3 -12
  6. wavepacket-0.2.0/doc/Makefile +20 -0
  7. wavepacket-0.2.0/doc/architecture.rst +67 -0
  8. wavepacket-0.2.0/doc/conf.py +53 -0
  9. wavepacket-0.2.0/doc/demos/pendular_states.md +170 -0
  10. wavepacket-0.2.0/doc/getting-started.rst +55 -0
  11. wavepacket-0.2.0/doc/index.rst +64 -0
  12. wavepacket-0.2.0/doc/make.bat +35 -0
  13. wavepacket-0.2.0/doc/representations.rst +130 -0
  14. wavepacket-0.2.0/doc/requirements.txt +248 -0
  15. wavepacket-0.2.0/doc/tutorials/plotting.md +197 -0
  16. wavepacket-0.2.0/doc/tutorials/schroedinger_cat.md +96 -0
  17. wavepacket-0.2.0/pyproject.toml +64 -0
  18. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/__init__.py +10 -8
  19. wavepacket-0.2.0/src/wavepacket/builder/__init__.py +9 -0
  20. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/builder/density.py +27 -0
  21. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/builder/wave_function.py +54 -0
  22. wavepacket-0.2.0/src/wavepacket/functions.py +90 -0
  23. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/generators.py +45 -1
  24. wavepacket-0.2.0/src/wavepacket/grid/__init__.py +13 -0
  25. wavepacket-0.2.0/src/wavepacket/grid/_utils.py +23 -0
  26. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/grid/grid.py +4 -0
  27. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/grid/planewavedof.py +8 -14
  28. wavepacket-0.2.0/src/wavepacket/grid/spherical_harmonics_dof.py +161 -0
  29. wavepacket-0.2.0/src/wavepacket/grid/state_utilities.py +250 -0
  30. wavepacket-0.2.0/src/wavepacket/operator/__init__.py +14 -0
  31. wavepacket-0.2.0/src/wavepacket/operator/fbroperators.py +184 -0
  32. wavepacket-0.2.0/src/wavepacket/operator/misc_operators.py +109 -0
  33. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/operator/operatorbase.py +75 -6
  34. wavepacket-0.2.0/src/wavepacket/operator/time_dependent_operators.py +70 -0
  35. wavepacket-0.2.0/src/wavepacket/plot/__init__.py +3 -0
  36. wavepacket-0.2.0/src/wavepacket/plot/plot_1d.py +221 -0
  37. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/typing/data_types.py +1 -1
  38. wavepacket-0.2.0/test/builder/test_density.py +78 -0
  39. wavepacket-0.2.0/test/builder/test_product_wave_function.py +42 -0
  40. wavepacket-0.2.0/test/builder/test_wave_function.py +60 -0
  41. wavepacket-0.2.0/test/conftest.py +14 -0
  42. wavepacket-0.2.0/test/expression/test_commutatorliouvillian.py +49 -0
  43. wavepacket-0.2.0/test/expression/test_schroedingerequation.py +32 -0
  44. wavepacket-0.2.0/test/grid/test_dofbase.py +51 -0
  45. wavepacket-0.2.0/test/grid/test_grid.py +105 -0
  46. wavepacket-0.2.0/test/grid/test_planewavedof_basics.py +60 -0
  47. wavepacket-0.2.0/test/grid/test_planewavedof_transformations.py +125 -0
  48. wavepacket-0.2.0/test/grid/test_sphericalharmonicsdof_basics.py +50 -0
  49. wavepacket-0.2.0/test/grid/test_sphericalharmonicsdof_transformations.py +110 -0
  50. wavepacket-0.2.0/test/grid/test_state.py +103 -0
  51. wavepacket-0.2.0/test/grid/test_state_utilities.py +177 -0
  52. wavepacket-0.2.0/test/operator/test_fbroperator.py +75 -0
  53. wavepacket-0.2.0/test/operator/test_misc_operators.py +112 -0
  54. wavepacket-0.2.0/test/operator/test_operator_arithmetic.py +113 -0
  55. wavepacket-0.2.0/test/operator/test_operatorbase.py +41 -0
  56. wavepacket-0.2.0/test/operator/test_operatorutils.py +40 -0
  57. wavepacket-0.2.0/test/operator/test_planewavefbroperator.py +72 -0
  58. wavepacket-0.2.0/test/operator/test_potential1d.py +57 -0
  59. wavepacket-0.2.0/test/operator/test_time_dependent_operators.py +35 -0
  60. wavepacket-0.2.0/test/solver/test_odesolver.py +46 -0
  61. wavepacket-0.2.0/test/solver/test_solverbase.py +57 -0
  62. wavepacket-0.2.0/test/test_base_exports.py +5 -0
  63. wavepacket-0.2.0/test/test_functions.py +56 -0
  64. wavepacket-0.2.0/test/test_generators.py +71 -0
  65. wavepacket-0.2.0/test/test_logging.py +8 -0
  66. wavepacket-0.1.0/pyproject.toml +0 -41
  67. wavepacket-0.1.0/src/wavepacket/builder/__init__.py +0 -8
  68. wavepacket-0.1.0/src/wavepacket/grid/__init__.py +0 -12
  69. wavepacket-0.1.0/src/wavepacket/grid/state_utilities.py +0 -89
  70. wavepacket-0.1.0/src/wavepacket/operator/__init__.py +0 -12
  71. wavepacket-0.1.0/src/wavepacket/operator/fbroperators.py +0 -94
  72. {wavepacket-0.1.0 → wavepacket-0.2.0}/LICENSE +0 -0
  73. {wavepacket-0.1.0 → wavepacket-0.2.0}/README.rst +0 -0
  74. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/exceptions.py +0 -0
  75. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/expression/__init__.py +0 -0
  76. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/expression/expressionbase.py +0 -0
  77. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/expression/liouvillian.py +0 -0
  78. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/expression/schroedingerequation.py +0 -0
  79. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/grid/dofbase.py +0 -0
  80. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/grid/state.py +0 -0
  81. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/logging.py +0 -0
  82. /wavepacket-0.1.0/src/wavepacket/operator/operatorutils.py → /wavepacket-0.2.0/src/wavepacket/operator/operator_utils.py +0 -0
  83. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/operator/potentials.py +0 -0
  84. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/solver/__init__.py +0 -0
  85. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/solver/odesolver.py +0 -0
  86. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/solver/solverbase.py +0 -0
  87. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/testing/__init__.py +0 -0
  88. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/testing/assertions.py +0 -0
  89. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/testing/dummydof.py +0 -0
  90. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/testing/dummyoperator.py +0 -0
  91. {wavepacket-0.1.0 → wavepacket-0.2.0}/src/wavepacket/testing/random.py +0 -0
  92. {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.1.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.12
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 ; extra == "demos"
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