Skip to content

Commit 17157fa

Browse files
tamaranormanTorax team
authored andcommitted
Add n_e_right_bc to EdgeModelOutputs and implement _update_density.
Complete the base core boundary condition interface by adding electron density (n_e_right_bc) to EdgeModelOutputs. In ExtendedLengyelOutputs, default n_e_right_bc to jnp.nan as Lengyel does not predict core density. Implement _update_density in torax/_src/edge/updaters.py to update runtime_params.profile_conditions.n_e_right_bc, and add unit test coverage in edge_updaters_test.py. PiperOrigin-RevId: 983998350
1 parent dd4f224 commit 17157fa

13 files changed

Lines changed: 689 additions & 608 deletions

‎torax/_src/edge/base.py‎

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"""Base classes for edge models."""
1616

1717
import abc
18+
from collections.abc import Mapping
1819
import dataclasses
1920
import chex
2021
import jax
@@ -40,44 +41,22 @@ class EdgeModelOutputs:
4041
Attributes:
4142
T_e_right_bc: Electron temperature boundary condition at LCFS [keV].
4243
T_i_right_bc: Ion temperature boundary condition at LCFS [keV].
43-
q_parallel: Parallel heat flux upstream [W/m^2].
44-
q_perpendicular_target: Heat flux perpendicular to the target [W/m^2].
45-
T_e_separatrix: Electron temperature at the separatrix [keV].
46-
T_e_target: Electron temperature at sheath entrance [eV].
47-
pressure_neutral_divertor: Neutral pressure in the divertor [Pa].
44+
n_e_right_bc: Electron density boundary condition at LCFS [m^-3].
45+
impurity_right_bc: Mapping from impurity symbol to its right boundary
46+
condition (n_e_ratio at LCFS).
4847
"""
4948

5049
T_e_right_bc: jax.Array
5150
T_i_right_bc: jax.Array
52-
q_parallel: jax.Array
53-
q_perpendicular_target: jax.Array
54-
T_e_separatrix: jax.Array
55-
T_e_target: jax.Array
56-
pressure_neutral_divertor: jax.Array
51+
n_e_right_bc: jax.Array
52+
impurity_right_bc: Mapping[str, jax.Array]
5753

5854
def to_output_dict(
5955
self, context: output_grid_context.OutputGridContext
6056
) -> dict[str, output_grid_context.OutputVar]:
6157
"""Returns a dictionary of standard edge output variable tuples."""
62-
outputs = {
63-
output_keys.Q_PARALLEL: context.pack(
64-
output_keys.Q_PARALLEL, self.q_parallel
65-
),
66-
output_keys.Q_PERPENDICULAR_TARGET: context.pack(
67-
output_keys.Q_PERPENDICULAR_TARGET, self.q_perpendicular_target
68-
),
69-
output_keys.T_E_SEPARATRIX: context.pack(
70-
output_keys.T_E_SEPARATRIX, self.T_e_separatrix
71-
),
72-
output_keys.T_E_TARGET: context.pack(
73-
output_keys.T_E_TARGET, self.T_e_target
74-
),
75-
output_keys.PRESSURE_NEUTRAL_DIVERTOR: context.pack(
76-
output_keys.PRESSURE_NEUTRAL_DIVERTOR,
77-
self.pressure_neutral_divertor,
78-
),
79-
}
80-
return {k: v for k, v in outputs.items() if v is not None}
58+
del context
59+
return {}
8160

8261
def to_xr_datatree(
8362
self, context: output_grid_context.OutputGridContext

‎torax/_src/edge/extended_lengyel/extended_lengyel_enums.py‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,27 @@ class SolverMode(enum.StrEnum):
4242
FIXED_POINT = 'fixed_point'
4343
NEWTON_RAPHSON = 'newton_raphson'
4444
HYBRID = 'hybrid'
45+
46+
47+
class FixedImpuritySourceOfTruth(enum.StrEnum):
48+
"""Source of truth for fixed impurity concentrations when using an edge model.
49+
50+
Determines how impurity concentrations are handled between the core plasma
51+
simulation and the edge model.
52+
53+
Attributes:
54+
CORE: * The core impurity profiles are the source of truth. * The edge
55+
model's impurity concentrations are derived from the core values at the
56+
last closed flux surface: `c_edge = c_core_face[-1] * enrichment_factor`.
57+
EDGE: * The edge model's `fixed_impurity_concentrations` are the source of
58+
truth. * The core impurity profiles (n_e_ratios) are scaled to match the
59+
values determined by the edge model. runtime_params still sets the profile
60+
shape: `c_core = c_core / c_core_face[-1] * c_edge / enrichment_factor`.
61+
62+
Note: For seeded impurities in the extended Lengyel edge model, the source of
63+
truth is always the edge model, regardless of this setting. This enum only
64+
controls the behavior for fixed impurities in that case.
65+
"""
66+
67+
CORE = 'core'
68+
EDGE = 'edge'

‎torax/_src/edge/extended_lengyel/extended_lengyel_model.py‎

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
"""Implementation of extended_lengyel instance of EdgeModel."""
1616

1717
import dataclasses
18-
import enum
1918
import logging
2019
from typing import Mapping
2120
import jax
@@ -32,6 +31,7 @@
3231
from torax._src.edge.extended_lengyel import divertor_sol_1d as divertor_sol_1d_lib
3332
from torax._src.edge.extended_lengyel import extended_lengyel_defaults
3433
from torax._src.edge.extended_lengyel import extended_lengyel_enums
34+
from torax._src.edge.extended_lengyel import extended_lengyel_formulas
3535
from torax._src.edge.extended_lengyel import extended_lengyel_solvers
3636
from torax._src.edge.extended_lengyel import extended_lengyel_standalone
3737
from torax._src.geometry import geometry
@@ -42,28 +42,6 @@
4242

4343

4444
# pylint: disable=invalid-name
45-
class FixedImpuritySourceOfTruth(enum.StrEnum):
46-
"""Source of truth for fixed impurity concentrations when using an edge model.
47-
48-
Determines how impurity concentrations are handled between the core plasma
49-
simulation and the edge model.
50-
51-
Attributes:
52-
CORE: * The core impurity profiles are the source of truth. * The edge
53-
model's impurity concentrations are derived from the core values at the
54-
last closed flux surface: `c_edge = c_core_face[-1] * enrichment_factor`.
55-
EDGE: * The edge model's `fixed_impurity_concentrations` are the source of
56-
truth. * The core impurity profiles (n_e_ratios) are scaled to match the
57-
values determined by the edge model. runtime_params still sets the profile
58-
shape: `c_core = c_core / c_core_face[-1] * c_edge / enrichment_factor`.
59-
60-
Note: For seeded impurities in the extended Lengyel edge model, the source of
61-
truth is always the edge model, regardless of this setting. This enum only
62-
controls the behavior for fixed impurities in that case.
63-
"""
64-
65-
CORE = 'core'
66-
EDGE = 'edge'
6745

6846

6947
@jax.tree_util.register_dataclass
@@ -87,7 +65,7 @@ class InitialGuessRuntimeParams:
8765

8866

8967
@jax.tree_util.register_dataclass
90-
@dataclasses.dataclass(frozen=True)
68+
@dataclasses.dataclass(frozen=True, kw_only=True)
9169
class RuntimeParams(edge_runtime_params.RuntimeParams):
9270
"""Runtime parameters for the extended Lengyel edge model."""
9371

@@ -100,11 +78,12 @@ class RuntimeParams(edge_runtime_params.RuntimeParams):
10078
solver_mode: extended_lengyel_enums.SolverMode = dataclasses.field(
10179
metadata={'static': True}
10280
)
103-
impurity_sot: FixedImpuritySourceOfTruth = dataclasses.field(
104-
metadata={'static': True}
81+
impurity_sot: extended_lengyel_enums.FixedImpuritySourceOfTruth = (
82+
dataclasses.field(metadata={'static': True})
10583
)
10684
# Not static to allow rapid sensitivity checking of edge-model impact.
10785
update_temperatures: array_typing.BoolScalar
86+
update_density: array_typing.BoolScalar
10887
update_impurities: array_typing.BoolScalar
10988
fixed_point_iterations: int
11089
newton_raphson_iterations: int
@@ -139,7 +118,7 @@ class RuntimeParams(edge_runtime_params.RuntimeParams):
139118
# --- Impurity parameters ---
140119
seed_impurity_weights: Mapping[str, array_typing.FloatScalar] | None
141120
fixed_impurity_concentrations: Mapping[str, array_typing.FloatScalar]
142-
enrichment_factor: Mapping[str, array_typing.FloatScalar]
121+
enrichment_factor: Mapping[str, array_typing.FloatScalar] | None
143122
use_enrichment_model: bool = dataclasses.field(metadata={'static': True})
144123
enrichment_model_multiplier: array_typing.FloatScalar
145124

@@ -238,7 +217,10 @@ def __call__(
238217
fixed_impurity_concentrations = edge_params.fixed_impurity_concentrations
239218
# If the source of truth for fixed impurities is the core, calculate the
240219
# edge concentrations from the core ratios.
241-
if edge_params.impurity_sot == FixedImpuritySourceOfTruth.CORE:
220+
if (
221+
edge_params.impurity_sot
222+
== extended_lengyel_enums.FixedImpuritySourceOfTruth.CORE
223+
):
242224
# Initialization
243225
fixed_impurity_concentrations = {}
244226
impurity_params = runtime_params.plasma_composition.impurity
@@ -255,10 +237,26 @@ def __call__(
255237
continue
256238

257239
# Calculate edge concentration: c_edge = c_core_lcfs * enrichment_factor
258-
# Enrichment factor exists for all species (validated in config)
259-
fixed_impurity_concentrations[species] = (
260-
ratio_face[-1] * edge_params.enrichment_factor[species]
261-
)
240+
if edge_params.use_enrichment_model:
241+
if previous_edge_outputs is not None:
242+
assert isinstance(
243+
previous_edge_outputs,
244+
extended_lengyel_standalone.ExtendedLengyelOutputs,
245+
)
246+
enrichment = previous_edge_outputs.calculated_enrichment[species]
247+
else:
248+
# For initial timestep when previous_edge_outputs is None
249+
enrichment = extended_lengyel_formulas.calc_enrichment_kallenbach(
250+
1.0, species, edge_params.enrichment_model_multiplier
251+
)
252+
elif edge_params.enrichment_factor is not None:
253+
enrichment = edge_params.enrichment_factor[species]
254+
else:
255+
raise ValueError(
256+
'enrichment_factor must be provided when use_enrichment_model is'
257+
' False.'
258+
)
259+
fixed_impurity_concentrations[species] = ratio_face[-1] * enrichment
262260

263261
# Determine initial guesses
264262
initial_guess = _get_initial_guess(edge_params, previous_edge_outputs)
@@ -308,6 +306,9 @@ def __call__(
308306
multistart_num_guesses=edge_params.multistart_num_guesses,
309307
enrichment_model_multiplier=edge_params.enrichment_model_multiplier,
310308
diverted=diverted,
309+
use_enrichment_model=edge_params.use_enrichment_model,
310+
enrichment_factor=edge_params.enrichment_factor,
311+
impurity_sot=edge_params.impurity_sot,
311312
initial_guess=initial_guess,
312313
)
313314

0 commit comments

Comments
 (0)