@galihru/mnp-material 0.1.0

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.
package/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # @galihru/mnp-material
2
+
3
+ Scientific dielectric-response models for plasmonic simulations.
4
+
5
+ Implemented formulation (Drude model):
6
+
7
+ $$
8
+ \varepsilon(\omega)=\varepsilon_\infty-\frac{\omega_p^2}{\omega(\omega+i\gamma)}
9
+ $$
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install @galihru/mnp-material
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```js
20
+ import { drudeEpsilon } from "@galihru/mnp-material";
21
+
22
+ const epsAu = drudeEpsilon("Au", 548.1);
23
+ console.log(epsAu);
24
+ ```
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@galihru/mnp-material",
3
+ "version": "0.1.0",
4
+ "description": "Material dielectric models for plasmonic electrodynamics.",
5
+ "type": "module",
6
+ "main": "./src/index.js",
7
+ "exports": {
8
+ ".": "./src/index.js"
9
+ },
10
+ "files": [
11
+ "src",
12
+ "README.md"
13
+ ],
14
+ "author": "GALIH RIDHO UTOMO <g4lihru@students.unnes.ac.id>",
15
+ "license": "GPL-2.0-only",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/galihru/mnpbem.git"
19
+ },
20
+ "publishConfig": {
21
+ "registry": "https://registry.npmjs.org/",
22
+ "access": "public"
23
+ },
24
+ "scripts": {
25
+ "test": "node --test"
26
+ }
27
+ }
package/src/complex.js ADDED
@@ -0,0 +1,35 @@
1
+ export function complex(re = 0, im = 0) {
2
+ return { re: Number(re), im: Number(im) };
3
+ }
4
+
5
+ export function add(a, b) {
6
+ return complex(a.re + b.re, a.im + b.im);
7
+ }
8
+
9
+ export function sub(a, b) {
10
+ return complex(a.re - b.re, a.im - b.im);
11
+ }
12
+
13
+ export function mul(a, b) {
14
+ return complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re);
15
+ }
16
+
17
+ export function div(a, b) {
18
+ const denom = b.re * b.re + b.im * b.im;
19
+ if (denom === 0) {
20
+ throw new Error("Division by zero complex number");
21
+ }
22
+ return complex((a.re * b.re + a.im * b.im) / denom, (a.im * b.re - a.re * b.im) / denom);
23
+ }
24
+
25
+ export function sqrtComplex(z) {
26
+ const r = Math.hypot(z.re, z.im);
27
+ const re = Math.sqrt((r + z.re) / 2);
28
+ const imSign = z.im < 0 ? -1 : 1;
29
+ const im = imSign * Math.sqrt(Math.max((r - z.re) / 2, 0));
30
+ return complex(re, im);
31
+ }
32
+
33
+ export function fromReal(x) {
34
+ return complex(x, 0);
35
+ }
package/src/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { EV_TO_NM, HARTREE_EV, constantEpsilon, drudeEpsilon, makeDrudeMaterial, wavenumberInMedium } from "./material.js";
2
+ export { add, complex, div, fromReal, mul, sqrtComplex, sub } from "./complex.js";
@@ -0,0 +1,64 @@
1
+ import { add, complex, div, fromReal, mul, sqrtComplex, sub } from "./complex.js";
2
+
3
+ export const EV_TO_NM = 1.0 / 8.0655477e-4;
4
+ export const HARTREE_EV = 27.2116;
5
+
6
+ const MATERIAL_TABLE = {
7
+ au: { rs: 3.0, eps0: 10.0, gammadAu: (0.66 / HARTREE_EV) / 10.0 },
8
+ gold: { rs: 3.0, eps0: 10.0, gammadAu: (0.66 / HARTREE_EV) / 10.0 },
9
+ ag: { rs: 3.0, eps0: 3.3, gammadAu: (0.66 / HARTREE_EV) / 30.0 },
10
+ silver: { rs: 3.0, eps0: 3.3, gammadAu: (0.66 / HARTREE_EV) / 30.0 },
11
+ al: { rs: 2.07, eps0: 1.0, gammadAu: 1.06 / HARTREE_EV },
12
+ aluminum: { rs: 2.07, eps0: 1.0, gammadAu: 1.06 / HARTREE_EV }
13
+ };
14
+
15
+ function mapInput(values, fn) {
16
+ if (Array.isArray(values)) {
17
+ return values.map(fn);
18
+ }
19
+ return fn(values);
20
+ }
21
+
22
+ export function makeDrudeMaterial(name) {
23
+ const key = String(name).toLowerCase();
24
+ const row = MATERIAL_TABLE[key];
25
+ if (!row) {
26
+ throw new Error(`Unknown material '${name}'. Expected one of: Au, Ag, Al.`);
27
+ }
28
+
29
+ const density = 3.0 / (4.0 * Math.PI * row.rs ** 3);
30
+ const wpAu = Math.sqrt(4.0 * Math.PI * density);
31
+
32
+ return {
33
+ name,
34
+ eps0: row.eps0,
35
+ gammad: row.gammadAu * HARTREE_EV,
36
+ wp: wpAu * HARTREE_EV
37
+ };
38
+ }
39
+
40
+ export function drudeEpsilon(materialName, wavelengthNm) {
41
+ const m = makeDrudeMaterial(materialName);
42
+ return mapInput(wavelengthNm, (wl) => {
43
+ const w = EV_TO_NM / Number(wl);
44
+ const numerator = fromReal(m.wp ** 2);
45
+ const denom = mul(fromReal(w), add(fromReal(w), complex(0, m.gammad)));
46
+ return sub(fromReal(m.eps0), div(numerator, denom));
47
+ });
48
+ }
49
+
50
+ export function constantEpsilon(value, wavelengthNm) {
51
+ return mapInput(wavelengthNm, () => complex(value, 0));
52
+ }
53
+
54
+ export function wavenumberInMedium(wavelengthNm, epsilonComplex) {
55
+ const computeOne = (wl, eps) => {
56
+ const factor = (2.0 * Math.PI) / Number(wl);
57
+ return mul(fromReal(factor), sqrtComplex(eps));
58
+ };
59
+
60
+ if (Array.isArray(wavelengthNm)) {
61
+ return wavelengthNm.map((wl, i) => computeOne(wl, epsilonComplex[i]));
62
+ }
63
+ return computeOne(wavelengthNm, epsilonComplex);
64
+ }