Skip to content

plasma_fields

PlasmaFields

Bases: Model

Source code in process/models/physics/plasma_fields.py
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
class PlasmaFields(Model):
    def __init__(self):
        self.outfile = constants.NOUT
        self.mfile = constants.MFILE
        self.current = PlasmaCurrent()

    def run(self):
        """Run the model. This model cannot yet be 'run'."""

    def calculate_surface_averaged_poloidal_field(
        self,
        i_plasma_current: int,
        ip: float,
        q95: float,
        aspect: float,
        eps: float,
        b_plasma_toroidal_on_axis: float,
        kappa: float,
        delta: float,
        perim: float,
    ) -> float:
        """Function to calculate surface-averaged poloidal field (⟨Bₚ(a)⟩) from the plasma current

        This function calculates the surface-averaged poloidal field from the plasma current in Tesla,
        using a simple calculation using Ampere's law for conventional
        tokamaks, or for TARTs, a scaling from Peng, Galambos and
        Shipe (1992).

        Parameters
        ----------
        i_plasma_current :
            current scaling model to use
        ip :
            plasma current (A)
        q95 :
            95% flux surface safety factor
        aspect :
            plasma aspect ratio
        eps :
            inverse aspect ratio
        b_plasma_toroidal_on_axis :
            toroidal field on axis (T)
        kappa :
            plasma elongation
        delta :
            plasma triangularity
        perim :
            plasma perimeter (m)

        Returns
        -------
        :
            surface-averaged poloidal field in Tesla ⟨Bₚ(a)⟩


        References
        ----------
            - J D Galambos, STAR Code : Spherical Tokamak Analysis and Reactor Code,
            unpublished internal Oak Ridge document
            - Peng, Y. K. M., Galambos, J. D., & Shipe, P. C. (1992).
            'Small Tokamaks for Fusion Technology Testing'. Fusion Technology, 21(3P2A),
            1729-1738. https://doi.org/10.13182/FST92-A29971

        """
        # Use Ampere's law using the plasma poloidal cross-section this simply returns
        # ⟨Bₚ(a)⟩
        if i_plasma_current != 2:
            return constants.RMU0 * ip / perim
        # Use the relation from Peng, Galambos and Shipe (1992) [STAR code] otherwise
        ff1, ff2, _, _ = self.current.plascar_bpol(aspect, eps, kappa, delta)

        # Transform q95 to qbar
        qbar = q95 * 1.3e0 * (1.0e0 - physics_variables.eps) ** 0.6e0

        return b_plasma_toroidal_on_axis * (ff1 + ff2) / (2.0 * np.pi * qbar)

    @staticmethod
    @nb.jit(cache=True)
    def calculate_plasma_inboard_toroidal_field(
        b_plasma_toroidal_on_axis: float,
        rmajor: float,
        rminor: float,
    ) -> float:
        """Calculate the toroidal field at the plasma inboard midplane (Bᴛ(R₀-a))

        Parameters
        ----------
        b_plasma_toroidal_on_axis :
            toroidal field on axis (T)
        rmajor :
            plasma major radius (m)
        rminor :
            plasma minor radius (m)

        Returns
        -------
        :
            toroidal field at the plasma inboard midplane (T)
        """

        return rmajor * b_plasma_toroidal_on_axis / (rmajor - rminor)

    @staticmethod
    @nb.jit(cache=True)
    def calculate_plasma_outboard_toroidal_field(
        b_plasma_toroidal_on_axis: float,
        rmajor: float,
        rminor: float,
    ) -> float:
        """Calculate the toroidal field at the plasma outboard midplane (Bᴛ(R₀+a))

        Parameters
        ----------
        b_plasma_toroidal_on_axis :
            toroidal field on axis (T)
        rmajor :
            plasma major radius (m)
        rminor :
            plasma minor radius (m)

        Returns
        -------
        :
            toroidal field at the plasma outboard midplane (T)
        """

        return rmajor * b_plasma_toroidal_on_axis / (rmajor + rminor)

    @staticmethod
    @nb.jit(cache=True)
    def calculate_toroidal_field_profile(
        b_plasma_toroidal_on_axis: float,
        rmajor: float,
        rminor: float,
        n_plasma_profile_elements: int,
    ) -> np.ndarray:
        """Calculate the toroidal field profile across the plasma midplane

        Parameters
        ----------
        b_plasma_toroidal_on_axis :
            toroidal field on axis (T)
        rmajor :
            plasma major radius (m)
        rminor :
            plasma minor radius (m)
        n_plasma_profile_elements :
            Number of elements to use in the plasma profile calculation
        """

        # Calculate the toroidal field across the plasma
        # Calculate the toroidal field profile across the plasma (1/R dependence)
        # Double element size to include both sides of the plasma
        rho = np.linspace(
            rmajor - rminor,
            rmajor + rminor,
            2 * n_plasma_profile_elements,
        )

        # Avoid division by zero at the magnetic axis
        rho = np.where(rho == 0, 1e-10, rho)
        return rmajor * b_plasma_toroidal_on_axis / rho

    @staticmethod
    @nb.jit(cache=True)
    def calculate_total_magnetic_field(
        b_plasma_toroidal: float, b_plasma_poloidal: float
    ) -> float:
        """Calculate the total magnetic field at the plasma edge

        Parameters
        ----------
        b_plasma_toroidal :
            toroidal field at point of interest (T)
        b_plasma_poloidal :
            poloidal field at point of interest (T)

        Returns
        -------
        :
            total magnetic field at the plasma edge (T)
        """
        return np.sqrt(b_plasma_toroidal**2 + b_plasma_poloidal**2)

    def output(self):
        po.oheadr(self.outfile, "Plasma magnetic fields")

        po.ovarrf(
            self.outfile,
            "Vertical field at plasma (T)",
            "(b_plasma_vertical_required)",
            physics_variables.b_plasma_vertical_required,
            "OP ",
        )

        po.ovarrf(
            self.outfile,
            "Vacuum toroidal field at R (T)",
            "(b_plasma_toroidal_on_axis)",
            physics_variables.b_plasma_toroidal_on_axis,
        )
        po.ovarrf(
            self.outfile,
            "Toroidal field at plasma inboard (T)",
            "(b_plasma_inboard_toroidal)",
            physics_variables.b_plasma_inboard_toroidal,
        )
        po.ovarrf(
            self.outfile,
            "Toroidal field at plasma outboard (T)",
            "(b_plasma_outboard_toroidal)",
            physics_variables.b_plasma_outboard_toroidal,
        )

        for i in range(len(physics_variables.b_plasma_toroidal_profile)):
            po.ovarre(
                self.mfile,
                f"Toroidal field in plasma at point {i}",
                f"b_plasma_toroidal_profile{i}",
                physics_variables.b_plasma_toroidal_profile[i],
            )
        po.ovarrf(
            self.outfile,
            "Plasma surface averaged poloidal field (T)",
            "(b_plasma_surface_poloidal_average)",
            physics_variables.b_plasma_surface_poloidal_average,
            "OP ",
        )

        po.ovarrf(
            self.outfile,
            "Total field (sqrt(b_plasma_surface_poloidal_average^2 + b_plasma_toroidal_on_axis^2)) (T)",
            "(b_plasma_total)",
            physics_variables.b_plasma_total,
            "OP ",
        )

outfile = constants.NOUT instance-attribute

mfile = constants.MFILE instance-attribute

current = PlasmaCurrent() instance-attribute

run()

Run the model. This model cannot yet be 'run'.

Source code in process/models/physics/plasma_fields.py
23
24
def run(self):
    """Run the model. This model cannot yet be 'run'."""

calculate_surface_averaged_poloidal_field(i_plasma_current, ip, q95, aspect, eps, b_plasma_toroidal_on_axis, kappa, delta, perim)

Function to calculate surface-averaged poloidal field (⟨Bₚ(a)⟩) from the plasma current

This function calculates the surface-averaged poloidal field from the plasma current in Tesla, using a simple calculation using Ampere's law for conventional tokamaks, or for TARTs, a scaling from Peng, Galambos and Shipe (1992).

Parameters:

Name Type Description Default
i_plasma_current int

current scaling model to use

required
ip float

plasma current (A)

required
q95 float

95% flux surface safety factor

required
aspect float

plasma aspect ratio

required
eps float

inverse aspect ratio

required
b_plasma_toroidal_on_axis float

toroidal field on axis (T)

required
kappa float

plasma elongation

required
delta float

plasma triangularity

required
perim float

plasma perimeter (m)

required

Returns:

Type Description
float

surface-averaged poloidal field in Tesla ⟨Bₚ(a)⟩

References
- J D Galambos, STAR Code : Spherical Tokamak Analysis and Reactor Code,
unpublished internal Oak Ridge document
- Peng, Y. K. M., Galambos, J. D., & Shipe, P. C. (1992).
'Small Tokamaks for Fusion Technology Testing'. Fusion Technology, 21(3P2A),
1729-1738. https://doi.org/10.13182/FST92-A29971
Source code in process/models/physics/plasma_fields.py
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
def calculate_surface_averaged_poloidal_field(
    self,
    i_plasma_current: int,
    ip: float,
    q95: float,
    aspect: float,
    eps: float,
    b_plasma_toroidal_on_axis: float,
    kappa: float,
    delta: float,
    perim: float,
) -> float:
    """Function to calculate surface-averaged poloidal field (⟨Bₚ(a)⟩) from the plasma current

    This function calculates the surface-averaged poloidal field from the plasma current in Tesla,
    using a simple calculation using Ampere's law for conventional
    tokamaks, or for TARTs, a scaling from Peng, Galambos and
    Shipe (1992).

    Parameters
    ----------
    i_plasma_current :
        current scaling model to use
    ip :
        plasma current (A)
    q95 :
        95% flux surface safety factor
    aspect :
        plasma aspect ratio
    eps :
        inverse aspect ratio
    b_plasma_toroidal_on_axis :
        toroidal field on axis (T)
    kappa :
        plasma elongation
    delta :
        plasma triangularity
    perim :
        plasma perimeter (m)

    Returns
    -------
    :
        surface-averaged poloidal field in Tesla ⟨Bₚ(a)⟩


    References
    ----------
        - J D Galambos, STAR Code : Spherical Tokamak Analysis and Reactor Code,
        unpublished internal Oak Ridge document
        - Peng, Y. K. M., Galambos, J. D., & Shipe, P. C. (1992).
        'Small Tokamaks for Fusion Technology Testing'. Fusion Technology, 21(3P2A),
        1729-1738. https://doi.org/10.13182/FST92-A29971

    """
    # Use Ampere's law using the plasma poloidal cross-section this simply returns
    # ⟨Bₚ(a)⟩
    if i_plasma_current != 2:
        return constants.RMU0 * ip / perim
    # Use the relation from Peng, Galambos and Shipe (1992) [STAR code] otherwise
    ff1, ff2, _, _ = self.current.plascar_bpol(aspect, eps, kappa, delta)

    # Transform q95 to qbar
    qbar = q95 * 1.3e0 * (1.0e0 - physics_variables.eps) ** 0.6e0

    return b_plasma_toroidal_on_axis * (ff1 + ff2) / (2.0 * np.pi * qbar)

calculate_plasma_inboard_toroidal_field(b_plasma_toroidal_on_axis, rmajor, rminor) staticmethod

Calculate the toroidal field at the plasma inboard midplane (Bᴛ(R₀-a))

Parameters:

Name Type Description Default
b_plasma_toroidal_on_axis float

toroidal field on axis (T)

required
rmajor float

plasma major radius (m)

required
rminor float

plasma minor radius (m)

required

Returns:

Type Description
float

toroidal field at the plasma inboard midplane (T)

Source code in process/models/physics/plasma_fields.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
@staticmethod
@nb.jit(cache=True)
def calculate_plasma_inboard_toroidal_field(
    b_plasma_toroidal_on_axis: float,
    rmajor: float,
    rminor: float,
) -> float:
    """Calculate the toroidal field at the plasma inboard midplane (Bᴛ(R₀-a))

    Parameters
    ----------
    b_plasma_toroidal_on_axis :
        toroidal field on axis (T)
    rmajor :
        plasma major radius (m)
    rminor :
        plasma minor radius (m)

    Returns
    -------
    :
        toroidal field at the plasma inboard midplane (T)
    """

    return rmajor * b_plasma_toroidal_on_axis / (rmajor - rminor)

calculate_plasma_outboard_toroidal_field(b_plasma_toroidal_on_axis, rmajor, rminor) staticmethod

Calculate the toroidal field at the plasma outboard midplane (Bᴛ(R₀+a))

Parameters:

Name Type Description Default
b_plasma_toroidal_on_axis float

toroidal field on axis (T)

required
rmajor float

plasma major radius (m)

required
rminor float

plasma minor radius (m)

required

Returns:

Type Description
float

toroidal field at the plasma outboard midplane (T)

Source code in process/models/physics/plasma_fields.py
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
@staticmethod
@nb.jit(cache=True)
def calculate_plasma_outboard_toroidal_field(
    b_plasma_toroidal_on_axis: float,
    rmajor: float,
    rminor: float,
) -> float:
    """Calculate the toroidal field at the plasma outboard midplane (Bᴛ(R₀+a))

    Parameters
    ----------
    b_plasma_toroidal_on_axis :
        toroidal field on axis (T)
    rmajor :
        plasma major radius (m)
    rminor :
        plasma minor radius (m)

    Returns
    -------
    :
        toroidal field at the plasma outboard midplane (T)
    """

    return rmajor * b_plasma_toroidal_on_axis / (rmajor + rminor)

calculate_toroidal_field_profile(b_plasma_toroidal_on_axis, rmajor, rminor, n_plasma_profile_elements) staticmethod

Calculate the toroidal field profile across the plasma midplane

Parameters:

Name Type Description Default
b_plasma_toroidal_on_axis float

toroidal field on axis (T)

required
rmajor float

plasma major radius (m)

required
rminor float

plasma minor radius (m)

required
n_plasma_profile_elements int

Number of elements to use in the plasma profile calculation

required
Source code in process/models/physics/plasma_fields.py
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
@staticmethod
@nb.jit(cache=True)
def calculate_toroidal_field_profile(
    b_plasma_toroidal_on_axis: float,
    rmajor: float,
    rminor: float,
    n_plasma_profile_elements: int,
) -> np.ndarray:
    """Calculate the toroidal field profile across the plasma midplane

    Parameters
    ----------
    b_plasma_toroidal_on_axis :
        toroidal field on axis (T)
    rmajor :
        plasma major radius (m)
    rminor :
        plasma minor radius (m)
    n_plasma_profile_elements :
        Number of elements to use in the plasma profile calculation
    """

    # Calculate the toroidal field across the plasma
    # Calculate the toroidal field profile across the plasma (1/R dependence)
    # Double element size to include both sides of the plasma
    rho = np.linspace(
        rmajor - rminor,
        rmajor + rminor,
        2 * n_plasma_profile_elements,
    )

    # Avoid division by zero at the magnetic axis
    rho = np.where(rho == 0, 1e-10, rho)
    return rmajor * b_plasma_toroidal_on_axis / rho

calculate_total_magnetic_field(b_plasma_toroidal, b_plasma_poloidal) staticmethod

Calculate the total magnetic field at the plasma edge

Parameters:

Name Type Description Default
b_plasma_toroidal float

toroidal field at point of interest (T)

required
b_plasma_poloidal float

poloidal field at point of interest (T)

required

Returns:

Type Description
float

total magnetic field at the plasma edge (T)

Source code in process/models/physics/plasma_fields.py
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
@staticmethod
@nb.jit(cache=True)
def calculate_total_magnetic_field(
    b_plasma_toroidal: float, b_plasma_poloidal: float
) -> float:
    """Calculate the total magnetic field at the plasma edge

    Parameters
    ----------
    b_plasma_toroidal :
        toroidal field at point of interest (T)
    b_plasma_poloidal :
        poloidal field at point of interest (T)

    Returns
    -------
    :
        total magnetic field at the plasma edge (T)
    """
    return np.sqrt(b_plasma_toroidal**2 + b_plasma_poloidal**2)

output()

Source code in process/models/physics/plasma_fields.py
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
def output(self):
    po.oheadr(self.outfile, "Plasma magnetic fields")

    po.ovarrf(
        self.outfile,
        "Vertical field at plasma (T)",
        "(b_plasma_vertical_required)",
        physics_variables.b_plasma_vertical_required,
        "OP ",
    )

    po.ovarrf(
        self.outfile,
        "Vacuum toroidal field at R (T)",
        "(b_plasma_toroidal_on_axis)",
        physics_variables.b_plasma_toroidal_on_axis,
    )
    po.ovarrf(
        self.outfile,
        "Toroidal field at plasma inboard (T)",
        "(b_plasma_inboard_toroidal)",
        physics_variables.b_plasma_inboard_toroidal,
    )
    po.ovarrf(
        self.outfile,
        "Toroidal field at plasma outboard (T)",
        "(b_plasma_outboard_toroidal)",
        physics_variables.b_plasma_outboard_toroidal,
    )

    for i in range(len(physics_variables.b_plasma_toroidal_profile)):
        po.ovarre(
            self.mfile,
            f"Toroidal field in plasma at point {i}",
            f"b_plasma_toroidal_profile{i}",
            physics_variables.b_plasma_toroidal_profile[i],
        )
    po.ovarrf(
        self.outfile,
        "Plasma surface averaged poloidal field (T)",
        "(b_plasma_surface_poloidal_average)",
        physics_variables.b_plasma_surface_poloidal_average,
        "OP ",
    )

    po.ovarrf(
        self.outfile,
        "Total field (sqrt(b_plasma_surface_poloidal_average^2 + b_plasma_toroidal_on_axis^2)) (T)",
        "(b_plasma_total)",
        physics_variables.b_plasma_total,
        "OP ",
    )