quadlib 0.1.0__py3-none-any.whl
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.
- quadlib/__init__.py +39 -0
- quadlib/basis/__init__.py +60 -0
- quadlib/basis/boson.py +61 -0
- quadlib/basis/discrete.py +71 -0
- quadlib/basis/expdvr.py +80 -0
- quadlib/basis/hodvr.py +51 -0
- quadlib/basis/jbasis.py +87 -0
- quadlib/basis/sindvr.py +97 -0
- quadlib/basis/spin.py +64 -0
- quadlib/cli/__init__.py +0 -0
- quadlib/cli/qlb_offset_oper_dof.py +34 -0
- quadlib/experimental/__init__.py +17 -0
- quadlib/experimental/cpd_eom.py +95 -0
- quadlib/experimental/mctdh.py +32 -0
- quadlib/experimental/node.py +259 -0
- quadlib/experimental/pdof.py +9 -0
- quadlib/experimental/tree.py +138 -0
- quadlib/hdmctdh/__init__.py +0 -0
- quadlib/hdmctdh/rundirectory.py +74 -0
- quadlib/legacy/__init__.py +14 -0
- quadlib/legacy/math.py +1337 -0
- quadlib/operator/sop.py +250 -0
- quadlib/propagation/__init__.py +17 -0
- quadlib/propagation/cpd.py +35 -0
- quadlib/propagation/exact.py +139 -0
- quadlib/propagation/integrators.py +108 -0
- quadlib/tools/__init__.py +0 -0
- quadlib/tools/bath.py +84 -0
- quadlib/tools/constants.py +289 -0
- quadlib/tools/iterators.py +276 -0
- quadlib/tools/linalg.py +215 -0
- quadlib/tools/pulses.py +187 -0
- quadlib/tools/spectra.py +179 -0
- quadlib/tools/tensor.py +227 -0
- quadlib/wavefunction/__init__.py +0 -0
- quadlib/wavefunction/wfn_cpd.py +266 -0
- quadlib/wavefunction/wfn_exact.py +147 -0
- quadlib-0.1.0.dist-info/METADATA +135 -0
- quadlib-0.1.0.dist-info/RECORD +43 -0
- quadlib-0.1.0.dist-info/WHEEL +5 -0
- quadlib-0.1.0.dist-info/entry_points.txt +2 -0
- quadlib-0.1.0.dist-info/licenses/LICENSE +19 -0
- quadlib-0.1.0.dist-info/top_level.txt +1 -0
quadlib/__init__.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# QuaDLib: QUAntum Dynamics LIBrary for research and methods development
|
|
2
|
+
# Copyright (C) 2018-2026, The Theoretical Chemistry Group, Heidelberg University
|
|
3
|
+
#
|
|
4
|
+
# This software is licensed under the MIT License (https://spdx.org/licenses/MIT.html)
|
|
5
|
+
|
|
6
|
+
import os.path
|
|
7
|
+
|
|
8
|
+
# -------------------------------------------------------------
|
|
9
|
+
# Make classes available in quadlib's namespace
|
|
10
|
+
from quadlib.wavefunction.wfn_exact import WfnExact
|
|
11
|
+
from quadlib.wavefunction.wfn_cpd import WfnCPD
|
|
12
|
+
|
|
13
|
+
from quadlib.basis.boson import Boson
|
|
14
|
+
from quadlib.basis.discrete import Discrete
|
|
15
|
+
from quadlib.basis.expdvr import Expdvr
|
|
16
|
+
from quadlib.basis.hodvr import HOdvr
|
|
17
|
+
from quadlib.basis.sindvr import Sindvr
|
|
18
|
+
from quadlib.basis.spin import Spin
|
|
19
|
+
from quadlib.basis.jbasis import Jbasis
|
|
20
|
+
|
|
21
|
+
from quadlib.operator.sop import SumOfProducts
|
|
22
|
+
from quadlib.operator.sop import SumOfProducts as SOP
|
|
23
|
+
from quadlib.operator.sop import OpType
|
|
24
|
+
|
|
25
|
+
from quadlib.hdmctdh.rundirectory import Rundirectory
|
|
26
|
+
#from quadlib.hdmctdh.mctdh_runner import MctdhRunner
|
|
27
|
+
|
|
28
|
+
# -------------------------------------------------------------
|
|
29
|
+
# Make submodules available
|
|
30
|
+
import quadlib.tools.constants as cons
|
|
31
|
+
import quadlib.tools.linalg as linalg
|
|
32
|
+
import quadlib.tools.spectra as spectra
|
|
33
|
+
import quadlib.tools.bath as bath
|
|
34
|
+
import quadlib.tools.tensor as tensor
|
|
35
|
+
import quadlib.wavefunction.wfn_exact as exactwfn
|
|
36
|
+
|
|
37
|
+
import quadlib.propagation as propagation
|
|
38
|
+
|
|
39
|
+
QDLPATH = os.path.dirname(__file__)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# QuaDLib: QUAntum Dynamics LIBrary for research and methods development
|
|
2
|
+
# Copyright (C) 2018-2026, The Theoretical Chemistry Group, Heidelberg University
|
|
3
|
+
#
|
|
4
|
+
# This software is licensed under the MIT License (https://spdx.org/licenses/MIT.html)
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Primitive basis classes.
|
|
8
|
+
|
|
9
|
+
Every basis class in this subpackage exposes at minimum the attribute `n`
|
|
10
|
+
(the dimension of the single-DOF Hilbert space it represents).
|
|
11
|
+
|
|
12
|
+
DVR (position-space) bases additionally expose `x`, `w`, `xmat`, `dq1`,
|
|
13
|
+
`dq2`, `u`; see the :class:`DVRBasis` Protocol below.
|
|
14
|
+
|
|
15
|
+
Algebraic bases (Boson, Spin, Jbasis, Discrete) expose the operators
|
|
16
|
+
relevant to their physics with conventional capitalised names
|
|
17
|
+
(``PauliX``, ``Jz``, ``Nop``, ``C``, ``A``, …). The dimension is always
|
|
18
|
+
the lowercase `n`.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from typing import Protocol, runtime_checkable
|
|
22
|
+
|
|
23
|
+
import numpy as np
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@runtime_checkable
|
|
27
|
+
class Basis(Protocol):
|
|
28
|
+
"""Minimum interface every basis class provides."""
|
|
29
|
+
|
|
30
|
+
n: int # dimension of the single-DOF Hilbert space
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@runtime_checkable
|
|
34
|
+
class DVRBasis(Basis, Protocol):
|
|
35
|
+
"""Position-space (DVR) basis.
|
|
36
|
+
|
|
37
|
+
All array attributes are real unless otherwise noted.
|
|
38
|
+
|
|
39
|
+
Attributes
|
|
40
|
+
----------
|
|
41
|
+
x : ndarray of shape (n,)
|
|
42
|
+
DVR grid points.
|
|
43
|
+
w : ndarray of shape (n,)
|
|
44
|
+
DVR quadrature weights.
|
|
45
|
+
xmat : ndarray of shape (n, n)
|
|
46
|
+
Position operator in the DVR basis, equal to ``np.diag(x)``.
|
|
47
|
+
dq1 : ndarray of shape (n, n)
|
|
48
|
+
First-derivative matrix in the DVR basis.
|
|
49
|
+
dq2 : ndarray of shape (n, n)
|
|
50
|
+
Second-derivative matrix in the DVR basis.
|
|
51
|
+
u : ndarray of shape (n, n)
|
|
52
|
+
FBR → DVR transformation matrix.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
x: np.ndarray
|
|
56
|
+
w: np.ndarray
|
|
57
|
+
xmat: np.ndarray
|
|
58
|
+
dq1: np.ndarray
|
|
59
|
+
dq2: np.ndarray
|
|
60
|
+
u: np.ndarray
|
quadlib/basis/boson.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Boson:
|
|
5
|
+
"""
|
|
6
|
+
Boson (harmonic oscillator in SQ) basis.
|
|
7
|
+
|
|
8
|
+
N -- integer: number of states, counting |0>.
|
|
9
|
+
|
|
10
|
+
Notes: the maximum number of particles for a given N is N-1
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, N):
|
|
15
|
+
"""
|
|
16
|
+
Initialize a boson (harmonic oscillator SQ) basis object
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
if not isinstance(N, (int, np.integer)):
|
|
20
|
+
raise ValueError('N needs to be an integer\n')
|
|
21
|
+
self.n = N
|
|
22
|
+
self.ONE = _ONE(N) # unit operator as a matrix
|
|
23
|
+
self.ONE_d = _ONE(N, diag=True) # unit operator as a diagonal oper.
|
|
24
|
+
self.Nop = _Bnum(N) # number operator
|
|
25
|
+
self.Nop_d = _Bnum(N, diag=True) # number operator as a diagonal oper.
|
|
26
|
+
self.C = _Bc(N) # creation operator
|
|
27
|
+
self.A = _Ba(N) # annihilation operator
|
|
28
|
+
self.H = np.diag(np.ones(N)*0.5) + self.Nop # Hamiltonian in au.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _ONE(n, diag=False):
|
|
32
|
+
if diag:
|
|
33
|
+
return np.ones(n, float)
|
|
34
|
+
else:
|
|
35
|
+
return np.diag(np.ones(n, float))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _Bnum(n, diag=False):
|
|
39
|
+
ln = np.asarray(list(range(0, n)), float)
|
|
40
|
+
if diag:
|
|
41
|
+
return ln
|
|
42
|
+
else:
|
|
43
|
+
return np.diag(ln)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _Bc(n):
|
|
47
|
+
bc = np.zeros((n, n), float)
|
|
48
|
+
for i in list(range(1, n)):
|
|
49
|
+
bc[i, i-1] = np.sqrt(i)
|
|
50
|
+
return bc
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _Ba(n):
|
|
54
|
+
ba = np.zeros((n, n), float)
|
|
55
|
+
for i in list(range(1, n)):
|
|
56
|
+
ba[i-1, i] = np.sqrt(i)
|
|
57
|
+
return ba
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Discrete:
|
|
5
|
+
"""
|
|
6
|
+
Discrete basis (e.g. to represent electronic-state degrees of freedom).
|
|
7
|
+
|
|
8
|
+
N -- integer: number of states, counting |0>.
|
|
9
|
+
|
|
10
|
+
Notes: the maximum number of particles for a given N is N-1
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
def __init__(self, N):
|
|
14
|
+
"""
|
|
15
|
+
Initialize a discrete basis object
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
if not isinstance(N, (int, np.integer)):
|
|
19
|
+
raise ValueError('N needs to be an integer\n')
|
|
20
|
+
self.n = N
|
|
21
|
+
self.ONE = _ONE(N) # unit operator as a matrix
|
|
22
|
+
self.ONE_d = _ONE(N, diag=True) # unit operator as a diagonal oper.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def P(self, n, diag=False):
|
|
26
|
+
"""
|
|
27
|
+
Projector |n><n|
|
|
28
|
+
|
|
29
|
+
n -- state number, n <= self.n
|
|
30
|
+
|
|
31
|
+
"""
|
|
32
|
+
p = np.zeros((self.n), float)
|
|
33
|
+
p[n] = 1.0
|
|
34
|
+
if diag:
|
|
35
|
+
return p
|
|
36
|
+
else:
|
|
37
|
+
return np.diag(p)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def S(self, n, m):
|
|
41
|
+
"""
|
|
42
|
+
Symmetric operator |n><m| + |m><n|
|
|
43
|
+
|
|
44
|
+
n, m -- state number, n, m <= self.n
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
p = np.zeros((self.n, self.n), float)
|
|
48
|
+
p[n, m] = 1.0
|
|
49
|
+
p[m, n] = 1.0
|
|
50
|
+
return p
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def Z(self, n, m):
|
|
54
|
+
"""
|
|
55
|
+
Off-diagonal operator |n><m|
|
|
56
|
+
|
|
57
|
+
n, m -- state number, n, m <= self.n
|
|
58
|
+
|
|
59
|
+
"""
|
|
60
|
+
p = np.zeros((self.n, self.n), float)
|
|
61
|
+
p[n, m] = 1.0
|
|
62
|
+
return p
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _ONE(n, diag=False):
|
|
66
|
+
if diag:
|
|
67
|
+
return np.ones(n, float)
|
|
68
|
+
else:
|
|
69
|
+
return np.diag(np.ones(n, float))
|
|
70
|
+
|
|
71
|
+
|
quadlib/basis/expdvr.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Expdvr:
|
|
5
|
+
"""
|
|
6
|
+
Exp DVR (plane wave) basis.
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, N, x0=0, L=2*np.pi):
|
|
11
|
+
"""
|
|
12
|
+
Initialize a exp DVR basis object
|
|
13
|
+
"""
|
|
14
|
+
if not isinstance(N, (int, np.integer)):
|
|
15
|
+
raise ValueError('N needs to be an odd integer\n')
|
|
16
|
+
if N%2 == 0:
|
|
17
|
+
raise ValueError('N needs to be an odd integer\n')
|
|
18
|
+
x0 = float(x0)
|
|
19
|
+
L = float(L)
|
|
20
|
+
self.n = N
|
|
21
|
+
self.x0 = x0
|
|
22
|
+
self.dX = L/N
|
|
23
|
+
self.xf = x0 + L - L/N # Last grid point
|
|
24
|
+
self.L = L
|
|
25
|
+
self.x, self.w, self.dq1, self.dq2, self.u = expdvr(N, x0, L)
|
|
26
|
+
self.xmat = np.diag(self.x)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def expdvr(N, x0, L):
|
|
30
|
+
weights = np.ones(N, float)*L/N
|
|
31
|
+
x, umat = _calcumat(N, x0, L)
|
|
32
|
+
d1dvr = _calcd1dvr(N, x0, L)
|
|
33
|
+
d2dvr = _calcd2dvr(N, x0, L)
|
|
34
|
+
return x, weights, d1dvr, d2dvr, umat
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _dx(N, L):
|
|
38
|
+
return L/N
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _calcumat(N, x0, L):
|
|
42
|
+
U = np.zeros((N, N), float)
|
|
43
|
+
X = np.zeros(N, float)
|
|
44
|
+
dx = L/N
|
|
45
|
+
N1 = N + 1
|
|
46
|
+
fac = np.sqrt(2.0/(N + 1))
|
|
47
|
+
for j in range(N):
|
|
48
|
+
X[j] = x0 + j*dx
|
|
49
|
+
for a in range(N):
|
|
50
|
+
U[j, a] = fac*np.sin(j*a*np.pi/N1)
|
|
51
|
+
return X, U
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _calcd1dvr(N, x0, L):
|
|
55
|
+
D1 = np.zeros((N, N), float)
|
|
56
|
+
fac = np.pi/L
|
|
57
|
+
for a in range(N):
|
|
58
|
+
for b in range(N):
|
|
59
|
+
if a==b:
|
|
60
|
+
continue
|
|
61
|
+
pref = fac*(-1)**(a - b)
|
|
62
|
+
D1[a, b] = pref/np.sin(np.pi*(a - b)/N)
|
|
63
|
+
return D1
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _calcd2dvr(N, x0, L):
|
|
67
|
+
D2 = np.zeros((N, N), float)
|
|
68
|
+
fac1 = -np.pi**2/(3*L**2)*(N**2 - 1)
|
|
69
|
+
fac2 = -2*np.pi**2/(L**2)
|
|
70
|
+
for a in range(N):
|
|
71
|
+
for b in range(N):
|
|
72
|
+
if a==b:
|
|
73
|
+
D2[a, b] = fac1
|
|
74
|
+
else:
|
|
75
|
+
pref = fac2*(-1)**(a - b)
|
|
76
|
+
c = np.cos(np.pi*(a - b)/N)
|
|
77
|
+
s2 = np.sin(np.pi*(a - b)/N)**2
|
|
78
|
+
D2[a, b] = pref*c/s2
|
|
79
|
+
return D2
|
|
80
|
+
|
quadlib/basis/hodvr.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
import quadlib.basis.boson as boson
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class HOdvr:
|
|
7
|
+
"""
|
|
8
|
+
Harmonic oscillator DVR basis.
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, N, m=1.0, w=1.0, x0=0.0):
|
|
13
|
+
"""
|
|
14
|
+
Initialize a HO DVR basis object
|
|
15
|
+
"""
|
|
16
|
+
if not isinstance(N, (int, np.integer)):
|
|
17
|
+
raise ValueError('N needs to be an integer\n')
|
|
18
|
+
m = float(m)
|
|
19
|
+
w = float(w)
|
|
20
|
+
mw = m*w
|
|
21
|
+
mw4 = (mw/np.pi)**-0.25
|
|
22
|
+
B = boson.Boson(N)
|
|
23
|
+
H = (B.Nop + np.diag(np.ones(N))*0.5)*w
|
|
24
|
+
x_fbr = (B.C + B.A)/np.sqrt(2*mw) + np.diag(np.ones(N))*x0
|
|
25
|
+
p_fbr = 1.0j*(B.C - B.A)*np.sqrt(mw/2)
|
|
26
|
+
x2_fbr = x_fbr @ x_fbr
|
|
27
|
+
v_fbr = 0.5*m*w**2 * x2_fbr
|
|
28
|
+
dq2_fbr = -2.0*m*(H - v_fbr)
|
|
29
|
+
# Line above is the correct way to obtain the second derivative matrix.
|
|
30
|
+
# It prevents the fbr basis truncation error
|
|
31
|
+
|
|
32
|
+
X, U = np.linalg.eigh(x_fbr)
|
|
33
|
+
for j, u0j in enumerate(U[0,:]):
|
|
34
|
+
if u0j < 0.0: U[:,j] = -1.0*U[:,j]
|
|
35
|
+
|
|
36
|
+
P_dvr = U.T @ p_fbr @ U
|
|
37
|
+
self.dq1 = -1.0j*P_dvr
|
|
38
|
+
self.P = P_dvr
|
|
39
|
+
|
|
40
|
+
self.dq2 = U.T @ dq2_fbr @ U
|
|
41
|
+
self.T = -0.5*self.dq2/m
|
|
42
|
+
|
|
43
|
+
self.n = N
|
|
44
|
+
self.u = U
|
|
45
|
+
self.x = X
|
|
46
|
+
self.xmat = np.diag(X)
|
|
47
|
+
self.x0 = self.x[0]
|
|
48
|
+
self.xf = self.x[-1]
|
|
49
|
+
w12 = mw4*np.exp(0.5*mw*X**2)*np.abs(U[0])
|
|
50
|
+
self.w = w12**2
|
|
51
|
+
|
quadlib/basis/jbasis.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Jbasis:
|
|
5
|
+
"""
|
|
6
|
+
General angular momentum basis.
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, M):
|
|
11
|
+
"""
|
|
12
|
+
Initialize a general angular momentum basis
|
|
13
|
+
|
|
14
|
+
M -- spin multiplicity, M = 2S + 1 (S is the total spin)
|
|
15
|
+
|
|
16
|
+
Notes:
|
|
17
|
+
- See e.g. Griffiths, Introduction to Quantum Mechanics
|
|
18
|
+
- |0> has the highest angular momentum projection along z.
|
|
19
|
+
"""
|
|
20
|
+
self.n = M
|
|
21
|
+
self.ONE = np.diag(np.ones(M, float))
|
|
22
|
+
self.Jz = _Jz(M)
|
|
23
|
+
self.Jx = _Jx(M)
|
|
24
|
+
self.Jy = _Jy(M)
|
|
25
|
+
self.Jp = _Jp(M)
|
|
26
|
+
self.Jm = _Jm(M)
|
|
27
|
+
self.J2 = _J2(M)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _bj(j, s):
|
|
31
|
+
t = (s + j)*(s + 1 - j)
|
|
32
|
+
return np.sqrt(t)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _Jx(M):
|
|
36
|
+
jx = np.zeros((M, M), float)
|
|
37
|
+
s = (M - 1.0)/2.0
|
|
38
|
+
for i in list(range(0, M - 1)):
|
|
39
|
+
j = s - i
|
|
40
|
+
bj = _bj(j, s)
|
|
41
|
+
jx[i + 1, i] = bj
|
|
42
|
+
jx[i, i + 1] = bj
|
|
43
|
+
jx = 0.5*jx
|
|
44
|
+
return jx
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _Jy(M):
|
|
48
|
+
jy = np.zeros((M, M), complex)
|
|
49
|
+
s = (M - 1.0)/2.0
|
|
50
|
+
for i in list(range(0, M - 1)):
|
|
51
|
+
j = s - i
|
|
52
|
+
bj = _bj(j, s)
|
|
53
|
+
jy[i + 1, i] = 1.0j*bj
|
|
54
|
+
jy[i, i + 1] = -1.0j*bj
|
|
55
|
+
jy = 0.5*jy
|
|
56
|
+
return jy
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _Jz(M):
|
|
60
|
+
jz = np.zeros((M, M), float)
|
|
61
|
+
s = (M - 1.0)/2.0
|
|
62
|
+
for i in list(range(0, M)):
|
|
63
|
+
j = s - i
|
|
64
|
+
jz[i, i] = j
|
|
65
|
+
return jz
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _Jp(M):
|
|
69
|
+
jx = _Jx(M)
|
|
70
|
+
jy = _Jy(M)
|
|
71
|
+
return np.real(jx + 1.0j*jy)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _Jm(M):
|
|
75
|
+
jx = _Jx(M)
|
|
76
|
+
jy = _Jy(M)
|
|
77
|
+
return np.real(jx - 1.0j*jy)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _J2(M):
|
|
81
|
+
jx = _Jx(M)
|
|
82
|
+
jy = _Jy(M)
|
|
83
|
+
jz = _Jz(M)
|
|
84
|
+
j2 = np.dot(jx, jx) + np.dot(jy, jy) + np.dot(jz, jz)
|
|
85
|
+
return np.real(j2)
|
|
86
|
+
|
|
87
|
+
|
quadlib/basis/sindvr.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Sindvr:
|
|
7
|
+
"""
|
|
8
|
+
Sin DVR (particle in a box) basis.
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, N, x0=-0.5, xf=0.5):
|
|
13
|
+
"""
|
|
14
|
+
Initialize a sin DVR basis object
|
|
15
|
+
"""
|
|
16
|
+
if not isinstance(N, (int, np.integer)):
|
|
17
|
+
raise ValueError('N needs to be an integer\n')
|
|
18
|
+
x0 = float(x0)
|
|
19
|
+
xf = float(xf)
|
|
20
|
+
self.n = N
|
|
21
|
+
self.x0 = x0
|
|
22
|
+
self.xf = xf
|
|
23
|
+
self.x, self.w, self.dq1, self.dq2, self.u = sindvr(N, x0, xf)
|
|
24
|
+
self.xmat = np.diag(self.x)
|
|
25
|
+
self.dX = _dx(N, x0, xf)
|
|
26
|
+
self.L = _L(N, x0, xf)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def sindvr(N, x0, xf):
|
|
30
|
+
weights = np.ones(N, float)*_dx(N, x0, xf)
|
|
31
|
+
x, umat = _calcumat(N, x0, xf)
|
|
32
|
+
d1dvr = _calcd1dvr(N, x0, xf, umat)
|
|
33
|
+
d2dvr = _calcd2dvr(N, x0, xf, umat)
|
|
34
|
+
return x, weights, d1dvr, d2dvr, umat
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _dx(N, x0, xf):
|
|
38
|
+
return (xf-x0) / (N-1)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _L(N, x0, xf):
|
|
42
|
+
return (xf-x0) * (N+1.0) / (N-1.0) # physical length of box
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _calcumat(N, x0, xf):
|
|
46
|
+
dx = _dx(N, x0, xf)
|
|
47
|
+
L = _L(N, x0, xf)
|
|
48
|
+
dkron = np.identity(N+1,int)
|
|
49
|
+
# Generate the matrix Q(z), where z=cos(pi(x-xo)/L)
|
|
50
|
+
Qz = np.zeros((N, N), float)
|
|
51
|
+
for i in range(N):
|
|
52
|
+
for j in range(N):
|
|
53
|
+
Qz[i, j] = 0.5 * float( dkron[i, j+1] + dkron[i, j-1] )
|
|
54
|
+
evals, evecs = np.linalg.eigh(Qz)
|
|
55
|
+
# Reverse order of eigevalues and eigenvectors for ascending grid points
|
|
56
|
+
idx = list(range(0, N))
|
|
57
|
+
idx.reverse()
|
|
58
|
+
evals = evals[idx]
|
|
59
|
+
evecs = evecs[:,idx]
|
|
60
|
+
evals[:] = (L/math.pi) * np.arccos(evals)
|
|
61
|
+
umat = evecs
|
|
62
|
+
# change sign of eigenvectors to ensure positive weights
|
|
63
|
+
for i in range(N):
|
|
64
|
+
if umat[0, i] < 0.0:
|
|
65
|
+
umat[:, i] = -1.0*umat[:, i]
|
|
66
|
+
x = evals + x0 - dx
|
|
67
|
+
return x, umat
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _calcd1dvr(N, x0, xf, umat):
|
|
71
|
+
d1vbr = np.zeros((N, N), float)
|
|
72
|
+
umatT = np.transpose(umat)
|
|
73
|
+
L = _L(N, x0, xf)
|
|
74
|
+
for j in range(N):
|
|
75
|
+
j1=j+1
|
|
76
|
+
for k in range(N):
|
|
77
|
+
k1=k+1
|
|
78
|
+
if j != k:
|
|
79
|
+
d1vbr[j,k] = float((j1-k1)%2) * \
|
|
80
|
+
(4.0/L) * j1*k1/(j1**2 - k1**2)
|
|
81
|
+
d1dvr = np.dot(umatT, np.dot(d1vbr, umat))
|
|
82
|
+
return d1dvr
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _calcd2dvr(N, x0, xf, umat):
|
|
86
|
+
d2vbr = np.zeros((N, N), float)
|
|
87
|
+
umatT = np.transpose(umat)
|
|
88
|
+
dkron = np.identity(N+1,int)
|
|
89
|
+
L = _L(N, x0, xf)
|
|
90
|
+
for j in range(N):
|
|
91
|
+
j1=j+1
|
|
92
|
+
for k in range(N):
|
|
93
|
+
k1=k+1
|
|
94
|
+
d2vbr[j,k] = -dkron[j1,k1] * (j1*math.pi/L)**2
|
|
95
|
+
d2dvr = np.dot(umatT, np.dot(d2vbr, umat))
|
|
96
|
+
return d2dvr
|
|
97
|
+
|
quadlib/basis/spin.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Spin:
|
|
5
|
+
"""
|
|
6
|
+
Spin (two-level system) basis.
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self):
|
|
11
|
+
"""
|
|
12
|
+
Initialize a spin basis object
|
|
13
|
+
|
|
14
|
+
Notes: we are using the convention
|
|
15
|
+
(1, 0)T --> |0>, spin-up
|
|
16
|
+
(0, 1)T --> |1>, spin-down.
|
|
17
|
+
This convention agrees with the definition of the general jbasis.
|
|
18
|
+
"""
|
|
19
|
+
self.n = 2
|
|
20
|
+
self.ONE = np.diag(np.ones(2, float))
|
|
21
|
+
self.PauliZ = _PauliZ()
|
|
22
|
+
self.PauliX = _PauliX()
|
|
23
|
+
self.PauliY = _PauliY()
|
|
24
|
+
self.Sz = 0.5*self.PauliZ
|
|
25
|
+
self.Sx = 0.5*self.PauliX
|
|
26
|
+
self.Sy = 0.5*self.PauliY
|
|
27
|
+
self.Sp = _Sp()
|
|
28
|
+
self.Sm = _Sm()
|
|
29
|
+
self.S2 = 0.75*self.ONE
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _PauliX():
|
|
33
|
+
sx = np.zeros((2,2), float)
|
|
34
|
+
sx[0, 1] = 1.0
|
|
35
|
+
sx[1, 0] = 1.0
|
|
36
|
+
return sx
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _PauliY():
|
|
40
|
+
sy = np.zeros((2, 2), complex)
|
|
41
|
+
sy[0, 1] = -1.0j
|
|
42
|
+
sy[1, 0] = 1.0j
|
|
43
|
+
return sy
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _PauliZ():
|
|
47
|
+
sz = np.diag(np.ones(2, float))
|
|
48
|
+
sz[1, 1] = -1.0
|
|
49
|
+
return sz
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _Sp():
|
|
53
|
+
sp = np.zeros((2,2), float)
|
|
54
|
+
sp[0, 1] = 1.0
|
|
55
|
+
return sp
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _Sm():
|
|
59
|
+
sm = np.zeros((2,2), float)
|
|
60
|
+
sm[1, 0] = 1.0
|
|
61
|
+
return sm
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
quadlib/cli/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# QuaDLib: QUAntum Dynamics LIBrary for research and methods development
|
|
3
|
+
# Copyright (C) 2018-2026, The Theoretical Chemistry Group, Heidelberg University
|
|
4
|
+
#
|
|
5
|
+
# This software is licensed under the MIT License (https://spdx.org/licenses/MIT.html)
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Add an offset to the mode numbers (|n) of an MCTDH operator.
|
|
9
|
+
|
|
10
|
+
Reads the operator from stdin, writes it to stdout:
|
|
11
|
+
qlb-offset-oper-dof -o 3 < in.op > out.op
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import re
|
|
16
|
+
import sys
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def offset_line(line, offset):
|
|
20
|
+
"""Return line with every '|<n>' replaced by '|<n + offset>'."""
|
|
21
|
+
return re.sub(r'\|[0-9]+', lambda m: '|' + str(int(m[0][1:]) + offset), line)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def main(argv=None):
|
|
25
|
+
parser = argparse.ArgumentParser(description=__doc__.strip().splitlines()[0])
|
|
26
|
+
parser.add_argument('-o', '--offset', type=int, default=0,
|
|
27
|
+
help='Offset added to the modenumbers of an MCTDH operator')
|
|
28
|
+
opts = parser.parse_args(argv)
|
|
29
|
+
for line in sys.stdin:
|
|
30
|
+
print(offset_line(line.rstrip('\n'), opts.offset), file=sys.stdout)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
if __name__ == '__main__':
|
|
34
|
+
main()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# QuaDLib: QUAntum Dynamics LIBrary for research and methods development
|
|
2
|
+
# Copyright (C) 2018-2026, The Theoretical Chemistry Group, Heidelberg University
|
|
3
|
+
#
|
|
4
|
+
# This software is licensed under the MIT License (https://spdx.org/licenses/MIT.html)
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Unfinished or known-incorrect code kept for ongoing method development.
|
|
8
|
+
|
|
9
|
+
Nothing here is imported by ``quadlib/__init__.py``; import the
|
|
10
|
+
submodules explicitly, e.g. ``import quadlib.experimental.cpd_eom``.
|
|
11
|
+
Nothing here is covered by the stability or correctness expectations of
|
|
12
|
+
the rest of the library.
|
|
13
|
+
|
|
14
|
+
node, tree, pdof - tree-tensor-network scaffolding (Node, Tree, Pdof)
|
|
15
|
+
mctdh - placeholders for the (ML-)MCTDH equations of motion
|
|
16
|
+
cpd_eom - coupled CPD equations (known incorrect)
|
|
17
|
+
"""
|