Skip to content

Commit 9cbeabe

Browse files
jcitrinTorax team
authored andcommitted
Clarify definition of B_0 in Torax geometry.
The parameter B_0 in Torax geometry is now consistently defined as the vacuum toroidal magnetic field at R_major, which is the geometric center of the LCFS. Previously, some descriptions referred to it as the field "on axis," which is ambiguous. The eqdsk.py loader has been updated to correctly calculate B_0 at R_major by scaling the EQDSK's bcentre (which is given at xcentre) using the 1/R dependence of the vacuum toroidal field. Docstrings and comments across various geometry and source files have been updated to reflect this clarified definition. See #2016 eqdsk and imas test cases regenerated due to minor B_0 modifications. O(1e-3 - 1e-5) relative profile differences. PiperOrigin-RevId: 904414309
1 parent 2b5d591 commit 9cbeabe

16 files changed

Lines changed: 64 additions & 36 deletions

docs/configuration.rst

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,13 +1076,15 @@ Geometry dicts for analytical circular geometry require the following additional
10761076
keys.
10771077

10781078
``R_major`` (float [default = 6.2])
1079-
Major radius "R" in meters.
1079+
Major radius, defined as the midplane average of the LCFS radius,
1080+
:math:`R_\mathrm{major} = (R_\mathrm{max} + R_\mathrm{min}) / 2`, in meters.
10801081

10811082
``a_minor`` (float [default = 2.0])
1082-
Minor radius "a" in meters.
1083+
Minor radius, defined as half the horizontal width of the LCFS,
1084+
:math:`a_\mathrm{minor} = (R_\mathrm{max} - R_\mathrm{min}) / 2`, in meters.
10831085

10841086
``B_0`` (float [default = 5.3])
1085-
Vacuum toroidal magnetic field on axis in :math:`T`.
1087+
Vacuum toroidal magnetic field at ``R_major``, in :math:`T`.
10861088

10871089
``elongation_LCFS`` (float [default = 1.72])
10881090
Sets the plasma elongation used for volume, area and q-profile corrections.
@@ -1091,13 +1093,15 @@ Geometry dicts for CHEASE geometry require the following additional keys for
10911093
denormalization.
10921094

10931095
``R_major`` (float [default = 6.2])
1094-
Major radius "R" in meters.
1096+
Major radius, defined as the midplane average of the LCFS radius,
1097+
:math:`R_\mathrm{major} = (R_\mathrm{max} + R_\mathrm{min}) / 2`, in meters.
10951098

10961099
``a_minor`` (float [default = 2.0])
1097-
Minor radius "a" in meters.
1100+
Minor radius, defined as half the horizontal width of the LCFS,
1101+
:math:`a_\mathrm{minor} = (R_\mathrm{max} - R_\mathrm{min}) / 2`, in meters.
10981102

10991103
``B_0`` (float [default = 5.3])
1100-
Vacuum toroidal magnetic field on axis :math:`T`.
1104+
Vacuum toroidal magnetic field at ``R_major``, in :math:`T`.
11011105

11021106
Geometry dicts for FBT geometry require the following additional keys.
11031107

docs/physics_models.rst

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ nonlinearity in the PDE system. TORAX currently offers five transport models:
141141
.. math::
142142
143143
\chi_{GB} = \frac{(A_i m_p)^{1/2}}{(eB_0)^2}
144-
\frac{(T_i k_B)^{3/2}}{R_\textit{maj}}
144+
\frac{(T_i k_B)^{3/2}}{R_\mathrm{major}}
145145
146146
and the |guo-romanelli| ion-temperature-gradient (ITG) mode critical
147147
gradient formula.
@@ -154,8 +154,8 @@ nonlinearity in the PDE system. TORAX currently offers five transport models:
154154
:math:`\chi`, :math:`L_{Ti}\equiv-\frac{T_i}{\nabla T_i}` is the ion
155155
temperature gradient length, :math:`A_i` is the main ion atomic mass number,
156156
:math:`m_p` the proton mass, :math:`e` the electron charge, :math:`B_0` the
157-
magnetic field on axis, and :math:`R_\mathrm{maj}` the major radius. The
158-
stiffness factor :math:`C` and the exponent :math:`\alpha` are
157+
vacuum toroidal magnetic field at the major radius :math:`R_\mathrm{major}`.
158+
The stiffness factor :math:`C` and the exponent :math:`\alpha` are
159159
user-configurable model parameters.
160160

161161
Regarding additional transport coefficient outputs, the electron heat
@@ -202,10 +202,10 @@ nonlinearity in the PDE system. TORAX currently offers five transport models:
202202
203203
where :math:`R_\text{min}` is the minor radius, :math:`q` is the safety
204204
factor, :math:`e` is the elementary charge, :math:`B_\text{0}` is the
205-
toroidal magnetic field at the magnetic axis, :math:`n_e` is the electron
206-
density, :math:`\rho_{\text{tor}}` is the (unnormalized) toroidal flux
207-
coordinate, :math:`p_e` is the electron pressure, and :math:`T_e` is the
208-
electron temperature.
205+
vacuum toroidal magnetic field at :math:`R_\mathrm{major}`, :math:`n_e` is
206+
the electron density, :math:`\rho_{\text{tor}}` is the (unnormalized)
207+
toroidal flux coordinate, :math:`p_e` is the electron pressure, and
208+
:math:`T_e` is the electron temperature.
209209

210210
The electron diffusivity is given by |garzotti2003|:
211211

torax/_src/geometry/chease.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class CheaseConfig(base.BaseGeometryConfig):
3636
calculated from the geometry file is scaled to match the desired `I_p`.
3737
R_major: Major radius (R) in meters.
3838
a_minor: Minor radius (a) in meters.
39-
B_0: Vacuum toroidal magnetic field on axis [T].
39+
B_0: Vacuum toroidal magnetic field at `R_major` [T].
4040
"""
4141

4242
geometry_type: Annotated[Literal['chease'], torax_pydantic.TIME_INVARIANT] = (
@@ -95,10 +95,12 @@ def _construct_intermediates_from_chease(
9595
Ip_from_parameters: If True, the Ip is taken from the parameters and the
9696
values in the Geometry are rescaled to match the new Ip.
9797
face_centers: Array of face center coordinates in normalized rho (0 to 1).
98-
R_major: major radius (R) in meters. CHEASE geometries are normalized, so
98+
R_major: Major radius (R) in meters, commonly defined in TORAX as the
99+
midplane average of the LCFS radius. CHEASE geometries are normalized, so
99100
this is used as an unnormalization factor.
100-
a_minor: minor radius (a) in meters
101-
B_0: Toroidal magnetic field on axis [T].
101+
a_minor: Minor radius (a) in meters, commonly defined in TORAX as half the
102+
horizontal width of the LCFS.
103+
B_0: Vacuum toroidal magnetic field at `R_major` [T].
102104
hires_factor: Grid refinement factor for poloidal flux <--> plasma current
103105
calculations.
104106

torax/_src/geometry/circular_geometry.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class CircularConfig(base.BaseGeometryConfig):
3030
geometry_type: Always set to 'circular'.
3131
R_major: Major radius (R) in meters.
3232
a_minor: Minor radius (a) in meters.
33-
B_0: Vacuum toroidal magnetic field on axis [T].
33+
B_0: Vacuum toroidal magnetic field at `R_major` [T].
3434
elongation_LCFS: Sets the plasma elongation used for volume, area and
3535
q-profile corrections.
3636
"""
@@ -75,7 +75,7 @@ def _build_circular_geometry(
7575
elongation_LCFS: Elongation at last closed flux surface.
7676
R_major: major radius (R) in meters
7777
a_minor: minor radius (a) in meters
78-
B_0: Toroidal magnetic field on axis [T]
78+
B_0: Vacuum toroidal magnetic field at `R_major` [T]
7979
hires_factor: Grid refinement factor for poloidal flux <--> plasma current
8080
calculations.
8181

torax/_src/geometry/eqdsk.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,12 @@ def calculate_area(x, z):
144144
# R_major taken as Rgeo (LCFS R_major)
145145
R_major = (eqfile['xbdry'].max() + eqfile['xbdry'].min()) / 2.0
146146
a_minor = (eqfile['xbdry'].max() - eqfile['xbdry'].min()) / 2.0
147-
B_0 = eqfile['bcentre']
147+
# Vacuum toroidal magnetic field at R_major. EQDSK vacuum field, bcentre, is
148+
# defined at an arbitrary reference radius, xcentre. To get B at R_major,
149+
# use B_vacuum ∝ 1/R.
150+
151+
# See EQDSKInterface in https://github.com/Fusion-Power-Plant-Framework/eqdsk
152+
B_0 = eqfile['bcentre'] * eqfile['xcentre'] / R_major
148153
Raxis = eqfile['xmag']
149154
Zaxis = eqfile['zmag']
150155
Btor_axis = eqfile['fpol'][0] / eqfile['xmag']

torax/_src/geometry/fbt.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ def _from_fbt(
419419
# Convert to bool instead of dim 0 array of ints
420420
diverted = bool(LY['lX'] == 1)
421421
R_major = LY['rgeom'][-1] # Major radius
422-
B_0 = LY['rBt'] / R_major # Vacuum toroidal magnetic field on axis
422+
B_0 = LY['rBt'] / R_major # Vacuum toroidal magnetic field at R_major
423423
a_minor = LY['aminor'][-1] # Minor radius
424424
# Toroidal flux including plasma contribution
425425
# load FtPVQ if it exists, otherwise use FtPQ for toroidal flux.

torax/_src/geometry/geometry.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,13 @@ class Geometry:
7878
torax_mesh: `Grid1D` object representing the radial mesh used by TORAX.
7979
Phi: Toroidal magnetic flux at each radial grid point [:math:`\mathrm{Wb}`].
8080
Phi_face: Toroidal magnetic flux at each radial face [:math:`\mathrm{Wb}`].
81-
R_major: Tokamak major radius (geometric center) [:math:`\mathrm{m}`].
82-
a_minor: Tokamak minor radius [:math:`\mathrm{m}`].
83-
B_0: Vacuum toroidal magnetic field on axis [:math:`\mathrm{T}`].
81+
R_major: Major radius defined as midplane average of the LCFS radius,
82+
:math:`R_\mathrm{major} = (R_\mathrm{max} + R_\mathrm{min}) / 2`
83+
[:math:`\mathrm{m}`].
84+
a_minor: Minor radius, defined as half the horizontal width of the LCFS,
85+
:math:`a_\mathrm{minor} = (R_\mathrm{max} - R_\mathrm{min}) / 2`
86+
[:math:`\mathrm{m}`].
87+
B_0: Vacuum toroidal magnetic field at ``R_major`` [:math:`\mathrm{T}`].
8488
volume: Plasma volume enclosed by each flux surface on cell grid
8589
[:math:`\mathrm{m}^3`].
8690
volume_face: Plasma volume enclosed by each flux surface on face grid
@@ -272,8 +276,8 @@ def rho(self) -> array_typing.Array:
272276
273277
The toroidal flux coordinate is defined as
274278
:math:`\rho=\sqrt{\frac{\Phi}{\pi B_0}}`, where :math:`\Phi` is the
275-
toroidal flux enclosed by the flux surface, and :math:`B_0` the magnetic
276-
field on the magnetic axis.
279+
toroidal flux enclosed by the flux surface, and :math:`B_0` is the vacuum
280+
toroidal magnetic field at the geometric center of the LCFS.
277281
"""
278282
return self.rho_norm * jnp.expand_dims(self.rho_b, axis=-1)
279283

torax/_src/geometry/standard_geometry.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,13 @@ class StandardGeometryIntermediates:
160160
EQDSK).
161161
Ip_from_parameters: If True, the Ip is taken from the parameters and the
162162
values in the Geometry are rescaled to match the new Ip.
163-
R_major: major radius on the magnetic axis in [:math:`\mathrm{m}`].
164-
a_minor: minor radius (a) in [:math:`\mathrm{m}`].
165-
B_0: Toroidal magnetic field on axis [:math:`\mathrm{T}`].
163+
R_major: Major radius defined as midplane average of the LCFS radius,
164+
:math:`R_\mathrm{major} = (R_\mathrm{max} + R_\mathrm{min}) / 2`
165+
[:math:`\mathrm{m}`].
166+
a_minor: Minor radius, defined as half the horizontal width of the LCFS,
167+
:math:`a_\mathrm{minor} = (R_\mathrm{max} - R_\mathrm{min}) / 2`
168+
[:math:`\mathrm{m}`].
169+
B_0: Vacuum toroidal magnetic field at ``R_major`` [:math:`\mathrm{T}`].
166170
psi: Poloidal flux profile [:math:`\mathrm{Wb}`].
167171
Ip_profile: Plasma current profile [:math:`\mathrm{A}`].
168172
Phi: Toroidal flux profile [:math:`\mathrm{Wb}`].

torax/_src/imas_tools/input/equilibrium.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,6 @@ def _geometry_from_single_slice(
104104
# cast these to standard numpy arrays using np.asarray() (or via implicit
105105
# numpy operations like np.abs), otherwise JAX JIT compilation will fail with
106106
# TypeErrors during PyTree tracing.
107-
R_major = np.asarray(equilibrium.vacuum_toroidal_field.r0)
108-
B_0 = np.abs(equilibrium.vacuum_toroidal_field.b0[0])
109107

110108
# Poloidal flux.
111109
psi = np.asarray(IMAS_data.profiles_1d.psi)
@@ -117,6 +115,15 @@ def _geometry_from_single_slice(
117115
R_in = IMAS_data.profiles_1d.r_inboard
118116
R_out = IMAS_data.profiles_1d.r_outboard
119117
R_major_profile = (R_in + R_out) / 2.0
118+
119+
# R_major is the geometric center of the LCFS.
120+
R_major = np.asarray(R_major_profile[-1])
121+
122+
# IMAS defines the vacuum toroidal field b0 at the reference radius r0.
123+
# Scale to R_major using B_vac ∝ 1/R, consistent with EQDSK/FBT loaders.
124+
r0 = np.asarray(equilibrium.vacuum_toroidal_field.r0)
125+
B_0 = np.abs(equilibrium.vacuum_toroidal_field.b0[0]) * r0 / R_major
126+
120127
# toroidal field flux function
121128
F = np.asarray(IMAS_data.profiles_1d.f)
122129

torax/_src/sources/ion_cyclotron_source.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747

4848
# Internal import.
4949

50-
5150
# Default value for the model function to be used for the ion cyclotron
5251
# source. This is also used as an identifier for the model function in
5352
# the default source config for Pydantic to "discriminate" against.
@@ -100,7 +99,10 @@ class ToricNNInputs:
10099
temperature_peaking_factor: array_typing.FloatScalar
101100
# Density profile peaking factor, training range = 1.15 to 1.65.
102101
density_peaking_factor: array_typing.FloatScalar
103-
# Toroidal magnetic field on axis in T, training range = 11.8 to 12.5.
102+
# Vacuum toroidal magnetic field at R_major [T].
103+
# Training range = 11.8 to 12.5.
104+
# TODO(b/350494588): double-check with TORIC-NN team on the definition of B_0
105+
# used during training.
104106
B_0: array_typing.FloatScalar
105107

106108

@@ -587,7 +589,7 @@ class IonCyclotronSource(source.Source):
587589
source.AffectedCoreProfile.TEMP_ION,
588590
source.AffectedCoreProfile.TEMP_EL,
589591
source.AffectedCoreProfile.FAST_IONS,
590-
)
592+
)
591593

592594
@classmethod
593595
def zero_fast_ions(

0 commit comments

Comments
 (0)