pystratify 0.10.2__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.
pystratify/drude.py ADDED
@@ -0,0 +1,82 @@
1
+ """Drude fits of Au, Ag and Al and the electron free-path correction for thin metal shells.
2
+
3
+ Tabulated optical constants are deliberately not shipped: take n + ik from a
4
+ database (e.g. refractiveindex.info) and pass it to :func:`~pystratify.solve`.
5
+ The Drude fits are needed only for what tables cannot supply - the damping
6
+ of the free electrons, which enters the free-path correction and the energy
7
+ prefactor of a dispersive shell. Wavelengths in this module are in
8
+ nanometres.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from dataclasses import dataclass
14
+
15
+ import numpy as np
16
+
17
+ __all__ = ["DrudeModel", "DRUDE", "free_path_correction"]
18
+
19
+
20
+ @dataclass(frozen=True)
21
+ class DrudeModel:
22
+ """Free-electron parameters, in wavelength form (lambda = 2 pi c / omega).
23
+
24
+ ``plasma_wavelength`` = 2 pi c / omega_p and ``damping_wavelength`` =
25
+ 2 pi c / gamma, both in nm; ``fermi_velocity`` is v_F / c.
26
+ """
27
+
28
+ plasma_wavelength: float
29
+ damping_wavelength: float
30
+ fermi_velocity: float
31
+
32
+ @property
33
+ def damping_ratio(self) -> float:
34
+ """gamma / omega_p."""
35
+ return self.plasma_wavelength / self.damping_wavelength
36
+
37
+
38
+ #: Ordal et al., Appl. Opt. 24, 4493 (1985) ("_Ord") and Blaber et al.,
39
+ #: J. Phys. Chem. C 113, 3041 (2009) ("_Blb"), as used by STRATIFY.
40
+ DRUDE = {
41
+ "Au_Ord": DrudeModel(137.36, 46436.02734, 0.014 / 3),
42
+ "Ag_Ord": DrudeModel(137.56, 68880.10723, 0.0139 / 3),
43
+ "Al_Ord": DrudeModel(84.05708, 15156.99181, 0.0206 / 3),
44
+ "Au_Blb": DrudeModel(144.93, 67382.71359, 0.014 / 3),
45
+ "Ag_Blb": DrudeModel(129.15, 54379.03202, 0.0139 / 3),
46
+ "Al_Blb": DrudeModel(81.03542, 2071.92836, 0.0206 / 3),
47
+ }
48
+
49
+
50
+ def effective_path(radii_nm) -> float:
51
+ """Mean free path limited by the boundaries: 4/3 R for a sphere, and
52
+ 4/3 (R2^3 - R1^3) / (R1^2 + R2^2) for a shell (Moroz, J. Phys. Chem. C
53
+ 112, 10641 (2008))."""
54
+ radii = np.atleast_1d(np.asarray(radii_nm, dtype=float))
55
+ if radii.size == 1:
56
+ return 4 / 3 * float(radii[0])
57
+ r1, r2 = float(radii[0]), float(radii[1])
58
+ return 4 / 3 * (r2**3 - r1**3) / (r1**2 + r2**2)
59
+
60
+
61
+ def surface_damping_wavelength(model: DrudeModel, radii_nm) -> float:
62
+ """2 pi c / gamma_s with gamma_s = gamma + v_F / L_eff."""
63
+ gamma_s = model.damping_ratio + model.fermi_velocity * model.plasma_wavelength / (
64
+ 2 * np.pi * effective_path(radii_nm)
65
+ )
66
+ return model.plasma_wavelength / gamma_s
67
+
68
+
69
+ def free_path_correction(wavelength_nm, n_bulk, radii_nm, model):
70
+ """Refractive index of a thin metal shell with surface-limited damping.
71
+
72
+ eps = eps_bulk + wp^2/(w(w + i gamma)) - wp^2/(w(w + i gamma_s)): the bulk
73
+ Drude damping is swapped for gamma_s = gamma + v_F / L_eff. ``radii_nm``
74
+ is ``(R,)`` for a core or ``(R_in, R_out)`` for a shell; ``model`` a
75
+ :class:`DrudeModel` or a key of :data:`DRUDE`.
76
+ """
77
+ model = DRUDE[model] if isinstance(model, str) else model
78
+ ratio = model.damping_ratio
79
+ ratio_s = model.plasma_wavelength / surface_damping_wavelength(model, radii_nm)
80
+ w = model.plasma_wavelength / np.asarray(wavelength_nm, dtype=float) # omega / omega_p
81
+ eps = np.asarray(n_bulk) ** 2 + 1 / (w * (w + 1j * ratio)) - 1 / (w * (w + 1j * ratio_s))
82
+ return np.sqrt(eps)