Source code for struphy.models.maxwell
import copy
from feectools.ddm.mpi import mpi as MPI
from struphy import BaseUnits
from struphy.io.options import LiteralOptions
from struphy.models.base import StruphyModel
from struphy.models.scalars import BilinearEnergyFEEC, Scalars
from struphy.models.species import (
FieldSpecies,
)
from struphy.models.variables import FEECVariable
from struphy.propagators.maxwell_weak_ampere import MaxwellWeakAmpere
rank = MPI.COMM_WORLD.Get_rank()
[docs]
class Maxwell(StruphyModel):
"""Maxwell's equations in vacuum for electromagnetic field evolution.
Parameters
----------
base_units: BaseUnits
Base units for normalization (default: BaseUnits())
"""
## species
class EMFields(FieldSpecies):
def __init__(self):
self.e_field = FEECVariable(space="Hcurl")
self.b_field = FEECVariable(space="Hdiv")
self.init_variables()
## propagators
class Propagators:
def __init__(self):
self.maxwell = MaxwellWeakAmpere()
## abstract methods
def __init__(self, base_units: BaseUnits = BaseUnits()):
# 0. store input parameters
self.params = copy.deepcopy(locals())
# 1. instantiate all species
self.em_fields = self.EMFields()
# 2. derive units (must be done after instantiating species to access charge and mass numbers)
self.setup_equation_params(base_units=base_units)
# 3. instantiate all propagators
self.propagators = self.Propagators()
# 4. assign variables to propagators
self.propagators.maxwell.variables.e = self.em_fields.e_field
self.propagators.maxwell.variables.b = self.em_fields.b_field
# 5. define scalars to be tracked during simulation
electric_energy = BilinearEnergyFEEC(self.em_fields.e_field)
magnetic_energy = BilinearEnergyFEEC(self.em_fields.b_field)
total_energy = electric_energy + magnetic_energy
self.scalars = Scalars(
electric_energy=electric_energy,
magnetic_energy=magnetic_energy,
total_energy=total_energy,
)
@property
def bulk_species(self):
return None
@property
def velocity_scale(self):
return "light"
def allocate_helpers(self):
pass
## abstract methods for documentation
@classmethod
def model_type(cls) -> LiteralOptions.ModelTypes:
return "Toy"
[docs]
@classmethod
def doc_pde(cls):
r"""**PDEs solved by model:**
Ampère's law (no current):
.. math::
\frac{\partial \mathbf{E}}{\partial t} - \nabla \times \mathbf{B} = 0
Faraday's law:
.. math::
\frac{\partial \mathbf{B}}{\partial t} + \nabla \times \mathbf{E} = 0
"""
[docs]
@classmethod
def doc_normalization(cls):
r"""Velocity and fields are normalized as:
.. math::
\hat v = c\,,\qquad \hat E = c \hat B
where :math:`c` is the speed of light."""
[docs]
@classmethod
def doc_scalar_quantities(cls):
r"""**The following scalars are tracked during simulation:**
- Electric energy: :math:`E_E = \frac{1}{2} \int |\mathbf E|^2 \, dV`
- Magnetic energy: :math:`E_B = \frac{1}{2} \int |\mathbf B|^2 \, dV`
- Total energy: :math:`E_{total} = E_E + E_B`"""
[docs]
@classmethod
def doc_discretization(cls):
"""Time integration is performed by the following propagators (in sequence):
1. :class:`~struphy.propagators.maxwell_weak_ampere.MaxwellWeakAmpere`
"""
doc = rf"""**1. propagators.maxwell.Maxwell:**
{MaxwellWeakAmpere.__doc__}
"""
return doc
[docs]
@classmethod
def doc_long_description(cls):
r"""This model simulates the propagation of electromagnetic waves in vacuum
using Maxwell's equations without sources.
It uses a finite element exterior calculus (FEEC) formulation
with the electric field in H(curl) and the magnetic field in H(div) spaces."""
[docs]
@classmethod
def doc_examples(cls):
r"""Create and initialize a Maxwell model:
.. code-block:: python
from struphy.models import Maxwell
model = Maxwell()
# Fields are accessible via:
model.em_fields.e_field
model.em_fields.b_field
"""
[docs]
@classmethod
def doc_use_cases(cls):
"""Propagation of electromagnetic waves in vacuum."""
[docs]
@classmethod
def doc_cannot_be_used_for(cls):
"""Plasma dynamics, plasma-field interactions, or any scenario involving charged particles.
This model does not include any particle species or coupling to matter."""