Contents Menu Expand Light mode Dark mode Auto light/dark, in light mode Auto light/dark, in dark mode Skip to content
MaxwellLink 0.3.7
Light Logo Dark Logo
MaxwellLink 0.3.7
  • MaxwellLink
    • Introduction
    • Installation
    • Usage Guide
    • Exascale simulations
    • Agent Skills
    • Tutorials
      • Introduction to real-time time-dependent Hartree-Fock theory
      • Driven dynamics with TLS
      • Rabi splitting with TLS
      • Rabi splitting of coupled harmonic oscillators
      • Electronic strong coupling with HCN
      • Collective, heterogeneous coupling of QuTiP + RT-TDDFT HCN molecules
      • Vibrational strong coupling with liquid water: Unix socket
      • Multimode Fabry-Perot cavity coupled to SHO drivers
      • Spontaneous emission of TLS: TCP socket
      • Vibrational strong coupling of liquid water in a Bragg resonator: Unix socket
      • Comparison between different kernel functions in polarization densities
      • DFTB+ socket coupling with MaxwellLink
    • Architecture
    • EM Solvers
      • Meep FDTD Solver
      • Single-Mode Cavity
      • Multimode Cavity
      • Laser-Driven Simulation
    • Drivers
      • TLS driver
      • SHO driver
      • QuTiP driver
      • RT-TDDFT driver
      • RT-TDDFT-Ehrenfest driver
      • ASE driver
      • Lorentz-Bath driver
      • LAMMPS driver
      • DFTB+ driver
      • CP2K driver
    • Contributing
    • API reference
      • maxwelllink package
        • maxwelllink.cli package
          • maxwelllink.cli.mxl module
          • maxwelllink.cli.mxl_clean module
          • maxwelllink.cli.mxl_hpc module
          • maxwelllink.cli.mxl_init module
        • maxwelllink.em_solvers package
          • maxwelllink.em_solvers.dummy_em module
          • maxwelllink.em_solvers.laser_driven module
          • maxwelllink.em_solvers.meep module
          • maxwelllink.em_solvers.multimode_cavity module
          • maxwelllink.em_solvers.single_mode_cavity module
        • maxwelllink.molecule package
          • maxwelllink.molecule.molecule module
          • maxwelllink.molecule.molecule_legacy module
        • maxwelllink.mxl_drivers package
          • maxwelllink.mxl_drivers.lammps package
            • maxwelllink.mxl_drivers.lammps.install module
          • maxwelllink.mxl_drivers.python package
            • maxwelllink.mxl_drivers.python.models package
              • maxwelllink.mxl_drivers.python.models.ase_model module
              • maxwelllink.mxl_drivers.python.models.dummy_model module
              • maxwelllink.mxl_drivers.python.models.lorentz_bath_model module
              • maxwelllink.mxl_drivers.python.models.qutip_model module
              • maxwelllink.mxl_drivers.python.models.rt_ehrenfest_model module
              • maxwelllink.mxl_drivers.python.models.rttddft_model module
              • maxwelllink.mxl_drivers.python.models.sho_model module
              • maxwelllink.mxl_drivers.python.models.tls_model module
            • maxwelllink.mxl_drivers.python.mxl_driver module
        • maxwelllink.sockets package
          • maxwelllink.sockets.aggregated module
          • maxwelllink.sockets.sockets module
        • maxwelllink.tools package
          • maxwelllink.tools.harmonic_oscillator_helper module
          • maxwelllink.tools.ir module
          • maxwelllink.tools.pulses module
          • maxwelllink.tools.tddft_spectrum module
          • maxwelllink.tools.transverse_components module
        • maxwelllink.units module
Back to top
View this page

DFTB+ socket coupling with MaxwellLink¶

This notebook shows how to run real-time TDDFTB dynamics by connecting a modified DFTB+ code (https://github.com/TEL-Research/dftbplus) to MaxwellLink.

Overall, to enable the coupling between DFTB+ with MaxwellLink, add the following MaxwellLinkSocket block within ElectronDynamics:

ElectronDynamics = {
  ...
  MaxwellLinkSocket = {
    File = "__MXL_SOCKET__"
    ResetDipole = Yes
  }
}

Here, we use the UNIX socket communication between the DFTB+ code and MaxwellLink.

To make our life simple, here we focus on:

  • A single H2 molecule forming electronic strong coupling in a single-mode cavity without the dipole self-energy term.

In this case, nuclear motion is enabled and the initial temperature is set as 0 K.

[1]:
from pathlib import Path
import os
import shutil
import subprocess
import time

import matplotlib.pyplot as plt
import numpy as np

import maxwelllink as mxl
from maxwelllink.tools import ir_spectrum, rt_tddft_spectrum

ROOT = Path.cwd()
INPUT_DIR = ROOT / "dftbplus_input"
RUN_ROOT = ROOT / "dftbplus_runs"
RUN_ROOT.mkdir(exist_ok=True)

AU_TO_CM = 219474.6313705
AU_TO_EV = 27.211386245988
AU_TO_FS = 0.024188843265857

DFTBPLUS_BIN = os.environ.get("DFTBPLUS_BIN") or shutil.which("dftb+")
if DFTBPLUS_BIN is None:
    raise RuntimeError("Could not find DFTB+. Set DFTBPLUS_BIN to a socket-enabled dftb+ executable.")

print("Using DFTB+:", DFTBPLUS_BIN)


def normalize_spectrum(sp):
    sp = np.asarray(sp, dtype=float)
    scale = np.nanmax(np.abs(sp)) if sp.size else 0.0
    return sp / scale if scale > 0.0 else sp


def fft_spectrum_cm(signal, dt_au):
    signal = np.asarray(signal, dtype=float)
    centered = signal - np.mean(signal)
    window = np.hanning(centered.size)
    spectrum = np.abs(np.fft.rfft(centered * window)) ** 2
    omega_au = 2.0 * np.pi * np.fft.rfftfreq(centered.size, d=dt_au)
    return omega_au[1:] * AU_TO_CM, spectrum[1:]

Using DFTB+: /Users/taoli/.local/bin/dftb+

1. Prepare and launch DFTB+¶

The template h2_electronic_socket.hsd in dftbplus_input/ is based on the standard DFTB+ H2 real-time singlet test. The helper functions below supplies the DFTB+ H2 input file with runtime parameters.

[2]:
def prepare_h2_electronic_run(socket_name: str, dt_au_value: float, steps: int):
    run_dir = RUN_ROOT / "h2_electronic_no_dse"
    run_dir.mkdir(parents=True, exist_ok=True)

    text = (INPUT_DIR / "h2_electronic_socket.hsd").read_text()
    text = text.replace("__MXL_SOCKET__", socket_name)
    text = text.replace("__DT_AU__", f"{dt_au_value:.16e}")
    text = text.replace("__STEPS__", str(int(steps)))
    (run_dir / "dftb_in.hsd").write_text(text)

    shutil.copy2(INPUT_DIR / "H-H.skf", run_dir / "H-H.skf")
    return run_dir


def launch_h2_electronic_dftb(run_dir: Path, sleep_time: float = 0.5):
    stdout = open(run_dir / "dftbplus.out", "w")
    print("Launching DFTB+ in", run_dir)
    proc = subprocess.Popen(
        [DFTBPLUS_BIN],
        cwd=run_dir,
        stdout=stdout,
        stderr=subprocess.STDOUT,
    )
    time.sleep(sleep_time)
    if proc.poll() is not None:
        stdout.close()
        tail = (run_dir / "dftbplus.out").read_text(errors="replace")[-4000:]
        raise RuntimeError(f"DFTB+ exited before socket coupling started. Tail of dftbplus.out:\n{tail}")
    return proc, stdout

2. Run the coupled electronic simulation¶

The DFTB+ electronic timestep and the MaxwellLink timestep are both 0.2 au. The approximate H2 electronic resonance used here is 17.2 eV. Here, we assume an initially purturbed cavity coordinate coupled to a ground-state H2 molecule.

[3]:
socket_h2 = "dftbplus_h2_electronic"
h2_dt_au = 0.2
h2_steps = 1200
h2_resonance_ev = 17.2
h2_frequency_au = h2_resonance_ev / AU_TO_EV

hub_h2 = mxl.SocketHub(unixsocket=socket_h2, timeout=20.0, latency=1e-5)
mol_h2 = mxl.Molecule(hub=hub_h2, rescaling_factor=1.0)

sim_h2 = mxl.SingleModeSimulation(
    hub=hub_h2,
    molecules=[mol_h2],
    frequency_au=h2_frequency_au,
    coupling_strength=5e-2,
    damping_au=0.0,
    coupling_axis="z",
    drive=0.0,
    dt_au=h2_dt_au,
    qc_initial=[0.0, 0.0, 1e-2],
    record_history=True,
    include_dse=False,
)

run_h2 = prepare_h2_electronic_run(socket_h2, h2_dt_au, h2_steps)
proc_h2, stdout_h2 = launch_h2_electronic_dftb(run_h2)
sim_h2.run(steps=h2_steps)

print("DFTB+ run directory:", run_h2)

[Init Molecule] Under socket mode, registered molecule with ID 0
Launching DFTB+ in /Users/taoli/Documents/Github/MaxwellLink/tutorials/dftbplus_runs/h2_electronic_no_dse
[SocketHub] CONNECTED: mol 0 <-
[SingleModeCavity] Completed 1000/1200 [83.3%] steps, time/step: 8.30e-04 seconds, remaining time: 0.17 seconds.
[SocketHub] DISCONNECTED: mol 0 from
[SocketHub] Unlinked unix socket path /tmp/socketmxl_dftbplus_h2_electronic
DFTB+ run directory: /Users/taoli/Documents/Github/MaxwellLink/tutorials/dftbplus_runs/h2_electronic_no_dse

3. Plot the electronic polariton spectrum and energy trace¶

Below we show the simulation results for the photonic coordinate and the DFTB+ dipole dynamics as well as their spectra. Energy conservation is also evaluated for checking the correctness of implementation.

[4]:
history_h2 = mol_h2.additional_data_history
t_h2_au = np.array([ad["time_au"] for ad in history_h2])
t_h2_fs = t_h2_au * AU_TO_FS
muz_h2 = np.array([ad["muz_au"] for ad in history_h2])
muz_h2_mid = np.array([ad.get("muz_m_au", ad["muz_au"]) for ad in history_h2])
qc_h2_z = np.array([q[2] for q in sim_h2.qc_history[: len(history_h2)]])

nskip_h2 = 5
freq_qc_ev, sp_qc_h2, _, _ = rt_tddft_spectrum(
    qc_h2_z[::nskip_h2],
    dt_au=sim_h2.dt * nskip_h2,
    sp_form="absolute",
    e_start_ev=0.1,
    e_cutoff_ev=25.0,
    sigma=1.0e5,
    w_step=2.0e-4,
)
freq_mu_ev, sp_mu_h2, _, _ = rt_tddft_spectrum(
    muz_h2[::nskip_h2],
    dt_au=sim_h2.dt * nskip_h2,
    sp_form="absolute",
    e_start_ev=0.1,
    e_cutoff_ev=25.0,
    sigma=1.0e5,
    w_step=2.0e-4,
)

fig, ax = plt.subplots(1, 2, figsize=(11, 4))
ax[0].plot(t_h2_fs, muz_h2, label=r"reported $\mu_z$")
ax[0].set_xlabel("Time (fs)")
ax[0].set_ylabel("Dipole (a.u.)")
ax[0].legend()

ax[1].plot(freq_qc_ev, normalize_spectrum(sp_qc_h2), label="$q_c$ spectrum")
ax[1].plot(freq_mu_ev, normalize_spectrum(sp_mu_h2), label=r"$\mu_z$ spectrum")
ax[1].axvline(h2_resonance_ev, color="k", ls="--", lw=1.0, label="bare H$_2$ / cavity")
ax[1].set_xlim(0, 25)
ax[1].set_xlabel("Energy (eV)")
ax[1].set_ylabel("Normalized spectral power")
ax[1].legend()
plt.tight_layout()
plt.show()

energy_molecule_h2 = np.array([ad["energy_au"] for ad in history_h2])
energy_total_h2 = np.array(sim_h2.energy_history[: len(history_h2)])
energy_photon_h2 = energy_total_h2 - energy_molecule_h2

plt.figure(figsize=(7, 4))
plt.plot(t_h2_fs, energy_molecule_h2 - energy_molecule_h2[0], label="DFTB+")
plt.plot(t_h2_fs, energy_photon_h2 - energy_photon_h2[0], label="photon")
plt.plot(t_h2_fs, energy_total_h2 - energy_total_h2[0], label="total")
plt.xlabel("Time (fs)")
plt.ylabel("Relative energy (a.u.)")
plt.title("H$_2$ electronic coupling energy trace")
plt.legend()
plt.tight_layout()
plt.show()

../../_images/tutorials_notebook_10_dftbplus_7_0.png
../../_images/tutorials_notebook_10_dftbplus_7_1.png
Next
Architecture
Previous
Comparison between different kernel functions in polarization densities
Copyright © TEL Research Group 2026
On this page
  • DFTB+ socket coupling with MaxwellLink
    • 1. Prepare and launch DFTB+
    • 2. Run the coupled electronic simulation
    • 3. Plot the electronic polariton spectrum and energy trace