hamop 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.
hamop/__init__.py ADDED
@@ -0,0 +1,29 @@
1
+ """hamop: one tight-binding Hamiltonian, every observable, strictly consistent.
2
+
3
+ Build a Hamiltonian once, as real-space blocks in an orthogonal or
4
+ nonorthogonal basis, and compute its band structure, density of states,
5
+ Kubo-Greenwood optical conductivity and Landauer transmission from the
6
+ same matrices, so that spectral, optical and transport statements about
7
+ one model can never drift apart.
8
+
9
+ Methodological basis: the study "Learning the quantum Hamiltonian of
10
+ defective monolayer MoS2 reveals collective vacancy brightness
11
+ decoupled from defect count" (code:
12
+ https://github.com/Tanvir-Mahmud-Mahim/mos2-vacancy-optics); this
13
+ package is the general-purpose engine distilled from that pipeline.
14
+ """
15
+ from .eigsolve import gen_eigh
16
+ from .kubo import carrier_count, sigma_optical
17
+ from .lattices import chain_lead_blocks, graphene, linear_chain, two_site
18
+ from .model import TightBindingModel
19
+ from .negf import sancho_rubio, transmission, transmission_direct
20
+ from .spectrum import band_edges, bands, dos, fermi_level
21
+
22
+ __version__ = "0.1.0"
23
+ __all__ = [
24
+ "TightBindingModel", "gen_eigh",
25
+ "bands", "dos", "fermi_level", "band_edges",
26
+ "sigma_optical", "carrier_count",
27
+ "sancho_rubio", "transmission", "transmission_direct",
28
+ "linear_chain", "two_site", "graphene", "chain_lead_blocks",
29
+ ]
hamop/eigsolve.py ADDED
@@ -0,0 +1,42 @@
1
+ """Generalized eigensolver with canonical orthogonalization.
2
+
3
+ A nonorthogonal basis can be mildly overcomplete, so the overlap matrix
4
+ S has eigenvalues close to zero. Errors in H that live in that
5
+ near-null space are amplified enormously by a naive generalized
6
+ eigensolver. Canonical orthogonalization is the standard remedy used
7
+ inside electronic-structure codes (Szabo and Ostlund, *Modern Quantum
8
+ Chemistry*, sec. 3.4.5): diagonalize S, drop directions whose overlap
9
+ eigenvalue falls below a threshold, and solve H in the remaining
10
+ well-conditioned subspace.
11
+
12
+ For a well-conditioned S this reduces to the ordinary generalized
13
+ eigenproblem; the test suite asserts agreement with
14
+ ``scipy.linalg.eigh(H, S)`` to near machine precision in that case.
15
+ """
16
+ from __future__ import annotations
17
+
18
+ import numpy as np
19
+ from scipy.linalg import eigh
20
+
21
+ __all__ = ["gen_eigh"]
22
+
23
+
24
+ def gen_eigh(H, S, thresh=1e-10, eigvals_only=True):
25
+ """Eigenvalues (and vectors) of H c = e S c, canonically orthogonalized.
26
+
27
+ thresh: overlap eigenvalues below this are dropped. Returned
28
+ eigenvectors are columns in the original basis, S-orthonormal within
29
+ the kept subspace.
30
+ """
31
+ H = 0.5 * (H + np.conj(H).T)
32
+ S = 0.5 * (S + np.conj(S).T)
33
+ s, U = eigh(S)
34
+ keep = s > thresh
35
+ if not np.any(keep):
36
+ raise ValueError("no overlap eigenvalue above the threshold")
37
+ X = U[:, keep] / np.sqrt(s[keep])
38
+ Hp = X.conj().T @ H @ X
39
+ if eigvals_only:
40
+ return eigh(Hp, eigvals_only=True)
41
+ w, Vp = eigh(Hp)
42
+ return w, X @ Vp
hamop/kubo.py ADDED
@@ -0,0 +1,96 @@
1
+ """Kubo-Greenwood optical conductivity from the same Bloch matrices.
2
+
3
+ The velocity operator uses the standard atomistic (Peierls-like)
4
+ position gauge: the position operator is taken diagonal at the sites,
5
+ so dH/dk carries a factor of the inter-site displacement and the
6
+ intra-atomic dipole contribution is neglected -- the common
7
+ approximation in tight-binding optics. In a nonorthogonal basis the
8
+ interband matrix element at k is
9
+
10
+ M_nm = <n| dH/dk - (e_n + e_m)/2 dS/dk |m>,
11
+
12
+ which is what makes the result invariant under a rigid shift
13
+ H -> H + c S of the energy zero; the test suite asserts that
14
+ invariance to near machine precision, along with the textbook anchors
15
+ described in the README.
16
+
17
+ Convention: the real part of the sheet conductivity is returned in
18
+ units of e^2 / (4 hbar) -- for reference, that unit is exactly the
19
+ universal optical sheet conductivity of graphene (Kuzmenko et al.,
20
+ Phys. Rev. Lett. 100, 117401 (2008)), and the test suite reproduces
21
+ sigma = 1 on the graphene plateau from the nearest-neighbour model.
22
+ Spin degeneracy enters as the explicit factor ``spin`` (default 2).
23
+ """
24
+ from __future__ import annotations
25
+
26
+ import numpy as np
27
+
28
+ from .eigsolve import gen_eigh
29
+
30
+ __all__ = ["sigma_optical", "carrier_count"]
31
+
32
+ KB = 8.617333262e-5 # eV / K
33
+
34
+
35
+ def sigma_optical(model, omega, mu, mesh=None, kpts=None, weights=None,
36
+ T=300.0, eta=0.05, direction=0, spin=2, thresh=1e-10):
37
+ """Real part of the optical sheet conductivity, in units of e^2/(4 hbar).
38
+
39
+ omega: photon energies (eV, > 0). mu: chemical potential (eV).
40
+ eta: Gaussian broadening of the energy-conservation delta (eV).
41
+ direction: Cartesian polarization axis. For a finite system
42
+ (cell=None) the "cell volume" is absent and the result is the
43
+ conductivity times the system area; divide by your geometric area.
44
+ """
45
+ omega = np.asarray(omega, dtype=float)
46
+ if np.any(omega <= 0):
47
+ raise ValueError("omega must be positive photon energies")
48
+ if mesh is not None or kpts is not None:
49
+ if mesh is not None:
50
+ kpts, weights = model.monkhorst_pack(mesh)
51
+ elif weights is None:
52
+ weights = np.full(len(kpts), 1.0 / len(kpts))
53
+ area = model.cell_volume
54
+ else:
55
+ if model.cell is not None:
56
+ raise ValueError("periodic model: give mesh or kpts")
57
+ kpts, weights, area = [None], [1.0], 1.0
58
+
59
+ sig = np.zeros_like(omega)
60
+ for k, w in zip(kpts, weights):
61
+ H, S = model.bloch(k)
62
+ dH, dS = model.bloch_derivative(k, direction)
63
+ e, c = gen_eigh(H, S, thresh=thresh, eigvals_only=False)
64
+ x = np.clip((e - mu) / (KB * T), -60.0, 60.0)
65
+ f = 1.0 / (1.0 + np.exp(x))
66
+ M = c.conj().T @ dH @ c
67
+ Sd = c.conj().T @ dS @ c
68
+ M = M - 0.5 * (e[:, None] + e[None, :]) * Sd
69
+ dE = e[None, :] - e[:, None] # E_m - E_n
70
+ df = f[:, None] - f[None, :] # f_n - f_m
71
+ A2 = np.abs(M) ** 2
72
+ mask = dE > 1e-3
73
+ for iw, hw in enumerate(omega):
74
+ g = np.exp(-0.5 * ((dE - hw) / eta) ** 2) \
75
+ / (eta * np.sqrt(2.0 * np.pi))
76
+ sig[iw] += w * (df * A2 * g / np.where(mask, dE, 1.0))[mask].sum()
77
+ # sigma / (e^2 / 4 hbar) = spin * 4 pi / area * sum, M in eV*A, dE in eV
78
+ return sig * spin * 4.0 * np.pi / area
79
+
80
+
81
+ def carrier_count(model, mu, mesh=None, kpts=None, weights=None, T=300.0,
82
+ spin=2, thresh=1e-10):
83
+ """Mean number of occupied states per unit cell (spin included)."""
84
+ if mesh is not None:
85
+ kpts, weights = model.monkhorst_pack(mesh)
86
+ elif kpts is None:
87
+ kpts, weights = [None], [1.0]
88
+ elif weights is None:
89
+ weights = np.full(len(kpts), 1.0 / len(kpts))
90
+ n = 0.0
91
+ for k, w in zip(kpts, weights):
92
+ H, S = model.bloch(k)
93
+ e = gen_eigh(H, S, thresh=thresh)
94
+ x = np.clip((e - mu) / (KB * T), -60.0, 60.0)
95
+ n += w * spin * float((1.0 / (1.0 + np.exp(x))).sum())
96
+ return n
hamop/lattices.py ADDED
@@ -0,0 +1,67 @@
1
+ """Reference lattices with closed-form physics, for tests and examples.
2
+
3
+ These builders exist because every one of them has textbook exact
4
+ results the package is validated against: the chain's dispersion, its
5
+ density of states and its unit transmission; the two-site molecule's
6
+ single absorption line; graphene's Dirac cones and universal optical
7
+ sheet conductivity. They double as templates for building your own
8
+ models.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ import numpy as np
13
+
14
+ from .model import TightBindingModel
15
+
16
+ __all__ = ["linear_chain", "two_site", "graphene", "chain_lead_blocks"]
17
+
18
+
19
+ def linear_chain(t=-1.0, e0=0.0, a=1.0, s=None):
20
+ """Infinite single-orbital chain: E(k) = e0 + 2 t cos(k a).
21
+
22
+ s: optional nearest-neighbour overlap (nonorthogonal chain).
23
+ """
24
+ m = TightBindingModel(positions=[[0.0]], norb=1, cell=[[a]])
25
+ m.add_hop(0, 0, (0,), [[e0]],
26
+ None if s is None else [[1.0]])
27
+ m.add_hop(0, 0, (1,), [[t]],
28
+ None if s is None else [[s]])
29
+ return m
30
+
31
+
32
+ def two_site(t=-1.0, e0=0.0, a=1.0, s=None):
33
+ """Finite two-site molecule: levels e0 -/+ |t| (orthogonal case),
34
+ one optical transition at 2|t|."""
35
+ m = TightBindingModel(positions=[[0.0], [a]], norb=1, cell=None)
36
+ m.add_hop(0, 0, (0,), [[e0]], None if s is None else [[1.0]])
37
+ m.add_hop(1, 1, (0,), [[e0]], None if s is None else [[1.0]])
38
+ m.add_hop(0, 1, (0,), [[t]], None if s is None else [[s]])
39
+ return m
40
+
41
+
42
+ def graphene(t=-2.7, a=2.46):
43
+ """Nearest-neighbour graphene: Dirac cones at K, bandwidth 6|t|,
44
+ and the universal optical sheet conductivity e^2/(4 hbar) on the
45
+ interband plateau."""
46
+ cell = a * np.array([[1.0, 0.0], [0.5, np.sqrt(3.0) / 2.0]])
47
+ pos = np.array([np.zeros(2), (cell[0] + cell[1]) / 3.0])
48
+ m = TightBindingModel(positions=pos, norb=1, cell=cell)
49
+ m.add_hop(0, 1, (0, 0), [[t]])
50
+ m.add_hop(0, 1, (-1, 0), [[t]])
51
+ m.add_hop(0, 1, (0, -1), [[t]])
52
+ return m
53
+
54
+
55
+ def chain_lead_blocks(t=-1.0, e0=0.0, per_layer=1):
56
+ """Principal-layer blocks of the single-orbital chain lead, with
57
+ ``per_layer`` sites per layer, for the NEGF module."""
58
+ n = per_layer
59
+ H00 = np.zeros((n, n), dtype=complex)
60
+ for i in range(n):
61
+ H00[i, i] = e0
62
+ if i + 1 < n:
63
+ H00[i, i + 1] = t
64
+ H00[i + 1, i] = np.conj(t)
65
+ H01 = np.zeros((n, n), dtype=complex)
66
+ H01[n - 1, 0] = t
67
+ return H00, H01
hamop/model.py ADDED
@@ -0,0 +1,209 @@
1
+ """The tight-binding model container: real-space blocks in, Bloch matrices out.
2
+
3
+ A model is a set of sites, each carrying ``norb`` orbitals, and a set of
4
+ directed hoppings between sites. Each hopping is stored once, as
5
+ ``(i, j, image, H_block, S_block)``: the block couples the orbitals of
6
+ site ``i`` in the home cell to the orbitals of site ``j`` in the cell
7
+ displaced by the integer lattice vector ``image``. The Hermitian
8
+ partner (``j`` back to ``i`` in the opposite image) is implied and added
9
+ by the assembly, so a bond is never double-counted. On-site blocks
10
+ (``i == j`` and zero image) must be Hermitian themselves.
11
+
12
+ Assembly follows the standard atomic-gauge convention: the Bloch phase
13
+ of a block is ``exp(i k . d)`` with ``d`` the *Cartesian* displacement
14
+ from site ``i`` to site ``j`` including the lattice vector, so the
15
+ k-derivative of the Hamiltonian carries a factor ``i d`` per block.
16
+ That derivative is exactly what the Kubo velocity operator needs, which
17
+ is why the two live in one class: the optics and the spectrum can never
18
+ drift out of sync with each other.
19
+
20
+ Units: energies in eV, positions in Angstrom, k in 1/Angstrom. Finite
21
+ (non-periodic) systems are models with ``cell=None`` and only zero
22
+ images; every observable then works at the single "k-point" k = 0.
23
+ """
24
+ from __future__ import annotations
25
+
26
+ import numpy as np
27
+
28
+ __all__ = ["TightBindingModel"]
29
+
30
+
31
+ class TightBindingModel:
32
+ """Sites, orbitals and directed hopping blocks; assembles H(k), S(k).
33
+
34
+ positions: (nsite, dim) Cartesian site positions (Angstrom).
35
+ norb: int or sequence, orbitals per site.
36
+ cell: (dim, dim) lattice vectors as rows (Angstrom), or None for a
37
+ finite system.
38
+ """
39
+
40
+ def __init__(self, positions, norb, cell=None):
41
+ self.positions = np.atleast_2d(np.asarray(positions, dtype=float))
42
+ n_site = self.positions.shape[0]
43
+ if np.isscalar(norb):
44
+ self.norb = np.full(n_site, int(norb))
45
+ else:
46
+ self.norb = np.asarray(norb, dtype=int)
47
+ if self.norb.shape != (n_site,):
48
+ raise ValueError("norb must be scalar or one entry per site")
49
+ self.cell = None if cell is None else np.atleast_2d(
50
+ np.asarray(cell, dtype=float))
51
+ self.offsets = np.concatenate([[0], np.cumsum(self.norb)])
52
+ self.nao = int(self.offsets[-1])
53
+ self._hops = []
54
+
55
+ # ------------------------------------------------------------------
56
+ def add_hop(self, i, j, image, H_block, S_block=None):
57
+ """Add one directed hopping block (the reverse partner is implied).
58
+
59
+ image: integer lattice vector of the cell containing site j
60
+ (all zeros for a finite system or an intra-cell bond).
61
+ H_block: (norb_i, norb_j) array. S_block defaults to zero for
62
+ an inter-site block; identity is used automatically for on-site
63
+ blocks when no overlap is given anywhere (orthogonal basis).
64
+ """
65
+ i, j = int(i), int(j)
66
+ image = tuple(int(m) for m in np.atleast_1d(image))
67
+ if self.cell is None and any(image):
68
+ raise ValueError("finite system: image must be zero")
69
+ H_block = np.asarray(H_block, dtype=complex)
70
+ if H_block.shape != (self.norb[i], self.norb[j]):
71
+ raise ValueError(
72
+ f"H block shape {H_block.shape} != "
73
+ f"({self.norb[i]}, {self.norb[j]}) for sites ({i}, {j})")
74
+ onsite = (i == j) and not any(image)
75
+ if onsite and not np.allclose(H_block, H_block.conj().T):
76
+ raise ValueError("on-site block must be Hermitian")
77
+ if S_block is not None:
78
+ S_block = np.asarray(S_block, dtype=complex)
79
+ if S_block.shape != H_block.shape:
80
+ raise ValueError("S block shape must match H block shape")
81
+ if onsite and not np.allclose(S_block, S_block.conj().T):
82
+ raise ValueError("on-site overlap block must be Hermitian")
83
+ self._hops.append((i, j, image, H_block, S_block))
84
+
85
+ def has_overlap(self):
86
+ return any(h[4] is not None for h in self._hops)
87
+
88
+ # ------------------------------------------------------------------
89
+ def _displacement(self, i, j, image):
90
+ d = self.positions[j] - self.positions[i]
91
+ if self.cell is not None:
92
+ d = d + np.asarray(image, dtype=float) @ self.cell
93
+ return d
94
+
95
+ def _terms(self):
96
+ """Yield (oi, oj, d, Hb, Sb) for every block and its implied
97
+ Hermitian partner, exactly once each."""
98
+ overlap = self.has_overlap()
99
+ seen_onsite_S = set()
100
+ for i, j, image, Hb, Sb in self._hops:
101
+ oi, oj = self.offsets[i], self.offsets[j]
102
+ d = self._displacement(i, j, image)
103
+ onsite = (i == j) and not any(image)
104
+ if Sb is None:
105
+ if onsite and overlap:
106
+ Sb = np.eye(self.norb[i], dtype=complex)
107
+ else:
108
+ Sb = np.zeros_like(Hb)
109
+ if onsite:
110
+ seen_onsite_S.add(i)
111
+ yield oi, oj, d, Hb, Sb
112
+ else:
113
+ yield oi, oj, d, Hb, Sb
114
+ yield oj, oi, -d, Hb.conj().T, Sb.conj().T
115
+ if overlap:
116
+ # sites whose on-site block was never given still need S = 1
117
+ given = {i for i, j, im, _, _ in self._hops
118
+ if i == j and not any(im)}
119
+ for i in range(len(self.norb)):
120
+ if i not in given:
121
+ oi = self.offsets[i]
122
+ yield (oi, oi, np.zeros(self.positions.shape[1]),
123
+ np.zeros((self.norb[i], self.norb[i]), complex),
124
+ np.eye(self.norb[i], dtype=complex))
125
+
126
+ # ------------------------------------------------------------------
127
+ def bloch(self, k=None):
128
+ """H(k), S(k) as dense Hermitian matrices.
129
+
130
+ k: Cartesian wave vector (1/Angstrom); None means k = 0. For a
131
+ finite system pass None. S(k) is the identity when the model
132
+ has no overlap blocks (orthogonal basis).
133
+ """
134
+ k = self._kvec(k)
135
+ H = np.zeros((self.nao, self.nao), dtype=complex)
136
+ S = np.zeros((self.nao, self.nao), dtype=complex)
137
+ overlap = self.has_overlap()
138
+ for oi, oj, d, Hb, Sb in self._terms():
139
+ ph = np.exp(1j * float(k @ d))
140
+ ni, nj = Hb.shape
141
+ H[oi:oi + ni, oj:oj + nj] += ph * Hb
142
+ S[oi:oi + ni, oj:oj + nj] += ph * Sb
143
+ H = 0.5 * (H + H.conj().T)
144
+ if overlap:
145
+ S = 0.5 * (S + S.conj().T)
146
+ else:
147
+ S = np.eye(self.nao, dtype=complex)
148
+ return H, S
149
+
150
+ def bloch_derivative(self, k=None, direction=0):
151
+ """dH/dk and dS/dk along a Cartesian direction, at wave vector k.
152
+
153
+ These are the matrices the Kubo velocity operator is built from;
154
+ they are Hermitian by construction because every block enters
155
+ together with its reversed partner at -d.
156
+ """
157
+ k = self._kvec(k)
158
+ dH = np.zeros((self.nao, self.nao), dtype=complex)
159
+ dS = np.zeros((self.nao, self.nao), dtype=complex)
160
+ for oi, oj, d, Hb, Sb in self._terms():
161
+ ph = 1j * d[direction] * np.exp(1j * float(k @ d))
162
+ ni, nj = Hb.shape
163
+ dH[oi:oi + ni, oj:oj + nj] += ph * Hb
164
+ dS[oi:oi + ni, oj:oj + nj] += ph * Sb
165
+ dH = 0.5 * (dH + dH.conj().T)
166
+ dS = 0.5 * (dS + dS.conj().T)
167
+ return dH, dS
168
+
169
+ def _kvec(self, k):
170
+ dim = self.positions.shape[1]
171
+ if k is None:
172
+ return np.zeros(dim)
173
+ k = np.atleast_1d(np.asarray(k, dtype=float))
174
+ if k.shape != (dim,):
175
+ raise ValueError(f"k must have dimension {dim}")
176
+ return k
177
+
178
+ # ------------------------------------------------------------------
179
+ def monkhorst_pack(self, mesh):
180
+ """Uniform Gamma-centered k-grid over the Brillouin zone.
181
+
182
+ mesh: number of points per reciprocal direction (int or sequence
183
+ matching the cell dimension). Returns (kpts_cart, weights) with
184
+ weights summing to one.
185
+ """
186
+ if self.cell is None:
187
+ raise ValueError("finite system has no Brillouin zone")
188
+ dim = self.cell.shape[0]
189
+ if np.isscalar(mesh):
190
+ mesh = (int(mesh),) * dim
191
+ recip = 2.0 * np.pi * np.linalg.inv(self.cell).T
192
+ grids = [np.arange(n) / n for n in mesh]
193
+ frac = np.stack(np.meshgrid(*grids, indexing="ij"),
194
+ axis=-1).reshape(-1, dim)
195
+ kpts = frac @ recip
196
+ w = np.full(len(kpts), 1.0 / len(kpts))
197
+ return kpts, w
198
+
199
+ @property
200
+ def cell_volume(self):
201
+ """Length / area / volume of the unit cell (Angstrom^dim)."""
202
+ if self.cell is None:
203
+ raise ValueError("finite system has no cell")
204
+ c = self.cell
205
+ if c.shape == (1, 1):
206
+ return float(abs(c[0, 0]))
207
+ if c.shape == (2, 2):
208
+ return float(abs(np.linalg.det(c)))
209
+ return float(abs(np.linalg.det(c)))
hamop/negf.py ADDED
@@ -0,0 +1,163 @@
1
+ """Landauer transmission by nonequilibrium Green functions.
2
+
3
+ Two-probe geometry: a device of N principal layers between two
4
+ semi-infinite periodic leads, with only nearest-layer coupling (choose
5
+ the principal layer at least as wide as the interaction range). The
6
+ surface Green function of each lead is computed by the Sancho-Rubio
7
+ decimation (M. P. Lopez Sancho, J. M. Lopez Sancho and J. Rubio,
8
+ J. Phys. F 15, 851 (1985)); the device is traversed by the standard
9
+ recursive Green function sweep, and the transmission is the Caroli
10
+ trace T = Tr[ Gamma_R G Gamma_L G^dagger ].
11
+
12
+ Everything takes explicit layer blocks, so any Hamiltonian source --
13
+ built by hand, assembled from a TightBindingModel supercell, or
14
+ imported from an LCAO code -- can be pushed through the same
15
+ transmission function. Nonorthogonal bases are supported throughout
16
+ (energy-dependent coupling z S - H).
17
+
18
+ The test suite checks the analytic single-band chain: unit transmission
19
+ across the band and zero outside, the closed-form surface Green
20
+ function, the closed-form single-impurity transmission, and exact
21
+ agreement between the recursive sweep and a direct inversion of the
22
+ full device Green function.
23
+ """
24
+ from __future__ import annotations
25
+
26
+ import numpy as np
27
+
28
+ __all__ = ["sancho_rubio", "transmission", "transmission_direct"]
29
+
30
+
31
+ def sancho_rubio(E, H00, H01, S00=None, S01=None, eta=1e-6, maxiter=400,
32
+ tol=1e-12):
33
+ """Retarded surface Green function of a semi-infinite periodic lead.
34
+
35
+ H00: principal-layer block; H01: coupling from one layer to the
36
+ next deeper layer. S blocks default to identity / zero
37
+ (orthogonal basis).
38
+ """
39
+ n = len(H00)
40
+ S00 = np.eye(n, dtype=complex) if S00 is None else S00
41
+ S01 = np.zeros_like(H01) if S01 is None else S01
42
+ z = E + 1j * eta
43
+ a = z * S01 - H01
44
+ b = a.conj().T
45
+ es = e = z * S00 - H00
46
+ I = np.eye(n, dtype=complex)
47
+ for _ in range(maxiter):
48
+ g = np.linalg.solve(e, I)
49
+ ab = a @ g @ b
50
+ ba = b @ g @ a
51
+ es = es - ab
52
+ e = e - ab - ba
53
+ a = a @ g @ a
54
+ b = b @ g @ b
55
+ if np.abs(a).max() + np.abs(b).max() < tol:
56
+ break
57
+ return np.linalg.solve(es, I)
58
+
59
+
60
+ def _lead_sigmas(E, lead_H00, lead_H01, lead_S00, lead_S01, eta):
61
+ """Self-energies and broadenings of the left and right leads."""
62
+ z = E + 1j * eta
63
+ gL = sancho_rubio(E, lead_H00, lead_H01.conj().T, lead_S00,
64
+ None if lead_S01 is None else lead_S01.conj().T, eta)
65
+ gR = sancho_rubio(E, lead_H00, lead_H01, lead_S00, lead_S01, eta)
66
+ S01 = np.zeros_like(lead_H01) if lead_S01 is None else lead_S01
67
+ tau = z * S01 - lead_H01
68
+ sigL = tau.conj().T @ gL @ tau
69
+ sigR = tau @ gR @ tau.conj().T
70
+ gamL = 1j * (sigL - sigL.conj().T)
71
+ gamR = 1j * (sigR - sigR.conj().T)
72
+ return sigL, sigR, gamL, gamR
73
+
74
+
75
+ def transmission(E_list, layers_H, coup_H, lead_H00, lead_H01,
76
+ layers_S=None, coup_S=None, lead_S00=None, lead_S01=None,
77
+ eta=1e-6):
78
+ """T(E) by the recursive Green function sweep.
79
+
80
+ layers_H[i]: on-layer Hamiltonian of device layer i.
81
+ coup_H[i]: coupling from layer i to layer i+1 (N-1 blocks).
82
+ lead_H00 / lead_H01: principal layer of the identical left and right
83
+ leads. The outermost device layers must couple to the leads through
84
+ lead_H01, i.e. they must be lead-like at their outer edge.
85
+ """
86
+ N = len(layers_H)
87
+ layers_S = [None] * N if layers_S is None else layers_S
88
+ coup_S = [None] * (N - 1) if coup_S is None else coup_S
89
+ T = np.zeros(len(E_list))
90
+ for iE, E in enumerate(E_list):
91
+ z = E + 1j * eta
92
+ sigL, sigR, gamL, gamR = _lead_sigmas(
93
+ E, lead_H00, lead_H01, lead_S00, lead_S01, eta)
94
+ Gs = []
95
+ g_prev = None
96
+ for i in range(N):
97
+ Si = layers_S[i]
98
+ h_eff = (z * (np.eye(len(layers_H[i])) if Si is None else Si)
99
+ - layers_H[i])
100
+ if i == 0:
101
+ h_eff = h_eff - sigL
102
+ if i == N - 1:
103
+ h_eff = h_eff - sigR
104
+ if i == 0:
105
+ g_prev = np.linalg.inv(h_eff)
106
+ else:
107
+ Sc = coup_S[i - 1]
108
+ tau = (z * (np.zeros_like(coup_H[i - 1]) if Sc is None
109
+ else Sc) - coup_H[i - 1])
110
+ g_prev = np.linalg.inv(h_eff - tau.conj().T @ g_prev @ tau)
111
+ Gs.append(g_prev)
112
+ prod = Gs[-1]
113
+ for i in range(N - 2, -1, -1):
114
+ Sc = coup_S[i]
115
+ tau = (z * (np.zeros_like(coup_H[i]) if Sc is None else Sc)
116
+ - coup_H[i])
117
+ prod = prod @ tau.conj().T @ Gs[i]
118
+ G1N = prod # G_{N,1}: right edge <- left edge
119
+ T[iE] = float(np.real(np.trace(
120
+ gamR @ G1N @ gamL @ G1N.conj().T)))
121
+ return T
122
+
123
+
124
+ def transmission_direct(E_list, layers_H, coup_H, lead_H00, lead_H01,
125
+ layers_S=None, coup_S=None, lead_S00=None,
126
+ lead_S01=None, eta=1e-6):
127
+ """T(E) by direct inversion of the full device Green function.
128
+
129
+ Numerically exact reference for :func:`transmission` on small
130
+ devices; the recursive sweep must agree with this to machine
131
+ precision, and the test suite asserts that it does.
132
+ """
133
+ N = len(layers_H)
134
+ layers_S = [None] * N if layers_S is None else layers_S
135
+ coup_S = [None] * (N - 1) if coup_S is None else coup_S
136
+ sizes = [len(h) for h in layers_H]
137
+ offs = np.concatenate([[0], np.cumsum(sizes)])
138
+ ntot = offs[-1]
139
+ T = np.zeros(len(E_list))
140
+ for iE, E in enumerate(E_list):
141
+ z = E + 1j * eta
142
+ sigL, sigR, gamL, gamR = _lead_sigmas(
143
+ E, lead_H00, lead_H01, lead_S00, lead_S01, eta)
144
+ A = np.zeros((ntot, ntot), dtype=complex)
145
+ for i in range(N):
146
+ Si = layers_S[i]
147
+ blk = (z * (np.eye(sizes[i]) if Si is None else Si)
148
+ - layers_H[i])
149
+ A[offs[i]:offs[i + 1], offs[i]:offs[i + 1]] = blk
150
+ if i < N - 1:
151
+ Sc = coup_S[i]
152
+ tau = (z * (np.zeros_like(coup_H[i]) if Sc is None else Sc)
153
+ - coup_H[i])
154
+ A[offs[i]:offs[i + 1], offs[i + 1]:offs[i + 2]] = tau
155
+ A[offs[i + 1]:offs[i + 2], offs[i]:offs[i + 1]] = \
156
+ tau.conj().T
157
+ A[offs[0]:offs[1], offs[0]:offs[1]] -= sigL
158
+ A[offs[N - 1]:offs[N], offs[N - 1]:offs[N]] -= sigR
159
+ G = np.linalg.inv(A)
160
+ G1N = G[offs[N - 1]:offs[N], offs[0]:offs[1]]
161
+ T[iE] = float(np.real(np.trace(
162
+ gamR @ G1N @ gamL @ G1N.conj().T)))
163
+ return T
hamop/spectrum.py ADDED
@@ -0,0 +1,100 @@
1
+ """Band structures, densities of states and band fillings.
2
+
3
+ Everything here diagonalizes the same Bloch matrices the Kubo module
4
+ uses, through the same canonically orthogonalized solver, so spectral
5
+ and optical statements about one model can never disagree about what
6
+ the eigenvalues are.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import numpy as np
11
+
12
+ from .eigsolve import gen_eigh
13
+
14
+ __all__ = ["bands", "dos", "fermi_level", "band_edges"]
15
+
16
+ KB = 8.617333262e-5 # Boltzmann constant, eV / K (CODATA 2018)
17
+
18
+
19
+ def _eigs(model, kpts, thresh):
20
+ out = []
21
+ for k in kpts:
22
+ H, S = model.bloch(k)
23
+ out.append(gen_eigh(H, S, thresh=thresh))
24
+ return np.array(out)
25
+
26
+
27
+ def bands(model, kpts, thresh=1e-10):
28
+ """Eigenvalues along a list of Cartesian k-points; shape (nk, nao)."""
29
+ return _eigs(model, kpts, thresh)
30
+
31
+
32
+ def dos(model, energies, mesh=None, kpts=None, weights=None, eta=0.05,
33
+ thresh=1e-10):
34
+ """Gaussian-broadened density of states per unit cell (states / eV).
35
+
36
+ Either ``mesh`` (a Monkhorst-Pack grid) or explicit ``kpts`` with
37
+ ``weights`` summing to one. Spin degeneracy is *not* included; the
38
+ integral over all energies equals the number of orbitals kept per
39
+ cell.
40
+ """
41
+ kpts, weights = _grid(model, mesh, kpts, weights)
42
+ rho = np.zeros_like(np.asarray(energies, dtype=float))
43
+ for k, w in zip(kpts, weights):
44
+ H, S = model.bloch(k)
45
+ e = gen_eigh(H, S, thresh=thresh)
46
+ for ei in e:
47
+ rho += w * np.exp(-0.5 * ((energies - ei) / eta) ** 2) \
48
+ / (eta * np.sqrt(2.0 * np.pi))
49
+ return rho
50
+
51
+
52
+ def fermi_level(model, filling, mesh=None, kpts=None, weights=None,
53
+ T=300.0, thresh=1e-10, tol=1e-10):
54
+ """Chemical potential at which the mean band occupation per cell
55
+ equals ``filling`` (states per cell, spin not included), by
56
+ bisection on the Fermi-Dirac-weighted eigenvalue count."""
57
+ kpts, weights = _grid(model, mesh, kpts, weights)
58
+ eigs = _eigs(model, kpts, thresh)
59
+
60
+ def count(mu):
61
+ x = np.clip((eigs - mu) / (KB * T), -60.0, 60.0)
62
+ f = 1.0 / (1.0 + np.exp(x))
63
+ return float((f * np.asarray(weights)[:, None]).sum())
64
+
65
+ lo, hi = eigs.min() - 5.0, eigs.max() + 5.0
66
+ if not (count(lo) <= filling <= count(hi)):
67
+ raise ValueError("filling outside the reachable range")
68
+ for _ in range(200):
69
+ mid = 0.5 * (lo + hi)
70
+ if count(mid) < filling:
71
+ lo = mid
72
+ else:
73
+ hi = mid
74
+ if hi - lo < tol:
75
+ break
76
+ return 0.5 * (lo + hi)
77
+
78
+
79
+ def band_edges(model, mu, mesh=None, kpts=None, weights=None, thresh=1e-10):
80
+ """(valence-band maximum, conduction-band minimum, gap) about mu."""
81
+ kpts, weights = _grid(model, mesh, kpts, weights)
82
+ eigs = _eigs(model, kpts, thresh)
83
+ below = eigs[eigs <= mu]
84
+ above = eigs[eigs > mu]
85
+ if below.size == 0 or above.size == 0:
86
+ raise ValueError("mu lies outside the spectrum")
87
+ vbm, cbm = float(below.max()), float(above.min())
88
+ return vbm, cbm, cbm - vbm
89
+
90
+
91
+ def _grid(model, mesh, kpts, weights):
92
+ if mesh is not None:
93
+ return model.monkhorst_pack(mesh)
94
+ if kpts is None:
95
+ if model.cell is not None:
96
+ raise ValueError("periodic model: give mesh or kpts")
97
+ return [None], [1.0]
98
+ if weights is None:
99
+ weights = np.full(len(kpts), 1.0 / len(kpts))
100
+ return kpts, weights
@@ -0,0 +1,208 @@
1
+ Metadata-Version: 2.4
2
+ Name: hamop
3
+ Version: 0.1.0
4
+ Summary: One tight-binding Hamiltonian, every observable: bands, DOS, Kubo optical conductivity and NEGF transmission from the same real-space blocks, nonorthogonal bases included
5
+ Author-email: "Tanvir M. Mahim" <tanvir.mahim@bracu.ac.bd>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://tanvir-mahmud-mahim.github.io/software/
8
+ Project-URL: Repository, https://github.com/TaN-MM-Org/hamop
9
+ Project-URL: Issues, https://github.com/TaN-MM-Org/hamop/issues
10
+ Project-URL: Changelog, https://github.com/TaN-MM-Org/hamop/releases
11
+ Keywords: tight binding,Kubo-Greenwood,NEGF,Landauer,optical conductivity,quantum transport,LCAO
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Scientific/Engineering :: Physics
17
+ Requires-Python: >=3.9
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: numpy>=1.22
21
+ Requires-Dist: scipy>=1.8
22
+ Provides-Extra: test
23
+ Requires-Dist: pytest; extra == "test"
24
+ Dynamic: license-file
25
+
26
+ # hamop
27
+
28
+ [![Tests](https://github.com/TaN-MM-Org/hamop/actions/workflows/ci.yml/badge.svg)](https://github.com/TaN-MM-Org/hamop/actions/workflows/ci.yml)
29
+ [![PyPI](https://img.shields.io/pypi/v/hamop?label=PyPI&color=blue)](https://pypi.org/project/hamop/)
30
+ [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
31
+
32
+ **One tight-binding Hamiltonian, every observable, strictly
33
+ consistent.** Build a Hamiltonian once, as real-space blocks in an
34
+ orthogonal or nonorthogonal basis, and compute its band structure,
35
+ density of states, Kubo-Greenwood optical conductivity and Landauer
36
+ (NEGF) transmission from the same matrices.
37
+
38
+ The point of the package is the consistency, not any single solver.
39
+ When the optics of a model and its spectrum are computed by different
40
+ codes with different conventions, they drift: a different gauge for the
41
+ velocity operator, a different treatment of the overlap matrix, a
42
+ different broadening, and suddenly the absorption edge no longer sits
43
+ at the band gap. Here every observable diagonalizes the same Bloch
44
+ matrices through the same canonically orthogonalized solver, and the
45
+ Kubo velocity operator is built from the exact k-derivative of the same
46
+ assembly, so spectral, optical and transport statements about one model
47
+ cannot disagree with each other.
48
+
49
+ ## What it does
50
+
51
+ - **`TightBindingModel`**: sites with any number of orbitals, directed
52
+ hopping blocks with automatic Hermitian completion, optional overlap
53
+ blocks (LCAO-style nonorthogonal bases), periodic in any dimension or
54
+ finite. Assembles H(k), S(k) and their exact k-derivatives in the
55
+ atomic gauge.
56
+ - **Spectrum** (`bands`, `dos`, `fermi_level`, `band_edges`): band
57
+ structures along arbitrary k-lists, Gaussian-broadened densities of
58
+ states, chemical potential at a given filling by bisection, band
59
+ edges and gap about a chemical potential.
60
+ - **Optics** (`sigma_optical`): Kubo-Greenwood real sheet conductivity
61
+ in units of e²/(4ℏ), with the nonorthogonal velocity correction
62
+ `v = dH/dk − (eₙ+eₘ)/2 dS/dk` that makes the result exactly
63
+ invariant under a shift of the energy zero.
64
+ - **Transport** (`sancho_rubio`, `transmission`,
65
+ `transmission_direct`): two-probe Landauer transmission with
66
+ Sancho-Rubio lead surface Green functions and a recursive Green
67
+ function sweep, nonorthogonal bases included, plus a dense
68
+ direct-inversion reference implementation of the same quantity.
69
+ - **`gen_eigh`**: generalized eigensolver with canonical
70
+ orthogonalization (Szabo and Ostlund, *Modern Quantum Chemistry*,
71
+ sec. 3.4.5), so mildly overcomplete overlaps cannot blow up the
72
+ spectrum — the standard remedy used inside electronic-structure
73
+ codes.
74
+
75
+ Dependencies: NumPy and SciPy. Nothing else.
76
+
77
+ ## Validation against closed forms
78
+
79
+ Every physical claim in the package is pinned by a test against an
80
+ exact result, not a stored number:
81
+
82
+ - the single-orbital chain reproduces E(k) = e₀ + 2t cos ka to machine
83
+ precision, and its nonorthogonal variant reproduces
84
+ E(k) = 2t cos ka / (1 + 2s cos ka);
85
+ - the chain density of states matches 1/(π√(4t² − E²)) and integrates
86
+ to the orbital count;
87
+ - graphene's nearest-neighbour model gives Dirac-point closure at K
88
+ exactly, ±3|t| at Γ exactly, and the **universal optical sheet
89
+ conductivity e²/(4ℏ)** on the interband plateau (Kuzmenko et al.,
90
+ Phys. Rev. Lett. 100, 117401 (2008)) — which is also the absolute
91
+ anchor for the package's conductivity unit;
92
+ - the two-site molecule absorbs at exactly 2|t| with the hand-derived
93
+ velocity matrix element |M| = |a t|;
94
+ - σ(ω) is invariant to 10⁻¹⁰ under H → H + cS with μ → μ + c, which
95
+ pins the nonorthogonal velocity term;
96
+ - the chain's lead surface Green function matches its closed form
97
+ (E − i√(4t² − E²))/(2t²); a pristine chain transmits exactly one
98
+ channel inside the band and nothing outside; two decoupled chains
99
+ transmit two; an on-site impurity ε reproduces
100
+ T = (4t² − E²)/((4t² − E²) + ε²);
101
+ - the recursive Green function sweep agrees with dense direct inversion
102
+ to machine precision, disorder and overlap included.
103
+
104
+ Run them yourself: `pip install -e .[test]` then `pytest`.
105
+
106
+ ## Install and use
107
+
108
+ ```
109
+ pip install hamop
110
+ ```
111
+
112
+ ```python
113
+ import numpy as np
114
+ from hamop import graphene, bands, dos, sigma_optical
115
+
116
+ g = graphene(t=-2.7, a=2.46) # eV, Angstrom
117
+ omega = np.linspace(0.5, 2.0, 60)
118
+ sigma = sigma_optical(g, omega, mu=0.0, mesh=120, eta=0.12)
119
+ # sigma is ~1.0 on the plateau: the universal e^2/(4 hbar)
120
+ ```
121
+
122
+ Building your own model:
123
+
124
+ ```python
125
+ from hamop import TightBindingModel, band_edges
126
+
127
+ m = TightBindingModel(positions=[[0.0], [0.7]], norb=1, cell=[[2.0]])
128
+ m.add_hop(0, 1, (0,), [[-1.0]]) # intra-cell bond
129
+ m.add_hop(1, 0, (1,), [[-0.6]]) # inter-cell bond
130
+ print(band_edges(m, mu=0.0, mesh=2001)) # the SSH gap, 2|t1 - t2|
131
+ ```
132
+
133
+ Conventions, stated once: energies in eV, positions in Angstrom, k in
134
+ 1/Angstrom, Cartesian. Each directed hopping block is added once and
135
+ its Hermitian partner is implied. Optical conductivity is the real
136
+ sheet conductivity in units of e²/(4ℏ) with spin degeneracy as an
137
+ explicit factor (default 2). The velocity operator uses the standard
138
+ atomistic position gauge (position operator diagonal at the sites);
139
+ the intra-atomic dipole contribution is neglected, the common
140
+ approximation in tight-binding optics.
141
+
142
+ ## Relation to existing tools
143
+
144
+ Excellent tools cover parts of this space: [PythTB](https://www.physics.rutgers.edu/pythtb/) and [pybinding](https://docs.pybinding.site/) build tight-binding models and their spectra, and [Kwant](https://kwant-project.org/) is the standard for quantum transport. hamop does not replace any of them, and for their core use cases they are more capable. Its niche is the combination they leave open: nonorthogonal (LCAO-style) overlap matrices as first-class citizens across *all* observables, optics and transport computed from the same Bloch assembly as the spectrum so the three can never disagree, and a deliberately small NumPy/SciPy-only core validated line by line against closed forms -- the shape of engine an LCAO electronic-structure pipeline exports its Hamiltonians into.
145
+
146
+ ## Status
147
+
148
+ v0.1.0 (alpha). Implemented and tested: the model container with exact
149
+ k-derivatives, canonical-orthogonalization eigensolver, band
150
+ structures, densities of states, filling-resolved chemical potentials,
151
+ band edges, Kubo-Greenwood optical conductivity for periodic and finite
152
+ systems, Sancho-Rubio surface Green functions, and recursive plus
153
+ direct-inversion Landauer transmission.
154
+
155
+ Not yet implemented, stated plainly: k-space symmetry reduction (grids
156
+ are full Monkhorst-Pack), Lorentzian and adaptive broadenings, the
157
+ Drude (intraband) term of the conductivity, spin-orbit-coupled blocks
158
+ as a first-class convention (complex blocks work, but no helper),
159
+ Hall/off-diagonal conductivity tensors, and interaction self-energies
160
+ in the transport module. Sparse or very large models are out of scope
161
+ for now: matrices are dense.
162
+
163
+ ## Where it comes from
164
+
165
+ Methodological basis:
166
+
167
+ > "Learning the quantum Hamiltonian of defective monolayer MoS2
168
+ > reveals collective vacancy brightness decoupled from defect count";
169
+ > code for the paper:
170
+ > https://github.com/Tanvir-Mahmud-Mahim/mos2-vacancy-optics
171
+
172
+ That study computes the optics, the electronic structure and the
173
+ transport of vacancy-disordered MoS2 supercells from one
174
+ density-functional Hamiltonian, so that a defect configuration's
175
+ optical and electronic signatures are strictly consistent — and its
176
+ conclusions depend on that consistency. This package is the
177
+ general-purpose engine distilled from that pipeline: the same
178
+ observables for any Hamiltonian a user supplies, with the
179
+ material-specific machinery (DFT extraction, machine-learned
180
+ Hamiltonians, MoS2 structures) left in the paper repository.
181
+
182
+ ## Support and governance
183
+
184
+ The package is written and maintained by Tanvir Mahmud Mahim
185
+ (Department of Electrical and Electronic Engineering, BRAC University),
186
+ who reviews every change and takes the final decision on scope and
187
+ releases. There is no separate governance body; design questions are
188
+ discussed in the open in issues and pull requests, and the standing
189
+ rule of [CONTRIBUTING.md](CONTRIBUTING.md) binds the maintainer exactly
190
+ as it binds contributors: a change that touches physics arrives with a
191
+ test, and a constant arrives with its source.
192
+
193
+ Support runs through the issue tracker at
194
+ https://github.com/TaN-MM-Org/hamop/issues. Usage questions are welcome
195
+ there alongside bug reports; a docstring that left a unit or a sign
196
+ convention unclear is treated as a documentation bug, not as user
197
+ error. The maintainer aims to respond within a week.
198
+
199
+ While the version is below 1.0 the API may still move between minor
200
+ versions; such changes are called out in the release notes. The
201
+ limitations named under Status are deliberate scope, recorded there
202
+ precisely so that a user can tell a designed-out feature from an
203
+ oversight.
204
+
205
+ ## License
206
+
207
+ Apache-2.0 (see [LICENSE](LICENSE)). Citation metadata is in
208
+ [CITATION.cff](CITATION.cff).
@@ -0,0 +1,12 @@
1
+ hamop/__init__.py,sha256=L25YfOtHTmhBgQOuz_TPHXEFr65SpN7VeGXJvo9XxGw,1301
2
+ hamop/eigsolve.py,sha256=MX100E8gvG-pz9EAt-nxm3nPxk4a860-QvjN-j8PX-4,1541
3
+ hamop/kubo.py,sha256=1JfYzvedPZ1M_0MaR33ARAb4pTin485XwjjlHVbmIMo,3985
4
+ hamop/lattices.py,sha256=U8Xhhc6nTTzW6TEjZUnIFBW7vu9k1tzYeuhnubSoLMw,2415
5
+ hamop/model.py,sha256=xaCb_jlRi4Zl7tW_z4wh6BF7ChPK-aEQPCkUOSHbWG8,9023
6
+ hamop/negf.py,sha256=x5vCAnXq5lCeakOf_XCMvZbQmVOM-OPFq9h2BJfieTU,6627
7
+ hamop/spectrum.py,sha256=cEZFa1ow4-PJuTccaq-wqCdZkQ1vvIDyNzwkwWJZPQ8,3408
8
+ hamop-0.1.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
9
+ hamop-0.1.0.dist-info/METADATA,sha256=QKKcIulDTshb5W880bzwrVe4fbk5fyh0gTlybzDq0Ns,10252
10
+ hamop-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
11
+ hamop-0.1.0.dist-info/top_level.txt,sha256=_ByXtlSRP4hTvxZpTXKhlPrPUUr4EOP7dApNrUxtrMw,6
12
+ hamop-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
@@ -0,0 +1 @@
1
+ hamop