Architecture
============
Architecture overview
---------------------
**MaxwellLink** separates electromagnetic propagation from molecular dynamics by
placing them in different processes (or even different nodes) and letting them
communicate through a socket protocol, inspired by the `i-PI `_ project:
1. The EM solver (such as `Meep `_ FDTD or single-mode cavity) advances Maxwell's equations.
2. After each time step, **MaxwellLink** measures the regularized electric field at
every coupled molecule and converts it to atomic units.
3. Those field vectors are sent to the driver processes through a ``SocketHub``
barrier call.
4. Each driver propagates its molecular model for one EM step (possibly using
sub-steps) and returns the time-derivative of the dipole moment and optional
metadata.
5. The returned amplitudes are converted back to EM units and injected to EM solvers
before the next time step begins.
.. image:: ../../media/workflow.png
:alt: MaxwellLink workflow diagram
:align: center
:scale: 25
SocketHub
---------
``SocketHub`` (:mod:`maxwelllink.sockets.sockets`) manages the inter-code communication:
- Supports both TCP sockets (``host``/``port``) and UNIX domain sockets
(``unixsocket``).
- Generates molecule IDs on demand.
- Implements the ``NEEDINIT -> INIT -> READY/HAVEDATA`` handshake for each client.
- Detects dropped connections during sends or receives and pauses the EM solver
until all expected drivers reconnect.
- Exposes helpers such as :func:`maxwelllink.sockets.sockets.get_available_host_port` for easy
use.
Abstract Molecule
-----------------
``Molecule`` (:mod:`maxwelllink.molecule.molecule`) provides a unified interface for constructing molecular
drivers for both socket communications and non-socket (single-process) runs. Pass
``hub=SocketHub(...)`` to connect to an external driver, or ``driver="..."`` (and
``driver_kwargs``) to instantiate the model locally. Every molecule records
time-resolved data in ``additional_data_history``.
In ``Molecule``, each molecule only stores the information necessary for
EM simulations, such as the center / size of the molecule in the EM grid and the
Gaussian width (``sigma``) for molecular polarization density distribution. The detailed
molecular parameters and dynamics are handled by each driver implementation.
EM solvers
---------------------
Currently, three EM solvers are available in **MaxwellLink**:
- The **Meep FDTD** engine: ``MeepSimulation`` (:mod:`maxwelllink.em_solvers.meep`)
- The **single-mode cavity** solver: ``SingleModeSimulation`` (:mod:`maxwelllink.em_solvers.single_mode_cavity`).
- The **laser-driven dynamics** solver: ``LaserDrivenSimulation`` (:mod:`maxwelllink.em_solvers.laser_driven`).
``MeepSimulation`` derives from `meep.Simulation `_ and automatically
inserts the appropriate step function for updating molecules when ``MeepSimulation.run()`` is called.
When using ``MeepSimulation``, three additional parameters should be specified compared to a regular
`meep.Simulation `_:
- ``molecules``: a list of :class:`~maxwelllink.molecule.molecule.Molecule` objects to couple to the EM solver.
- ``time_units_fs``: the mapping between Meep time units and real time in femtoseconds. Meep uses
dimensionless units internally, so specifying this parameter is necessary to convert between Meep units and other units systems.
- ``hub``: an optional :class:`~maxwelllink.sockets.sockets.SocketHub` object for socket-based drivers.
.. note::
With a ``SocketHub`` a step function :func:`maxwelllink.em_solvers.meep.update_molecules` is inserted in Meep FDTD simulation;
without a hub the step function falls back to :func:`maxwelllink.em_solvers.meep.update_molecules_no_socket`.
``SingleModeSimulation``, defined in :class:`~maxwelllink.em_solvers.single_mode_cavity.SingleModeSimulation`,
approximates the field as a single damped harmonic oscillator evolving in atomic
units. It supports the same socket and non-socket molecule interfaces, making it
useful for rapid prototyping or unit tests without launching Meep.
``LaserDrivenSimulation``, defined in :class:`~maxwelllink.em_solvers.laser_driven.LaserDrivenSimulation`,
applies user-defined classical electric fields to molecules without back-action from the molecular system.
Please read :doc:`em_solvers/index` section for detailed definitions of different EM solvers.
Molecular drivers
---------------------
While ``Molecule`` defines molecular locations and size in EM grid, a set of molecular
drivers implement the actual dynamics. All Python-based drivers inherit from :func:`maxwelllink.mxl_drivers.python.models.dummy_model.DummyModel`
and use the unified API when communicating with the hub. The following Python drivers ship with **MaxwellLink**:
- **Two-level system (tls)**: a lightweight quantum model that propagates
the von Neumann equation for a TLS.
- **QuTiP model Hamiltonians (qutip)**: an interface to user-defined Hamiltonians
using the `QuTiP `_ package.
- **Psi4 RT-TDDFT (rttddft)**: real-time time-dependent density functional theory
implemented using `Psi4 `_.
- **Psi4 RT-Ehrenfest dynamics (rtehrenfest)**: RT-TDDFT with nuclear Ehrenfest
dynamics using `Psi4 `_.
- **ASE molecular mechanics (ase)**: first-principles Born-Oppenheimer molecular dynamics using
the `Atomic Simulation Environment (ASE) `_.
An additional C++ `LAMMPS `_ driver implements ``fix mxl``, which communicates with the hub
using the same socket protocol. See :doc:`installation` for instructions on building
the LAMMPS binary with **MaxwellLink** support.
Please read :doc:`drivers/index` section for detailed definitions of different molecular drivers.
MPI Parallelism
---------------
EM solvers, such as `Meep `_ FDTD, can be launched under MPI. **MaxwellLink** is compatible with MPI,
allowing for distributed simulations. Only the master
rank (rank 0) interacts with sockets; field integrals and returned molecule responses
are broadcast to the other ranks via ``mpi4py``.
Checkpointing
--------------------------
Driver classes that inherit from :class:`DummyModel`
support checkpointing. When ``checkpoint=true`` the driver writes state files
after each step; setting ``restart=true`` lets a reconnected driver resume from
disk. The hub blocks the EM solver inside ``wait_until_bound`` until all
expected molecules report back, so even long-lived RT-TDDFT simulations remain
consistent if a driver is restarted.