""" Dataclasses to store the configs """
import os
import configparser
from dataclasses import dataclass, field
[docs]
@dataclass
class ConfigGrid:
""" Holds the config of the Grid3Scales class. """
spatialGridSize: int = 40
""" Number of grid points in the spatial direction (M in 2204.13120). """
momentumGridSize: int = 11
"""
Number of grid points in the momentum directions (N in 2204.13120).
MUST BE ODD.
"""
ratioPointsWall: float = 0.5
"""
Fraction of points inside the wall defined by the interval
[-wallThickness+wallCenter, wallThickness+wallCenter]. Should be a number between 0
and 1.
"""
smoothing: float = 0.1
""" Smoothing factor of the mapping function (the larger the smoother). """
[docs]
@dataclass
class ConfigEOM:
""" Holds the config of the EOM class. """
errTol: float = 1e-3
""" The absolute error tolerance for the wall velocity result. """
pressRelErrTol: float = 0.1
""" Relative error tolerance for the pressure. """
maxIterations: int = 20
""" Maximum number of iterations for the convergence of the pressure. """
conserveEnergyMomentum: bool = True
r"""
Flag to enforce conservation of energy and momentum. Normally, this should be set to
True, but it can help with numerical stability to set it to False. If True, there is
an ambiguity in the separation between :math:`f_{eq}` and :math:`\delta f` when the
out-of-equilibrium particles form a closed system (or nearly closed). This can lead
to a divergence of the iterative loop. In the end, it is better to set this to False
if most of the degrees of freedom are treated as out-of-equilibrium particle. If
most of the dofs are in the background fluid, setting it to True will give better
results.
"""
wallThicknessBounds: list[float] = field(default_factory=lambda: [0.1, 100.0])
""" Lower and upper bounds on wall thickness (in units of 1/Tnucl). """
wallOffsetBounds: list[float] = field(default_factory=lambda: [-10.0, 10.0])
""" Lower and upper bounds on wall offset. """
## The following parameters are only used for detonation solutions ##
vwMaxDeton: float = 0.99
""" Maximal Velocity at which the solver will look to find a detonation solution """
nbrPointsMinDeton: int = 5
""" Minimal number of points probed to bracket the detonation roots. """
nbrPointsMaxDeton: int = 20
""" Maximal number of points probed to bracket the detonation roots. """
overshootProbDeton: float = 0.05
"""
Desired probability of overshooting a root. Must be between 0 and 1. A smaller value
will lead to more pressure evaluations (and thus a longer time), but is less likely
to miss a root.
"""
[docs]
@dataclass
class ConfigHydrodynamics:
""" Holds the config of the Hydrodynamics class. """
tmin: float = 0.01
""" Minimum temperature that is probed in Hydrodynamics (in units of Tnucl). """
tmax: float = 10.0
""" Maximum temperature that is probed in Hydrodynamics (in units of Tnucl). """
relativeTol: float = 1e-6
""" Relative tolerance used in Hydrodynamics. """
absoluteTol: float = 1e-10
""" Absolute tolerance used in Hydrodynamics. """
[docs]
@dataclass
class ConfigThermodynamics:
""" Holds the config of the Hydrodynamics class. """
tmin: float = 0.8
"""
Minimum temperature used in the phase tracing (in units of the estimate for the
minimum temperature obtained in the template model).
"""
tmax: float = 1.2
"""
Maximum temperature used in the phase tracing (in units of the estimate for the
maximum temperature obtained in the template model).
"""
phaseTracerTol: float = 1e-6
"""
Desired accuracy of the phase tracer and the resulting FreeEnergy interpolation.
"""
phaseTracerFirstStep: float | None = None
r"""
Starting step for phaseTrace. If a float, this gives the starting step
size in units of the maximum step size :py:data:`dT`. If :py:data:`None` then
uses the initial step size algorithm of :py:mod:`scipy.integrate.solve_ivp`.
"""
interpolationDegree: int = 1
"""
Degree of the splines used in FreeEnergy to interpolate the potential and its
derivatives.
"""
[docs]
@dataclass
class ConfigBoltzmannSolver:
""" Holds the config of the BoltzmannSolver class. """
basisM: str = 'Cardinal'
""" The position polynomial basis type, either 'Cardinal' or 'Chebyshev'. """
basisN: str = 'Chebyshev'
""" The momentum polynomial basis type, either 'Cardinal' or 'Chebyshev'. """
collisionMultiplier: float = 1.0
"""
Factor multiplying the collision term in the Boltzmann equation. Can be used for
testing or for studying the solution's sensibility to the collision integrals. Don't
forget to adjust meanFreePathScale accordingly if this is different from 1
(meanFreePathScale should scale like 1/collisionMultiplier).
WARNING: THIS CHANGES THE COLLISION TERMS WRT TO THEIR PHYSICAL VALUE.
"""
truncationOption: str = 'AUTO'
""" Truncation option for spectral expansions. Can be 'NONE' for no
truncation, 'AUTO' to automatically detect if the spectral expansion
is converging and truncate if not, or 'THIRD' which always truncates
the last third. """
[docs]
@dataclass
class Config:
"""
Data class that holds all the model-independent configs.
It contains objects of the data classes ConfigGrid, ConfigEOM,
ConfigEffectivePotential, ConfigHydrodynamics, ConfigThermodynamics and
ConfigBoltzmannSolver.
It can also load the configs from an .ini file.
"""
configGrid: ConfigGrid = field(default_factory=lambda: ConfigGrid())
""" Holds the config of the Grid3Scales class. """
configEOM: ConfigEOM = field(default_factory=lambda: ConfigEOM())
""" Holds the config of the EOM class. """
configHydrodynamics: ConfigHydrodynamics = field(
default_factory=lambda: ConfigHydrodynamics())
""" Holds the config of the Hydrodynamics class. """
configThermodynamics: ConfigThermodynamics = field(
default_factory=lambda: ConfigThermodynamics())
""" Holds the config of the Thermodynamics class. """
configBoltzmannSolver: ConfigBoltzmannSolver = field(
default_factory=lambda: ConfigBoltzmannSolver())
""" Holds the config of the BoltzmannSolver class. """
[docs]
def loadConfigFromFile(self, filePath: str) -> None:
"""
Load the configs from a file.
Parameters
----------
filePath : str
Path of the file where the configs are.
"""
# Make sure that the file exists
if not os.path.isfile(filePath):
raise FileNotFoundError(filePath)
parser = configparser.ConfigParser()
parser.optionxform = str
parser.read(filePath)
# Read the Grid configs
if 'Grid' in parser.sections():
keys = parser['Grid'].keys()
if 'spatialGridSize' in keys:
self.configGrid.spatialGridSize = parser.getint("Grid",
"spatialGridSize")
if 'momentumGridSize' in keys:
self.configGrid.momentumGridSize = parser.getint("Grid",
"momentumGridSize")
if 'ratioPointsWall' in keys:
self.configGrid.ratioPointsWall = parser.getfloat("Grid",
"ratioPointsWall")
if 'smoothing' in keys:
self.configGrid.smoothing = parser.getfloat("Grid", "smoothing")
# Read the EOM configs
if 'EquationOfMotion' in parser.sections():
keys = parser['EquationOfMotion'].keys()
if 'errTol' in keys:
self.configEOM.errTol = parser.getfloat("EquationOfMotion", "errTol")
if 'pressRelErrTol' in keys:
self.configEOM.pressRelErrTol = parser.getfloat("EquationOfMotion",
"pressRelErrTol")
if 'maxIterations' in keys:
self.configEOM.maxIterations = parser.getint("EquationOfMotion",
"maxIterations")
if 'conserveEnergyMomentum' in keys:
self.configEOM.conserveEnergyMomentum = parser.getboolean(
"EquationOfMotion",
"conserveEnergyMomentum")
if 'wallThicknessLowerBound' in keys:
self.configEOM.wallThicknessBounds[0] = parser.getfloat(
"EquationOfMotion",
"wallThicknessLowerBound")
if 'wallThicknessUpperBound' in keys:
self.configEOM.wallThicknessBounds[1] = parser.getfloat(
"EquationOfMotion",
"wallThicknessUpperBound")
if 'wallOffsetLowerBound' in keys:
self.configEOM.wallOffsetBounds[0] = parser.getfloat(
"EquationOfMotion",
"wallOffsetLowerBound")
if 'wallOffsetUpperBound' in keys:
self.configEOM.wallOffsetBounds[1] = parser.getfloat(
"EquationOfMotion",
"wallOffsetUpperBound")
if 'vwMaxDeton' in keys:
self.configEOM.vwMaxDeton = parser.getfloat("EquationOfMotion",
"vwMaxDeton")
if 'nbrPointsMinDeton' in keys:
self.configEOM.nbrPointsMinDeton = parser.getint("EquationOfMotion",
"nbrPointsMinDeton")
if 'nbrPointsMaxDeton' in keys:
self.configEOM.nbrPointsMaxDeton = parser.getint("EquationOfMotion",
"nbrPointsMaxDeton")
if 'overshootProbDeton' in keys:
self.configEOM.overshootProbDeton = parser.getfloat("EquationOfMotion",
"overshootProbDeton")
# Read the Hydrodynamics configs
if 'Hydrodynamics' in parser.sections():
keys = parser['Hydrodynamics'].keys()
if 'tmin' in keys:
self.configHydrodynamics.tmin = parser.getfloat("Hydrodynamics", "tmin")
if 'tmax' in keys:
self.configHydrodynamics.tmax = parser.getfloat("Hydrodynamics", "tmax")
if 'relativeTol' in keys:
self.configHydrodynamics.relativeTol = parser.getfloat("Hydrodynamics",
"relativeTol")
if 'absoluteTol' in keys:
self.configHydrodynamics.absoluteTol = parser.getfloat("Hydrodynamics",
"absoluteTol")
# Read the Thermodynamics configs
if 'Thermodynamics' in parser.sections():
keys = parser['Thermodynamics'].keys()
if 'tmin' in keys:
self.configThermodynamics.tmin = parser.getfloat("Thermodynamics",
"tmin")
if 'tmax' in keys:
self.configThermodynamics.tmax = parser.getfloat("Thermodynamics",
"tmax")
if 'phaseTracerTol' in keys:
self.configThermodynamics.phaseTracerTol = parser.getfloat(
"Thermodynamics",
"phaseTracerTol"
)
if 'phaseTracerFirstStep' in keys:
# either float or None
try:
self.configThermodynamics.phaseTracerFirstStep = parser.getfloat(
"Thermodynamics", "phaseTracerFirstStep"
)
except ValueError as valErr:
if str(valErr) == "could not convert string to float: 'None'":
self.configThermodynamics.phaseTracerFirstStep = None
else:
raise
if 'interpolationDegree' in keys:
self.configThermodynamics.interpolationDegree = parser.getint(
"Thermodynamics",
"interpolationDegree"
)
# Read the BoltzmannSolver configs
if 'BoltzmannSolver' in parser.sections():
keys = parser['BoltzmannSolver'].keys()
if 'collisionMultiplier' in keys:
self.configBoltzmannSolver.collisionMultiplier = parser.getfloat("BoltzmannSolver", "collisionMultiplier")
if 'basisM' in keys:
self.configBoltzmannSolver.basisM = parser.get(
"BoltzmannSolver", "basisM")
if 'basisN' in keys:
self.configBoltzmannSolver.basisN = parser.get(
"BoltzmannSolver", "basisN")
if 'truncationOption' in keys:
self.configBoltzmannSolver.truncationOption = parser.get(
"BoltzmannSolver", "truncationOption")