Source code for struphy.physics.physics
import logging
from dataclasses import dataclass
import cunumpy as xp
from feectools.ddm.mpi import mpi as MPI
from struphy.io.options import BaseUnits
logger = logging.getLogger("struphy")
@dataclass
class ConstantsOfNature:
e = 1.602176634e-19 # elementary charge (C)
mH = 1.67262192369e-27 # proton mass (kg)
mu0 = 1.25663706212e-6 # magnetic constant (N/A^2)
eps0 = 8.8541878128e-12 # vacuum permittivity (F/m)
kB = 1.380649e-23 # Boltzmann constant (J/K)
c = 299792458 # speed of light (m/s)
[docs]
class Units:
"""
Colllects base units and derives other units from these. See :ref:`normalization`.
"""
def __init__(self, base: BaseUnits = None):
if base is None:
base = BaseUnits()
self._x = base.x
self._B = base.B
self._n = base.n * 1e20
self._kBT = base.kBT
@property
def x(self):
return self._x
@property
def B(self):
return self._B
@property
def n(self):
"""Unit of particle number density in 1/m^3."""
return self._n
@property
def kBT(self):
return self._kBT
@property
def v(self):
"""Unit of velocity in m/s."""
if not hasattr(self, "_v"):
raise AttributeError("Must call Units.derive_units() to get full set of units.")
return self._v
@property
def t(self):
"""Unit of time in s."""
if not hasattr(self, "_t"):
raise AttributeError("Must call Units.derive_units() to get full set of units.")
return self._t
@property
def p(self):
"""Unit of pressure in Pa, equal to B^2/mu0 if velocity_scale='alfvén'."""
if not hasattr(self, "_p"):
raise AttributeError("Must call Units.derive_units() to get full set of units.")
return self._p
@property
def rho(self):
"""Unit of mass density in kg/m^3."""
if not hasattr(self, "_rho"):
raise AttributeError("Must call Units.derive_units() to get full set of units.")
return self._rho
@property
def j(self):
"""Unit of current density in A/m^2."""
if not hasattr(self, "_j"):
raise AttributeError("Must call Units.derive_units() to get full set of units.")
return self._j
[docs]
def derive_units(self, velocity_scale: str = "light", A_bulk: int = None, Z_bulk: int = None):
"""Derive the remaining units from the base units, velocity scale and bulk species' A and Z."""
con = ConstantsOfNature()
# velocity (m/s)
if velocity_scale is None:
self._v = 1.0
elif velocity_scale == "light":
self._v = con.c
elif velocity_scale == "alfvén":
assert A_bulk is not None, 'Need bulk species to choose velocity scale "alfvén".'
self._v = self.B / xp.sqrt(self.n * A_bulk * con.mH * con.mu0)
elif velocity_scale == "cyclotron":
assert Z_bulk is not None, 'Need bulk species to choose velocity scale "cyclotron".'
assert A_bulk is not None, 'Need bulk species to choose velocity scale "cyclotron".'
self._v = Z_bulk * con.e * self.B / (A_bulk * con.mH) * self.x
elif velocity_scale == "thermal":
assert A_bulk is not None, 'Need bulk species to choose velocity scale "thermal".'
assert self.kBT is not None
self._v = xp.sqrt(self.kBT * 1000 * con.e / (con.mH * A_bulk))
# time (s)
self._t = self.x / self.v
# return if no bulk is present
if A_bulk is None:
self._p = None
self._rho = None
self._j = None
else:
# pressure (Pa), equal to B^2/mu0 if velocity_scale='alfvén'
self._p = A_bulk * con.mH * self.n * self.v**2
# mass density (kg/m^3)
self._rho = A_bulk * con.mH * self.n
# current density (A/m^2)
self._j = con.e * self.n * self.v
[docs]
def show_units(self):
units_used = (
" m",
" T",
" m⁻³",
"keV",
" m/s",
" s",
" bar",
" kg/m³",
" A/m²",
)
print("")
for (k, v), u in zip(self.__dict__.items(), units_used):
if v is None:
print(f"Unit of {k[1:]} not specified.")
else:
print(
f"Unit of {k[1:]}:".ljust(25),
"{:4.3e}".format(v) + u,
)