Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 0 additions & 64 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1469,58 +1469,6 @@ transport model.
Width of HWHM Gaussian smoothing kernel operating on transport model outputs.
If using the ``QLKNN_7_11`` transport model, the default is set to 0.1.

``smooth_everywhere`` (bool [default = False])
Smooth across entire radial domain regardless of inner and outer patches.

``apply_inner_patch`` (**time-varying-scalar** [default = False])
If ``True``, set a patch for inner core transport coefficients below
``rho_inner``. Typically used as an ad-hoc measure for MHD (e.g. sawteeth) or
EM (e.g. KBM) transport in the inner-core. If using a
`CombinedTransportModel`, ensure that the inner patch is only set on the
global model rather than its component models to avoid conflicts.

``D_e_inner`` (**time-varying-scalar** [default = 0.2])
Particle diffusivity value for inner transport patch.

``V_e_inner`` (**time-varying-scalar** [default = 0.0])
Particle convection value for inner transport patch.

``chi_i_inner`` (**time-varying-scalar** [default = 1.0])
Ion heat conduction value for inner transport patch.

``chi_e_inner`` (**time-varying-scalar** [default = 1.0])
Electron heat conduction value for inner transport patch.

``rho_inner`` (**time-varying-scalar** [default = 0.3])
:math:`\hat{\rho}` below which inner patch is applied.
Note that ``rho_inner`` and ``rho_outer`` must have the same interpolation
mode to simplify the validation test ``rho_inner < rho_outer`` at all times.

``apply_outer_patch`` (**time-varying-scalar** [default = False])
If ``True``, set a patch for outer core transport coefficients above
``rho_outer``. Useful for the L-mode near-edge region where models like
QLKNN10D are not applicable. Only used if ``set_pedestal==False``.
If using a `CombinedTransportModel`, ensure that the outer patch is
only set on the global model rather than its component models to avoid
conflicts.

``D_e_outer`` (**time-varying-scalar** [default = 0.2])
Particle diffusivity value for outer transport patch.

``V_e_outer`` (**time-varying-scalar** [default = 0.0])
Particle convection value for outer transport patch.

``chi_i_outer`` (**time-varying-scalar** [default = 1.0])
Ion heat conduction value for outer transport patch.

``chi_e_outer`` (**time-varying-scalar** [default = 1.0])
Electron heat conduction value for outer transport patch.

``rho_outer`` (**time-varying-scalar** [default = 0.9])
:math:`\hat{\rho}` above which outer patch is applied.
Note that ``rho_inner`` and ``rho_outer`` must have the same interpolation
mode to simplify the validation test ``rho_inner < rho_outer`` at all times.

``fast_ion_stabilization`` (**time-varying-scalar** [default = False])
If ``True``, apply a fast ion stabilization correction to the :math:`R/L_{Ti}`
input of quasilinear transport models (QLKNN, TGLFNN, QuaLiKiz). The fast ion
Expand Down Expand Up @@ -3003,18 +2951,6 @@ CHEASE geometry), is shown below. The configuration file is also available in
},
'transport': {
'model_name': 'qlknn',
'apply_inner_patch': True,
'D_e_inner': 0.25,
'V_e_inner': 0.0,
'chi_i_inner': 1.5,
'chi_e_inner': 1.5,
'rho_inner': 0.3,
'apply_outer_patch': True,
'D_e_outer': 0.1,
'V_e_outer': 0.0,
'chi_i_outer': 2.0,
'chi_e_outer': 2.0,
'rho_outer': 0.9,
'chi_min': 0.05,
'chi_max': 100,
'D_e_min': 0.05,
Expand Down
2 changes: 1 addition & 1 deletion torax/_src/config/runtime_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class RuntimeParams:
profile_conditions: profile_conditions.RuntimeParams
solver: solver_params.RuntimeParams
sources: Mapping[str, sources_params.RuntimeParams]
transport: transport_model_params.RuntimeParams
transport: transport_model_params.CombinedRuntimeParams
time_step_calculator: time_step_calculator_runtime_params.RuntimeParams


Expand Down
4 changes: 2 additions & 2 deletions torax/_src/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from torax._src.pedestal_model import pedestal_model as pedestal_model_lib
from torax._src.sources import source_models as source_models_lib
from torax._src.time_step_calculator.time_step_calculator import TimeStepCalculator
from torax._src.transport_model import transport_model as transport_model_lib
from torax._src.transport_model import combined as combined_lib


@dataclasses.dataclass(frozen=True, eq=False)
Expand All @@ -36,7 +36,7 @@ class Models(static_dataclass.StaticDataclass):
"""

source_models: source_models_lib.SourceModels
transport_model: transport_model_lib.TransportModel
transport_model: combined_lib.CombinedTransportModel
pedestal_model: pedestal_model_lib.PedestalModel
neoclassical_models: neoclassical_models_lib.NeoclassicalModels
mhd_models: mhd_model_lib.MHDModels
Expand Down
80 changes: 46 additions & 34 deletions torax/_src/transport_model/combined.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@
A class for combining transport models.
"""

# pylint: disable=invalid-name

import dataclasses
from typing import Callable, Sequence, Tuple
import chex
from typing import Callable, Sequence
import jax
import jax.numpy as jnp
from torax._src import array_typing
from torax._src import constants
from torax._src import jax_utils
from torax._src import state
from torax._src import static_dataclass
from torax._src.config import runtime_params as runtime_params_lib
from torax._src.geometry import geometry
from torax._src.pedestal_model import pedestal_model_output as pedestal_model_output_lib
Expand All @@ -37,27 +38,12 @@
MIN_SMOOTHING_WIDTH = 1e-5


@chex.dataclass
class SmoothingZoneParams:
rho_min: array_typing.FloatScalar
rho_max: array_typing.FloatScalar
smoothing_width: array_typing.FloatScalar


@jax.tree_util.register_dataclass
@dataclasses.dataclass(frozen=True)
class RuntimeParams(transport_runtime_params_lib.RuntimeParams):
"""Runtime parameters for the CombinedTransportModel."""

transport_model_params: Tuple[transport_runtime_params_lib.RuntimeParams, ...]
pedestal_transport_model_params: Tuple[
transport_runtime_params_lib.RuntimeParams, ...
]
smoothing_zones: Tuple[SmoothingZoneParams, ...]
SmoothingZoneParams = transport_runtime_params_lib.SmoothingZoneParams
RuntimeParams = transport_runtime_params_lib.CombinedRuntimeParams


@dataclasses.dataclass(frozen=True, eq=False)
class CombinedTransportModel(transport_model_lib.TransportModel):
class CombinedTransportModel(static_dataclass.StaticDataclass):
"""Combines coefficients from a tuple of transport models."""

transport_models: tuple[transport_model_lib.TransportModel, ...]
Expand All @@ -82,23 +68,12 @@ def __call__(
core_profiles,
pedestal_model_output,
)

# In contrast to the base TransportModel, we do not apply domain restriction
# or output masking (enabled/disabled channels) as these are handled at the
# component model level in call_implementation here.

# Apply min/max clipping
transport_coeffs = self._apply_clipping(
transport_runtime_params,
transport_coeffs,
)

# In contrast to the base TransportModel, we do not apply patches, as these
# should be handled by instantiating constant component models instead.
# However, the rho_inner and rho_outer arguments are currently required
# in the case where the inner/outer region are to be excluded from
# smoothing.

transport_coeffs = self._smooth_coeffs(
runtime_params,
geo,
Expand All @@ -110,7 +85,7 @@ def __call__(

def call_implementation(
self,
transport_runtime_params: transport_runtime_params_lib.RuntimeParams,
transport_runtime_params: transport_runtime_params_lib.CombinedRuntimeParams,
runtime_params: runtime_params_lib.RuntimeParams,
geo: geometry.Geometry,
core_profiles: state.CoreProfiles,
Expand All @@ -120,7 +95,8 @@ def call_implementation(

Args:
transport_runtime_params: Input runtime parameters for this transport
model. Can change without triggering a JAX recompilation.
model (expected to be an instance of combined.RuntimeParams at runtime).
Can change without triggering a JAX recompilation.
runtime_params: Runtime parameters for the simulation at the current time.
geo: Geometry of the torus at the current time.
core_profiles: Core plasma profiles.
Expand Down Expand Up @@ -255,6 +231,42 @@ def _combine(

return transport_model_lib.TurbulentTransport(**accumulators)

def _apply_clipping(
self,
transport_runtime_params: transport_runtime_params_lib.CombinedRuntimeParams,
transport_coeffs: transport_model_lib.TurbulentTransport,
) -> transport_model_lib.TurbulentTransport:
"""Applies min/max clipping to transport coefficients for PDE stability."""
assert isinstance(transport_runtime_params, RuntimeParams)
chi_face_ion = jnp.clip(
transport_coeffs.chi_face_ion,
transport_runtime_params.chi_min,
transport_runtime_params.chi_max,
)
chi_face_el = jnp.clip(
transport_coeffs.chi_face_el,
transport_runtime_params.chi_min,
transport_runtime_params.chi_max,
)
d_face_el = jnp.clip(
transport_coeffs.d_face_el,
transport_runtime_params.D_e_min,
transport_runtime_params.D_e_max,
)
v_face_el = jnp.clip(
transport_coeffs.v_face_el,
transport_runtime_params.V_e_min,
transport_runtime_params.V_e_max,
)

return dataclasses.replace(
transport_coeffs,
chi_face_ion=chi_face_ion,
chi_face_el=chi_face_el,
d_face_el=d_face_el,
v_face_el=v_face_el,
)

def _smooth_coeffs(
self,
runtime_params: runtime_params_lib.RuntimeParams,
Expand Down
88 changes: 40 additions & 48 deletions torax/_src/transport_model/pydantic_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import copy
import dataclasses
import itertools
from typing import Annotated, Any, Literal, Sequence
from absl import logging
import chex
Expand Down Expand Up @@ -170,9 +169,6 @@ def _conform_data(cls, data: Any) -> Any:
# The QLK version this specific QLKNN was trained on tends to
# underpredict ITG electron heat flux in shaped, high-beta scenarios.
data['ITG_flux_ratio_correction'] = 2.0
else:
if 'smoothing_width' not in data:
data['smoothing_width'] = 0.1
return data

def build_transport_model(self) -> qlknn_transport_model.QLKNNTransportModel:
Expand Down Expand Up @@ -457,14 +453,19 @@ class SmoothingZone(torax_pydantic.BaseModelFrozen):
smoothing_width: pydantic.NonNegativeFloat


class CombinedTransportModel(pydantic_model_base.TransportBase):
class CombinedTransportModel(torax_pydantic.BaseModelFrozen):
"""Model for the Combined transport model.

Note: smoothing and patches should be applied on the combined model, not the
individual component models.

Attributes:
model_name: The transport model to use. Hardcoded to 'combined'.
chi_min: Lower bound on heat conductivity.
chi_max: Upper bound on heat conductivity (can be helpful for stability).
D_e_min: minimum electron density diffusivity.
D_e_max: maximum electron density diffusivity.
V_e_min: minimum electron density convection.
V_e_max: maximum electron density convection.
smoothing_width: Width of HWHM Gaussian smoothing kernel operating on
transport model outputs.
transport_models: A sequence of transport models, whose outputs will be
summed to give the combined core transport coefficients.
pedestal_transport_models: A sequence of models that will be combined for
Expand All @@ -475,6 +476,13 @@ class CombinedTransportModel(pydantic_model_base.TransportBase):
means that zone will not be used for the smoothing of other zones.
"""

chi_min: torax_pydantic.MeterSquaredPerSecond = 0.05
chi_max: torax_pydantic.MeterSquaredPerSecond = 100.0
D_e_min: torax_pydantic.MeterSquaredPerSecond = 0.05
D_e_max: torax_pydantic.MeterSquaredPerSecond = 100.0
V_e_min: torax_pydantic.MeterPerSecond = -50.0
V_e_max: torax_pydantic.MeterPerSecond = 50.0
smoothing_width: pydantic.NonNegativeFloat = 0.0
# TODO(b/434175938) V2: rename `transport_models` to `core_transport_models`
transport_models: Sequence[CombinedCompatibleTransportModel] = pydantic.Field(
default_factory=list
Expand Down Expand Up @@ -506,7 +514,6 @@ def build_transport_model(self) -> combined.CombinedTransportModel:
)

def build_runtime_params(self, t: chex.Numeric) -> combined.RuntimeParams:
base_kwargs = dataclasses.asdict(super().build_runtime_params(t))
transport_model_params = tuple(
model.build_runtime_params(t) for model in self.transport_models
)
Expand All @@ -525,28 +532,18 @@ def build_runtime_params(self, t: chex.Numeric) -> combined.RuntimeParams:
)
)
return combined.RuntimeParams(
chi_min=self.chi_min,
chi_max=self.chi_max,
D_e_min=self.D_e_min,
D_e_max=self.D_e_max,
V_e_min=self.V_e_min,
V_e_max=self.V_e_max,
smoothing_width=self.smoothing_width,
transport_model_params=transport_model_params,
pedestal_transport_model_params=pedestal_transport_model_params,
smoothing_zones=tuple(smoothing_zones),
**base_kwargs,
)

@pydantic.model_validator(mode='after')
def _check_no_smoothing_in_components(self) -> typing_extensions.Self:
for model_list in ['transport_models', 'pedestal_transport_models']:
for i, model in enumerate(getattr(self, model_list)):
if model.smoothing_width > 0.0:
logging.warning(
'smoothing_width > 0.0 is not supported for component models of'
' CombinedTransportModel; instead, smoothing_width should be set'
' on the CombinedTransportModel itself. Smoothing width set on %s'
' component %i (%s) will be ignored.',
model_list,
i,
model.model_name,
)
return self

@pydantic.model_validator(mode='after')
def _check_smoothing_width_minimum(self) -> typing_extensions.Self:
smoothing_widths = [
Expand All @@ -566,29 +563,24 @@ def _check_smoothing_width_minimum(self) -> typing_extensions.Self:

@pydantic.model_validator(mode='after')
def _check_fields(self) -> typing_extensions.Self:
super()._check_fields() # pyrefly: ignore[not-callable]
if (
any([
np.any(model.apply_inner_patch.value)
or np.any(model.apply_outer_patch.value)
# Use itertools.chain to iterate over both lists of models without
# needing to make a new list.
for model in itertools.chain(
self.transport_models, self.pedestal_transport_models
)
])
or np.any(self.apply_inner_patch.value)
or np.any(self.apply_outer_patch.value)
):
raise ValueError(
'apply_inner_patch and apply_outer_patch not supported for'
' CombinedTransportModel or its component models.'
)
if np.any(self.rho_min.value != 0.0) or np.any(self.rho_max.value != 1.0):
raise ValueError(
'rho_min and rho_max should not be set for CombinedTransportModel, as'
' it should be applied across the whole rho domain.'
if not self.chi_min < self.chi_max:
raise ValueError('chi_min must be less than chi_max.')
if not self.D_e_min < self.D_e_max:
raise ValueError('D_e_min must be less than D_e_max.')
if not self.V_e_min < self.V_e_max:
raise ValueError('V_e_min must be less than V_e_max.')
if self.smoothing_width == 0.0:
has_qlknn = any(
isinstance(m, qlknn_transport_model.QLKNNTransportModel)
for m in list(self.transport_models)
+ list(self.pedestal_transport_models)
)
if has_qlknn:
logging.warning(
'QLKNN transport model is configured in CombinedTransportModel'
' with smoothing_width=0. Stiff QLKNN transport coefficients'
' without spatial smoothing may degrade solver convergence.'
)
if any([
np.any(model.rho_min.value != 0.0) or np.any(model.rho_max.value != 1.0)
for model in self.pedestal_transport_models
Expand Down
Loading
Loading