"""
Normalization parameters, used for converting to SI units.
Based on the pint unit-handling library.
The typical usage is as follows;
1. Use read_normalization_file to read a formatted fortran namelist, typically called 'physical_parameters.nml'
and return a dictionary called 'normalization'
2. Pass the 'normalization' dictionary to dependent parameters
i.e. rho_s0(**normalization)
which converts the dictionary into keyword arguments
Alternatively, one can manually generate the normalization dictionary
"""
from pathlib import Path
import numpy as np
import xarray as xr
from torx.normalization.read_normalization_file_m import read_normalization_file
from torx import Quantity as Q_
from torx.autodoc_decorators_m import autodoc_class
[docs]
@autodoc_class
class Normalization:
"""dict-like class for converting from dimensionless arrays to SI units."""
[docs]
def __init__(self, normalization_dictionary: dict):
"""
Initialize the normalization object.
Each element of the input normalization dictionary is copied as an attribute of the object.
i.e. If you define
norm = Normalization({'a':1, 'b':2})
then
norm.a == 1 and norm.b == 2
"""
self.B0 = np.nan
self.Te0 = np.nan
self.Ti0 = np.nan
self.n0 = np.nan
self.R0 = np.nan
self.Mi = np.nan
self.Z = np.nan
self.Z_eff = np.nan
self.__dict__ = normalization_dictionary
def __repr__(self):
"""Return a string representation for each element of the namelist."""
string = f"\t{'Value':<30}\t{'Magnitude':<10}\t{'Units':<20}\n"
for parameter_name in sorted(dir(self), key=str.casefold):
parameter = getattr(self, parameter_name, None)
if isinstance(parameter, Q_):
magnitude = parameter.magnitude
units = str(parameter.units)
string += f"\t{parameter_name:<30}\t{magnitude:<10.4e}\t{units:<30}\n"
return string
[docs]
def __getitem__(self, key):
"""Allow normalization to be indexed like a dictionary."""
return getattr(self, key)
[docs]
def convert_norm(self, input_array: xr.DataArray):
"""Convert the norm attribute of an xarray to a quantity."""
assert isinstance(
input_array, xr.DataArray
), "convert_norm requires an xr.DataArray input"
assert (
"norm" in input_array.attrs
), "convert_norm requires that the DataArray has an attribute 'norm'"
if isinstance(input_array.norm, str):
input_array.attrs["norm"] = getattr(self, input_array.norm)
elif not isinstance(input_array.norm, Q_):
raise NotImplementedError(
f"Error: norm must be string or Quantity, but type was {type(input_array.norm)}"
)
return input_array
[docs]
def normalize_to_Lperp(self, array: xr.DataArray):
"""Convert the length norm from default R0 to perp scale rho_s0."""
assert "norm" in array.attrs, "No normalization found in the input array."
try:
length_pow = dict(array.norm.dimensionality)["[length]"]
except KeyError:
return array
else:
array *= (self.delta**length_pow).m
array.attrs["norm"] /= self.delta**(length_pow)
array.attrs["normalized_to_Lperp"] = True
return array
[docs]
def as_dict(self):
"""Return a dict representation of the normalization."""
return_dict = {}
for parameter_name in sorted(dir(self), key=str.casefold):
parameter = getattr(self, parameter_name, None)
if isinstance(parameter, Q_):
return_dict[parameter_name] = parameter
return return_dict
[docs]
@classmethod
def initialize_from_normalization_file(cls, normalization_filepath: Path):
"""Make a Normalization from a fortran namelist file."""
return cls(read_normalization_file(normalization_filepath))
from .unit_conversions_m import (
elementary_charge,
electron_mass,
proton_mass,
atomic_mass_units,
speed_of_light,
mu0,
epsilon0,
rho_s0,
c_s0,
v_A0,
tau_0,
Coulomb_logarithm_ee,
mu,
delta,
rhostar,
beta_0,
zeta,
lnLambda0,
tau_ee,
tau_ii,
tau_e0,
tau_i0,
tau_e_norm,
tau_i_norm,
nu_e0,
nu_i0,
chipar_e,
chipar_i,
etapar_e,
etapar_i,
)