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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Density Profile | `NeProfile(Profile)`
# Density Profile | `ElectronDensityProfile(Profile)`

The density profile class is organised around a central runner function that is called each time the plasma is parameterised by the parent [`PlasmaProfile()`](./plasma_profiles.md) class. It is called by [`pedestal_parameterisation()`](plasma_profiles.md#pedestal_parameterisation) and [`parabolic parameterisation()`](./plasma_profiles.md#parabolic_parameterisation). The sequence of the runner function can be seen below along with explanation of the following calculations.

Expand All @@ -19,7 +19,7 @@ $$
n_{\text{i0}} = \left(\frac{n_\text{i}}{n_\text{e}}\right)n_{\text{e0}}
$$

#### Electron core density of a pedestalised profile | `ncore()`
#### Electron core density of a pedestalised profile | `calculate_pedestal_profile_on_axis_density()`

This function calculates the core electron density for a pedestalsied profile (`i_plasma_pedestal == 1`). It takes in values of

Expand Down Expand Up @@ -110,6 +110,70 @@ $\blacksquare$

4. The y profile is then calculated using [`calculate_profile_y()`](plasma_density_profile.md#calculate-density-at-each-radius-position-calculate_profile_y). This routine calculates the density at each normalised minor radius position $\rho$ for a HELIOS-type density pedestal profile[^1]


---------------

#### Electron core density of a parabolic profile | `calculate_parabolic_profile_on_axis_density()`

###### Derivation

We calculate the volume integrated profile and then divide by the volume of integration to get the volume average density $\langle n \rangle$. If we assume the plasma to be a torus of circular cross-section then we can use spherical coordinates. We can simplify the problem by representing the torus as a cylinder of height equal to the circumference of the torus equal to $2\pi R$ where $R$ is the major radius of the torus.

The cylindrical volume element is given by:

$$
V = \int \int \int dV = \int^{2\pi R}_0 \int^{2\pi}_0 \int^a_0 r \ dr \ d\theta \ dz
$$

Inserting our density function in the form where $\rho$ is expanded as $\rho = r/a$ we get:

$$
\int^{2\pi R}_0 \int^{2\pi}_0 \int^a_0 r \left(n_0(1-r^2/a^2)^{\alpha_n}\right) \ dr \ d\theta \ dz
$$

Since our density function is only a function of $r$, and the torus is symmetric around its center, the integration simplifies to integrating over $r$ and the $d\theta ,\ dz$ integrals are solved to give values for the full poloidal angle and cylindrical height and torus length, leading to:

$$
4\pi^2R \int^a_0 r \left(n_0(1-r^2/a^2)^{\alpha_n}\right) \ dr
$$

In the form of volume average density where the volume integrated density function has to be divided by the volume of the cylinder / torus we get:

$$
\langle n \rangle = \frac{4\pi^2R \int^a_0 r \left(n_0(1-r^2/a^2)^{\alpha_n}\right) \ dr}{2\pi^2Ra^2}
$$

Simplify:

$$
\langle n \rangle = \frac{2 \int^a_0 r \left(n_0(1-r^2/a^2)^{\alpha_n}\right) \ dr}{a^2}
$$

Integrate:

$$
\langle n \rangle = \frac{2}{a^2} \frac{a^2n_0}{2(\alpha_n+1)}
$$

$$
\therefore \langle n \rangle = \frac{n_0}{\alpha_n+1}
$$

This is in agreement with the derivation from the ITER Physics Design 1989. [^iter_design_89]

Since all parabolic profiles are of the same form this proof holds for the density and temperature.

A similar derivation is found in normalised coordinates, $\rho$ if the line averaged integral is swept around the poloidal circumference then divided by the poloidal area.

$$
\langle n \rangle = \frac{2\pi \int^1_0 \rho \left(n_0(1-\rho^2)^{\alpha_n}\right) \ d\rho}{\pi\rho^2}
$$

$\blacksquare$

------


### Calculate density at each radius position | `calculate_profile_y()`

A table of the input variables can be found below
Expand Down Expand Up @@ -176,3 +240,5 @@ and `ixc = 152` respectively


[^1]: Jean, J. (2011). *HELIOS: A Zero-Dimensional Tool for Next Step and Reactor Studies*. Fusion Science and Technology, 59(2), 308–349. <https://doi.org/10.13182/FST11-A11650>

[^iter_design_89]: N.A. Uckan and ITER Physics Group, 'ITER Physics Design Guidelines: 1989',
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

In `PROCESS` the density, temperature and current profiles of the plasma for electrons and ions can take two forms depending on the switch value for `i_plasma_pedestal`. Either without a [pedestal](http://fusionwiki.ciemat.es/wiki/Pedestal), `i_plasma_pedestal == 0` or with a pedestal `i_plasma_pedestal == 1`. `i_plasma_pedestal == 0` is better suited for modelling L-mode plasmas, while `i_plasma_pedestal == 1` is better suited for modelling [H-mode](https://en.wikipedia.org/wiki/High-confinement_mode) plasmas.

The files responsible for calculating and storing the profiles are `plasma_profiles.py` and `profiles.py`. A central plasma profile object is created from the [`PlasmaProfile`](plasma_profiles.md#plasma-profile-class-plasmaprofile) class that contains attributes for the plasma density and temperature. The density and temperature profiles are in themselves objects of the [`Profile`](./plasma_profiles_abstract_class.md) abstract base class. [`Profile`](./plasma_profiles_abstract_class.md), [`NeProfile`](plasma_density_profile.md) and [`TeProfile`](./plasma_temperature_profile.md) are all defined in `profiles.py`. [`PlasmaProfile`](plasma_profiles.md#plasma-profile-class-plasmaprofile) is exclusively in `plasma_profiles.py`
The files responsible for calculating and storing the profiles are `plasma_profiles.py` and `profiles.py`. A central plasma profile object is created from the [`PlasmaProfile`](plasma_profiles.md#plasma-profile-class-plasmaprofile) class that contains attributes for the plasma density and temperature. The density and temperature profiles are in themselves objects of the [`Profile`](./plasma_profiles_abstract_class.md) abstract base class. [`Profile`](./plasma_profiles_abstract_class.md), [`ElectronDensityProfile`](plasma_density_profile.md) and [`ElectronTemperatureProfile`](./plasma_temperature_profile.md) are all defined in `profiles.py`. [`PlasmaProfile`](plasma_profiles.md#plasma-profile-class-plasmaprofile) is exclusively in `plasma_profiles.py`

<figure markdown>
![UML of profiles](./uml_classes_PlasmaProfile.png){height="1000px"}
Expand Down Expand Up @@ -238,7 +238,7 @@ The graph below is for a standard pedestal profile. You can vary its attributes

## Plasma Profile Class | `PlasmaProfile`
### Initialization | `__init__()`
The parent plasma profile class is `PlasmaProfile`. Initialization sets the profile class size and `neprofile` and `teprofile` to [`NeProfile`](plasma_density_profile.md) & [`TeProfile`](plasma_temperature_profile.md) objects from `profiles.py`
The parent plasma profile class is `PlasmaProfile`. Initialization sets the profile class size and `neprofile` and `teprofile` to [`ElectronDensityProfile`](plasma_density_profile.md) & [`ElectronTemperatureProfile`](plasma_temperature_profile.md) objects from `profiles.py`

???+ Note

Expand Down Expand Up @@ -266,7 +266,7 @@ Depending on the value of `i_plasma_pedestal` different functions will be ran, t

If pedestal profile values are set they are reset to have values that agree with the original form of the parabolic profiles. Such that $\rho_{\text{ped}} = 1$ and that pedestal and separatrix densities and temperatures are zero. This will then warn the user in the terminal.

The density and temperature profile runner function [`TeProfile/NeProfile.run()`](plasma_density_profile.md#runner-function-run) is then called to re-calculate the profile and core values.
The density and temperature profile runner function [`ElectronTemperatureProfile/ElectronDensityProfile.run()`](plasma_density_profile.md#runner-function-run) is then called to re-calculate the profile and core values.

Ratio of density-weighted to volume-averaged temperature factor is calculated:

Expand Down Expand Up @@ -593,7 +593,7 @@ $$

##### `pedestal_parameterisation()`

The density and temperature profile runner function [`TeProfile/NeProfile.run()`](plasma_density_profile.md#runner-function-run) is firstly called to re-calculate the profile and core values.
The density and temperature profile runner function [`ElectronTemperatureProfile/ElectronDensityProfile.run()`](plasma_density_profile.md#runner-function-run) is firstly called to re-calculate the profile and core values.

Perform integrations to calculate ratio of density-weighted to volume-averaged temperature, etc. Density-weighted temperature = $\frac{\int{nT \ dV}}{\int{n \ dV}}$, which is approximately equal to the ratio $\frac{\int{\rho \ n(\rho) T(\rho) \ d\rho}}{\int{\rho \ n(\rho) \ d\rho}}$

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Temperature Profile | `TeProfile(Profile)`
# Temperature Profile | `ElectronTemperatureProfile(Profile)`

The temperature profile class is organised around a central runner function that is called each time the plasma is parameterised by the parent [`PlasmaProfile()`](plasma_profiles.md#plasma-profile-class-plasmaprofile) class. It is called by [`pedestal_parameterisation()`](plasma_profiles.md#pedestal_parameterisation) and [`parabolic parameterisation()`](plasma_profiles.md#parabolic_parameterisation). The sequence of the runner function can be seen below along with explanation of the following calculations.

Expand All @@ -14,15 +14,15 @@ The temperature profile class is organised around a central runner function that

The core electron temperature is calculated using the [`tcore`](plasma_temperature_profile.md#electron-core-density-of-a-pedestalised-profile--tcore) method.

#### Electron core density of a pedestalised profile | `tcore()`
#### Electron core temperature of a pedestalised profile | `calculate_pedestal_profile_on_axis_temperature()`

This function calculates the core electron density for a pedestalsied profile in $\text{keV}$. The inclusion of a new $\beta_T$ exponent term allows a more accurate description of temperature profiles with a triangular shape or a strong gradient near the pedestal (characteristic of regimes with an [internal transport barrier](https://wiki.fusion.ciemat.es/wiki/Internal_Transport_Barrier)).
This function calculates the core electron temperature for a pedestalsied profile in $\text{keV}$. The inclusion of a new $\beta_T$ exponent term allows a more accurate description of temperature profiles with a triangular shape or a strong gradient near the pedestal (characteristic of regimes with an [internal transport barrier](https://wiki.fusion.ciemat.es/wiki/Internal_Transport_Barrier)).

A list of input parameters for calculating the core plasma temperature can be found below.

| Profile parameter / Input | Temperature |
|----------------------------------|-----------|
| Pedestal radius (r/a) | `radius_plasma_pedestal_density_norm`, $\rho_{\text{ped,T}}$ |
| Pedestal radius (r/a) | `radius_plasma_pedestal_temp_norm`, $\rho_{\text{ped,T}}$ |
| Pedestal value | `nd_plasma_pedestal_electron`, $T_{\text{ped}}$ |
| Separatrix value | `nd_plasma_separatrix_electron`, $T_{\text{sep}}$ |
| Average temperature | `nd_plasma_electrons_vol_avg`, $\langle T_\text{e} \rangle$ |
Expand All @@ -39,7 +39,7 @@ Where $\text{B}$ is the [Beta function](https://en.wikipedia.org/wiki/Beta_funct

##### Derivation

We calculate the volume integrated profile and then divide by the volume of integration to get the volume average density $\langle T_{\text{e}} \rangle$. If we assume the plasma to be a torus of circular cross-section then we can use spherical coordinates. We can simplify the problem by representing the torus as a cylinder of height equal to the circumference of the torus equal to $2\pi R$ where $R$ is the major radius of the torus, and $a$ is the plasma minor radius in the poloidal plane.
We calculate the volume integrated profile and then divide by the volume of integration to get the volume average temperature $\langle T_{\text{e}} \rangle$. If we assume the plasma to be a torus of circular cross-section then we can use spherical coordinates. We can simplify the problem by representing the torus as a cylinder of height equal to the circumference of the torus equal to $2\pi R$ where $R$ is the major radius of the torus, and $a$ is the plasma minor radius in the poloidal plane.

The cylindrical volume element is given by:

Expand Down Expand Up @@ -97,6 +97,68 @@ $\blacksquare$

-----

#### Electron core temperature of a parabolic profile | `calculate_parabolic_profile_on_axis_temperature()`

###### Derivation

We calculate the volume integrated profile and then divide by the volume of integration to get the volume average temperature $\langle T \rangle$. If we assume the plasma to be a torus of circular cross-section then we can use spherical coordinates. We can simplify the problem by representing the torus as a cylinder of height equal to the circumference of the torus equal to $2\pi R$ where $R$ is the major radius of the torus.

The cylindrical volume element is given by:

$$
V = \int \int \int dV = \int^{2\pi R}_0 \int^{2\pi}_0 \int^a_0 r \ dr \ d\theta \ dz
$$

Inserting our temperature function in the form where $\rho$ is expanded as $\rho = r/a$ we get:

$$
\int^{2\pi R}_0 \int^{2\pi}_0 \int^a_0 r \left(T_0(1-r^2/a^2)^{\alpha_T}\right) \ dr \ d\theta \ dz
$$

Since our temperature function is only a function of $r$, and the torus is symmetric around its center, the integration simplifies to integrating over $r$ and the $d\theta ,\ dz$ integrals are solved to give values for the full poloidal angle and cylindrical height and torus length, leading to:

$$
4\pi^2R \int^a_0 r \left(T_0(1-r^2/a^2)^{\alpha_T}\right) \ dr
$$

In the form of volume average temperature where the volume integrated temperature function has to be divided by the volume of the cylinder / torus we get:

$$
\langle n \rangle = \frac{4\pi^2R \int^a_0 r \left(T_0(1-r^2/a^2)^{\alpha_T}\right) \ dr}{2\pi^2Ra^2}
$$

Simplify:

$$
\langle n \rangle = \frac{2 \int^a_0 r \left(T_0(1-r^2/a^2)^{\alpha_T}\right) \ dr}{a^2}
$$

Integrate:

$$
\langle T \rangle = \frac{2}{a^2} \frac{a^2 T_0}{2(\alpha_T+1)}
$$

$$
\therefore \langle T \rangle = \frac{T_0}{\alpha_T+1}
$$

This is in agreement with the derivation from the ITER Physics Design 1989. [^iter_design_89]

Since all parabolic profiles are of the same form this proof holds for the density and temperature.

A similar derivation is found in normalised coordinates, $\rho$ if the line averaged integral is swept around the poloidal circumference then divided by the poloidal area.

$$
\langle T \rangle = \frac{2\pi \int^1_0 \rho \left(T_0(1-\rho^2)^{\alpha_T}\right) \ d\rho}{\pi\rho^2}
$$

$\blacksquare$

------



The core ion temperature is then set such as:

$$
Expand All @@ -115,7 +177,7 @@ A table of the input variables can be found below
|----------------------------------|-----------|
| Normalised plasma radii | `profile_x` |
| Pedestal radius (r/a) | `radius_plasma_pedestal_temp_norm`, $\rho_{\text{ped,T}}$ |
| Core density | `temp_plasma_electron_on_axis_kev`, $T_{\text{e0}}$ |
| Core temperature | `temp_plasma_electron_on_axis_kev`, $T_{\text{e0}}$ |
| Pedestal value | `temp_plasma_pedestal_kev`, $T_{\text{ped}}$ |
| Separatrix value | `temp_plasma_separatrix_kev`, $T_{\text{sep}}$ |
| Profile index/ peaking parameter | `alphat`, $\alpha_T$ |
Expand All @@ -130,7 +192,7 @@ $$
The central temperature ($T_0$) is then checked to make sure it is not less than the pedestal temperature, $T_{\text{ped}}$.
If it is less than a logger warning is pushed to the terminal at runtime.

Values of the profile temperature are then assigned based on the density function below across bounds from 0 to `radius_plasma_pedestal_density_norm` and `radius_plasma_pedestal_density_norm` to 1.
Values of the profile temperature are then assigned based on the temperature function below across bounds from 0 to `radius_plasma_pedestal_temp_norm` and `radius_plasma_pedestal_temp_norm` to 1.

$$\begin{aligned}
\mbox{Temperature:} \ \ T(\rho) = \left\{
Expand All @@ -146,3 +208,5 @@ $$\begin{aligned}
5. Profile is then integrated with `integrate_profile_y()` using Simpsons integration from the profile abstract base class

[^1]: Jean, J. (2011). *HELIOS: A Zero-Dimensional Tool for Next Step and Reactor Studies*. Fusion Science and Technology, 59(2), 308–349. <https://doi.org/10.13182/FST11-A11650>

[^iter_design_89]: N.A. Uckan and ITER Physics Group, 'ITER Physics Design Guidelines: 1989',
9 changes: 6 additions & 3 deletions process/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@
from process.models.physics.plasma_fields import PlasmaFields
from process.models.physics.plasma_geometry import PlasmaGeom
from process.models.physics.plasma_profiles import PlasmaProfile
from process.models.physics.profiles import NeProfile, TeProfile
from process.models.physics.profiles import (
ElectronDensityProfile,
ElectronTemperatureProfile,
)
from process.models.physics.scrape_off_layer import ScrapeOffLayer
from process.models.power import Power
from process.models.pulse import Pulse
Expand Down Expand Up @@ -664,8 +667,8 @@ def __init__(self, data: DataStructure):
self.pulse = Pulse()
self.shield = Shield()
self.ife = IFE(availability=self.availability, costs=self.costs)
self.ne_profile = NeProfile()
self.te_profile = TeProfile()
self.ne_profile = ElectronDensityProfile()
self.te_profile = ElectronTemperatureProfile()
self.plasma_profile = PlasmaProfile(self.ne_profile, self.te_profile)
self.fw = FirstWall()
self.blanket_library = BlanketLibrary(fw=self.fw)
Expand Down
8 changes: 5 additions & 3 deletions process/models/physics/plasma_profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ def __init__(self, ne_profile, te_profile):
Args:
profile_size (int): The size of the plasma profile.
outfile (str): The output file path.
neprofile (NeProfile): An instance of the NeProfile class.
teprofile (TeProfile): An instance of the TeProfile class.
neprofile (ElectronDensityProfile): An instance of the ElectronDensityProfile
class.
teprofile (ElectronTemperatureProfile): An instance of the
ElectronTemperatureProfile class.
"""
# Default profile_size = 201, but it's possible to experiment with this value.
# See `n_plasma_profile_elements`
Expand Down Expand Up @@ -195,7 +197,7 @@ def pedestal_parameterisation(self):
`temp_plasma_electron_density_weighted_kev` and
`temp_plasma_ion_density_weighted_kev`.
"""
# Run TeProfile and NeProfile class methods:
# Run ElectronTemperatureProfile and ElectronDensityProfile class methods:
# Re-calculate core and profile values

self.teprofile.run()
Expand Down
Loading
Loading