Dyadic Green’s Function via Sommerfeld Integrals¶
Goal¶
In this tutorial you will compute the dyadic Green’s function \(\overleftrightarrow{G}(\mathbf{r}_D, \mathbf{r}_A, \omega)\) for a two-layer planar system (vacuum above a semi-infinite substrate) using the Fresnel-coefficient / Sommerfeld-integral method implemented in MQED-QD.
By the end you will know how to:
run the
mqed_GF_Sommerfeldcommand with default and custom parameters,specify single-frequency, multi-frequency (list), and swept-frequency (dict) inputs (including segmented nonuniform windows),
choose dielectric models from YAML (
excel,constant,Drude,Drude-Lorentz),accelerate multi-frequency sweeps with joblib (multicore) or MPI (cluster) parallelism,
locate and interpret the HDF5 output file.
See also
Two-Layer Planar Geometry for the mathematical derivation of the Sommerfeld integrals and Fresnel reflection coefficients used by this solver.
Prerequisites¶
Make sure you have installed the package and activated the environment as described in Installation.
Quick start¶
Run from the repository root with all defaults:
mqed_GF_Sommerfeld
This uses the YAML configuration at configs/Dyadic_GF/GF_Sommerfeld.yaml.
The default settings compute the Green’s function for a single energy
(1.0 eV) at a height of 5 nm above a silver (Ag) surface.
Specifying the emitter frequency¶
You can override any configuration key on the command line using Hydra syntax.
Single energy
mqed_GF_Sommerfeld simulation.energy_eV=1.864
List of energies
mqed_GF_Sommerfeld simulation.energy_eV=[1.5,1.8,2.0]
Swept range (dict input)
mqed_GF_Sommerfeld simulation.energy_eV.min=1.0 \
simulation.energy_eV.max=2.0 \
simulation.energy_eV.points=11
This generates 11 linearly spaced energies from 1.0 to 2.0 eV.
Segmented nonuniform sweep (piecewise ranges)
mqed_GF_Sommerfeld \
simulation.energy_eV.segments[0].min=0.0 \
simulation.energy_eV.segments[0].max=3.0 \
simulation.energy_eV.segments[0].points=21 \
simulation.energy_eV.segments[1].min=3.0 \
simulation.energy_eV.segments[1].max=4.5 \
simulation.energy_eV.segments[1].points=301 \
simulation.energy_eV.segments[2].min=4.5 \
simulation.energy_eV.segments[2].max=6.0 \
simulation.energy_eV.segments[2].points=21
This is useful when the spectrum is mostly flat away from resonance and needs fine resolution only near the plasmonic window.
Choosing the dielectric model¶
The dielectric source is selected by material.source_type:
excel: interpolate from the configured Excel sheetconstant: use a fixed complex permittivityDrude: use the Drude modelDrude-Lorentz: use Drude + Lorentz oscillators
Examples:
# Constant epsilon
mqed_GF_Sommerfeld material.source_type=constant material.constant_value="9.0+0.2j"
# Drude model with eV parameters
mqed_GF_Sommerfeld material.source_type=Drude \
material.drude_config.eps_inf=1.0 \
material.drude_config.omega_p_eV=9.01 \
material.drude_config.gamma_eV=0.048
# Drude-Lorentz model with two oscillators
mqed_GF_Sommerfeld material.source_type=Drude-Lorentz \
material.drude_lorentz_config.eps_inf=1.0 \
material.drude_lorentz_config.omega_p_eV=9.01 \
material.drude_lorentz_config.gamma_eV=0.048 \
material.drude_lorentz_config.oscillators[0].strength=0.85 \
material.drude_lorentz_config.oscillators[0].omega_0_eV=3.8 \
material.drude_lorentz_config.oscillators[0].gamma_eV=0.25 \
material.drude_lorentz_config.oscillators[1].strength=0.20 \
material.drude_lorentz_config.oscillators[1].omega_0_eV=4.9 \
material.drude_lorentz_config.oscillators[1].gamma_eV=0.35
Note
For each frequency-like model parameter, provide exactly one unit key:
*_eV or *_rad_s.
Tip
You can use wavelength instead of energy by setting
simulation.spectral_param=wavelength_nm and providing
simulation.wavelength_nm values in the same single / list / dict
format.
Using a custom configuration file¶
Every MQED command loads its default YAML from the configs/ directory.
Hydra provides two flags that let you swap the entire configuration file
without editing code:
Use a different YAML in the same config directory
mqed_GF_Sommerfeld --config-name=my_GF
This loads configs/Dyadic_GF/my_GF.yaml instead of the default
GF_Sommerfeld.yaml. Your custom file must live in the same
configs/Dyadic_GF/ directory.
Use a YAML from an arbitrary directory
mqed_GF_Sommerfeld --config-dir=/path/to/my/configs --config-name=my_GF
This tells Hydra to look for my_GF.yaml in /path/to/my/configs/
instead of the default config directory.
Tip
You can combine --config-name (or --config-dir) with individual
parameter overrides:
mqed_GF_Sommerfeld --config-name=my_GF simulation.energy_eV=2.0
Parallel execution¶
When computing the Green’s function over many frequencies (e.g. a 200-point spectral density sweep), the sequential loop can take tens of minutes. Because each energy point is completely independent, the frequency axis can be parallelized with no inter-worker communication.
MQED-QD supports two parallel backends, selectable via the parallel
configuration group.
Joblib (shared-memory multiprocessing)
Best for laptops and single-node workstations. Uses Python’s
multiprocessing under the hood via joblib.
# Use all available CPU cores
mqed_GF_Sommerfeld \
simulation.energy_eV='{min: 0.5, max: 4.0, points: 200}' \
parallel.backend=joblib
# Limit to 4 workers
mqed_GF_Sommerfeld \
simulation.energy_eV='{min: 0.5, max: 4.0, points: 200}' \
parallel.backend=joblib parallel.n_jobs=4
Setting parallel.n_jobs=-1 (the default) uses all available cores.
Tip
On a machine with 8 cores, a 200-energy sweep that takes ~30 min
sequentially will finish in ~4 min with parallel.backend=joblib.
MPI (distributed parallelism)
Best for HPC clusters with multi-node allocation. Requires mpi4py and an MPI runtime (e.g. OpenMPI or MPICH).
Auto-launch mode (default) — the script detects it is not inside an MPI
communicator and re-launches itself under mpiexec:
mqed_GF_Sommerfeld \
simulation.energy_eV='{min: 0.5, max: 4.0, points: 200}' \
parallel.backend=mpi parallel.mpi_nproc=16
Manual launch — submit from a job scheduler (SLURM, PBS, etc.) with
mpi_auto_launch=false:
# Inside a SLURM job script, for example:
srun -n 32 mqed_GF_Sommerfeld \
simulation.energy_eV='{min: 0.5, max: 4.0, points: 200}' \
parallel.backend=mpi parallel.mpi_auto_launch=false
Energy points are scattered round-robin across MPI ranks. Only rank 0 writes the final HDF5 file.
Parameter |
Description |
Default |
|---|---|---|
|
Execution mode: |
|
|
Number of joblib workers ( |
|
|
Number of MPI ranks for auto-launch |
|
|
Re-launch under |
|
|
Path to MPI launcher binary |
|
Configuration reference¶
The full default configuration file
(configs/Dyadic_GF/GF_Sommerfeld.yaml) is reproduced below with
annotations.
# ── Material ────────────────────────────────────────────
material:
source_type: excel # excel, constant, Drude, Drude-Lorentz
constant_value: 9.0+0.0j # used only when source_type = 'constant'
excel_config:
filepath: "DielectricFunction/dielectric function.xlsx"
sheet_name: "Ag_BEM"
drude_config: # used only when source_type = 'Drude'
eps_inf: 1.0
omega_p_eV: 9.01 # or omega_p_rad_s
gamma_eV: 0.048 # or gamma_rad_s
drude_lorentz_config: # used only when source_type = 'Drude-Lorentz'
eps_inf: 1.0
omega_p_eV: 9.01
gamma_eV: 0.048
oscillators:
- strength: 0.85
omega_0_eV: 3.8 # or omega_0_rad_s
gamma_eV: 0.25 # or gamma_rad_s
# ── Simulation ──────────────────────────────────────────
simulation:
material: "Ag" # label used in the output filename
spectral_param: "energy_eV" # 'energy_eV' or 'wavelength_nm'
energy_eV: # single value, list, dict, or piecewise segments
min: 1.0
max: 1.0
points: 1
# segments:
# - {min: 0.0, max: 3.0, points: 21}
# - {min: 3.0, max: 4.5, points: 301}
# - {min: 4.5, max: 6.0, points: 21}
wavelength_nm: # same three formats as energy_eV
min: 500.0
max: 500.0
points: 1
position:
zD: 5.0e-9 # donor height above surface (m)
zD_nm: 5 # donor height label for filename (nm)
zA: 5.0e-9 # acceptor height above surface (m)
Rx_nm: # horizontal donor–acceptor distances
start: 0.0
stop: 300.0
points: 301 # 0, 1, 2, …, 300 nm
integration: # numerical quadrature controls
qmax: null # finite cutoff for evanescent tail; null → ∞
epsabs: 1.0e-10 # absolute tolerance
epsrel: 1.0e-10 # relative tolerance
limit: 400 # max sub-intervals for quad_vec
split_propagating: true # split at k₀ for propagating / evanescent
# ── Output ──────────────────────────────────────────────
output:
filename: "Fresnel_GF_planar_${simulation.material}_height_${simulation.position.zD_nm}nm.hdf5"
# ── Parallel execution ──────────────────────────────────
parallel:
backend: sequential # 'sequential', 'joblib', or 'mpi'
n_jobs: -1 # joblib workers; -1 = all cores
mpi_nproc: 4 # MPI ranks for auto-launch
mpi_auto_launch: true # re-launch under mpiexec if needed
mpi_exec: mpiexec # path to MPI launcher
Parameter |
Description |
Default |
|---|---|---|
|
Source of the dielectric function ( |
|
|
Which spectral unit to use ( |
|
|
Donor height above the surface in meters |
|
|
Acceptor height above the surface in meters |
|
|
Horizontal distance grid ( |
0 – 300 nm, 301 pts |
|
Absolute tolerance for Sommerfeld quadrature |
|
|
Maximum sub-intervals for adaptive quadrature |
|
Expected output¶
After the simulation finishes, a success message is printed to the terminal
(and to the Hydra log file
outputs/Dyadic_GF_Sommerfeld/.../Dyadic_GF_Sommerfeld.log):
2025-10-24 11:40:02.818 | SUCCESS | mqed.Dyadic_GF.main:run_simulation:114
- Simulation complete. Output saved to:
/.../MacroscopicQED/outputs/Dyadic_GF_Sommerfeld/Y-M-D/H-M-S/YOUR_NAME.hdf5
The output is an HDF5 file that stores:
the 9-component dyadic Green’s function (total and vacuum) as 4-D complex arrays of shape
[nE, nR, 3, 3],the energy grid (
energy_eV),the horizontal distance grid (
Rx_nm),the donor and acceptor heights (
zD,zA).
Using the output in downstream analyses¶
Many MQED-QD workflows read a cached Green’s function file as their input. The recommended workflow is:
Create a cache directory under the project root (if it does not exist):
mkdir -p data/GF_cache
Copy (or symlink) the HDF5 result into the cache:
cp outputs/Dyadic_GF_Sommerfeld/<date>/<time>/YOUR_NAME.hdf5 \ data/GF_cache/
Update the
greens.h5_pathorinput_filekey in the downstream configuration to point to this cached file.
See also
Field Enhancement – compute the field enhancement using the Green’s function produced here.
Quantum Dynamics – run Lindblad or NHSE dynamics with this Green’s function as input.