diff --git a/dev/anomalous_transport/index.html b/dev/anomalous_transport/index.html index 0db8c8e8..927e363e 100644 --- a/dev/anomalous_transport/index.html +++ b/dev/anomalous_transport/index.html @@ -1,5 +1,5 @@ -Anomalous Transport · HallThruster.jl

Anomalous Transport

HallThruster has a few anomalous transport models built in and allows users to define their own. This page describes these models and the process by which algebraic and multi-equation transport models can be added by the user.

Interface not finalized

The AnomalousTransportModel interface is not yet finalized and subject to revision. Keep this in mind when using this feature.

Built-in Models

NoAnom()

Model for no anomalous transport (anomalous collision frequency = 0).

anom_model = NoAnom()

Bohm(c)

Model where the anomalous collision frequency scales with the electron cyclotron frequency ωce times some scaling factor c

TwoZoneBohm(c1, c2)

HallThruster's default anomalous transport option. This is a standard model of anomalous transport frequently used in Hall thruster simulations. The anomalous collision frequency is defined as

\[\begin{aligned} +Anomalous Transport · HallThruster.jl

Anomalous Transport

HallThruster has a few anomalous transport models built in and allows users to define their own. This page describes these models and the process by which algebraic and multi-equation transport models can be added by the user.

Interface not finalized

The AnomalousTransportModel interface is not yet finalized and subject to revision. Keep this in mind when using this feature.

Built-in Models

!!! warning Incomplete documentation Some models (those relating to pressure-dependent effects) have not been finalized and are not represented in this documentation. Please see the source code for a complete listing.

NoAnom()

Model for no anomalous transport (anomalous collision frequency = 0).

anom_model = NoAnom()

Bohm(c)

Model where the anomalous collision frequency scales with the electron cyclotron frequency ωce times some scaling factor c

TwoZoneBohm(c1, c2)

HallThruster's default anomalous transport option. This is a standard model of anomalous transport frequently used in Hall thruster simulations. The anomalous collision frequency is defined as

\[\begin{aligned} \nu_{AN} &= c_1 \omega_{ce} \quad z < L_{ch} \\ &= c_2 \omega_{ce} \quad z > L_{ch} \end{aligned}\]

In the above expression, $c_1$ and $c_2$ are tunable coefficients, $\omega_{ce} = e B / m_e$ is the electron cyclotron frequency, and $L_{ch}$ is the channel length. A TwoZoneBohm model is initialized as follows

anom_model = TwoZoneBohm(c1, c2)

The transition between the zones is determined by the user-provided transition function. This defaults to a step function.

MultiLogBohm(z, c)

Model similar to that employed in Hall2De, where the mobility is Bohm-like (i.e. νan(z) = c(z) * ωce(z)) and z is in meters.

The function c(z) is defined by a sequence of nodes (z, c) provided by the user. At z = z[1], c(z) = c[1], and so forth.

At z[i] < z < z[i+1], log(c) is defined by linearly interpolating between log(c[i]) and log(c[i+1]).

For z < z[1], c = c[1] and for z > z[end], c(z) = c[end].

The user may also provide a single array of [z[1], z[2], ..., z[end], c[1], c[2], ..., c[end]]. The number of zvalues must be equal to the number of c values.

The AnomalousTransportModel interface

Currently, HallThruster.jl expects all models to be written to be callable structs, taking arguments U, params, i, where U is the system state vector, params are the simulation parameters (including the cache of all variables), and i is the index of the cell.

Custom anomalous transport models

Users of HallThruster may define their own models by defining a custom subtype of AnomalousTransportModel. Suppose we want to implement $nu_{AN} = \beta \omega_{ce}$ (classic Bohm diffusion). This is a fixed anomalous transport model and does not change as the simulation progresses. We would first define our type:

using HallThruster
@@ -23,7 +23,7 @@
 \end{aligned}\]

In this expression, $K$ is a tunable coefficient, $u_i$ is the ion velocity, $W = n_e k_B T_e$ is the wave energy density, $m_e$ is the electron mass, $n_e$ is the electron number density, $c_s$ is the ion sound speed, and $v_{de}$ is the electron azimuthal drift speed. Let's say we want to save the wave energy density in addition to the anomalous collision frequency. We begin by defining the model:

    struct LafleurModel <: AnomalousTransportModel
         K::Float64
     end

Next, we add a method to the num_anom_variables function. Since we want to save the wave energy density, we need 1 additional anomalous transport variable.

    num_anom_variables(::LafleurModel) = 1

Now, we define the behavior of the model in a function. Since the model is based on assuming the wave energy convects with the ions, we will use upwind differencing for the gradient.

function (model::LafleurModel)(νan, params)
-    
+
     (;config, cache) = params
     mi = config.propellant.m
     K = model.K
@@ -53,7 +53,7 @@
 
         # Save W to cache.anom_variables[1]
         anom_variables[1][i] = W
-        
+
         # Return anomalous collision frequency
         νan[i] = abs(K * grad_ui_W / (me * cs * vde * ne))
     end
@@ -63,7 +63,7 @@
     anom_variables[1][end] = anom_variables[1][end-1]
     νan[1] = νan[2]
     νan[end] = νan[end-1]
-    
+
     return νan
 end

The saved value of the wave energy density can then be recovered as

    solution.savevals[frame].anom_variables[1]

where solution is the Solution object resulting from a call to run_simulation

Solving arbitrary PDEs using the AnomalousTransportModel interface

We can use this basic interface to solve PDEs within HallThruster.jl. We demonstrate this by solving the scalar advection equation using first-order upwind differencing in space and forward Euler integration in time, with periodic boundary conditions. The scalar advection equation is given by:

\[ \begin{aligned} \frac{\partial u}{\partial t} + a \frac{\partial u}{\partial x} = 0 @@ -78,17 +78,17 @@ # 1) Advected quantity u # 2) gradient of advected quantity (du/dz) HallThruster.num_anom_variables(::ScalarAdvection) = 2

Next, we define the model function:

function (model::ScalarAdvection)(νan, params)
-    
+
     ncells = length(νan)
-    
-    # Extract variables from params 
+
+    # Extract variables from params
     cache = params.cache
     z = params.z_cell
     u = cache.anom_variables[1]
     du_dz = cache.anom_variables[2]
     a = model.advection_velocity
     dt = params.dt
-    
+
     if params.iteration[] < 1
         # Initialize
         model.initializer(u, z)
@@ -151,9 +151,9 @@
 # Run simulation
 solution = HallThruster.run_simulation(
     config;
-    ncells, 
+    ncells,
     dt,
-    duration = nsteps * dt, 
+    duration = nsteps * dt,
     nsave = nsteps
 )
 
@@ -164,7 +164,7 @@
 # Time needed to transit the domain
 t_transit = L / advection_velocity
 
-# Number of periods 
+# Number of periods
 num_periods = floor(Int, nsteps * dt / t_transit)
 
 # Plot results
@@ -189,17 +189,17 @@
 HallThruster.num_anom_variables(::ScalarAdvection) = 2
 
 function (model::ScalarAdvection)(νan, params)
-    
+
     ncells = length(νan)
-    
-    # Extract variables from params 
+
+    # Extract variables from params
     cache = params.cache
     z = params.z_cell
     u = cache.anom_variables[1]
     du_dz = cache.anom_variables[2]
     a = model.advection_velocity
     dt = params.dt
-    
+
     if params.iteration[] < 1
         # Initialize
         model.initializer(u, z)
@@ -277,9 +277,9 @@
 # Run simulation
 solution = HallThruster.run_simulation(
     config;
-    ncells, 
+    ncells,
     dt,
-    duration = nsteps * dt, 
+    duration = nsteps * dt,
     nsave = nsteps
 )
 
@@ -292,7 +292,7 @@
 # Time needed to transit the domain
 t_transit = L / advection_velocity
 
-# Number of periods 
+# Number of periods
 num_periods = floor(Int, nsteps * dt / t_transit)
 
 # Plot results
@@ -304,4 +304,4 @@
         linecolor = cgrad(:turbo, num_periods + 1, categorical = true)[i+1]
     )
 end
-display(p)
+display(p)
diff --git a/dev/background/index.html b/dev/background/index.html index 23d9ba47..5d3713c1 100644 --- a/dev/background/index.html +++ b/dev/background/index.html @@ -1,2 +1,2 @@ -Background · HallThruster.jl

Background

Hall thrusters are a widely-used class of spacecraft electric propulsion device. They are annular crossed-field devices in which a voltage drop is applied across a steady radial magnetic field. Electrons in the device become trapped in an strong azimuthal Hall current. They impact injected neutral atoms, ionizing them. These ions are then accelerated out of the channel by the electric field, which generates thrust.

Hall thrusters offer moderate to high specific impulse and high thrust density compared to other electric propulsion systems, and can achieve total efficiencies higher than 50%. They are commonly used for in-space propulsion for commercial communications and surveillance satellites as well as increasingly for deep space missions.

+Background · HallThruster.jl

Background

Hall thrusters are a widely-used class of spacecraft electric propulsion device. They are annular crossed-field devices in which a voltage drop is applied across a steady radial magnetic field. Electrons in the device become trapped in an strong azimuthal Hall current. They impact injected neutral atoms, ionizing them. These ions are then accelerated out of the channel by the electric field, which generates thrust.

Hall thrusters offer moderate to high specific impulse and high thrust density compared to other electric propulsion systems, and can achieve total efficiencies higher than 50%. They are commonly used for in-space propulsion for commercial communications and surveillance satellites as well as increasingly for deep space missions.

diff --git a/dev/boundary_conditions/index.html b/dev/boundary_conditions/index.html index fc986afc..2be157d2 100644 --- a/dev/boundary_conditions/index.html +++ b/dev/boundary_conditions/index.html @@ -1,2 +1,2 @@ -Boundary Conditions · HallThruster.jl

Boundary Conditions

HallThruster.jl solves fluid hyperbolic conservation laws. As such, boundary conditions on at least one side have to be specified. Dirichlet boundary conditions are applied on both sides in the potential equation.

Background

The outflow side, which in the 1D domain conincides with the cathode, is usually left unspecified, i.e. no boundary conditions are applied. On the left side, corresponding to the anode, the neutral mass inflow is fixed, while the ion velocity is forced to be at least the Bohm velocity. The anode mass flow rate can be set in the Configuration. The potential employs Dirichlet boundary conditions at both anode and cathode (subject to change once a more accurate anode sheath model has been implemented). Currently the cathode potential is set to zero, and the anode potential can be set using discharge_voltage in the Configuration. The electron energy uses Dirichlet boundaries as well on both the anode and cathode, usually fixed to 2 or 3 eV. Note that this does not correspond to Dirichlet boundaries on the internal energy equations, since this is solved for the product of internal energy and density.

+Boundary Conditions · HallThruster.jl

Boundary Conditions

HallThruster.jl solves fluid hyperbolic conservation laws. As such, boundary conditions on at least one side have to be specified. Dirichlet boundary conditions are applied on both sides in the potential equation.

Background

The outflow side, which in the 1D domain conincides with the cathode, is usually left unspecified, i.e. no boundary conditions are applied. On the left side, corresponding to the anode, the neutral mass inflow is fixed, while the ion velocity is forced to be at least the Bohm velocity. The anode mass flow rate can be set in the Configuration. The potential employs Dirichlet boundary conditions at both anode and cathode (subject to change once a more accurate anode sheath model has been implemented). Currently the cathode potential is set to zero, and the anode potential can be set using discharge_voltage in the Configuration. The electron energy uses Dirichlet boundaries as well on both the anode and cathode, usually fixed to 2 or 3 eV. Note that this does not correspond to Dirichlet boundaries on the internal energy equations, since this is solved for the product of internal energy and density.

diff --git a/dev/citation/index.html b/dev/citation/index.html index 95ea1774..20eca17f 100644 --- a/dev/citation/index.html +++ b/dev/citation/index.html @@ -1,2 +1,2 @@ -Citation · HallThruster.jl

Citation

If you use the code in a published scientific paper, we request that you cite the code. We will have a DOI soon.

+Citation · HallThruster.jl

Citation

If you use the code in a published scientific paper, we request that you cite the code. We will have a DOI soon.

diff --git a/dev/collisions/index.html b/dev/collisions/index.html index 42ef002d..247ce95e 100644 --- a/dev/collisions/index.html +++ b/dev/collisions/index.html @@ -57,4 +57,4 @@ rate_coeff = FunctionWrapper{Float64, Tuple{Float64}}(kiz) ) return rxn -end

The above advice works identically for defining your own ExcitationModel, with the sole exception that ExcitationReaction objects do not have a product field. Similarly, we can define our own ElectronNeutralModel, noting that ElasticCollisions do not have an energy field or a product field. We would also not need to define maximum_charge_state for an ElectronNeutralModel.

+end

The above advice works identically for defining your own ExcitationModel, with the sole exception that ExcitationReaction objects do not have a product field. Similarly, we can define our own ElectronNeutralModel, noting that ElasticCollisions do not have an energy field or a product field. We would also not need to define maximum_charge_state for an ElectronNeutralModel.

diff --git a/dev/config/index.html b/dev/config/index.html index f166fde8..f4c4daf1 100644 --- a/dev/config/index.html +++ b/dev/config/index.html @@ -1,2 +1,2 @@ -Configuration · HallThruster.jl

Configuration

The Config struct contains all of the options you need to run a simulation. On this page, we will explain what options are available and what they do. Note that all arguments must be provided as keywords.

There are four absolutely mandatory arguments. These are:

  • discharge_voltage: The difference in potential between the anode and cathode, in Volts. This is used to set the left boundary condition. If the cathode potential is zero, then the anode potential is equal to the discharge voltage.
  • thruster: This is a Thruster object containing important geometric and magnetic information about the thruster being simulated. See the page about Thrusters for more.
  • domain: This is a Tuple containing the locations of the left and right boundaries of the simulation domain, in meters. For instance, if your simulation domain starts at z = 0.0 and is 5 cm long, you would write domain = (0.0, 0.05).
  • anode_mass_flow_rate: The propellant mass flow rate at the anode, in kg/s

Aside from these arguments, all others have default values provided. These are detailed below:

  • initial_condition: A function used for initializing the simulation. See the page about Initialization for more information.
  • ncharge: Number of charge states to simulate. Defaults to 1.
  • propellant: Propellant gas. Defaults to Xenon. Other options are described on the Propellants page.
  • scheme: Numerical scheme to employ for integrating the ion equations. This is a HyperbolicScheme struct with fields flux_function, limiter, and reconstruct. Defaults to HyperbolicScheme(flux_function = rusanov, limiter = minmod, reconstruct = false). For more information, see Fluxes.
  • cathode_potential: The potential at the right boundary of the simulation. Defaults to 0.0
  • anode_Te: The electron temperature at the anode, in eV. Acts as a Dirichlet boundary condition for the energy equation. Defaults to 3.0.
  • cathode_Te: The electron temperature at the cathode, in eV. Acts as a Dirichlet boundary condition for the energy equation. Defaults to 3.0.
  • wall_loss_model: How radial losses due to sheaths are computed. Defaults to ConstantSheathPotential(sheath_potential=-20.0, inner_loss_coeff = 1.0, outer_loss_coeff = 1.0), which is the loss term from LANDMARK case 1. Other wall loss models are described on the Wall Loss Models page.
  • wall_collision_freq: Extra "wall collisions" to be added to the total electron momentum transfer collision frequency inside of the channel. Units of Hz. Defaults to 0.0.
  • anom_model: Model for computing the anomalous collision frequency. Defaults to TwoZoneBohm(1/160, 1/16). Further details on the Anomalous Transport page.
  • conductivity_model: Model for the perpendicular electron thermal conductivity. Defaults to Mitchner(). Further details can be found on the Electron Thermal Conductivity page.
  • ionization_model: Model for ionization. Defaults to IonizationLookup(), which uses a lookup table to compute ionization rate coefficients as a function of electron energy. Other options are described on the Collisions and Reactions page.
  • excitation_model: Model for excitation reactions. Defaults to ExcitationLookup(), which uses a lookup table to compute excitation rate coefficients as a function of electron energy.. Other models are described on the Collisions and Reactions page.
  • electron_neutral_model: Model for elastic scattering collisions between electrons and neutral atoms. Defaults to ElectronNeutralLookup(), which uses a lookup table to compute the elastic scattering rate coefficient. Other models are described on the Collisions and Reactions page.
  • electron_ion_collisions: Whether to include electron-ion collisions. Defaults to true. More information on the Collisions and Reactions page.
  • neutral_velocity: Neutral velocity in m/s. Defaults to 300.0
  • neutral_temperature: Neutral temperature in Kelvins. Defaults to 300.0.
  • ion_temperature: Ion temperature in Kelvins. Defaults to 100.0
  • implicit_energy: The degree to which the energy is solved implicitly. 0.0 is a fully-explicit forward Euler, 0.5 is Crank-Nicholson, and 1.0 is backward Euler. Defaults to 1.0.
  • min_number_density: Minimum allowable number density for any species. Defaults to 1e6
  • min_electron_temperature: Minimum allowable electron temperature. Defaults to 1.0.
  • magnetic_field_scale: Factor by which the magnetic field is increased or decreased compared to the one in the provided Thruster struct. Defaults to 1.0.
  • source_neutrals: Extra user-provided neutral source term. Can be an arbitrary function, but must take (U, params, i) as arguments. Defaults to Returns(0.0). See User-Provided Source Terms for more information.
  • source_ion_continuity: Vector of extra source terms for ion continuity, one for each charge state. Defaults to fill(Returns(0.0), ncharge) . See User-Provided Source Terms for more information.
  • source_ion_momentum: Vector of extra source terms for ion momentum, one for each charge state. Defaults to fill(Returns(0.0), ncharge) . See User-Provided Source Terms for more information.
  • source_potential: Extra source term for potential equation. Defaults to Returns(0.0). See User-Provided Source Terms for more information.
  • source_electron_energy: Extra source term for electron energy equation. Defaults to Returns(0.0). See User-Provided Source Terms for more information.
  • LANDMARK: Whether we are using the LANDMARK physics model. This affects whether certain terms are included in the equations, such as electron and heavy species momentum transfer due to ionization and the form of the electron thermal conductivity. Also affects whether we use an anode sheath model. Defaults to false.
  • ion_wall_losses: Whether we model ion losses to the walls. Defaults to false.
  • solve_background_neutrals: Turns on an additional mass flow rate due to neutral ingestion
  • background_pressure: The pressure of the background neutrals, in Pascals
  • background_neutral_temperature: The temperature of the background neutrals, in K
  • anode_boundary_condition: Can be either :sheath or :dirichlet
  • anom_smoothing_iters: How many times to smooth the anomalous transport profile
  • solve_plume: Whether to solve for plume area variation and divergence losses
  • electron_losses_in_plume: Whether electron radial/wall losses are applied in the plume region
+Configuration · HallThruster.jl

Configuration

The Config struct contains all of the options you need to run a simulation. On this page, we will explain what options are available and what they do. Note that all arguments must be provided as keywords.

There are four absolutely mandatory arguments. These are:

  • discharge_voltage: The difference in potential between the anode and cathode, in Volts. This is used to set the left boundary condition. If the cathode potential is zero, then the anode potential is equal to the discharge voltage.
  • thruster: This is a Thruster object containing important geometric and magnetic information about the thruster being simulated. See the page about Thrusters for more.
  • domain: This is a Tuple containing the locations of the left and right boundaries of the simulation domain, in meters. For instance, if your simulation domain starts at z = 0.0 and is 5 cm long, you would write domain = (0.0, 0.05).
  • anode_mass_flow_rate: The propellant mass flow rate at the anode, in kg/s

Aside from these arguments, all others have default values provided. These are detailed below:

  • initial_condition: A function used for initializing the simulation. See the page about Initialization for more information.
  • ncharge: Number of charge states to simulate. Defaults to 1.
  • propellant: Propellant gas. Defaults to Xenon. Other options are described on the Propellants page.
  • scheme: Numerical scheme to employ for integrating the ion equations. This is a HyperbolicScheme struct with fields flux_function, limiter, and reconstruct. Defaults to HyperbolicScheme(flux_function = rusanov, limiter = minmod, reconstruct = false). For more information, see Fluxes.
  • cathode_potential: The potential at the right boundary of the simulation. Defaults to 0.0
  • anode_Te: The electron temperature at the anode, in eV. Acts as a Dirichlet boundary condition for the energy equation. Defaults to 3.0.
  • cathode_Te: The electron temperature at the cathode, in eV. Acts as a Dirichlet boundary condition for the energy equation. Defaults to 3.0.
  • wall_loss_model: How radial losses due to sheaths are computed. Defaults to ConstantSheathPotential(sheath_potential=-20.0, inner_loss_coeff = 1.0, outer_loss_coeff = 1.0), which is the loss term from LANDMARK case 1. Other wall loss models are described on the Wall Loss Models page.
  • wall_collision_freq: Extra "wall collisions" to be added to the total electron momentum transfer collision frequency inside of the channel. Units of Hz. Defaults to 0.0.
  • anom_model: Model for computing the anomalous collision frequency. Defaults to TwoZoneBohm(1/160, 1/16). Further details on the Anomalous Transport page.
  • conductivity_model: Model for the perpendicular electron thermal conductivity. Defaults to Mitchner(). Further details can be found on the Electron Thermal Conductivity page.
  • ionization_model: Model for ionization. Defaults to IonizationLookup(), which uses a lookup table to compute ionization rate coefficients as a function of electron energy. Other options are described on the Collisions and Reactions page.
  • excitation_model: Model for excitation reactions. Defaults to ExcitationLookup(), which uses a lookup table to compute excitation rate coefficients as a function of electron energy.. Other models are described on the Collisions and Reactions page.
  • electron_neutral_model: Model for elastic scattering collisions between electrons and neutral atoms. Defaults to ElectronNeutralLookup(), which uses a lookup table to compute the elastic scattering rate coefficient. Other models are described on the Collisions and Reactions page.
  • electron_ion_collisions: Whether to include electron-ion collisions. Defaults to true. More information on the Collisions and Reactions page.
  • neutral_velocity: Neutral velocity in m/s. Defaults to 300.0
  • neutral_temperature: Neutral temperature in Kelvins. Defaults to 300.0.
  • ion_temperature: Ion temperature in Kelvins. Defaults to 100.0
  • implicit_energy: The degree to which the energy is solved implicitly. 0.0 is a fully-explicit forward Euler, 0.5 is Crank-Nicholson, and 1.0 is backward Euler. Defaults to 1.0.
  • min_number_density: Minimum allowable number density for any species. Defaults to 1e6
  • min_electron_temperature: Minimum allowable electron temperature. Defaults to 1.0.
  • magnetic_field_scale: Factor by which the magnetic field is increased or decreased compared to the one in the provided Thruster struct. Defaults to 1.0.
  • source_neutrals: Extra user-provided neutral source term. Can be an arbitrary function, but must take (U, params, i) as arguments. Defaults to Returns(0.0). See User-Provided Source Terms for more information.
  • source_ion_continuity: Vector of extra source terms for ion continuity, one for each charge state. Defaults to fill(Returns(0.0), ncharge) . See User-Provided Source Terms for more information.
  • source_ion_momentum: Vector of extra source terms for ion momentum, one for each charge state. Defaults to fill(Returns(0.0), ncharge) . See User-Provided Source Terms for more information.
  • source_potential: Extra source term for potential equation. Defaults to Returns(0.0). See User-Provided Source Terms for more information.
  • source_electron_energy: Extra source term for electron energy equation. Defaults to Returns(0.0). See User-Provided Source Terms for more information.
  • LANDMARK: Whether we are using the LANDMARK physics model. This affects whether certain terms are included in the equations, such as electron and heavy species momentum transfer due to ionization and the form of the electron thermal conductivity. Also affects whether we use an anode sheath model. Defaults to false.
  • ion_wall_losses: Whether we model ion losses to the walls. Defaults to false.
  • solve_background_neutrals: Turns on an additional mass flow rate due to neutral ingestion
  • background_pressure: The pressure of the background neutrals, in Pascals
  • background_neutral_temperature: The temperature of the background neutrals, in K
  • anode_boundary_condition: Can be either :sheath or :dirichlet
  • anom_smoothing_iters: How many times to smooth the anomalous transport profile
  • solve_plume: Whether to solve for plume area variation and divergence losses
  • apply_thrust_divergence_correction: Whether the thrust output by HallThruster.jl should include a divergence correction factor of cos(δ)^2
  • electron_losses_in_plume: Whether electron radial/wall losses are applied in the plume region
diff --git a/dev/contribution/index.html b/dev/contribution/index.html index aa9c179a..f82b8aa6 100644 --- a/dev/contribution/index.html +++ b/dev/contribution/index.html @@ -1,2 +1,2 @@ -Contribution · HallThruster.jl

Contribution

We welcome all contributions. If you would like a new feature added, please open an issue on the HallThruster.jl repo, and if you modify the code on your end, please consider opening a pull request and contributing back to the main repo.

+Contribution · HallThruster.jl

Contribution

We welcome all contributions. If you would like a new feature added, please open an issue on the HallThruster.jl repo, and if you modify the code on your end, please consider opening a pull request and contributing back to the main repo.

diff --git a/dev/electron_thermal_conductivity/index.html b/dev/electron_thermal_conductivity/index.html index 34f7d9d0..1ff0e68d 100644 --- a/dev/electron_thermal_conductivity/index.html +++ b/dev/electron_thermal_conductivity/index.html @@ -20,4 +20,4 @@ end return κ -end

We could now employ this model by setting `conductivitymodel = BraginskiiClassical()' in the user-defined configuration.

+end

We could now employ this model by setting `conductivitymodel = BraginskiiClassical()' in the user-defined configuration.

diff --git a/dev/fluxes/index.html b/dev/fluxes/index.html index 163bd075..cdaf78ca 100644 --- a/dev/fluxes/index.html +++ b/dev/fluxes/index.html @@ -1,2 +1,2 @@ -Fluxes · HallThruster.jl

Fluxes

HallThruster.jl uses the Finite Volume method, and as such the face values of the fluxes need to be reconstructed. See Numerics for more information.

The fluxes $F_{_{i+\frac{1}{2}}}$ and $F_{_{i-\frac{1}{2}}}$ are reconstructed at the cell interfaces, and for this flux reconstruction multiple options are available. These are set using the object HyperbolicScheme consisting of fields flux, limiter, and reconstruct. Three different flux approximations are available.

FluxDescription
upwindSimple first order accurate flux approximation, that as a results does not distinguish between cell centered and cell average values and adapts reconstruction according to sign of advection velocity. Very diffusive. No Riemann solver or approximation.
HLLEApproximate Riemann solver. The Harten-Lax-van Leer-Einfeldt scheme approximates a Riemann problem with three constant states. see reference. The scheme is positively-conservative if stability bounds for maximum and minimum wavespeeds are met, which makes it useful in its application with HallThruster.jl. First order accurate in space. B. Einfeldt. On godunov-type methods for gas dynamics. Journal of Computational Physics, 25:294-318, 1988.
rusanovApproximate Riemann solver. Also known as the local Lax-Friedrich flux. Has slighlty modified choice of wave speeds. Adds viscosity to a centered flux. More diffusive than HLLE. Chi-Wang Shu, Lecture Notes: Numerical Methods for Hyperbolic Conservation Laws (AM257)

These flux approximations are all first order accurate in space (piecewise constant recontruction), but can be extended to piecewise linear reconstruction within a cell. To satisfy stability bounds and keep the scheme total variation diminishing (TVD), it has to be coupled with a limiter. Many limiters have been proposed, the ones implemented in HallThruster.jl are the following: koren, minmod, osher, van_albada, van_leer. If the field reconstruction is set to true, the selected limiter will be used.

+Fluxes · HallThruster.jl

Fluxes

HallThruster.jl uses the Finite Volume method, and as such the face values of the fluxes need to be reconstructed. See Numerics for more information.

The fluxes $F_{_{i+\frac{1}{2}}}$ and $F_{_{i-\frac{1}{2}}}$ are reconstructed at the cell interfaces, and for this flux reconstruction multiple options are available. These are set using the object HyperbolicScheme consisting of fields flux, limiter, and reconstruct. Three different flux approximations are available.

FluxDescription
upwindSimple first order accurate flux approximation, that as a results does not distinguish between cell centered and cell average values and adapts reconstruction according to sign of advection velocity. Very diffusive. No Riemann solver or approximation.
HLLEApproximate Riemann solver. The Harten-Lax-van Leer-Einfeldt scheme approximates a Riemann problem with three constant states. see reference. The scheme is positively-conservative if stability bounds for maximum and minimum wavespeeds are met, which makes it useful in its application with HallThruster.jl. First order accurate in space. B. Einfeldt. On godunov-type methods for gas dynamics. Journal of Computational Physics, 25:294-318, 1988.
rusanovApproximate Riemann solver. Also known as the local Lax-Friedrich flux. Has slighlty modified choice of wave speeds. Adds viscosity to a centered flux. More diffusive than HLLE. Chi-Wang Shu, Lecture Notes: Numerical Methods for Hyperbolic Conservation Laws (AM257)

These flux approximations are all first order accurate in space (piecewise constant recontruction), but can be extended to piecewise linear reconstruction within a cell. To satisfy stability bounds and keep the scheme total variation diminishing (TVD), it has to be coupled with a limiter. Many limiters have been proposed, the ones implemented in HallThruster.jl are the following: koren, minmod, osher, van_albada, van_leer. If the field reconstruction is set to true, the selected limiter will be used.

diff --git a/dev/grid/index.html b/dev/grid/index.html index 3c70a3c9..a5915917 100644 --- a/dev/grid/index.html +++ b/dev/grid/index.html @@ -6,4 +6,4 @@ return base_density + exp(-((z - midpoint) / (width))^2) end -my_grid = UnevenGrid(30, my_density)

HallThruster.jl expects a custom density function to take four arguments–-z (the axial location), z0 and z1 (the left and right edges of the domain, respectively, in meters), and L, the channel length. These are automatically populated based on the domain and thruster you pass to the configuration file.

With the density function defined, we can then compare this to our other grids.

+my_grid = UnevenGrid(30, my_density)

HallThruster.jl expects a custom density function to take four arguments–-z (the axial location), z0 and z1 (the left and right edges of the domain, respectively, in meters), and L, the channel length. These are automatically populated based on the domain and thruster you pass to the configuration file.

With the density function defined, we can then compare this to our other grids.

diff --git a/dev/index.html b/dev/index.html index 6e652a78..cdc491ba 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,2 +1,2 @@ -Home · HallThruster.jl

HallThruster.jl

Repository link

HallThruster.jl is an open-source, 1D fluid Hall thruster code written in Julia. It was initially developed by the University of Michigan's Plasmadynamics and Electric Propulsion Laboratory and is licensed under the MIT license.

Installation

To install HallThruster.jl, you must first install Julia 1.7 or above from the official Julia site, or by using juliaup. We recommend using the latest Julia release when possible. Once installed, launch Julia and type

julia> ]add https://github.com/UM-PEPL/HallThruster.jl

This will install HallThruster.jl using Julia's package manager. For details on setting up and running Hall thruster simulations, see the official documentation. A Tutorial is available here.

Contribution

Users are welcome to suggest and implement features for the code, as well as report bugs or numerical issues they encounter. Please feel free to open an issue on this repository describing your desired change or bug-fix. Pull requests are also welcome!

+Home · HallThruster.jl

HallThruster.jl

Repository link

HallThruster.jl is an open-source, 1D fluid Hall thruster code written in Julia. It was initially developed by the University of Michigan's Plasmadynamics and Electric Propulsion Laboratory and is licensed under the MIT license.

Installation

To install HallThruster.jl, you must first install Julia 1.7 or above from the official Julia site, or by using juliaup. We recommend using the latest Julia release when possible. Once installed, launch Julia and type

julia> ]add https://github.com/UM-PEPL/HallThruster.jl

This will install HallThruster.jl using Julia's package manager. For details on setting up and running Hall thruster simulations, see the official documentation. A Tutorial is available here.

Contribution

Users are welcome to suggest and implement features for the code, as well as report bugs or numerical issues they encounter. Please feel free to open an issue on this repository describing your desired change or bug-fix. Pull requests are also welcome!

diff --git a/dev/initialization/index.html b/dev/initialization/index.html index 4bf39ecd..a645ebf7 100644 --- a/dev/initialization/index.html +++ b/dev/initialization/index.html @@ -37,4 +37,4 @@ # output -true +true diff --git a/dev/internals/index.html b/dev/internals/index.html index 317aec69..605bea4b 100644 --- a/dev/internals/index.html +++ b/dev/internals/index.html @@ -1,39 +1,39 @@ -Internals · HallThruster.jl
HallThruster.LOOKUP_ZSConstant

Lookup for thermal conductivity coefficients, from Table 1 of S. I. Braginskii, in Reviews of Plasma Physics (1965), Vol. 1, p. 205.

source
HallThruster.BohmType
Bohm(c) <: AnomalousTransportModel

Model where the anomalous collision frequency scales with the electron cyclotron frequency ωce times some scaling factor c

source
HallThruster.BraginskiiType
Braginskii conductivity model for fully-ionized plasmasa
-S. I. Braginskii, in Reviews of Plasma Physics (1965), Vol. 1, p. 205.
source
HallThruster.ConfigType
struct Config{A<:HallThruster.AnomalousTransportModel, TC<:HallThruster.ThermalConductivityModel, W<:HallThruster.WallLossModel, IZ<:HallThruster.IonizationModel, EX<:HallThruster.ExcitationModel, EN<:HallThruster.ElectronNeutralModel, HET<:HallThruster.Thruster, S_N, S_IC, S_IM, S_ϕ, S_E, T<:HallThruster.TransitionFunction, IC<:HallThruster.InitialCondition, HS<:HallThruster.HyperbolicScheme}

Hall thruster configuration struct. Only four mandatory fields: discharge_voltage, thruster, anode_mass_flow_rate, and domain.

Fields

  • discharge_voltage::Float64

  • cathode_potential::Float64

  • anode_Te::Float64

  • cathode_Te::Float64

  • wall_loss_model::HallThruster.WallLossModel

  • neutral_velocity::Float64

  • neutral_temperature::Float64

  • implicit_energy::Float64

  • propellant::HallThruster.Gas

  • ncharge::Int64

  • ion_temperature::Float64

  • anom_model::HallThruster.AnomalousTransportModel

  • conductivity_model::HallThruster.ThermalConductivityModel

  • ionization_model::HallThruster.IonizationModel

  • excitation_model::HallThruster.ExcitationModel

  • electron_neutral_model::HallThruster.ElectronNeutralModel

  • electron_ion_collisions::Bool

  • min_number_density::Float64

  • min_electron_temperature::Float64

  • transition_function::HallThruster.TransitionFunction

  • initial_condition::HallThruster.InitialCondition

  • magnetic_field_scale::Float64

  • source_neutrals::Any

  • source_ion_continuity::Any

  • source_ion_momentum::Any

  • source_potential::Any

  • source_energy::Any

  • scheme::HallThruster.HyperbolicScheme

  • thruster::HallThruster.Thruster

  • domain::Tuple{Float64, Float64}

  • LANDMARK::Bool

  • anode_mass_flow_rate::Float64

  • ion_wall_losses::Bool

  • solve_background_neutrals::Bool

  • background_pressure::Float64

  • background_neutral_temperature::Float64

  • anode_boundary_condition::Symbol

  • anom_smoothing_iters::Int64

  • solve_plume::Bool

  • electron_plume_loss_scale::Float64

source
HallThruster.ExcitationLookupType
ExcitationLookup(;[directories::Vector{String} = String[]])

Default excitation model for HallThruster.jl. Reads excitation rate coefficients from file. Looks (preferentially) in provided directories and in the reactions subfolder for rate coefficient files

source
HallThruster.GasType
Gas

A chemical element in the gaseous state. Container for element properties used in fluid computations.

Fields

name::String Full name of gas (i.e. Xenon)

short_name::String Short name/symbol (i.e. Xe for Xenon)

γ::Float64 Specific heat ratio / adiabatic index

M::Float64 Molar mass (grams/mol) or atomic mass units

m::Float64 Mass of atom in kg

cp::Float64 Specific heat at constant pressure in J / kg / K

cv::Float64 Specific heat at constant volume in J / kg / K

R::Float64 Gas constant in J / kg / K

source
HallThruster.GasMethod
Gas(name::String, short_name::String; γ::Float64, M::Float64)

Instantiate a new Gas, providing a name, short name, the adiabatic index, and the molar mass. Other gas properties, including gas constant, specific heats at constant pressure/volume, and mass of atom/molecule in kg will are then computed.

julia> Gas("Xenon", "Xe", γ = 5/3, M = 83.798)
-Xenon
source
HallThruster.Grid1DMethod
Grid1D(geometry, z_edge)

Given 1-D edge coordinates and thruster geometry, compute cell centers and cell volumes for grid

source
HallThruster.IonizationLookupType
IonizationLookup(;[directories::Vector{String} = String[]])

Default ionization model for HallThruster.jl. Reads ionization rate coefficients from file. Looks (preferentially) in provided directories and in the reactions subfolder for rate coefficient files

source
HallThruster.LandmarkExcitationLookupType
LandmarkExcitationLookup()

Excitation model for the LANDMARK benchmark.

Reads excitation rate coefficients from the landmark/landmark_rates.csv file in the HallThruster.jl main directory. Supports only singly-charged Xenon.

source
HallThruster.LandmarkIonizationLookupType
LandmarkIonizationLookup()

Ionization model for the LANDMARK benchmark.

Reads ionization rate coefficients from the landmark/landmark_rates.csv file in the HallThruster.jl main directory. Supports only singly-charged Xenon.

source
HallThruster.MitchnerType
Mitchner-Kruger conductivity model for partially-ionized plasmas
-M. Mitchner and C. H. Kruger, Jr., Partially Ionized Gases (1973). Pg. 94
source
HallThruster.MultiLogBohmType
MultiLogBohm(zs, cs) <: AnomalousTransportModel

Model similar to that employed in Hall2De, where the mobility is Bohm-like (i.e. νan(z) = c(z) * ωce(z)) and z is in meters.

The function c(z) is defined by a sequence of nodes (z, c) provided by the user. At z = z[1], c(z) = c[1], and so forth.

At z[i] < z < z[i+1], log(c) is defined by linearly interpolating between log(c[i]) and log(c[i+1]).

For z < z[1], c = c[1] and for z > z[end], c(z) = c[end].

The user may also provide a single array of [z[1], z[2], ..., z[end], c[1], c[2], ..., c[end]]. The number of z values must be equal to the number of c values.

source
HallThruster.ShiftedTwoZoneBohmType
ShiftedTwoZoneBohm(coeffs, z0, dz, alpha, pstar) <: AnomalousTransportModel

Model where the anomalous collision frequency has two values: c1 * ωce before some transition location and c2 * ωce after. Takes two arguments: c1 and c2. The transition between these values can be smoothed by the user-provided transition function. The location of the transition is based on the background pressure and the user-provided coefficients.

source
HallThruster.SpeciesType
Species

Represents a gas with a specific charge state. In a plasma, different ionization states of the same gas may coexist, so we need to be able to differentiate between these.

julia> Species(Xenon, 0)
+Internals · HallThruster.jl
HallThruster.LOOKUP_ZSConstant

Lookup for thermal conductivity coefficients, from Table 1 of S. I. Braginskii, in Reviews of Plasma Physics (1965), Vol. 1, p. 205.

source
HallThruster.BohmType
Bohm(c) <: AnomalousTransportModel

Model where the anomalous collision frequency scales with the electron cyclotron frequency ωce times some scaling factor c

source
HallThruster.BraginskiiType
Braginskii conductivity model for fully-ionized plasmasa
+S. I. Braginskii, in Reviews of Plasma Physics (1965), Vol. 1, p. 205.
source
HallThruster.ConfigType
struct Config{A<:HallThruster.AnomalousTransportModel, TC<:HallThruster.ThermalConductivityModel, W<:HallThruster.WallLossModel, IZ<:HallThruster.IonizationModel, EX<:HallThruster.ExcitationModel, EN<:HallThruster.ElectronNeutralModel, HET<:HallThruster.Thruster, S_N, S_IC, S_IM, S_ϕ, S_E, T<:HallThruster.TransitionFunction, IC<:HallThruster.InitialCondition, HS<:HallThruster.HyperbolicScheme}

Hall thruster configuration struct. Only four mandatory fields: discharge_voltage, thruster, anode_mass_flow_rate, and domain.

Fields

  • discharge_voltage::Float64

  • cathode_potential::Float64

  • anode_Te::Float64

  • cathode_Te::Float64

  • wall_loss_model::HallThruster.WallLossModel

  • neutral_velocity::Float64

  • neutral_temperature::Float64

  • implicit_energy::Float64

  • propellant::HallThruster.Gas

  • ncharge::Int64

  • ion_temperature::Float64

  • anom_model::HallThruster.AnomalousTransportModel

  • conductivity_model::HallThruster.ThermalConductivityModel

  • ionization_model::HallThruster.IonizationModel

  • excitation_model::HallThruster.ExcitationModel

  • electron_neutral_model::HallThruster.ElectronNeutralModel

  • electron_ion_collisions::Bool

  • min_number_density::Float64

  • min_electron_temperature::Float64

  • transition_function::HallThruster.TransitionFunction

  • initial_condition::HallThruster.InitialCondition

  • magnetic_field_scale::Float64

  • source_neutrals::Any

  • source_ion_continuity::Any

  • source_ion_momentum::Any

  • source_potential::Any

  • source_energy::Any

  • scheme::HallThruster.HyperbolicScheme

  • thruster::HallThruster.Thruster

  • domain::Tuple{Float64, Float64}

  • LANDMARK::Bool

  • anode_mass_flow_rate::Float64

  • ion_wall_losses::Bool

  • solve_background_neutrals::Bool

  • background_pressure::Float64

  • background_neutral_temperature::Float64

  • anode_boundary_condition::Symbol

  • anom_smoothing_iters::Int64

  • solve_plume::Bool

  • apply_thrust_divergence_correction::Bool

  • electron_plume_loss_scale::Float64

source
HallThruster.ExcitationLookupType
ExcitationLookup(;[directories::Vector{String} = String[]])

Default excitation model for HallThruster.jl. Reads excitation rate coefficients from file. Looks (preferentially) in provided directories and in the reactions subfolder for rate coefficient files

source
HallThruster.GasType
Gas

A chemical element in the gaseous state. Container for element properties used in fluid computations.

Fields

name::String Full name of gas (i.e. Xenon)

short_name::String Short name/symbol (i.e. Xe for Xenon)

γ::Float64 Specific heat ratio / adiabatic index

M::Float64 Molar mass (grams/mol) or atomic mass units

m::Float64 Mass of atom in kg

cp::Float64 Specific heat at constant pressure in J / kg / K

cv::Float64 Specific heat at constant volume in J / kg / K

R::Float64 Gas constant in J / kg / K

source
HallThruster.GasMethod
Gas(name::String, short_name::String; γ::Float64, M::Float64)

Instantiate a new Gas, providing a name, short name, the adiabatic index, and the molar mass. Other gas properties, including gas constant, specific heats at constant pressure/volume, and mass of atom/molecule in kg will are then computed.

julia> Gas("Xenon", "Xe", γ = 5/3, M = 83.798)
+Xenon
source
HallThruster.Grid1DMethod
Grid1D(geometry, z_edge)

Given 1-D edge coordinates and thruster geometry, compute cell centers and cell volumes for grid

source
HallThruster.IonizationLookupType
IonizationLookup(;[directories::Vector{String} = String[]])

Default ionization model for HallThruster.jl. Reads ionization rate coefficients from file. Looks (preferentially) in provided directories and in the reactions subfolder for rate coefficient files

source
HallThruster.LandmarkExcitationLookupType
LandmarkExcitationLookup()

Excitation model for the LANDMARK benchmark.

Reads excitation rate coefficients from the landmark/landmark_rates.csv file in the HallThruster.jl main directory. Supports only singly-charged Xenon.

source
HallThruster.LandmarkIonizationLookupType
LandmarkIonizationLookup()

Ionization model for the LANDMARK benchmark.

Reads ionization rate coefficients from the landmark/landmark_rates.csv file in the HallThruster.jl main directory. Supports only singly-charged Xenon.

source
HallThruster.MitchnerType
Mitchner-Kruger conductivity model for partially-ionized plasmas
+M. Mitchner and C. H. Kruger, Jr., Partially Ionized Gases (1973). Pg. 94
source
HallThruster.MultiLogBohmType
MultiLogBohm(zs, cs) <: AnomalousTransportModel

Model similar to that employed in Hall2De, where the mobility is Bohm-like (i.e. νan(z) = c(z) * ωce(z)) and z is in meters.

The function c(z) is defined by a sequence of nodes (z, c) provided by the user. At z = z[1], c(z) = c[1], and so forth.

At z[i] < z < z[i+1], log(c) is defined by linearly interpolating between log(c[i]) and log(c[i+1]).

For z < z[1], c = c[1] and for z > z[end], c(z) = c[end].

The user may also provide a single array of [z[1], z[2], ..., z[end], c[1], c[2], ..., c[end]]. The number of z values must be equal to the number of c values.

source
HallThruster.ShiftedGaussianBohmType
ShiftedGaussianBohm(trough_location, trough_width, trough_depth, z0, dz, alpha, pstar) <: AnomalousTransportModel

Model in which the anomalous collision frequency is Bohm-like (νan ~ ωce), except in a Gaussian-shaped region defined by the parameters troughlocation, troughwidth, troughmax, and troughmin where the collision frequency is lower. The location of the trough is based on the background pressure and the user-provided coefficients.

Arguments

  • trough_location: the axial position (in meters) of the mean of the Gaussian trough
  • trough_width: the standard deviation (in meters) of the Gaussian trough
  • trough_min: the minimum Hall parameter
  • trough_max: the maximum Hall parameter
  • z0: the furthest upstream displacement permitted at high back-pressures, relative to trough_location
  • dz: the maximum allowable amount of axial displacement
  • pstar: the background pressure at which the shift upstream halts/plateaus
  • alpha: the slope of the pressure response curve, with a higher value corresponding to a steeper pressure response
source
HallThruster.ShiftedMultiBohmType
ShiftedMultiBohm(zs, cs, z0, dz, alpha, pstar) <: AnomalousTransportModel

A version of MultiLogBohm where the coefficients are shifted depending on the background pressure.

source
HallThruster.ShiftedTwoZoneBohmType
ShiftedTwoZoneBohm(coeffs, z0, dz, alpha, pstar) <: AnomalousTransportModel

Model where the anomalous collision frequency has two values: c1 * ωce before some transition location and c2 * ωce after. Takes two arguments: c1 and c2. The transition between these values can be smoothed by the user-provided transition function. The location of the transition is based on the background pressure and the user-provided coefficients.

source
HallThruster.SpeciesType
Species

Represents a gas with a specific charge state. In a plasma, different ionization states of the same gas may coexist, so we need to be able to differentiate between these.

julia> Species(Xenon, 0)
 Xe
 
 julia> Species(Xenon, 1)
 Xe+
 
 julia> Species(Xenon, 3)
-Xe3+
source
HallThruster.ThrusterType
Thruster

Struct containing information about a Hall thruster. This includes a name, geometry (a Geometry1D object), magnetic_field (radial magnetic field along centerline, a function which takes z in meters and outputs B in Tesla), and a shielded (a flag indicating whether the thruster is magnetically-shielded).

Fields

  • name::String

  • geometry::HallThruster.Geometry1D

  • magnetic_field::Any

  • shielded::Bool

source
HallThruster.TwoZoneBohmType
TwoZoneBohm(c1, c2) <: AnomalousTransportModel

Model where the anomalous collision frequency has two values: c1 * ωce inside the channel and c2 * ωce outside of the channel. Takes two arguments: c1 and c2. The transition between these values can be smoothed by the user-provided transition function.

source
HallThruster.WallLossModelType
abstract type WallLossModel

Abstract type for wall loss models in the electron energy equation. Types included with HallThruster.jl are:

  • NoWallLosses No electron energy losses to the wall.
  • ConstantSheathPotential(sheath_potential, inner_loss_coeff, outer_loss_coeff) Power to the walls scales with α * exp(-sheath_potential)), where α = inner_loss_coeff inside the channel and α = outer_loss_coeff outside.
  • WallSheath(material::WallMaterial) Power to the walls is computed self-consistently using a sheath model, dependent on the secondary electron emission yield of the provided material. See WallMaterial for material options.

Users implementing their own WallLossModel will need to implement at least three methods 1) freq_electron_wall(model, U, params, i): Compute the electron-wall momentum transfer collision frequency in cell i 2) wall_power_loss(model, U, params, i): Compute the electron power lost to the walls

A third method, wall_electron_current(model, U, params, i), will compute the electron current to the walls in cell i. If left unimplemented, it defaults to Ie,w = e ne νew Vcell where Vcell is the cell volume.

A fourth method, wall_ion_current(model, U, params, i, Z), for computing the current of ions of charge Z to the walls in cell i, may also be implemented. If left unimplemented, it will default to computing the current assuming Ie,w = Ii,w.

source
HallThruster.UnevenGridFunction
UnevenGrid(n, density = HallThruster.default_density)

Construct an unevenly-spaced grid according to provided density function. Defaults to twice as many grids inside of channel than outside. Provided density functions must have a signature of (z, z0, z1, Lch) where z is the location, (z0, z1) are the extents of the domain and Lch is the channel length

source
HallThruster.allocate_anom_variablesMethod
allocate_anom_variables(::AnomalousTransportModel, ncells)

Allocate arrays for anomalous transport state variables. ncells is the length of the arrays to be allocated. These anomalous transport variables are then stored in params.cache.anom_variables

source
HallThruster.backward_diff_coeffsMethod
backward_diff_coeffs(x0, x1, x2)

Generate finite difference coefficients for a backward first derivative approximation at the point x2 on a three-point stencil at points x0, x1, and x2

julia> backward_diff_coeffs(-2//1, -1//1, 0//1)
+Xe3+
source
HallThruster.ThrusterType
Thruster

Struct containing information about a Hall thruster. This includes a name, geometry (a Geometry1D object), magnetic_field (radial magnetic field along centerline, a function which takes z in meters and outputs B in Tesla), and a shielded (a flag indicating whether the thruster is magnetically-shielded).

Fields

  • name::String

  • geometry::HallThruster.Geometry1D

  • magnetic_field::Any

  • shielded::Bool

source
HallThruster.TwoZoneBohmType
TwoZoneBohm(c1, c2) <: AnomalousTransportModel

Model where the anomalous collision frequency has two values: c1 * ωce inside the channel and c2 * ωce outside of the channel. Takes two arguments: c1 and c2. The transition between these values can be smoothed by the user-provided transition function.

source
HallThruster.WallLossModelType
abstract type WallLossModel

Abstract type for wall loss models in the electron energy equation. Types included with HallThruster.jl are:

  • NoWallLosses No electron energy losses to the wall.
  • ConstantSheathPotential(sheath_potential, inner_loss_coeff, outer_loss_coeff) Power to the walls scales with α * exp(-sheath_potential)), where α = inner_loss_coeff inside the channel and α = outer_loss_coeff outside.
  • WallSheath(material::WallMaterial) Power to the walls is computed self-consistently using a sheath model, dependent on the secondary electron emission yield of the provided material. See WallMaterial for material options.

Users implementing their own WallLossModel will need to implement at least three methods 1) freq_electron_wall(model, U, params, i): Compute the electron-wall momentum transfer collision frequency in cell i 2) wall_power_loss(model, U, params, i): Compute the electron power lost to the walls

A third method, wall_electron_current(model, U, params, i), will compute the electron current to the walls in cell i. If left unimplemented, it defaults to Ie,w = e ne νew Vcell where Vcell is the cell volume.

A fourth method, wall_ion_current(model, U, params, i, Z), for computing the current of ions of charge Z to the walls in cell i, may also be implemented. If left unimplemented, it will default to computing the current assuming Ie,w = Ii,w.

source
HallThruster.UnevenGridFunction
UnevenGrid(n, density = HallThruster.default_density)

Construct an unevenly-spaced grid according to provided density function. Defaults to twice as many grids inside of channel than outside. Provided density functions must have a signature of (z, z0, z1, Lch) where z is the location, (z0, z1) are the extents of the domain and Lch is the channel length

source
HallThruster.allocate_anom_variablesMethod
allocate_anom_variables(::AnomalousTransportModel, ncells)

Allocate arrays for anomalous transport state variables. ncells is the length of the arrays to be allocated. These anomalous transport variables are then stored in params.cache.anom_variables

source
HallThruster.backward_diff_coeffsMethod
backward_diff_coeffs(x0, x1, x2)

Generate finite difference coefficients for a backward first derivative approximation at the point x2 on a three-point stencil at points x0, x1, and x2

julia> backward_diff_coeffs(-2//1, -1//1, 0//1)
 (1//2, -2//1, 3//2)
 julia> backward_diff_coeffs(-3//2, -1//1, 0//1)
-(4//3, -3//1, 5//3)
source
HallThruster.backward_differenceMethod
backward_difference(f0, f1, f2, x0, x1, x2)

Given three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the derivative at x2

f(x) = x^4
+(4//3, -3//1, 5//3)
source
HallThruster.backward_differenceMethod
backward_difference(f0, f1, f2, x0, x1, x2)

Given three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the derivative at x2

f(x) = x^4
 x0, x1, x2 = 1.9999998, 1.9999999, 2
 bd = backward_difference(f(x0), f(x1), f(x2), x0, x1, x2)
 bd ≈ 32
 
 # output
 
-true
source
HallThruster.central_diff_coeffsMethod
central_diff_coeffs(x0, x1, x2)

Generate finite difference coefficients for a central first derivative approximation at the point x1 on a three-point stencil at points x0, x1, and x2

julia> central_diff_coeffs(-1//1, 0//1, 1//1)
+true
source
HallThruster.central_diff_coeffsMethod
central_diff_coeffs(x0, x1, x2)

Generate finite difference coefficients for a central first derivative approximation at the point x1 on a three-point stencil at points x0, x1, and x2

julia> central_diff_coeffs(-1//1, 0//1, 1//1)
 (-1//2, 0//1, 1//2)
 julia> central_diff_coeffs(-1//2, 0//1, 1//1)
-(-4//3, 1//1, 1//3)
source
HallThruster.central_differenceMethod
central_difference(f0, f1, f2, x0, x1, x2)

Given three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the derivative at x1

f(x) = x^4
+(-4//3, 1//1, 1//3)
source
HallThruster.central_differenceMethod
central_difference(f0, f1, f2, x0, x1, x2)

Given three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the derivative at x1

f(x) = x^4
 x0, x1, x2 = 1.9999999, 2, 2.0000001
 cd = central_difference(f(x0), f(x1), f(x2), x0, x1, x2)
 cd ≈ 32
 
 # output
 
-true
source
HallThruster.channel_areaMethod
channel_area(outer_radius, inner_radius)

Compute the cross-sectional area of a Hall thruster channel from its dimensions

source
HallThruster.channel_perimeterMethod
channel_perimeter(outer_radius, inner_radius)

Compute the perimeteter of the thruster channel, equal to the sum of the inner and outer circumferences

source
HallThruster.coulomb_logarithmFunction
coulomb_logarithm(ne, Tev, Z = 1)

calculate coulomb logarithm for electron-ion collisions as a function of ion charge state Z, electron number density in m^-3, and electron temperature in eV.

source
HallThruster.downwind_diff_coeffsMethod
downwind_diff_coeffs(x0, x1, x2)

Generate finite difference coefficients for a downwind first derivative approximation at the point x2 on a three-point stencil at points x0, x1, and x2 (uses only points x1 and x2)

julia> downwind_diff_coeffs(-1//1, 0//1, 2//1)
-(0//1, -1//2, 1//2)
source
HallThruster.electron_mobilityMethod
electron_mobility(νe, B)

calculates electron transport according to the generalized Ohm's law as a function of sum of the classical and anomalous collision frequencies and the magnetic field.

source
HallThruster.forward_diff_coeffsMethod
forward_diff_coeffs(x0, x1, x2)

Generate finite difference coefficients for a forward first derivative approximation at the point x0 on a three-point stencil at points x0, x1, and x2

julia> forward_diff_coeffs(1.0, 2.0, 3.0)
+true
source
HallThruster.channel_areaMethod
channel_area(outer_radius, inner_radius)

Compute the cross-sectional area of a Hall thruster channel from its dimensions

source
HallThruster.channel_perimeterMethod
channel_perimeter(outer_radius, inner_radius)

Compute the perimeteter of the thruster channel, equal to the sum of the inner and outer circumferences

source
HallThruster.coulomb_logarithmFunction
coulomb_logarithm(ne, Tev, Z = 1)

calculate coulomb logarithm for electron-ion collisions as a function of ion charge state Z, electron number density in m^-3, and electron temperature in eV.

source
HallThruster.downwind_diff_coeffsMethod
downwind_diff_coeffs(x0, x1, x2)

Generate finite difference coefficients for a downwind first derivative approximation at the point x2 on a three-point stencil at points x0, x1, and x2 (uses only points x1 and x2)

julia> downwind_diff_coeffs(-1//1, 0//1, 2//1)
+(0//1, -1//2, 1//2)
source
HallThruster.electron_mobilityMethod
electron_mobility(νe, B)

calculates electron transport according to the generalized Ohm's law as a function of sum of the classical and anomalous collision frequencies and the magnetic field.

source
HallThruster.forward_diff_coeffsMethod
forward_diff_coeffs(x0, x1, x2)

Generate finite difference coefficients for a forward first derivative approximation at the point x0 on a three-point stencil at points x0, x1, and x2

julia> forward_diff_coeffs(1.0, 2.0, 3.0)
 (-1.5, 2.0, -0.5)
 julia> forward_diff_coeffs(0//1, 1//2, 3//2)
-(-8//3, 3//1, -1//3)
source
HallThruster.forward_differenceMethod
forward_difference(f0, f1, f2, x0, x1, x2)

Given three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the derivative at x0

f(x) = x^4
+(-8//3, 3//1, -1//3)
source
HallThruster.forward_differenceMethod
forward_difference(f0, f1, f2, x0, x1, x2)

Given three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the derivative at x0

f(x) = x^4
 x0, x1, x2 = 2.0, 2.000001, 2.000002
 fd = forward_difference(f(x0), f(x1), f(x2), x0, x1, x2)
 fd ≈ 32
@@ -41,7 +41,7 @@
 # output
 
 true
-
source
HallThruster.generate_gridMethod
generate_grid(geometry, ncells)

Generate a one-dimensional uniform grid on the domain specified in the geomety. Returns number of cells, coordinates of cell centers (plus ghost cells face coordinates), interface/edges and volume of a cell for number density calculations.

source
HallThruster.interpolation_coeffsMethod
interpolation_coeffs(x, x0, x1, y0, y1)

Compute the coefficients for interpolation between two points (x0, y0) and (x1, y1) such that y = c0 * y0 + c1 * y1 ```jldoctest;setup = :(using HallThruster: itpcoeffs, lerp) julia> c0, c1 = interpolationcoeffs(0.5, 0.0, 1.0, 0.0, 2.0) (0.5, 0.5) julia> c0 * 0.0 + c1 * 2.0 == lerp(0.5, 0.0, 1.0, 0.0, 2.0) true

source
HallThruster.lerpMethod
lerp(x, x0, x1, y0, y1)

Interpolate between two points (x0, y0) and (x1, y1) ```jldoctest;setup = :(using HallThruster: lerp) julia> lerp(0.5, 0.0, 1.0, 0.0, 2.0) 1.0

source
HallThruster.load_reactionsMethod
load_reactions(model::ReactionModel, species)::Vector{IonizationReaction}

Load ionization reactions for the provided species and ionization model

source
HallThruster.maximum_charge_stateMethod
maximum_charge_state(model::ReactionModel)::Int

Return the maximum supported charge state for a given reaction model. If 0 is returned, then no charge state restriction is applied.

source
HallThruster.nodes_from_densityMethod
nodes_from_density(density, x0, x1, N)

Given bounds x0, x1, a number of points N, and a density function density(x), generate N nodes betweeen x0 and x1 spaced according to the provided desity function using inverse CDF transformation.

source
HallThruster.num_anom_variablesMethod
num_anom_variables(::AnomalousTransportModel)::Int

The number of variable arrays that should be allocated for the provided anomalous transport model. These arrays are used to save state beyond the anomalous collision frequency, and are useful for defining more complex anomalous transport models. If not defined by the user, this defaults to zero.

source
HallThruster.generate_gridMethod
generate_grid(geometry, ncells)

Generate a one-dimensional uniform grid on the domain specified in the geomety. Returns number of cells, coordinates of cell centers (plus ghost cells face coordinates), interface/edges and volume of a cell for number density calculations.

source
HallThruster.interpolation_coeffsMethod
interpolation_coeffs(x, x0, x1, y0, y1)

Compute the coefficients for interpolation between two points (x0, y0) and (x1, y1) such that y = c0 * y0 + c1 * y1 ```jldoctest;setup = :(using HallThruster: itpcoeffs, lerp) julia> c0, c1 = interpolationcoeffs(0.5, 0.0, 1.0, 0.0, 2.0) (0.5, 0.5) julia> c0 * 0.0 + c1 * 2.0 == lerp(0.5, 0.0, 1.0, 0.0, 2.0) true

source
HallThruster.lerpMethod
lerp(x, x0, x1, y0, y1)

Interpolate between two points (x0, y0) and (x1, y1) ```jldoctest;setup = :(using HallThruster: lerp) julia> lerp(0.5, 0.0, 1.0, 0.0, 2.0) 1.0

source
HallThruster.load_reactionsMethod
load_reactions(model::ReactionModel, species)::Vector{IonizationReaction}

Load ionization reactions for the provided species and ionization model

source
HallThruster.maximum_charge_stateMethod
maximum_charge_state(model::ReactionModel)::Int

Return the maximum supported charge state for a given reaction model. If 0 is returned, then no charge state restriction is applied.

source
HallThruster.nodes_from_densityMethod
nodes_from_density(density, x0, x1, N)

Given bounds x0, x1, a number of points N, and a density function density(x), generate N nodes betweeen x0 and x1 spaced according to the provided desity function using inverse CDF transformation.

source
HallThruster.num_anom_variablesMethod
num_anom_variables(::AnomalousTransportModel)::Int

The number of variable arrays that should be allocated for the provided anomalous transport model. These arrays are used to save state beyond the anomalous collision frequency, and are useful for defining more complex anomalous transport models. If not defined by the user, this defaults to zero.

source
HallThruster.run_simulationMethod
run_simulation(
     config;
     grid,
     ncells,
@@ -61,15 +61,15 @@
     dtmax,
     verbose
 )
-

Run a Hall thruster simulation using the provided Config object.

Arguments

  • config: a Config containing simulation parameters.
  • dt: The timestep, in seconds. Typical values are O(10 ns) (1e-8 seconds).
  • duration: How long to run the simulation, in seconds (simulation time, not wall time). Typical runtimes are O(1 ms) (1e-3 seconds).
  • ncells: How many cells to use. Typical values are 100 - 1000 cells.
  • nsave: How many frames to save.
source
HallThruster.second_deriv_central_diffMethod
second_deriv_central_diff(f0, f1, f2, x0, x1, x2)

Given three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the second derivative at x1

f(x) = x^4
+

Run a Hall thruster simulation using the provided Config object.

Arguments

  • config: a Config containing simulation parameters.
  • dt: The timestep, in seconds. Typical values are O(10 ns) (1e-8 seconds).
  • duration: How long to run the simulation, in seconds (simulation time, not wall time). Typical runtimes are O(1 ms) (1e-3 seconds).
  • ncells: How many cells to use. Typical values are 100 - 1000 cells.
  • nsave: How many frames to save.
source
HallThruster.second_deriv_central_diffMethod
second_deriv_central_diff(f0, f1, f2, x0, x1, x2)

Given three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the second derivative at x1

f(x) = x^4
 x0, x1, x2 = 1.9999, 2.0, 2.0001
 sd = second_deriv_central_diff(f(x0), f(x1), f(x2), x0, x1, x2)
 sd ≈ 48
 
 # output
 
-true
source
HallThruster.second_deriv_coeffsMethod
second_deriv_coeffs(x0, x1, x2)

Generate finite difference coefficients for a central second derivative approximation at the point x1 on a three-point stencil at points x0, x1, and x2

julia> second_deriv_coeffs(-2//1, 0//1, 2//1)
+true
source
HallThruster.second_deriv_coeffsMethod
second_deriv_coeffs(x0, x1, x2)

Generate finite difference coefficients for a central second derivative approximation at the point x1 on a three-point stencil at points x0, x1, and x2

julia> second_deriv_coeffs(-2//1, 0//1, 2//1)
 (1//4, -1//2, 1//4)
 julia> second_deriv_coeffs(-1//2, 0//1, 1//1)
-(8//3, -4//1, 4//3)
source
HallThruster.sheath_potentialMethod
sheath_potential(Tev, γ, mi))

compute wall sheath to be used for radiative losses and loss to wall. Goebel Katz equ. 7.3-29, 7.3-44. Assumed nₑuₑ/nᵢuᵢ ≈ 0.5 Sheath potentials are positive by convention in HallThruster.jl.

source
HallThruster.supported_gasesMethod
supported_gases(model::ReactionModel)::Vector{HallThruster.Gas}

Check which gases are supported by a given reaction model. If an empty vector is provided, then there are no restrictions on what gases can be used.

source
HallThruster.time_averageFunction
time_average(sol, tstampstart)

compute time-averaged solution, input Solution type and the frame at which averaging starts. Returns a Solution object with a single frame.

source
HallThruster.upwind_diff_coeffsMethod
upwind_diff_coeffs(x0, x1, x2)

Generate finite difference coefficients for a upwind first derivative approximation at the point x2 on a three-point stencil at points x0, x1, and x2 (uses only points x0 and x1)

julia> upwind_diff_coeffs(-3//1, 0//1, 2//1)
-(-1//3, 1//3, 0//1)
source
HallThruster.write_restartMethod
write_restart(path::AbstractString, sol)

Write a JLD2 restart file to path`.

This can be reloaded to resume a simulation.

source
HallThruster.σ_enMethod
σ_en(Tev)

Electron neutral collision cross section in m² as a function of electron temperature in eV. Eq. 3.6-13, from Fundamentals of Electric Propulsion, Goebel and Katz, 2008.

source
+(8//3, -4//1, 4//3)
source
HallThruster.sheath_potentialMethod
sheath_potential(Tev, γ, mi))

compute wall sheath to be used for radiative losses and loss to wall. Goebel Katz equ. 7.3-29, 7.3-44. Assumed nₑuₑ/nᵢuᵢ ≈ 0.5 Sheath potentials are positive by convention in HallThruster.jl.

source
HallThruster.supported_gasesMethod
supported_gases(model::ReactionModel)::Vector{HallThruster.Gas}

Check which gases are supported by a given reaction model. If an empty vector is provided, then there are no restrictions on what gases can be used.

source
HallThruster.time_averageFunction
time_average(sol, tstampstart)

compute time-averaged solution, input Solution type and the frame at which averaging starts. Returns a Solution object with a single frame.

source
HallThruster.upwind_diff_coeffsMethod
upwind_diff_coeffs(x0, x1, x2)

Generate finite difference coefficients for a upwind first derivative approximation at the point x2 on a three-point stencil at points x0, x1, and x2 (uses only points x0 and x1)

julia> upwind_diff_coeffs(-3//1, 0//1, 2//1)
+(-1//3, 1//3, 0//1)
source
HallThruster.write_restartMethod
write_restart(path::AbstractString, sol)

Write a JLD2 restart file to path`.

This can be reloaded to resume a simulation.

source
HallThruster.σ_enMethod
σ_en(Tev)

Electron neutral collision cross section in m² as a function of electron temperature in eV. Eq. 3.6-13, from Fundamentals of Electric Propulsion, Goebel and Katz, 2008.

source
diff --git a/dev/numerics/index.html b/dev/numerics/index.html index d892b8aa..3a5285fb 100644 --- a/dev/numerics/index.html +++ b/dev/numerics/index.html @@ -1,2 +1,2 @@ -Numerics · HallThruster.jl

Numerics

As described in Configuration and Initialization different flux options are available in HyperbolicScheme. Timemarching for the heavy species is handled using a second order strong-stability preserving Runge-Kutta scheme (SSPRK22). The left hand side of the electron energy equation is integrated implicitly using a Crank Nicolson Adams Bashforth (CNAB) scheme. This enables larger timessteps due to the severe restrictions due to the electron heat flux.

Spatial discretization for heavy species

Neutrals and ions are considered heavy species (compared to electrons). HallThruster.jl uses the finite volume method (FVM). FVM has the advantage that it is by definition conservative, which is a useful property when solving hyperbolic conservation laws such as the Euler equations. Currently, only the continuity equation is solved for the neutrals and the isothermal Euler equations for the ion species. Possibly, the full Euler equations will be added in the future, its implementation has been verified using the Sod Shock tube. The following provides and example of the control volume approach applied to the continuity equation.

\[\int_{i-\frac{1}{2}}^{i+\frac{1}{2}} \frac{\partial n_n}{\partial t} \,dz + \int_{i-\frac{1}{2}}^{i+\frac{1}{2}} \frac{\partial n_n u_n}{\partial z} \,dz = \int_{i-\frac{1}{2}}^{i+\frac{1}{2}} \dot{n}_n \, dz\]

The $n_n u_n$ can be replaced by a generic flux term $F(z)$ and generalized to any advection like equation. Treatment of the source term is described in Collisions and Reactions. Integration results in

\[h\frac{\partial n_n}{\partial t} + \left(F_{_{i+\frac{1}{2}}} - F_{_{i-\frac{1}{2}}}\right) = h \dot{n}_n\]

See Fluxes for the implemented fluxes, and possible limiters to be used in reconstruction to ensure a total variation diminishing scheme (TVD).

Time discretization of heavy species

We employ a strong stability preserving second-order Runge Kutta schemes (SSPRK22) for timestepping

The user has the option to supply a fixed timestep, or a CFL number. In the former case, the user will need to select a timestep that obeys the CFL condition, defined as

\[ \sigma = \frac{u_i \Delta t}{\Delta x} < 1\]

Using a maximum ion velocity of 22000 m/s, a domain length of 0.05m and 200 cells, results in $\Delta t \leq 1.2 \times 10^{-8}$ s. In practice, it needs to be a bit lower in order to handle transients as the solution oscillates. This restriction is valid for the continuity and isothermal euler equations. Information on setting dt and selecting the integration scheme can be found in the Tutorial.

In most cases, it is better to let HallThruster.jl handle timestepping automatically using its adaptive timestepping option. If adaptive timestepping is enabled, the user-defined timestep is ignored in favor of a timestep based on the minimum of three conditions and a user-supplied CFL number. Mathematically the timstep is choosen as:

\[ \Delta t = min(\sigma \frac{\Delta x}{max(u_i + a_i, u_i - a_i)}, \sigma \frac{\dot{n}_i}{n_i}, \sqrt{\frac{\sigma m_i \Delta x}{q_i E}})\]

Where $a_i$ is the ion sound speed. Physically, these three conditions represent timestep limits imposed by the flux, ionization, and electrostatic acceleration. Keep in mind that due to stability limits imposed by the ionization condition, the CFL number cannot be higher than 0.799 to remain stable. This limit will be imposed by HallThruster.jl if the user-defined value is too high.

Electron energy equation discretization

While the ions can be explicitly solved with $\Delta t \sim 10^{-8}$s, the heat condution term in the electron energy equation adds additional constraints which would lower the timestep by about a factor of 10. In order to not further increase the timestepping restrictions and increase computation time, the electron energy equation is solved semi-implicitly in time using a backward Euler or Crank-Nicholson scheme. See Configuration for information on how to select which scheme is used.

The spatial discretization of the electron energy equation uses central finite differences in a manner similar to the potential solver (see below). This, combined with the semi-implicit timestepping, creates a tridiagonal linear system which can be efficiently solved using the Thomas algorithm.

If adaptive timestepping is enabled, the timestep used for the explicit terms is limited by:

\[ \Delta t = \abs{\frac{3\sigma n_eT_e}{W_{loss} + S_{coll}}}\]

As this timestep may be significantly smaller than the timestep used for the heavy species, the electron energy equation is updated using a series of sub-steps with the $\Delta t$ enforced by the equation above until a total $\Delta t$ equal to that set by the heavy species is reached.

Evaluation of derivatives

Some computations require the numerical approximation of derivatives, for example the evaluation of the electron velocity from the equation for electron current using the generalized Ohm's law, see Physics model. The derivatives are evaluated to second order using forward difference, central difference or backward difference depending on the location in the domain.

+Numerics · HallThruster.jl

Numerics

As described in Configuration and Initialization different flux options are available in HyperbolicScheme. Timemarching for the heavy species is handled using a second order strong-stability preserving Runge-Kutta scheme (SSPRK22). The left hand side of the electron energy equation is integrated implicitly using a Crank Nicolson Adams Bashforth (CNAB) scheme. This enables larger timessteps due to the severe restrictions due to the electron heat flux.

Spatial discretization for heavy species

Neutrals and ions are considered heavy species (compared to electrons). HallThruster.jl uses the finite volume method (FVM). FVM has the advantage that it is by definition conservative, which is a useful property when solving hyperbolic conservation laws such as the Euler equations. Currently, only the continuity equation is solved for the neutrals and the isothermal Euler equations for the ion species. Possibly, the full Euler equations will be added in the future, its implementation has been verified using the Sod Shock tube. The following provides and example of the control volume approach applied to the continuity equation.

\[\int_{i-\frac{1}{2}}^{i+\frac{1}{2}} \frac{\partial n_n}{\partial t} \,dz + \int_{i-\frac{1}{2}}^{i+\frac{1}{2}} \frac{\partial n_n u_n}{\partial z} \,dz = \int_{i-\frac{1}{2}}^{i+\frac{1}{2}} \dot{n}_n \, dz\]

The $n_n u_n$ can be replaced by a generic flux term $F(z)$ and generalized to any advection like equation. Treatment of the source term is described in Collisions and Reactions. Integration results in

\[h\frac{\partial n_n}{\partial t} + \left(F_{_{i+\frac{1}{2}}} - F_{_{i-\frac{1}{2}}}\right) = h \dot{n}_n\]

See Fluxes for the implemented fluxes, and possible limiters to be used in reconstruction to ensure a total variation diminishing scheme (TVD).

Time discretization of heavy species

We employ a strong stability preserving second-order Runge Kutta schemes (SSPRK22) for timestepping

The user has the option to supply a fixed timestep, or a CFL number. In the former case, the user will need to select a timestep that obeys the CFL condition, defined as

\[ \sigma = \frac{u_i \Delta t}{\Delta x} < 1\]

Using a maximum ion velocity of 22000 m/s, a domain length of 0.05m and 200 cells, results in $\Delta t \leq 1.2 \times 10^{-8}$ s. In practice, it needs to be a bit lower in order to handle transients as the solution oscillates. This restriction is valid for the continuity and isothermal euler equations. Information on setting dt and selecting the integration scheme can be found in the Tutorial.

In most cases, it is better to let HallThruster.jl handle timestepping automatically using its adaptive timestepping option. If adaptive timestepping is enabled, the user-defined timestep is ignored in favor of a timestep based on the minimum of three conditions and a user-supplied CFL number. Mathematically the timstep is choosen as:

\[ \Delta t = min(\sigma \frac{\Delta x}{max(u_i + a_i, u_i - a_i)}, \sigma \frac{\dot{n}_i}{n_i}, \sqrt{\frac{\sigma m_i \Delta x}{q_i E}})\]

Where $a_i$ is the ion sound speed. Physically, these three conditions represent timestep limits imposed by the flux, ionization, and electrostatic acceleration. Keep in mind that due to stability limits imposed by the ionization condition, the CFL number cannot be higher than 0.799 to remain stable. This limit will be imposed by HallThruster.jl if the user-defined value is too high.

Electron energy equation discretization

While the ions can be explicitly solved with $\Delta t \sim 10^{-8}$s, the heat condution term in the electron energy equation adds additional constraints which would lower the timestep by about a factor of 10. In order to not further increase the timestepping restrictions and increase computation time, the electron energy equation is solved semi-implicitly in time using a backward Euler or Crank-Nicholson scheme. See Configuration for information on how to select which scheme is used.

The spatial discretization of the electron energy equation uses central finite differences in a manner similar to the potential solver (see below). This, combined with the semi-implicit timestepping, creates a tridiagonal linear system which can be efficiently solved using the Thomas algorithm.

If adaptive timestepping is enabled, the timestep used for the explicit terms is limited by:

\[ \Delta t = \abs{\frac{3\sigma n_eT_e}{W_{loss} + S_{coll}}}\]

As this timestep may be significantly smaller than the timestep used for the heavy species, the electron energy equation is updated using a series of sub-steps with the $\Delta t$ enforced by the equation above until a total $\Delta t$ equal to that set by the heavy species is reached.

Evaluation of derivatives

Some computations require the numerical approximation of derivatives, for example the evaluation of the electron velocity from the equation for electron current using the generalized Ohm's law, see Physics model. The derivatives are evaluated to second order using forward difference, central difference or backward difference depending on the location in the domain.

diff --git a/dev/physics/index.html b/dev/physics/index.html index 91e9092c..48c81417 100644 --- a/dev/physics/index.html +++ b/dev/physics/index.html @@ -12,4 +12,4 @@ \mu_{\perp} = \frac{e}{m_e \nu_e} \frac{1}{1+\Omega_e^2}\]

With the discharge current known, the axial electric field is computed locally as

\[E_z = \frac{I_d}{en_e\mu_{\perp}A_{ch}} - \frac{1}{en_e} \frac{\partial p_e}{\partial z} - \frac{j_{iz}}{en_e\mu_{\perp}} \]

As the electric field is the negative gradient of the electrostatic potential, the potential is finally calculted by integrating the negative electric field using the trapezoid rule.

Electron energy equation

The electron internal energy equation in one dimension is

\[ \frac{\partial}{\partial t}\left(\frac{3}{2} n_e k_B T_e\right) + \frac{\partial}{\partial z}\left(\frac{5}{2} n_e k_B T_e u_{ez} + q_{ez}\right) = n_e u_{ez} \frac{\partial\phi}{\partial z} - W_{loss} - S_{coll}\]

Here, $q_ez$ is the electron heat conduction in one dimension and $S_{wall}$, see Wall Loss Models, represents the loss of electron energy to the thruster walls and $S_{coll}$, see Collisions and Reactions captures the loss of energy due to inelastic collisions. The heat conduction is defined by Fourier's Law:

\[\begin{aligned} q_{ez} &= -\kappa_{e\perp} \nabla_{\perp} T_e\\ -\end{aligned}\]

In this expression, $\kappa_{e\perp}$ is the cross-field (axial) electron thermal conductivity, for which various forms exist. More details can be found on the Electron Thermal Conductivity page.

The heat transfer terms slightly change when considering the Landmark case study, while the different wall and inelastic collision loss models are described in Wall Loss Models and Collisions and Reactions.

Sheath considerations

HallThruster.jl, being a fluid globally quasineutral model, is not designed to resolve plasma sheaths. However, the sheath and presheath are important to model Hall Thruster discharges accurately. As this is a 1D axial solver, we do not have any direct fluxes towards the walls, the energy losses can however be taken into account by a source term in the energy equation. This term and the boundary conditions implemented at the anode employ the following presheath approximations and assumptions. They are absolutely critical to replicate experimental Hall Thruster behaviour.

In the following, potential differences $e\phi$ are assumed to be on the order of the electron temperature $k T_e$. Furthermore, assume that cold ions fall through an arbitrary potential of $\phi_0$ while they move towards the wall. Through conservation of energy, their arrival velocity at the sheath edge can be related to the potential difference.

\[ \frac{1}{2} m_i v_0^2 = e \phi_0\]

Additionally, the ion flux during acceleration toward the wall is conserved.

\[ n_i v = n_0 v_0\]

The relation for ion velocity as a function of position in the sheath can be written as

\[ \frac{1}{2} m_i v^2 = \frac{1}{2} m_i v_0^2 - e\phi (x)\]

Rewriting both energy conservation and above expression for $v_0$ and $v$, and dividing gives

\[ \frac{v_0}{v} = \sqrt{\frac{\phi_0}{\phi_0 - \phi}}\]

which by applying flux conservation results in

\[ n_i = n_0 \sqrt{\frac{\phi_0}{\phi_0 - \phi}}\]

Close to the sheath edge the density equation can be expanded as a Taylor series, as $\phi$ is small compared to $\phi_0$.

\[ n_i = n_0 \left(1 - \frac{1}{2}\frac{\phi}{\phi_0} + ...\right)\]

In one dimension, neglecting collisions with other species and assuming isentropic temperature and pressure terms, no convection and no electron inertia, the electrons can be described by the Boltzmann relation.

\[ n_e = n_0 exp\left(\frac{e \phi}{k T_e}\right)\]

In this regime, the electron density is diffusion dominated and dictated by the electrostatic field. This assumption is generally valid along magnetic field lines and across weak magnetic fields with sufficient electron electron collisions. The Boltzmann relation can be expanded by assuming that the change in potential at the sheath edge is small compared to the electron temperature.

\[ n_e = n_0 \left(1 - \frac{e\phi}{k T_e} + ... \right)\]

Taking Poisson's equation of the form

\[ \nabla^2 \phi = - \frac{e}{k Te_0}(n_i - n_e)\]

and substituting expanded Boltzmann relation and expanded ion density leads after rearranging to

\[ \nabla^2 \phi = \frac{e n_0 \phi}{\epsilon_0}\left(\frac{1}{2\phi_0} - \frac{e}{kT_e}\right)\]

As the sheath is assumed to be ion attracting, it can by definition not slow or repell ions. As a result, the right hand side of \autoref{eq:poissonsubexpanded} has to always be positive, which leads to the following requirement.

\[ \phi_0 > \frac{kT_e}{2e}\]

By substituting energy conservation equation, the ion Bohm speed can be recovered. This condition is applied to the anode boundary and will be discussed in the boundary conditions.

\[ v_0 > \sqrt{\frac{kT_e}{m_i}}\]

+\end{aligned}\]

In this expression, $\kappa_{e\perp}$ is the cross-field (axial) electron thermal conductivity, for which various forms exist. More details can be found on the Electron Thermal Conductivity page.

The heat transfer terms slightly change when considering the Landmark case study, while the different wall and inelastic collision loss models are described in Wall Loss Models and Collisions and Reactions.

Sheath considerations

HallThruster.jl, being a fluid globally quasineutral model, is not designed to resolve plasma sheaths. However, the sheath and presheath are important to model Hall Thruster discharges accurately. As this is a 1D axial solver, we do not have any direct fluxes towards the walls, the energy losses can however be taken into account by a source term in the energy equation. This term and the boundary conditions implemented at the anode employ the following presheath approximations and assumptions. They are absolutely critical to replicate experimental Hall Thruster behaviour.

In the following, potential differences $e\phi$ are assumed to be on the order of the electron temperature $k T_e$. Furthermore, assume that cold ions fall through an arbitrary potential of $\phi_0$ while they move towards the wall. Through conservation of energy, their arrival velocity at the sheath edge can be related to the potential difference.

\[ \frac{1}{2} m_i v_0^2 = e \phi_0\]

Additionally, the ion flux during acceleration toward the wall is conserved.

\[ n_i v = n_0 v_0\]

The relation for ion velocity as a function of position in the sheath can be written as

\[ \frac{1}{2} m_i v^2 = \frac{1}{2} m_i v_0^2 - e\phi (x)\]

Rewriting both energy conservation and above expression for $v_0$ and $v$, and dividing gives

\[ \frac{v_0}{v} = \sqrt{\frac{\phi_0}{\phi_0 - \phi}}\]

which by applying flux conservation results in

\[ n_i = n_0 \sqrt{\frac{\phi_0}{\phi_0 - \phi}}\]

Close to the sheath edge the density equation can be expanded as a Taylor series, as $\phi$ is small compared to $\phi_0$.

\[ n_i = n_0 \left(1 - \frac{1}{2}\frac{\phi}{\phi_0} + ...\right)\]

In one dimension, neglecting collisions with other species and assuming isentropic temperature and pressure terms, no convection and no electron inertia, the electrons can be described by the Boltzmann relation.

\[ n_e = n_0 exp\left(\frac{e \phi}{k T_e}\right)\]

In this regime, the electron density is diffusion dominated and dictated by the electrostatic field. This assumption is generally valid along magnetic field lines and across weak magnetic fields with sufficient electron electron collisions. The Boltzmann relation can be expanded by assuming that the change in potential at the sheath edge is small compared to the electron temperature.

\[ n_e = n_0 \left(1 - \frac{e\phi}{k T_e} + ... \right)\]

Taking Poisson's equation of the form

\[ \nabla^2 \phi = - \frac{e}{k Te_0}(n_i - n_e)\]

and substituting expanded Boltzmann relation and expanded ion density leads after rearranging to

\[ \nabla^2 \phi = \frac{e n_0 \phi}{\epsilon_0}\left(\frac{1}{2\phi_0} - \frac{e}{kT_e}\right)\]

As the sheath is assumed to be ion attracting, it can by definition not slow or repell ions. As a result, the right hand side of \autoref{eq:poissonsubexpanded} has to always be positive, which leads to the following requirement.

\[ \phi_0 > \frac{kT_e}{2e}\]

By substituting energy conservation equation, the ion Bohm speed can be recovered. This condition is applied to the anode boundary and will be discussed in the boundary conditions.

\[ v_0 > \sqrt{\frac{kT_e}{m_i}}\]

diff --git a/dev/propellants/index.html b/dev/propellants/index.html index 6e50cefd..63fe06ce 100644 --- a/dev/propellants/index.html +++ b/dev/propellants/index.html @@ -5,4 +5,4 @@ # output -Neon

If we then selected Neon as a propellant in our Config struct and used one of the lookup table models for ionization, HallThruster.jl would know to search for files beginning ionization_Ne....

+Neon

If we then selected Neon as a propellant in our Config struct and used one of the lookup table models for ionization, HallThruster.jl would know to search for files beginning ionization_Ne....

diff --git a/dev/run/index.html b/dev/run/index.html index 865c4706..df33da58 100644 --- a/dev/run/index.html +++ b/dev/run/index.html @@ -166,4 +166,4 @@ 34.700016 seconds (7.27 M allocations: 1016.374 MiB, 0.79% gc time, 5.42% compilation time) Hall thruster solution with 10000 saved frames Retcode: Success -End time: 0.001 seconds

If we plot the currents, we see that the simulation remained at the steady state established in the initial run:

+End time: 0.001 seconds

If we plot the currents, we see that the simulation remained at the steady state established in the initial run:

diff --git a/dev/search/index.html b/dev/search/index.html index dfa404d9..d8fe07c2 100644 --- a/dev/search/index.html +++ b/dev/search/index.html @@ -1,2 +1,2 @@ -Search · HallThruster.jl

Loading search...

    +Search · HallThruster.jl

    Loading search...

      diff --git a/dev/search_index.js b/dev/search_index.js index 2c7851c1..637b3f6e 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"wall_loss_models/#Wall-Loss-Models","page":"Wall Loss Models","title":"Wall Loss Models","text":"","category":"section"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"HallThruster.jl allows you to choose from three different wall loss models. They approximate the electron energy lost to the thruster walls in radial direction. As the computational axis of the 1D code is axially in the thruster, the wall loss is not directly resolved by the fluid and applied in each cell as an electron energy loss term. ","category":"page"},{"location":"wall_loss_models/#Background","page":"Wall Loss Models","title":"Background","text":"","category":"section"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"The core of the wall loss models in HallThruster.jl is the abstract type WallLossModel. It has three children: NoWallLosses, ConstantSheathPotential, and WallSheath. ConstantSheathPotential has three fields. A wall sheath_potential to be set by the user, and an inner_loss_coeff and outer_loss_coeff which allow to scale the energy loss inside vs. outside the thruster channel. WallSheath has two field: material, which is of type WallMaterial and includes information about secondary electron emission yields, and α, which is a constant wall loss scaling coefficient (values around 0.1-0.2 are good usually, but this may need to be calibrated against some data).","category":"page"},{"location":"wall_loss_models/#Provided-wall-loss-models","page":"Wall Loss Models","title":"Provided wall loss models","text":"","category":"section"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"HallThruster.jl provides three models out of the box. These are","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"Model Supported species Description\nNoWallLosses Any Ignores electron energy losses to the walls. May cause numerical issues.\nConstantSheathPotential Any Employs a simple sheath energy loss model with constant sheath potential, based on the electron Boltzmann equation for electron density in the sheath as a function of electron temperature. Uses constants to scale losses inside and outside the thruster. See also JP Boeuf, Low frequency oscillations in a stationary plasma thruster, Journal of Applied Physics 84, 3541, 1998 and Landmark study\nWallSheath Any Conceputally similar loss model as ConstantSheathPotential, but evaluates constants and sheath potential given in the previously mentioned using approximations. We compute the power loss to the walls as","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":" P_w = nu_ew(2 T_ev - phi_s)","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"where nu_ew is the electron wall collision frequency, T_ev is the electron temperature in electron-volts, and phi_s is the wall sheath potential in volts. The sheath potential is computed as:","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"phi_w = T_ev lnleft(1 - gamma) sqrtfracm_i2pi m_eright","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"Here, gamma is the secondary electron emission coefficient, which is computed according to the choice of WallMaterial. For a plasma with only once charge state, the electron-wall collision frequency is:","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"nu_ew = fracalpha1 - gammasqrtfrace T_eVm_ifrac1R_o - R_i","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"where R_o and R_i are the channel inner radius and outer radii respectively. For multiply-charged plasmas, the ion currents of each species are first computed as:","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"j_iwZ = alpha Z e n_iZ sqrtfracZ e T_eVm_i","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"Then, the electron wall current minus the secondary electron current are equal to the total ion wall current:","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"(1 - gamma) j_ew = j_iw = sum_Z j_iw Z","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"Lastly, we compute the electron-wall collision frequency as","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"nu_ew = fracj_ewe n_e frac1R_o - R_i","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"The ion current of each species is also used to compute ion wall losses if ion_wall_losses is set to true in config. Ions are assumed to recombine at the walls and the flux is re-injected as neutrals.","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"dotn_iw Z = -fracj_iw Zefrac1R_o - R_i","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"dotn_nw Z = -sum_Z dotn_iw Z","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"If thruster.shielded is true, the electron temperature at the walls is assumed to be equal to the electron temperature at the anode, see Thrusters for the option.","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"The density relation in the WallSheath model is based upon the electron Boltzmann relation. Note that at this point the model does not differentiate between axial positions inside and outside the thruster. The same loss model is applied over the entire domain. This approximation seems to work ok when comparing to 2D simulations due to isothermal magnetic field lines. More fidelity will most likely be added. ","category":"page"},{"location":"wall_loss_models/#Impact-of-magnetic-shielding","page":"Wall Loss Models","title":"Impact of magnetic shielding","text":"","category":"section"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"The effect on magnetic shielding on the electron energy can be seen below. Compared are time-averaged electron energy profiles for a Xenon SPT-100 type thruster using Boron Nitride walls.","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"(Image: unshielded_vs_shielded)","category":"page"},{"location":"contribution/#Contribution","page":"Contribution","title":"Contribution","text":"","category":"section"},{"location":"contribution/","page":"Contribution","title":"Contribution","text":"We welcome all contributions. If you would like a new feature added, please open an issue on the HallThruster.jl repo, and if you modify the code on your end, please consider opening a pull request and contributing back to the main repo.","category":"page"},{"location":"verification/#Verification","page":"Verification","title":"Verification","text":"","category":"section"},{"location":"verification/","page":"Verification","title":"Verification","text":"Tests can be found in the test folder, and are split in unit_tests and order_verification tests. The julia Test environment is used. We verify that the PDEs are discretized correctly using the Method of Manufactured Solutions and perform order verification studies in order to ensure that the actual order of accuracy matches the predicted order. For more details on the discretization, see Fluxes and Numerics.","category":"page"},{"location":"verification/#Landmark","page":"Verification","title":"Landmark","text":"","category":"section"},{"location":"verification/","page":"Verification","title":"Verification","text":"In addition to the MMS studies discussed above, we also compare the results to the Landmark test cases for 1D fluid Hall Thruster discharges. Below, we compare the time-averaged output of HallThruster.jl for each of the three test cases to the expected results from Landmark. The cases differ only in the amount of electron energy lost to to radial sheaths inside the thruster. For the purpose of verification, the boundary conditions, source terms, collision models and anomalous collision frequency has been set to match Landmark. The results shown are time-averaged, performed using 160 cells using the first-order Rusanov flux and without gradient reconstruction. ","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"Landmark energy loss term:","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":" W = nu_epsilon expleft(frac-20epsilonright)","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"where","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":" nu_epsilon=\n begincases\n alpha_1 times 10^7 z - z_0 leq L_ch \n alpha_2 times 10^7 z - z_0 L_ch\n endcases","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"and","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"epsilon = frac32 T_ev","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"In the above, L_ch refers to thruster channel length and z_0 is domain[1], or the z-location of the anode.","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"Case 1 alpha_1 = 10 alpha_2 = 10 (Image: Landmark1)","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"Case 2 alpha_1 = 05 alpha_2 = 10 (Image: Landmark2)","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"Case 3 alpha_1 = 04 alpha_2 = 10 (Image: Landmark3)","category":"page"},{"location":"config/#Configuration","page":"Configuration","title":"Configuration","text":"","category":"section"},{"location":"config/","page":"Configuration","title":"Configuration","text":"The Config struct contains all of the options you need to run a simulation. On this page, we will explain what options are available and what they do. Note that all arguments must be provided as keywords.","category":"page"},{"location":"config/","page":"Configuration","title":"Configuration","text":"There are four absolutely mandatory arguments. These are:","category":"page"},{"location":"config/","page":"Configuration","title":"Configuration","text":"discharge_voltage: The difference in potential between the anode and cathode, in Volts. This is used to set the left boundary condition. If the cathode potential is zero, then the anode potential is equal to the discharge voltage.\nthruster: This is a Thruster object containing important geometric and magnetic information about the thruster being simulated. See the page about Thrusters for more.\ndomain: This is a Tuple containing the locations of the left and right boundaries of the simulation domain, in meters. For instance, if your simulation domain starts at z = 0.0 and is 5 cm long, you would write domain = (0.0, 0.05).\nanode_mass_flow_rate: The propellant mass flow rate at the anode, in kg/s","category":"page"},{"location":"config/","page":"Configuration","title":"Configuration","text":"Aside from these arguments, all others have default values provided. These are detailed below:","category":"page"},{"location":"config/","page":"Configuration","title":"Configuration","text":"initial_condition: A function used for initializing the simulation. See the page about Initialization for more information.\nncharge: Number of charge states to simulate. Defaults to 1.\npropellant: Propellant gas. Defaults to Xenon. Other options are described on the Propellants page.\nscheme: Numerical scheme to employ for integrating the ion equations. This is a HyperbolicScheme struct with fields flux_function, limiter, and reconstruct. Defaults to HyperbolicScheme(flux_function = rusanov, limiter = minmod, reconstruct = false). For more information, see Fluxes.\ncathode_potential: The potential at the right boundary of the simulation. Defaults to 0.0\nanode_Te: The electron temperature at the anode, in eV. Acts as a Dirichlet boundary condition for the energy equation. Defaults to 3.0.\ncathode_Te: The electron temperature at the cathode, in eV. Acts as a Dirichlet boundary condition for the energy equation. Defaults to 3.0.\nwall_loss_model: How radial losses due to sheaths are computed. Defaults to ConstantSheathPotential(sheath_potential=-20.0, inner_loss_coeff = 1.0, outer_loss_coeff = 1.0), which is the loss term from LANDMARK case 1. Other wall loss models are described on the Wall Loss Models page.\nwall_collision_freq: Extra \"wall collisions\" to be added to the total electron momentum transfer collision frequency inside of the channel. Units of Hz. Defaults to 0.0.\nanom_model: Model for computing the anomalous collision frequency. Defaults to TwoZoneBohm(1/160, 1/16). Further details on the Anomalous Transport page.\nconductivity_model: Model for the perpendicular electron thermal conductivity. Defaults to Mitchner(). Further details can be found on the Electron Thermal Conductivity page.\nionization_model: Model for ionization. Defaults to IonizationLookup(), which uses a lookup table to compute ionization rate coefficients as a function of electron energy. Other options are described on the Collisions and Reactions page.\nexcitation_model: Model for excitation reactions. Defaults to ExcitationLookup(), which uses a lookup table to compute excitation rate coefficients as a function of electron energy.. Other models are described on the Collisions and Reactions page.\nelectron_neutral_model: Model for elastic scattering collisions between electrons and neutral atoms. Defaults to ElectronNeutralLookup(), which uses a lookup table to compute the elastic scattering rate coefficient. Other models are described on the Collisions and Reactions page.\nelectron_ion_collisions: Whether to include electron-ion collisions. Defaults to true. More information on the Collisions and Reactions page.\nneutral_velocity: Neutral velocity in m/s. Defaults to 300.0\nneutral_temperature: Neutral temperature in Kelvins. Defaults to 300.0.\nion_temperature: Ion temperature in Kelvins. Defaults to 100.0\nimplicit_energy: The degree to which the energy is solved implicitly. 0.0 is a fully-explicit forward Euler, 0.5 is Crank-Nicholson, and 1.0 is backward Euler. Defaults to 1.0.\nmin_number_density: Minimum allowable number density for any species. Defaults to 1e6\nmin_electron_temperature: Minimum allowable electron temperature. Defaults to 1.0.\nmagnetic_field_scale: Factor by which the magnetic field is increased or decreased compared to the one in the provided Thruster struct. Defaults to 1.0.\nsource_neutrals: Extra user-provided neutral source term. Can be an arbitrary function, but must take (U, params, i) as arguments. Defaults to Returns(0.0). See User-Provided Source Terms for more information.\nsource_ion_continuity: Vector of extra source terms for ion continuity, one for each charge state. Defaults to fill(Returns(0.0), ncharge) . See User-Provided Source Terms for more information.\nsource_ion_momentum: Vector of extra source terms for ion momentum, one for each charge state. Defaults to fill(Returns(0.0), ncharge) . See User-Provided Source Terms for more information.\nsource_potential: Extra source term for potential equation. Defaults to Returns(0.0). See User-Provided Source Terms for more information.\nsource_electron_energy: Extra source term for electron energy equation. Defaults to Returns(0.0). See User-Provided Source Terms for more information.\nLANDMARK: Whether we are using the LANDMARK physics model. This affects whether certain terms are included in the equations, such as electron and heavy species momentum transfer due to ionization and the form of the electron thermal conductivity. Also affects whether we use an anode sheath model. Defaults to false.\nion_wall_losses: Whether we model ion losses to the walls. Defaults to false.\nsolve_background_neutrals: Turns on an additional mass flow rate due to neutral ingestion\nbackground_pressure: The pressure of the background neutrals, in Pascals\nbackground_neutral_temperature: The temperature of the background neutrals, in K\nanode_boundary_condition: Can be either :sheath or :dirichlet\nanom_smoothing_iters: How many times to smooth the anomalous transport profile\nsolve_plume: Whether to solve for plume area variation and divergence losses\nelectron_losses_in_plume: Whether electron radial/wall losses are applied in the plume region","category":"page"},{"location":"electron_thermal_conductivity/#Electron-Thermal-Conductivity","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"","category":"section"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"HallThruster has a few electron thermal conductivity models built in and allows users to define their own. This page describes these models and the process by which algebraic transport models can be added by the user.","category":"page"},{"location":"electron_thermal_conductivity/#Built-in-Models","page":"Electron Thermal Conductivity","title":"Built-in Models","text":"","category":"section"},{"location":"electron_thermal_conductivity/#Mitchner()","page":"Electron Thermal Conductivity","title":"Mitchner()","text":"","category":"section"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"HallThruster.jl's default electron thermal conductivity option. This model employs the form described in Mitchner & Kruger \"Partially Ionized Gases\" (1973). The thermal conductivity takes the form:","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"beginaligned\n kappa_eperp approx frac11+Omega_H^2 frac241+ fracnu_iesqrt2nu fracneTe (eV)nu m_e \n nu = nu_ei + nu_en + nu_AN \nendaligned","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"The model is initialized by default but can be explicitly enabled by including:","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"conductivity_model = Mitchner()","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"In the user-defined configuration","category":"page"},{"location":"electron_thermal_conductivity/#Braginskii()","page":"Electron Thermal Conductivity","title":"Braginskii()","text":"","category":"section"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"This form of the thermal conductivity follows the result of S. I. Braginskii, in Reviews of Plasma Physics, edited by M. A. Leontovich (Consultants Bureau, New York, 1965), Vol. 1, p. 205.:","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"\\begin{aligned} \\kappa{e\\perp} & \\approx C \\frac{neTe (eV) \\nu}{me \\omega{ce}^2} \\\n \\nu = \\nu{ei} + \\nu{en} + \\nu{AN} \\\n\\end{aligned}","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"Where C is a constant that is based on the value of the effective charge for multiple charge states and Table 1 of the Braginskii reference. A Braginskii model can be initialized in the user-defined configuration as:","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"conductivity_model = Braginskii()","category":"page"},{"location":"electron_thermal_conductivity/#Custom-thermal-conductivity-models","page":"Electron Thermal Conductivity","title":"Custom thermal conductivity models","text":"","category":"section"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"The procedure for adding additional thermal conductivity models generally follows that of adding anomalous transport models, as described on the Anomalous Transport page. The two main differences is that the model type is of 'ThermalConductivityModel' rather than 'AnomalousTransportModel' and that the function needs to return kappa rather than nu an. For demonstration pursposes however, let's say we wanted to implement the Braginskii model but without the anomalous collision frequency and a coefficient of 4.66 (singly charged ions only). We first define the type:","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"using HallThruster\n\nstruct Braginskii_Classical <: ThermalConductivityModel end","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"With the type defined, we then need to define the function that describes the model. This function should take two arguements, the vector of thermal conductivity values and the solver params.","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"function (model::Braginskii_Classical)(κ, params)\n\n me = HallThruster.me\n e = HallThruster.e\n B = params.cache.B\n ne = params.cache.ne\n Te = params.cache.Tev\n\n for i in eachindex(κ)\n ωce = e * B[i] / me\n κ[i] = 4.66 * ne * e * Te * params.cache.νc[i] / (me * ωce^2)\n end\n\n return κ\nend","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"We could now employ this model by setting `conductivitymodel = BraginskiiClassical()' in the user-defined configuration. ","category":"page"},{"location":"run/#Tutorial:-running-and-analyzing-a-simulation","page":"Tutorial","title":"Tutorial: running and analyzing a simulation","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"This page will walk you through running a simulation and analyzing the output, in the process discussing many of the key features of HallThruster.jl. An interactive Jupyter notebook tutorial covering similar topics and convering the process of comparing the results of the code to an established benchmark is also available here.","category":"page"},{"location":"run/#Defining-geometry","page":"Tutorial","title":"Defining geometry","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"The first thing we need to simulate a Hall thruster is geometry. Let's invent a fictional Hall thruster with a channel length of 3 cm, inner channel radius of 5 cm, and outer channel radius of 6.5 cm. To define the geometry, we create a HallThruster.Geometry1D object:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"using HallThruster\n\n# All units are in meters!\nmy_geometry = HallThruster.Geometry1D(\n inner_radius = 0.05,\n outer_radius = 0.065,\n channel_length = 0.03\n)","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"For clarity and ease of readability, you may also input dimensional numbers from the lovely Unitful package as shown below:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"using HallThruster\nusing Unitful\n\n# Units will be correctly converted!\nmy_geometry = HallThruster.Geometry1D(\n inner_radius = 5.0u\"cm\",\n outer_radius = 6.5u\"cm\",\n channel_length = 3.0u\"cm\"\n)","category":"page"},{"location":"run/#Magnetic-field","page":"Tutorial","title":"Magnetic field","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"The next thing we need is a magnetic field function. This can by any callable object, so long as it takes in an axial location in meters and returns a magnetic field strength in Teslas. Let's use a magnetic field with a Gaussian shape and a peak radial magnetic field strength of 200 Gauss at the channel exit plane:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"function my_magnetic_field(z)\n if z < 0.03\n return 0.02 * exp(-((z - 0.03) / 0.02)^2)\n else\n return 0.02 * exp(-((z - 0.03) / 0.04)^2)\n end\nend","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"Alternatively, we may want to load in a magnetic field from a file. Suppose we have a magnetic field stored in a file my_bfield.csv which has the following first few lines:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"z(m),Br(T)\n0.0,0.0021079844912372868\n0.001,0.0024430133907998\n0.002,0.0028171684184209005\n0.003,0.0032324238493067863\n0.004,0.003690390479859787\n0.005,0.004192227743021959\n0.006,0.004738555173642436\n0.007,0.005329365956270483\n0.008,0.005963945588597749\n0.009,0.006640798906893217\n0.01,0.00735758882342885\n...","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"We could load this in using the DelimitedFiles package","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"my_magnetic_field_data, header = readdlm(\"my_bfield.csv\", ',', header=true)","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"We can then construct a function which interpolates the data (here a linear interpolation, but you can use more complex interpolations using the Interpolations.jl package):","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"z_data = my_magnetic_field_data[:, 1]\nBr_data = my_magnetic_field_data[:, 2]\nmy_magnetic_field_itp = HallThruster.LinearInterpolation(z_data, Br_data)","category":"page"},{"location":"run/#Creating-a-Thruster","page":"Tutorial","title":"Creating a Thruster","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"Once we have a geometry and a magnetic field, we can construct a Thruster:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"my_thruster = HallThruster.Thruster(\n\tname = \"My thruster\",\n magnetic_field = my_magnetic_field,\n geometry = my_geometry,\n shielded = false,\n)","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"In addition to a magnetic field and a geometry, we have also provided a name (optional) and designated whether the thruster is magnetically shielded or not. If true, then the electron temperature used for electron wall loss computations will be the anode temperature instead of the temperature on centerline. HallThruster.jl also includes a built-in definition for the widely-known SPT-100 thruster, accessible as HallThruster.SPT_100.","category":"page"},{"location":"run/#Defining-a-Config","page":"Tutorial","title":"Defining a Config","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"We can now define a Config. We will run a simulation using Xenon propellant and two ion charge states, with a discharge voltage of 300 V and a mass flow rate of 6 mg/s. For anomalous transport, we use a multi-zone Bohm-like transport model. Many more options than these can be tweaked. For more information and a list all possible options, see the Configuration page.","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"my_config = HallThruster.Config(\n ncharge = 2,\n discharge_voltage = 300u\"V\",\n thruster = my_thruster,\n domain = (0.0u\"cm\", 8.0u\"cm\"),\n anode_mass_flow_rate = 8.0u\"mg/s\",\n wall_loss_model = HallThruster.WallSheath(HallThruster.BoronNitride),\n anom_model = HallThruster.MultiLogBohm([0.02, 0.03, 0.04, 0.06, 0.006, 0.2]),\n propellant = Xenon,\n neutral_velocity = 500.0u\"m/s\",\n neutral_temperature = 500.0u\"K\",\n ion_temperature = 500.0u\"K\",\n cathode_Te = 2.5u\"eV\",\n anode_Te = 2.5u\"eV\",\n ion_wall_losses = true,\n)","category":"page"},{"location":"run/#Running-a-simulation","page":"Tutorial","title":"Running a simulation","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"Now we can run a simulation. To do this, we use the run_simulation function. In addition to the Config object we just created, we also pass in the grid we want to run the simulation with, the number of frames we want to save, the timestep, in seconds and the simulation duration (also in seconds).","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> @time my_solution = HallThruster.run_simulation(my_config; grid= EvenGrid(150), nsave=10000, dt=1e-8, duration=1e-3)\n 36.058672 seconds (783.66 k allocations: 519.964 MiB)\nHall thruster solution with 10000 saved frames\nRetcode: success\nEnd time: 0.001 seconds","category":"page"},{"location":"run/#Postprocessing-and-analysis","page":"Tutorial","title":"Postprocessing and analysis","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"Once you have run a Hall thruster simulation, you will want to analyze the results to see how your simulation performed. This section describes the utilities available for such tasks.","category":"page"},{"location":"run/#The-Solution-object","page":"Tutorial","title":"The Solution object","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"Running a simulation returns a HallThruster.Solution object, which has the following fields:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"t: A vector of times at which the simulation state is saved u: A vector of simulation state matrices saved at each of the times in t savevals: A Vector of NamedTuples containing saved derived plasma properties at each of the times in t retcode: A Symbol describing how the simulation finished. This should be :Success if the simulation succeeded, but may be :NaNDetected if the simulation failed. params: A NamedTuple containing simulation parameters, such as the Config the simulation was run with, the computational grid, and more. params.cache contains all of the variables not contained in u","category":"page"},{"location":"run/#Extracting-performance-metrics","page":"Tutorial","title":"Extracting performance metrics","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"After running a simulation, the two things we might care the most about are the predicted thrust and discharge current. These can be computed with the thrust and discharge_current functions, respectively.","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> HallThruster.thrust(my_solution) # Thrust in Newtons at every saved frame\n10000-element Vector{Float64}:\n 0.24759825170838257\n 0.23553180163085566\n ⋮\n 0.1677545384599781\n 0.1677545384591017\n\njulia> HallThruster.thrust(my_solution, 12) # Thrust in Newtons at the twelfth frame\n0.16887856098607704","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> HallThruster.discharge_current(my_solution) # Discharge current in A at every frame\n10000-element Vector{Float64}:\n 16.594260447976414\n 16.491449186956455\n ⋮\n 12.635410795570154\n 12.63541079552306\n\njulia> HallThruster.discharge_current(my_solution, 1999) # Discharge current in A at the 1999th frame\n12.137864749597252\n","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"We can plot the ion, electron, and total currents using our plotting package of choice. In this case, we use Plots","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"using Plots\ntime_us = my_solution.t .* 1_000_000 # Convert time from seconds to microseconds\nI_ion = ion_current(my_solution)\nI_total = discharge_current(my_solution)\nI_electron = I_total .- I_ion # we can also just type electron_current(my_solution)\n\np = plot(\n time_us, I_ion;\n label = \"Ion current\",\n xlabel = \"Time (microseconds)\",\n\tylabel = \"Current (A)\"\n)\nplot!(p, time_us, I_electron; label = \"Electron current\")\nplot!(p, time_us, I_total; label = \"Discharge current\", linewidth = 2)\n\ndisplay(p)\n","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"(Image: )","category":"page"},{"location":"run/#Time-averaging-results","page":"Tutorial","title":"Time averaging results","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"In the above case, the simulation settled to a steady state after 250 microseconds, so we could just look at the last frame to obtain our performance and plasma properties. However, Hall thrusters are often oscillatory. To see this, let's cut the minimum anomalous collision frequency in half and re-run the simulation. The new config is:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"my_config = HallThruster.Config(\n ncharge = 2,\n discharge_voltage = 300u\"V\",\n thruster = my_thruster,\n domain = (0.0u\"cm\", 8.0u\"cm\"),\n anode_mass_flow_rate = 8u\"mg/s\",\n wall_loss_model = HallThruster.WallSheath(HallThruster.BoronNitride),\n # change second to last number here from 0.006 to 0.003\n anom_model = HallThruster.MultiLogBohm([0.02, 0.03, 0.04, 0.06, 0.003, 0.2]),\n propellant = Xenon,\n neutral_velocity = 500.0u\"m/s\",\n neutral_temperature = 500.0u\"K\",\n ion_temperature = 500.0u\"K\",\n cathode_Te = 2.5u\"eV\",\n anode_Te = 2.5u\"eV\",\n ion_wall_losses = true,\n)","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"Plotting the current, we find that the solution now no longer converges to a steady value but instead oscillates strongly about a mean:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"(Image: )","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"To compute performance, we want to average over several of the oscillations. To do this, we employ the time_average function","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> my_time_average = time_average(my_solution)\nHall thruster solution with 1 saved frames\nRetcode: Success\nEnd time: 0.001 seconds","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"The time_average function returns another Solution object, just like my_solution, with a single saved frame holding the time-averaged simulation data. In the case of our oscillatory simulation above, the simulation doesn't settle into a stationary mode until about 100 microseconds have elapsed (about 1000 frames, since we saved 10000 total). If we want to only average the last 9000 frames, we would type","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> my_time_average = time_average(my_solution, 1000) # start averaging at frame 1000","category":"page"},{"location":"run/#Plotting","page":"Tutorial","title":"Plotting","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"HallThruster.jl includes plotting recipes to allow you to plot your simulation results if the Plots package is installed. To plot the last frame of the simulation, you can type:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"using Plots\n\nplot(my_solution)","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"(Image: )","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"To plot a different frame, you can do plot(my_solution, frame_you_want). You can also plot time averaged solutions, as they are no different from a standard solution. You can also plot certain parts on a log scale using the yaxis=:log argument, add labels using label = \"label\", and plot solutions over each other using plot!, just as normal using Plots.jl.","category":"page"},{"location":"run/#Computing-efficiencies","page":"Tutorial","title":"Computing efficiencies","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"There are several key efficiency metrics that are employed to judge how well a Hall thruster performs. The most common is the anode efficiency, defined as the ratio of thrust power to power put into the plasma:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"eta_a = frac12fracT^2dotm V_d I_d","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"We can compute this using the compute_anode_eff function, which returns the anode efficiency at every timestep:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> HallThruster.anode_eff(my_solution)\n10000-element Vector{Float64}:\n 0.769654845938557\n 0.7008079984180736\n ⋮\n 0.46399997114634145\n 0.46399997114322283","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"warning: Computing average efficiencies\nWhen computing time-averaged efficiencies, it is better to first time-average the simulation and then compute the efficiencies from the averaged plasma properties then it is to average the instantaneous efficiencies. For example,avg_eff = mean(HallThruster.anode_eff(my_solution)) # not ideal\navg_eff = HallThruster.anode_eff(time_average(my_solution)[] # better","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"The mass utilization efficiency is the ratio of the ion beam mass flow rate to the total anode input mass flow rate and is computed with compute_mass_eff:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> HallThruster.mass_eff(my_solution)\n10000-element Vector{Float64}:\n 1.3406882897286088\n 1.2966376960524595\n ⋮\n 1.0022667540786294\n 1.0022667540739632","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"The current utilization efficiency is the ratio of the ion current to the discharge current:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> HallThruster.current_eff(my_solution)\n10000-element Vector{Float64}:\n 0.599052550532874\n 0.58182111692138\n ⋮\n 0.552664262832069\n 0.5526642628312223","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"The voltage utilization efficiency is the ratio of the effective acceleration voltage to the discharge voltage:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> HallThruster.voltage_eff(my_solution)\n10000-element Vector{Float64}:\n 0.9962185160007747\n 0.9699301625865606\n ⋮\n 0.8856545575551746\n 0.8856545575546175","category":"page"},{"location":"run/#Extracting-plasma-properties","page":"Tutorial","title":"Extracting plasma properties","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"To access a plasma property, you index the solution by the symbol corresponding to that property. For example, to get the plasma density at every frame, I would type:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> ne = my_solution[:ne]\n10000-element Vector{Vector{Float64}}:\n...","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"This returns a Vector of Vectors containing the number density at every frame and every cell. To get the number density just in the 325th frame, I would type","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> ne_end = my_solution[:ne][325]\n152-element Vector{Float64}:\n 9.638776090165182e16\n 9.638776090165182e16\n 1.1364174787296864e17\n ⋮\n 2.568578735293536e17\n 2.532630941584664e17\n 2.532630941584664e17","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"This has 152 elements, one for each of the 150 interior cells and 2 for the left and right boundary. To get the axial locations of these cells in meters, we can access sol.params.z_cell.","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"For ion parameters (ion density and velocity), we specify which charge state we want to extract. For example, to get the velocity (in m/s) of doubly-charged Xenon at the 4900th frame, we would type:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> ui = my_solution[:ui, 2][4900]\n152-element Vector{Float64}:\n -1795.4362688519843\n -1724.298256534735\n -1647.858433966283\n ⋮\n 27654.42396859592\n 27735.77112807524\n 27735.756446024698","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"Here, indexing by [:ui, 2] means we want the velocity for doubly-charged ions. We could similarly index by [:ni, 1] for the density of singly-charged ions.","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"A list of parameters that support this sort of indexing can be found by calling HallThruster.saved_fields(). A few of these are:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"B: Magnetic field strength in Tesla\nωce: Cyclotron frequency in Hz\nνan: Anomalous collision frequency in Hz\nνe: Total electron collision frequency in Hz\nνc: Classical collision frequency in Hz\nνei: Electron-ion collision frequency in Hz\nνen: Electron-neutral collision frequency in Hz\nνex: Excitation collision frequency in Hz\nνiz: Ionization collision frequency in Hz\nradial_loss_frequency: Electron-wall collision frequency for wall loss calculation in Hz\nνew_momentum: Electron-wall collision frequency for mobility calculation in Hz\nμ: Electron mobility\nE: Electric field\nϕ: plasma potential at cell centers in V\nTev: Electron temperature in eV\npe: Electron pressure in eV/m^3\n∇pe: Electron pressure gradient\nnn: Neutral density\nni: Ion density (default 1st charge state, index by [:ni, Z] to get charge state Z)\nui: Ion velocity (default 1st charge state, index by [:ui, Z] to get charge state Z)","category":"page"},{"location":"run/#Saving-simulations-for-use-as-restarts","page":"Tutorial","title":"Saving simulations for use as restarts","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"To save a simulation for later, you can use the write_restart function. We can then read it back with the read_restart function:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> HallThruster.write_restart(\"my_restart.jld2\", my_solution);\n\njulia> HallThruster.read_restart(\"my_restart.jld2\")\nHall thruster solution with 10000 saved frames\nRetcode: Success\nEnd time: 0.001 seconds","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"To use a restart as the initial condition for a simulation, you can use the restart keyword argument in the run_simulation function:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> @time my_solution = HallThruster.run_simulation(my_config; ncells=150, nsave=10000, dt=1e-8, duration=1e-3, restart = \"my_restart.jld2\")\n 34.700016 seconds (7.27 M allocations: 1016.374 MiB, 0.79% gc time, 5.42% compilation time)\nHall thruster solution with 10000 saved frames\nRetcode: Success\nEnd time: 0.001 seconds","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"If we plot the currents, we see that the simulation remained at the steady state established in the initial run:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"(Image: )","category":"page"},{"location":"internals/","page":"Internals","title":"Internals","text":"CurrentModule = HallThruster","category":"page"},{"location":"internals/","page":"Internals","title":"Internals","text":"","category":"page"},{"location":"internals/","page":"Internals","title":"Internals","text":"Modules = [HallThruster]","category":"page"},{"location":"internals/#HallThruster.Air","page":"Internals","title":"HallThruster.Air","text":"Air::Gas\n\nEarth air at standard temperature and pressure\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.Argon","page":"Internals","title":"HallThruster.Argon","text":"Argon::Gas\n\nArgon gas\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.Bismuth","page":"Internals","title":"HallThruster.Bismuth","text":"Bismuth::Gas\n\nBismuth vapor\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.Electron","page":"Internals","title":"HallThruster.Electron","text":"Electron::Species\n\nElectron\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.Krypton","page":"Internals","title":"HallThruster.Krypton","text":"Krypton::Gas\n\nKrypton gas\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.LOOKUP_ZS","page":"Internals","title":"HallThruster.LOOKUP_ZS","text":"Lookup for thermal conductivity coefficients, from Table 1 of S. I. Braginskii, in Reviews of Plasma Physics (1965), Vol. 1, p. 205.\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.Mercury","page":"Internals","title":"HallThruster.Mercury","text":"Mercury::Gas\n\nMercury vapor\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.NA","page":"Internals","title":"HallThruster.NA","text":"NA\n\nNumber of atoms in a kg-mol (6.02214076e26 / kmol)\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.R0","page":"Internals","title":"HallThruster.R0","text":"R0\n\nUniversal gas constant (8314.46261815324 J / kmol K)\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.Xenon","page":"Internals","title":"HallThruster.Xenon","text":"Xenon::Gas\n\nXenon gas\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.e","page":"Internals","title":"HallThruster.e","text":"e\n\nElectron charge (1.602176634e-19 Coulomb)\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.kB","page":"Internals","title":"HallThruster.kB","text":"kB\n\nBoltzmann constant (1.380649e-23 J/K)\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.me","page":"Internals","title":"HallThruster.me","text":"me\n\nElectron mass (9.10938356e-31 kilograms)\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.AnomalousTransportModel","page":"Internals","title":"HallThruster.AnomalousTransportModel","text":"AnomalousTransportModel\n\nThe abstract supertype of all types of anomalous transport models. Subtype this to define your own model.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Bohm","page":"Internals","title":"HallThruster.Bohm","text":"Bohm(c) <: AnomalousTransportModel\n\nModel where the anomalous collision frequency scales with the electron cyclotron frequency ωce times some scaling factor c\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Braginskii","page":"Internals","title":"HallThruster.Braginskii","text":"Braginskii conductivity model for fully-ionized plasmasa\nS. I. Braginskii, in Reviews of Plasma Physics (1965), Vol. 1, p. 205.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Config","page":"Internals","title":"HallThruster.Config","text":"struct Config{A<:HallThruster.AnomalousTransportModel, TC<:HallThruster.ThermalConductivityModel, W<:HallThruster.WallLossModel, IZ<:HallThruster.IonizationModel, EX<:HallThruster.ExcitationModel, EN<:HallThruster.ElectronNeutralModel, HET<:HallThruster.Thruster, S_N, S_IC, S_IM, S_ϕ, S_E, T<:HallThruster.TransitionFunction, IC<:HallThruster.InitialCondition, HS<:HallThruster.HyperbolicScheme}\n\nHall thruster configuration struct. Only four mandatory fields: discharge_voltage, thruster, anode_mass_flow_rate, and domain.\n\nFields\n\ndischarge_voltage::Float64\ncathode_potential::Float64\nanode_Te::Float64\ncathode_Te::Float64\nwall_loss_model::HallThruster.WallLossModel\nneutral_velocity::Float64\nneutral_temperature::Float64\nimplicit_energy::Float64\npropellant::HallThruster.Gas\nncharge::Int64\nion_temperature::Float64\nanom_model::HallThruster.AnomalousTransportModel\nconductivity_model::HallThruster.ThermalConductivityModel\nionization_model::HallThruster.IonizationModel\nexcitation_model::HallThruster.ExcitationModel\nelectron_neutral_model::HallThruster.ElectronNeutralModel\nelectron_ion_collisions::Bool\nmin_number_density::Float64\nmin_electron_temperature::Float64\ntransition_function::HallThruster.TransitionFunction\ninitial_condition::HallThruster.InitialCondition\nmagnetic_field_scale::Float64\nsource_neutrals::Any\nsource_ion_continuity::Any\nsource_ion_momentum::Any\nsource_potential::Any\nsource_energy::Any\nscheme::HallThruster.HyperbolicScheme\nthruster::HallThruster.Thruster\ndomain::Tuple{Float64, Float64}\nLANDMARK::Bool\nanode_mass_flow_rate::Float64\nion_wall_losses::Bool\nsolve_background_neutrals::Bool\nbackground_pressure::Float64\nbackground_neutral_temperature::Float64\nanode_boundary_condition::Symbol\nanom_smoothing_iters::Int64\nsolve_plume::Bool\nelectron_plume_loss_scale::Float64\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.ExcitationLookup","page":"Internals","title":"HallThruster.ExcitationLookup","text":"ExcitationLookup(;[directories::Vector{String} = String[]])\n\nDefault excitation model for HallThruster.jl. Reads excitation rate coefficients from file. Looks (preferentially) in provided directories and in the reactions subfolder for rate coefficient files\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Gas","page":"Internals","title":"HallThruster.Gas","text":"Gas\n\nA chemical element in the gaseous state. Container for element properties used in fluid computations.\n\nFields\n\nname::String Full name of gas (i.e. Xenon)\n\nshort_name::String Short name/symbol (i.e. Xe for Xenon)\n\nγ::Float64 Specific heat ratio / adiabatic index\n\nM::Float64 Molar mass (grams/mol) or atomic mass units\n\nm::Float64 Mass of atom in kg\n\ncp::Float64 Specific heat at constant pressure in J / kg / K\n\ncv::Float64 Specific heat at constant volume in J / kg / K\n\nR::Float64 Gas constant in J / kg / K\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Gas-Tuple{Any, Any}","page":"Internals","title":"HallThruster.Gas","text":"Gas(name::String, short_name::String; γ::Float64, M::Float64)\n\nInstantiate a new Gas, providing a name, short name, the adiabatic index, and the molar mass. Other gas properties, including gas constant, specific heats at constant pressure/volume, and mass of atom/molecule in kg will are then computed.\n\njulia> Gas(\"Xenon\", \"Xe\", γ = 5/3, M = 83.798)\nXenon\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.Grid1D-Tuple{Any, Any}","page":"Internals","title":"HallThruster.Grid1D","text":"Grid1D(geometry, z_edge)\n\nGiven 1-D edge coordinates and thruster geometry, compute cell centers and cell volumes for grid\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.IonizationLookup","page":"Internals","title":"HallThruster.IonizationLookup","text":"IonizationLookup(;[directories::Vector{String} = String[]])\n\nDefault ionization model for HallThruster.jl. Reads ionization rate coefficients from file. Looks (preferentially) in provided directories and in the reactions subfolder for rate coefficient files\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.LANDMARK_conductivity","page":"Internals","title":"HallThruster.LANDMARK_conductivity","text":"LANDMARK, uses 10/9 μnϵ\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.LandmarkExcitationLookup","page":"Internals","title":"HallThruster.LandmarkExcitationLookup","text":"LandmarkExcitationLookup()\n\nExcitation model for the LANDMARK benchmark.\n\nReads excitation rate coefficients from the landmark/landmark_rates.csv file in the HallThruster.jl main directory. Supports only singly-charged Xenon.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.LandmarkIonizationLookup","page":"Internals","title":"HallThruster.LandmarkIonizationLookup","text":"LandmarkIonizationLookup()\n\nIonization model for the LANDMARK benchmark.\n\nReads ionization rate coefficients from the landmark/landmark_rates.csv file in the HallThruster.jl main directory. Supports only singly-charged Xenon.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Mitchner","page":"Internals","title":"HallThruster.Mitchner","text":"Mitchner-Kruger conductivity model for partially-ionized plasmas\nM. Mitchner and C. H. Kruger, Jr., Partially Ionized Gases (1973). Pg. 94\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.MultiLogBohm","page":"Internals","title":"HallThruster.MultiLogBohm","text":"MultiLogBohm(zs, cs) <: AnomalousTransportModel\n\nModel similar to that employed in Hall2De, where the mobility is Bohm-like (i.e. νan(z) = c(z) * ωce(z)) and z is in meters.\n\nThe function c(z) is defined by a sequence of nodes (z, c) provided by the user. At z = z[1], c(z) = c[1], and so forth.\n\nAt z[i] < z < z[i+1], log(c) is defined by linearly interpolating between log(c[i]) and log(c[i+1]).\n\nFor z < z[1], c = c[1] and for z > z[end], c(z) = c[end].\n\nThe user may also provide a single array of [z[1], z[2], ..., z[end], c[1], c[2], ..., c[end]]. The number of z values must be equal to the number of c values.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.NoAnom","page":"Internals","title":"HallThruster.NoAnom","text":"NoAnom <: AnomalousTransportModel\n\nNo anomalous collision frequency included in simulation\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.NoExcitation","page":"Internals","title":"HallThruster.NoExcitation","text":"NoExcitation <: ExcitationModel\n\nModel for neglecting excitation energy losses\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.ShiftedTwoZoneBohm","page":"Internals","title":"HallThruster.ShiftedTwoZoneBohm","text":"ShiftedTwoZoneBohm(coeffs, z0, dz, alpha, pstar) <: AnomalousTransportModel\n\nModel where the anomalous collision frequency has two values: c1 * ωce before some transition location and c2 * ωce after. Takes two arguments: c1 and c2. The transition between these values can be smoothed by the user-provided transition function. The location of the transition is based on the background pressure and the user-provided coefficients.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Species","page":"Internals","title":"HallThruster.Species","text":"Species\n\nRepresents a gas with a specific charge state. In a plasma, different ionization states of the same gas may coexist, so we need to be able to differentiate between these.\n\njulia> Species(Xenon, 0)\nXe\n\njulia> Species(Xenon, 1)\nXe+\n\njulia> Species(Xenon, 3)\nXe3+\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.ThermalConductivityModel","page":"Internals","title":"HallThruster.ThermalConductivityModel","text":"Thermal_Conductivity\n\nThe abstract supertype of all types of thermal conductivity models. Subtype this to define your own model.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Thruster","page":"Internals","title":"HallThruster.Thruster","text":"Thruster\n\nStruct containing information about a Hall thruster. This includes a name, geometry (a Geometry1D object), magnetic_field (radial magnetic field along centerline, a function which takes z in meters and outputs B in Tesla), and a shielded (a flag indicating whether the thruster is magnetically-shielded).\n\nFields\n\nname::String\ngeometry::HallThruster.Geometry1D\nmagnetic_field::Any\nshielded::Bool\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.TwoZoneBohm","page":"Internals","title":"HallThruster.TwoZoneBohm","text":"TwoZoneBohm(c1, c2) <: AnomalousTransportModel\n\nModel where the anomalous collision frequency has two values: c1 * ωce inside the channel and c2 * ωce outside of the channel. Takes two arguments: c1 and c2. The transition between these values can be smoothed by the user-provided transition function.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.WallLossModel","page":"Internals","title":"HallThruster.WallLossModel","text":"abstract type WallLossModel\n\nAbstract type for wall loss models in the electron energy equation. Types included with HallThruster.jl are:\n\nNoWallLosses No electron energy losses to the wall.\nConstantSheathPotential(sheath_potential, inner_loss_coeff, outer_loss_coeff) Power to the walls scales with α * exp(-sheath_potential)), where α = inner_loss_coeff inside the channel and α = outer_loss_coeff outside.\nWallSheath(material::WallMaterial) Power to the walls is computed self-consistently using a sheath model, dependent on the secondary electron emission yield of the provided material. See WallMaterial for material options.\n\nUsers implementing their own WallLossModel will need to implement at least three methods 1) freq_electron_wall(model, U, params, i): Compute the electron-wall momentum transfer collision frequency in cell i 2) wall_power_loss(model, U, params, i): Compute the electron power lost to the walls\n\nA third method, wall_electron_current(model, U, params, i), will compute the electron current to the walls in cell i. If left unimplemented, it defaults to Ie,w = e ne νew Vcell where Vcell is the cell volume.\n\nA fourth method, wall_ion_current(model, U, params, i, Z), for computing the current of ions of charge Z to the walls in cell i, may also be implemented. If left unimplemented, it will default to computing the current assuming Ie,w = Ii,w.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.EvenGrid-Tuple{Any}","page":"Internals","title":"HallThruster.EvenGrid","text":"EvenGrid(n)\n\nConstruct an evenly-spaced grid with n cells.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.UnevenGrid","page":"Internals","title":"HallThruster.UnevenGrid","text":"UnevenGrid(n, density = HallThruster.default_density)\n\nConstruct an unevenly-spaced grid according to provided density function. Defaults to twice as many grids inside of channel than outside. Provided density functions must have a signature of (z, z0, z1, Lch) where z is the location, (z0, z1) are the extents of the domain and Lch is the channel length\n\n\n\n\n\n","category":"function"},{"location":"internals/#HallThruster.allocate_anom_variables-Tuple{HallThruster.AnomalousTransportModel, Any}","page":"Internals","title":"HallThruster.allocate_anom_variables","text":"allocate_anom_variables(::AnomalousTransportModel, ncells)\n\nAllocate arrays for anomalous transport state variables. ncells is the length of the arrays to be allocated. These anomalous transport variables are then stored in params.cache.anom_variables\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.backward_diff_coeffs-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.backward_diff_coeffs","text":"backward_diff_coeffs(x0, x1, x2)\n\nGenerate finite difference coefficients for a backward first derivative approximation at the point x2 on a three-point stencil at points x0, x1, and x2\n\njulia> backward_diff_coeffs(-2//1, -1//1, 0//1)\n(1//2, -2//1, 3//2)\njulia> backward_diff_coeffs(-3//2, -1//1, 0//1)\n(4//3, -3//1, 5//3)\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.backward_difference-NTuple{6, Any}","page":"Internals","title":"HallThruster.backward_difference","text":"backward_difference(f0, f1, f2, x0, x1, x2)\n\nGiven three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the derivative at x2\n\nf(x) = x^4\nx0, x1, x2 = 1.9999998, 1.9999999, 2\nbd = backward_difference(f(x0), f(x1), f(x2), x0, x1, x2)\nbd ≈ 32\n\n# output\n\ntrue\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.central_diff_coeffs-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.central_diff_coeffs","text":"central_diff_coeffs(x0, x1, x2)\n\nGenerate finite difference coefficients for a central first derivative approximation at the point x1 on a three-point stencil at points x0, x1, and x2\n\njulia> central_diff_coeffs(-1//1, 0//1, 1//1)\n(-1//2, 0//1, 1//2)\njulia> central_diff_coeffs(-1//2, 0//1, 1//1)\n(-4//3, 1//1, 1//3)\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.central_difference-NTuple{6, Any}","page":"Internals","title":"HallThruster.central_difference","text":"central_difference(f0, f1, f2, x0, x1, x2)\n\nGiven three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the derivative at x1\n\nf(x) = x^4\nx0, x1, x2 = 1.9999999, 2, 2.0000001\ncd = central_difference(f(x0), f(x1), f(x2), x0, x1, x2)\ncd ≈ 32\n\n# output\n\ntrue\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.channel_area-Tuple{Any, Any}","page":"Internals","title":"HallThruster.channel_area","text":"channel_area(outer_radius, inner_radius)\n\nCompute the cross-sectional area of a Hall thruster channel from its dimensions\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.channel_perimeter-Tuple{Any, Any}","page":"Internals","title":"HallThruster.channel_perimeter","text":"channel_perimeter(outer_radius, inner_radius)\n\nCompute the perimeteter of the thruster channel, equal to the sum of the inner and outer circumferences\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.channel_width-Tuple{Any, Any}","page":"Internals","title":"HallThruster.channel_width","text":"channel_width(outer_radius, inner_radius)\n\nCompute the thruster channel width\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.compute_current","page":"Internals","title":"HallThruster.compute_current","text":"compute_current(sol, location)\n\ncompute current at anode or cathode = outflow in 1D code.\n\n\n\n\n\n","category":"function"},{"location":"internals/#HallThruster.coulomb_logarithm","page":"Internals","title":"HallThruster.coulomb_logarithm","text":"coulomb_logarithm(ne, Tev, Z = 1)\n\ncalculate coulomb logarithm for electron-ion collisions as a function of ion charge state Z, electron number density in m^-3, and electron temperature in eV.\n\n\n\n\n\n","category":"function"},{"location":"internals/#HallThruster.downwind_diff_coeffs-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.downwind_diff_coeffs","text":"downwind_diff_coeffs(x0, x1, x2)\n\nGenerate finite difference coefficients for a downwind first derivative approximation at the point x2 on a three-point stencil at points x0, x1, and x2 (uses only points x1 and x2)\n\njulia> downwind_diff_coeffs(-1//1, 0//1, 2//1)\n(0//1, -1//2, 1//2)\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.electron_mobility-Tuple{Any, Any}","page":"Internals","title":"HallThruster.electron_mobility","text":"electron_mobility(νe, B)\n\ncalculates electron transport according to the generalized Ohm's law as a function of sum of the classical and anomalous collision frequencies and the magnetic field.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.forward_diff_coeffs-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.forward_diff_coeffs","text":"forward_diff_coeffs(x0, x1, x2)\n\nGenerate finite difference coefficients for a forward first derivative approximation at the point x0 on a three-point stencil at points x0, x1, and x2\n\njulia> forward_diff_coeffs(1.0, 2.0, 3.0)\n(-1.5, 2.0, -0.5)\njulia> forward_diff_coeffs(0//1, 1//2, 3//2)\n(-8//3, 3//1, -1//3)\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.forward_difference-NTuple{6, Any}","page":"Internals","title":"HallThruster.forward_difference","text":"forward_difference(f0, f1, f2, x0, x1, x2)\n\nGiven three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the derivative at x0\n\nf(x) = x^4\nx0, x1, x2 = 2.0, 2.000001, 2.000002\nfd = forward_difference(f(x0), f(x1), f(x2), x0, x1, x2)\nfd ≈ 32\n\n# output\n\ntrue\n\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.freq_electron_electron-Tuple{Number, Number}","page":"Internals","title":"HallThruster.freq_electron_electron","text":"freq_electron_electron(ne, Tev)\n\nEffective frequency at which electrons are scattered due to collisions with other electrons\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.freq_electron_ion-Tuple{Number, Number, Number}","page":"Internals","title":"HallThruster.freq_electron_ion","text":"freq_electron_ion(ne, Tev, Z)\n\nEffective frequency at which electrons are scattered due to collisions with ions\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.freq_electron_neutral-Union{Tuple{T}, Tuple{Array{HallThruster.ElasticCollision{T}, 1}, Number, Number}} where T","page":"Internals","title":"HallThruster.freq_electron_neutral","text":"freq_electron_neutral(model::ElectronNeutralModel, nn, Tev)\n\nEffective frequency of electron scattering caused by collisions with neutrals\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.generate_grid-Union{Tuple{F}, Tuple{Any, Any, HallThruster.HallThrusterGrid{F}}} where F","page":"Internals","title":"HallThruster.generate_grid","text":"generate_grid(geometry, ncells)\n\nGenerate a one-dimensional uniform grid on the domain specified in the geomety. Returns number of cells, coordinates of cell centers (plus ghost cells face coordinates), interface/edges and volume of a cell for number density calculations.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.interpolation_coeffs-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.interpolation_coeffs","text":"interpolation_coeffs(x, x0, x1, y0, y1)\n\nCompute the coefficients for interpolation between two points (x0, y0) and (x1, y1) such that y = c0 * y0 + c1 * y1 ```jldoctest;setup = :(using HallThruster: itpcoeffs, lerp) julia> c0, c1 = interpolationcoeffs(0.5, 0.0, 1.0, 0.0, 2.0) (0.5, 0.5) julia> c0 * 0.0 + c1 * 2.0 == lerp(0.5, 0.0, 1.0, 0.0, 2.0) true\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.lerp-NTuple{5, Any}","page":"Internals","title":"HallThruster.lerp","text":"lerp(x, x0, x1, y0, y1)\n\nInterpolate between two points (x0, y0) and (x1, y1) ```jldoctest;setup = :(using HallThruster: lerp) julia> lerp(0.5, 0.0, 1.0, 0.0, 2.0) 1.0\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.load_reactions-Tuple{HallThruster.ChargeExchangeFit, Any}","page":"Internals","title":"HallThruster.load_reactions","text":"Charge exchange fits from Hause, Prince and Bemish, 2013\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.load_reactions-Tuple{HallThruster.ReactionModel, Any}","page":"Internals","title":"HallThruster.load_reactions","text":"load_reactions(model::ReactionModel, species)::Vector{IonizationReaction}\n\nLoad ionization reactions for the provided species and ionization model\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.maximum_charge_state-Tuple{HallThruster.ReactionModel}","page":"Internals","title":"HallThruster.maximum_charge_state","text":"maximum_charge_state(model::ReactionModel)::Int\n\nReturn the maximum supported charge state for a given reaction model. If 0 is returned, then no charge state restriction is applied.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.nodes_from_density-NTuple{5, Any}","page":"Internals","title":"HallThruster.nodes_from_density","text":"nodes_from_density(density, x0, x1, N)\n\nGiven bounds x0, x1, a number of points N, and a density function density(x), generate N nodes betweeen x0 and x1 spaced according to the provided desity function using inverse CDF transformation.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.num_anom_variables-Tuple{HallThruster.AnomalousTransportModel}","page":"Internals","title":"HallThruster.num_anom_variables","text":"num_anom_variables(::AnomalousTransportModel)::Int\n\nThe number of variable arrays that should be allocated for the provided anomalous transport model. These arrays are used to save state beyond the anomalous collision frequency, and are useful for defining more complex anomalous transport models. If not defined by the user, this defaults to zero. \n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.read_restart-Tuple{AbstractString}","page":"Internals","title":"HallThruster.read_restart","text":"read_restart(path::AbstractString)\n\nLoad a JLD2 restart file from path.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.run_simulation-Tuple{HallThruster.Config}","page":"Internals","title":"HallThruster.run_simulation","text":"run_simulation(\n config;\n grid,\n ncells,\n dt,\n duration,\n nsave,\n restart,\n CFL,\n adaptive,\n control_current,\n target_current,\n Kp,\n Ti,\n Td,\n time_constant,\n dtmin,\n dtmax,\n verbose\n)\n\n\nRun a Hall thruster simulation using the provided Config object.\n\nArguments\n\nconfig: a Config containing simulation parameters.\ndt: The timestep, in seconds. Typical values are O(10 ns) (1e-8 seconds).\nduration: How long to run the simulation, in seconds (simulation time, not wall time). Typical runtimes are O(1 ms) (1e-3 seconds).\nncells: How many cells to use. Typical values are 100 - 1000 cells.\nnsave: How many frames to save.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.second_deriv_central_diff-NTuple{6, Any}","page":"Internals","title":"HallThruster.second_deriv_central_diff","text":"second_deriv_central_diff(f0, f1, f2, x0, x1, x2)\n\nGiven three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the second derivative at x1\n\nf(x) = x^4\nx0, x1, x2 = 1.9999, 2.0, 2.0001\nsd = second_deriv_central_diff(f(x0), f(x1), f(x2), x0, x1, x2)\nsd ≈ 48\n\n# output\n\ntrue\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.second_deriv_coeffs-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.second_deriv_coeffs","text":"second_deriv_coeffs(x0, x1, x2)\n\nGenerate finite difference coefficients for a central second derivative approximation at the point x1 on a three-point stencil at points x0, x1, and x2\n\njulia> second_deriv_coeffs(-2//1, 0//1, 2//1)\n(1//4, -1//2, 1//4)\njulia> second_deriv_coeffs(-1//2, 0//1, 1//1)\n(8//3, -4//1, 4//3)\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.sheath_potential-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.sheath_potential","text":"sheath_potential(Tev, γ, mi))\n\ncompute wall sheath to be used for radiative losses and loss to wall. Goebel Katz equ. 7.3-29, 7.3-44. Assumed nₑuₑ/nᵢuᵢ ≈ 0.5 Sheath potentials are positive by convention in HallThruster.jl.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.supported_gases-Tuple{HallThruster.ReactionModel}","page":"Internals","title":"HallThruster.supported_gases","text":"supported_gases(model::ReactionModel)::Vector{HallThruster.Gas}\n\nCheck which gases are supported by a given reaction model. If an empty vector is provided, then there are no restrictions on what gases can be used.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.time_average","page":"Internals","title":"HallThruster.time_average","text":"time_average(sol, tstampstart)\n\ncompute time-averaged solution, input Solution type and the frame at which averaging starts. Returns a Solution object with a single frame.\n\n\n\n\n\n","category":"function"},{"location":"internals/#HallThruster.upwind_diff_coeffs-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.upwind_diff_coeffs","text":"upwind_diff_coeffs(x0, x1, x2)\n\nGenerate finite difference coefficients for a upwind first derivative approximation at the point x2 on a three-point stencil at points x0, x1, and x2 (uses only points x0 and x1)\n\njulia> upwind_diff_coeffs(-3//1, 0//1, 2//1)\n(-1//3, 1//3, 0//1)\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.write_restart-Tuple{AbstractString, Any}","page":"Internals","title":"HallThruster.write_restart","text":"write_restart(path::AbstractString, sol)\n\nWrite a JLD2 restart file to path`.\n\nThis can be reloaded to resume a simulation.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.σ_en-Tuple{Any}","page":"Internals","title":"HallThruster.σ_en","text":"σ_en(Tev)\n\nElectron neutral collision cross section in m² as a function of electron temperature in eV. Eq. 3.6-13, from Fundamentals of Electric Propulsion, Goebel and Katz, 2008.\n\n\n\n\n\n","category":"method"},{"location":"boundary_conditions/#Boundary-Conditions","page":"Boundary Conditions","title":"Boundary Conditions","text":"","category":"section"},{"location":"boundary_conditions/","page":"Boundary Conditions","title":"Boundary Conditions","text":"HallThruster.jl solves fluid hyperbolic conservation laws. As such, boundary conditions on at least one side have to be specified. Dirichlet boundary conditions are applied on both sides in the potential equation. ","category":"page"},{"location":"boundary_conditions/#Background","page":"Boundary Conditions","title":"Background","text":"","category":"section"},{"location":"boundary_conditions/","page":"Boundary Conditions","title":"Boundary Conditions","text":"The outflow side, which in the 1D domain conincides with the cathode, is usually left unspecified, i.e. no boundary conditions are applied. On the left side, corresponding to the anode, the neutral mass inflow is fixed, while the ion velocity is forced to be at least the Bohm velocity. The anode mass flow rate can be set in the Configuration. The potential employs Dirichlet boundary conditions at both anode and cathode (subject to change once a more accurate anode sheath model has been implemented). Currently the cathode potential is set to zero, and the anode potential can be set using discharge_voltage in the Configuration. The electron energy uses Dirichlet boundaries as well on both the anode and cathode, usually fixed to 2 or 3 eV. Note that this does not correspond to Dirichlet boundaries on the internal energy equations, since this is solved for the product of internal energy and density. ","category":"page"},{"location":"numerics/#Numerics","page":"Numerics","title":"Numerics","text":"","category":"section"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"As described in Configuration and Initialization different flux options are available in HyperbolicScheme. Timemarching for the heavy species is handled using a second order strong-stability preserving Runge-Kutta scheme (SSPRK22). The left hand side of the electron energy equation is integrated implicitly using a Crank Nicolson Adams Bashforth (CNAB) scheme. This enables larger timessteps due to the severe restrictions due to the electron heat flux.","category":"page"},{"location":"numerics/#Spatial-discretization-for-heavy-species","page":"Numerics","title":"Spatial discretization for heavy species","text":"","category":"section"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"Neutrals and ions are considered heavy species (compared to electrons). HallThruster.jl uses the finite volume method (FVM). FVM has the advantage that it is by definition conservative, which is a useful property when solving hyperbolic conservation laws such as the Euler equations. Currently, only the continuity equation is solved for the neutrals and the isothermal Euler equations for the ion species. Possibly, the full Euler equations will be added in the future, its implementation has been verified using the Sod Shock tube. The following provides and example of the control volume approach applied to the continuity equation.","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"int_i-frac12^i+frac12 fracpartial n_npartial t dz + int_i-frac12^i+frac12 fracpartial n_n u_npartial z dz = int_i-frac12^i+frac12 dotn_n dz","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"The n_n u_n can be replaced by a generic flux term F(z) and generalized to any advection like equation. Treatment of the source term is described in Collisions and Reactions. Integration results in","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"hfracpartial n_npartial t + left(F__i+frac12 - F__i-frac12right) = h dotn_n","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"See Fluxes for the implemented fluxes, and possible limiters to be used in reconstruction to ensure a total variation diminishing scheme (TVD).","category":"page"},{"location":"numerics/#Time-discretization-of-heavy-species","page":"Numerics","title":"Time discretization of heavy species","text":"","category":"section"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"We employ a strong stability preserving second-order Runge Kutta schemes (SSPRK22) for timestepping","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"The user has the option to supply a fixed timestep, or a CFL number. In the former case, the user will need to select a timestep that obeys the CFL condition, defined as","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":" sigma = fracu_i Delta tDelta x 1","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"Using a maximum ion velocity of 22000 m/s, a domain length of 0.05m and 200 cells, results in Delta t leq 12 times 10^-8 s. In practice, it needs to be a bit lower in order to handle transients as the solution oscillates. This restriction is valid for the continuity and isothermal euler equations. Information on setting dt and selecting the integration scheme can be found in the Tutorial.","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"In most cases, it is better to let HallThruster.jl handle timestepping automatically using its adaptive timestepping option. If adaptive timestepping is enabled, the user-defined timestep is ignored in favor of a timestep based on the minimum of three conditions and a user-supplied CFL number. Mathematically the timstep is choosen as:","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":" Delta t = min(sigma fracDelta xmax(u_i + a_i u_i - a_i) sigma fracdotn_in_i sqrtfracsigma m_i Delta xq_i E)","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"Where a_i is the ion sound speed. Physically, these three conditions represent timestep limits imposed by the flux, ionization, and electrostatic acceleration. Keep in mind that due to stability limits imposed by the ionization condition, the CFL number cannot be higher than 0.799 to remain stable. This limit will be imposed by HallThruster.jl if the user-defined value is too high.","category":"page"},{"location":"numerics/#Electron-energy-equation-discretization","page":"Numerics","title":"Electron energy equation discretization","text":"","category":"section"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"While the ions can be explicitly solved with Delta t sim 10^-8s, the heat condution term in the electron energy equation adds additional constraints which would lower the timestep by about a factor of 10. In order to not further increase the timestepping restrictions and increase computation time, the electron energy equation is solved semi-implicitly in time using a backward Euler or Crank-Nicholson scheme. See Configuration for information on how to select which scheme is used.","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"The spatial discretization of the electron energy equation uses central finite differences in a manner similar to the potential solver (see below). This, combined with the semi-implicit timestepping, creates a tridiagonal linear system which can be efficiently solved using the Thomas algorithm.","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"If adaptive timestepping is enabled, the timestep used for the explicit terms is limited by:","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":" Delta t = absfrac3sigma n_eT_eW_loss + S_coll","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"As this timestep may be significantly smaller than the timestep used for the heavy species, the electron energy equation is updated using a series of sub-steps with the Delta t enforced by the equation above until a total Delta t equal to that set by the heavy species is reached.","category":"page"},{"location":"numerics/#Evaluation-of-derivatives","page":"Numerics","title":"Evaluation of derivatives","text":"","category":"section"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"Some computations require the numerical approximation of derivatives, for example the evaluation of the electron velocity from the equation for electron current using the generalized Ohm's law, see Physics model. The derivatives are evaluated to second order using forward difference, central difference or backward difference depending on the location in the domain.","category":"page"},{"location":"source_terms/#User-Provided-Source-Terms","page":"User-Provided Source Terms","title":"User-Provided Source Terms","text":"","category":"section"},{"location":"source_terms/","page":"User-Provided Source Terms","title":"User-Provided Source Terms","text":"HallThruster allows users to provide additional source terms if they want. We make use of this function internally when we perform order verification studies (see Verification, as well as our order verification tests in /tests/order_verification.jl). This may also be useful when implementing additional physics. Users may provide seperate source terms for each of the solved equations. The corresponding fields in the Config struct are","category":"page"},{"location":"source_terms/","page":"User-Provided Source Terms","title":"User-Provided Source Terms","text":"source_neutrals\nsource_potential\nsource_electron_energy\nsource_ion_continuity\nsource_ion_momentum","category":"page"},{"location":"source_terms/","page":"User-Provided Source Terms","title":"User-Provided Source Terms","text":"The first three act similarly. HallThruster expects a function which takes (U, params, i) as an argument, where U is the state matrix, params is the NamedTuple of paramters, and i is the cell index. The source term should then return a scalar, which is added to the right-hand side of the corresponding equation.","category":"page"},{"location":"source_terms/","page":"User-Provided Source Terms","title":"User-Provided Source Terms","text":"As we allow for multiple ion charge states, source_ion_continuity and source_ion_momentum should be of type Tuple or Vector and contain one function for each charge state, with the same expected signature and return type as above.","category":"page"},{"location":"source_terms/","page":"User-Provided Source Terms","title":"User-Provided Source Terms","text":"warning: Concrete vs abstract types\nFor performance, it is important that Julia is able to infer the return type of your source term. Therefore, you must ensure that the values passed to source_ion_continuity and source_ion_momentum are concretely-typed. For example, this would not be ideal:source_ion_momentum = [\n (U, params, i) -> 2.0,\n (U, params, i) -> 3.0,\n (U, params, i) -> -1\n]because the type of this term is not concrete:julia> typeof(source_ion_momentum)\nVector{Function} (alias for Array{Function, 1})\n\njulia> isconcretetype(ans)\nfalseBetter would be to implement a callable type, as shown below:struct MySource\n number::Float64\nend\n\n(s::MySource)(U, params, i) = s.number\n\nsource_ion_momentum_concrete = [\n MySource(2.0),\n MySource(3.0),\n MySource(-1),\n]This has identical behavior to the first example, but is a concrete type:julia> typeof(source_ion_momentum_concrete)\nVector{MySource} (alias for Array{MySource, 1})\n\njulia> isconcretetype(ans)\ntrue","category":"page"},{"location":"anomalous_transport/#Anomalous-Transport","page":"Anomalous Transport","title":"Anomalous Transport","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"HallThruster has a few anomalous transport models built in and allows users to define their own. This page describes these models and the process by which algebraic and multi-equation transport models can be added by the user.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"warning: Interface not finalized\nThe AnomalousTransportModel interface is not yet finalized and subject to revision. Keep this in mind when using this feature.","category":"page"},{"location":"anomalous_transport/#Built-in-Models","page":"Anomalous Transport","title":"Built-in Models","text":"","category":"section"},{"location":"anomalous_transport/#NoAnom()","page":"Anomalous Transport","title":"NoAnom()","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Model for no anomalous transport (anomalous collision frequency = 0).","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"anom_model = NoAnom()","category":"page"},{"location":"anomalous_transport/#Bohm(c)","page":"Anomalous Transport","title":"Bohm(c)","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Model where the anomalous collision frequency scales with the electron cyclotron frequency ωce times some scaling factor c","category":"page"},{"location":"anomalous_transport/#TwoZoneBohm(c1,-c2)","page":"Anomalous Transport","title":"TwoZoneBohm(c1, c2)","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"HallThruster's default anomalous transport option. This is a standard model of anomalous transport frequently used in Hall thruster simulations. The anomalous collision frequency is defined as","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"beginaligned\n nu_AN = c_1 omega_ce quad z L_ch \n = c_2 omega_ce quad z L_ch\nendaligned","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"In the above expression, c_1 and c_2 are tunable coefficients, omega_ce = e B m_e is the electron cyclotron frequency, and L_ch is the channel length. A TwoZoneBohm model is initialized as follows","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"anom_model = TwoZoneBohm(c1, c2)","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"The transition between the zones is determined by the user-provided transition function. This defaults to a step function.","category":"page"},{"location":"anomalous_transport/#MultiLogBohm(z,-c)","page":"Anomalous Transport","title":"MultiLogBohm(z, c)","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Model similar to that employed in Hall2De, where the mobility is Bohm-like (i.e. νan(z) = c(z) * ωce(z)) and z is in meters.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"The function c(z) is defined by a sequence of nodes (z, c) provided by the user. At z = z[1], c(z) = c[1], and so forth.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"At z[i] < z < z[i+1], log(c) is defined by linearly interpolating between log(c[i]) and log(c[i+1]).","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"For z < z[1], c = c[1] and for z > z[end], c(z) = c[end].","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"The user may also provide a single array of [z[1], z[2], ..., z[end], c[1], c[2], ..., c[end]]. The number of zvalues must be equal to the number of c values.","category":"page"},{"location":"anomalous_transport/#The-AnomalousTransportModel-interface","page":"Anomalous Transport","title":"The AnomalousTransportModel interface","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Currently, HallThruster.jl expects all models to be written to be callable structs, taking arguments U, params, i, where U is the system state vector, params are the simulation parameters (including the cache of all variables), and i is the index of the cell.","category":"page"},{"location":"anomalous_transport/#Custom-anomalous-transport-models","page":"Anomalous Transport","title":"Custom anomalous transport models","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Users of HallThruster may define their own models by defining a custom subtype of AnomalousTransportModel. Suppose we want to implement nu_AN = beta omega_ce (classic Bohm diffusion). This is a fixed anomalous transport model and does not change as the simulation progresses. We would first define our type:","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"using HallThruster\n\nstruct BohmDiffusion <: AnomalousTransportModel\n β::Float64\nend","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"We then need to define the function which computes the anomalous transport in each cell. This is a mutating function which takes two arguments: the vector of anomalous collision frequency values to be updated, and the solver params.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"function (model::BohmDiffusion)(νan, params)\n\n e = HallThruster.e\n me = HallThruster.me\n B = params.cache.B\n\n for i in eachindex(νan)\n ωce = e * B[i] / me\n νan[i] = model.β * ωce\n end\n\n return νan\nend","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"We can now set anom_model = BohmDiffusion in our config struct (see Configuration) and the simulation will correctly compute the anomalous transport according to our model.","category":"page"},{"location":"anomalous_transport/#More-complex-anomalous-transport-models","page":"Anomalous Transport","title":"More complex anomalous transport models","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Up until now, we have only defined algebraic models of anomalous electron transport. For more high-fidelity models, we might need to solve multiple partial differential equations. Even if we don't want to do that, we still might want to compute other anomalous transport- related quantities at the same time that we update the anomalous transport. Lets see how we might do this.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"As a first example, let's compute an anomalous transport that depends on energy density of electrostatic waves in the plasma. This model derives from Lafleur, Chabert, and Balruud (2016) and has the following form:","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"beginaligned\n nu_AN = K fracnabla cdot mathbfu_i Wm_e n_e c_s v_de\nendaligned","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"In this expression, K is a tunable coefficient, u_i is the ion velocity, W = n_e k_B T_e is the wave energy density, m_e is the electron mass, n_e is the electron number density, c_s is the ion sound speed, and v_de is the electron azimuthal drift speed. Let's say we want to save the wave energy density in addition to the anomalous collision frequency. We begin by defining the model:","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":" struct LafleurModel <: AnomalousTransportModel\n K::Float64\n end","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Next, we add a method to the num_anom_variables function. Since we want to save the wave energy density, we need 1 additional anomalous transport variable.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":" num_anom_variables(::LafleurModel) = 1","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Now, we define the behavior of the model in a function. Since the model is based on assuming the wave energy convects with the ions, we will use upwind differencing for the gradient.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"function (model::LafleurModel)(νan, params)\n \n (;config, cache) = params\n mi = config.propellant.m\n K = model.K\n e = HallThruster.e\n me = HallThruster.me\n (;ne, Tev, ue, ui, νe, anom_variables) = cache\n\n ncells = length(νan)\n\n for i in 2:ncells-1\n\n W = e * ne[i] * Tev[i]\n Hall_param = e * B[i] / me / νe[i]\n vde = Hall_param * ue[i]\n cs = sqrt(e * Tev[i] / mi)\n\n # Upwind differencing of gradient term\n if ui > 0\n dz = params.z_cell[i] - params.z_cell[i-1]\n W_left = e * cache.ne[i-1] * cache.Te[i-1]\n grad_ui_W = (ui[1, i] * W[i] - cache.ui[1, i-1] * W_left) / dz\n else\n dz = params.z_cell[i+1] - params.z_cell[i]\n W_right = e * cache.ne[i+1] * cache.Te[i+1]\n grad_ui_W = (cache.ui[1, i+1] * W_right - ui[i] * W[i]) / dz\n end\n\n # Save W to cache.anom_variables[1]\n anom_variables[1][i] = W\n \n # Return anomalous collision frequency\n νan[i] = abs(K * grad_ui_W / (me * cs * vde * ne))\n end\n\n # Neumann BC anomalous transport\n anom_variables[1][1] = anom_variables[1][2]\n anom_variables[1][end] = anom_variables[1][end-1]\n νan[1] = νan[2]\n νan[end] = νan[end-1]\n \n return νan\nend","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"The saved value of the wave energy density can then be recovered as","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":" solution.savevals[frame].anom_variables[1]","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"where solution is the Solution object resulting from a call to run_simulation","category":"page"},{"location":"anomalous_transport/#Solving-arbitrary-PDEs-using-the-AnomalousTransportModel-interface","page":"Anomalous Transport","title":"Solving arbitrary PDEs using the AnomalousTransportModel interface","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"We can use this basic interface to solve PDEs within HallThruster.jl. We demonstrate this by solving the scalar advection equation using first-order upwind differencing in space and forward Euler integration in time, with periodic boundary conditions. The scalar advection equation is given by:","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":" beginaligned\n fracpartial upartial t + a fracpartial upartial x = 0\n endaligned","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"To begin, we define the model struct and the number of variables we need.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"using HallThruster, Plots\n\nstruct ScalarAdvection{F} <: HallThruster.AnomalousTransportModel\n advection_velocity::Float64 # Advection advection_velocity\n initializer::F # Initialization function\nend\n\n# Save two auxilliary variables\n# 1) Advected quantity u\n# 2) gradient of advected quantity (du/dz)\nHallThruster.num_anom_variables(::ScalarAdvection) = 2","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Next, we define the model function:","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"function (model::ScalarAdvection)(νan, params)\n \n ncells = length(νan)\n \n # Extract variables from params \n cache = params.cache\n z = params.z_cell\n u = cache.anom_variables[1]\n du_dz = cache.anom_variables[2]\n a = model.advection_velocity\n dt = params.dt\n \n if params.iteration[] < 1\n # Initialize\n model.initializer(u, z)\n else\n for i in eachindex(νan)\n # Setup for periodic boundary conditions\n if i == 1\n i_minus_1 = ncells\n dz_minus = z[2] - z[1]\n else\n i_minus_1 = i - 1\n dz_minus = z[i] - z[i-1]\n end\n\n if i == ncells\n i_plus_1 = 1\n dz_plus = z[2] - z[1]\n else\n i_plus_1 = i + 1\n dz_plus = z[i+1] - z[i]\n end\n\n # Update gradient\n if a > 0\n du_dz[i] = (u[i] - u[i_minus_1]) / dz_minus\n else\n du_dz[i] = (u[i_plus_1] - u[i]) / dz_plus\n end\n end\n\n # Update advected quantity\n for i in eachindex(νan)\n u[i] -= a * du_dz[i] * dt\n end\n end\n\n # Return a two-zone bohm anomalous transport result,\n # since we don't really care about the anomalous transport.\n return HallThruster.TwoZoneBohm(1/160, 1/16)(νan, params)\nend","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"And that's it! Now all there is to do is define our simulation parameters and run!","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"\n# Set up config\nadvection_velocity = 1e5\nL = 0.08\n\nconfig = HallThruster.Config(\n domain = (0.0, L),\n anom_model = ScalarAdvection(advection_velocity, initializer),\n thruster = HallThruster.SPT_100,\n discharge_voltage = 300.0,\n anode_mass_flow_rate = 5e-6\n)\n\n# Define dt such that CFL condition is obeyed\nncells = 200\ndx = L / ncells\nCFL = 0.9\ndt = min(1e-8, dx * CFL / advection_velocity)\nnsteps = 1000\n\n# Run simulation\nsolution = HallThruster.run_simulation(\n config;\n ncells, \n dt,\n duration = nsteps * dt, \n nsave = nsteps\n)\n\n# Extract variables from solution\nz = solution.params.z_cell\nu = [saveval.anom_variables[1] for saveval in solution.savevals]","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"We can now visualize the results to make sure everything worked well.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"using Plots\n\n# Time needed to transit the domain\nt_transit = L / advection_velocity\n\n# Number of periods \nnum_periods = floor(Int, nsteps * dt / t_transit)\n\n# Plot results\np = plot(; framestyle = :box, xlabel = \"x\", ylabel = \"u\", title = \"First order upwind for scalar advection\")\nfor i in 0:num_periods\n index = round(Int, i * t_transit / dt) + 1\n plot!(\n p, z, u[index], label = \"After $i periods\",\n linecolor = cgrad(:turbo, num_periods + 1, categorical = true)[i+1]\n )\nend\ndisplay(p)","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"(Image: )","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"This looks correct! In this case, we haven't coupled our PDE solution to the anomalous transport, but one could easily do this. In the same way, systems of two, three, or more coupled PDEs can be solved and related to the anomalous collision frequency.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"The full script is reproduced below:","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"using HallThruster\n\nstruct ScalarAdvection{F} <: HallThruster.AnomalousTransportModel\n advection_velocity::Float64 # Advection advection_velocity\n initializer::F # Initialization function\nend\n\n# Save two auxilliary variables\n# 1) Advected quantity u\n# 2) gradient of advected quantity (du/dz)\nHallThruster.num_anom_variables(::ScalarAdvection) = 2\n\nfunction (model::ScalarAdvection)(νan, params)\n \n ncells = length(νan)\n \n # Extract variables from params \n cache = params.cache\n z = params.z_cell\n u = cache.anom_variables[1]\n du_dz = cache.anom_variables[2]\n a = model.advection_velocity\n dt = params.dt\n \n if params.iteration[] < 1\n # Initialize\n model.initializer(u, z)\n else\n for i in eachindex(νan)\n # Setup for periodic boundary conditions\n if i == 1\n i_minus_1 = ncells\n dz_minus = z[2] - z[1]\n else\n i_minus_1 = i - 1\n dz_minus = z[i] - z[i-1]\n end\n\n if i == ncells\n i_plus_1 = 1\n dz_plus = z[2] - z[1]\n else\n i_plus_1 = i + 1\n dz_plus = z[i+1] - z[i]\n end\n\n # Update gradient\n if a > 0\n du_dz[i] = (u[i] - u[i_minus_1]) / dz_minus\n else\n du_dz[i] = (u[i_plus_1] - u[i]) / dz_plus\n end\n end\n\n # Update advected quantity\n for i in eachindex(νan)\n u[i] -= a * du_dz[i] * dt\n end\n end\n\n # Return a two-zone bohm anomalous transport result,\n # since we don't really care about the anomalous transport.\n return HallThruster.TwoZoneBohm(1/160, 1/16)(νan, params)\nend\n\n\n# Define initializer function, which is a step function\n# between z = 0.01 and z = 0.02\nfunction initializer(u, z)\n for i in eachindex(u)\n if 0.01 < z[i] < 0.02\n u[i] = 1.0\n else\n u[i] = 0.0\n end\n end\n return u\nend\n\n# Set up config\nadvection_velocity = 1e5\nL = 0.08\n\nconfig = HallThruster.Config(\n domain = (0.0, L),\n anom_model = ScalarAdvection(advection_velocity, initializer),\n thruster = HallThruster.SPT_100,\n discharge_voltage = 300.0,\n anode_mass_flow_rate = 5e-6\n)\n\n# Define dt such that CFL condition is obeyed\nncells = 200\ndx = L / ncells\nCFL = 0.9\ndt = min(1e-8, dx * CFL / advection_velocity)\nnsteps = 1000\n\n# Run simulation\nsolution = HallThruster.run_simulation(\n config;\n ncells, \n dt,\n duration = nsteps * dt, \n nsave = nsteps\n)\n\n# Extract variables from solution\nz = solution.params.z_cell\nu = [saveval.anom_variables[1] for saveval in solution.savevals]\n\nusing Plots\n\n# Time needed to transit the domain\nt_transit = L / advection_velocity\n\n# Number of periods \nnum_periods = floor(Int, nsteps * dt / t_transit)\n\n# Plot results\np = plot(; framestyle = :box, xlabel = \"x\", ylabel = \"u\", title = \"First order upwind for scalar advection\")\nfor i in 0:num_periods\n index = round(Int, i * t_transit / dt) + 1\n plot!(\n p, z, u[index], label = \"After $i periods\",\n linecolor = cgrad(:turbo, num_periods + 1, categorical = true)[i+1]\n )\nend\ndisplay(p)","category":"page"},{"location":"initialization/#Initialization","page":"Initialization","title":"Initialization","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"HallThruster.jl provides sensible defaults for simulation initialization, or allows you to specify your own initial condition.","category":"page"},{"location":"initialization/#Default","page":"Initialization","title":"Default","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"The default is DefaultInitialization(), which initializes the solution domain as described in the following sections. Below, z_0 and z_N are domain[1] and domain[2], as passed into the Config object (see Configuration), L_ch and A_ch are config.thruster.geometry.channel_length and config.thruster.geometry.channel_area, respectively, and dotm is config.anode_mass_flow_rate.","category":"page"},{"location":"initialization/#Ion-densities","page":"Initialization","title":"Ion densities","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"The ion densities are Gaussian with a constant offset and a scaling factor proportional to the mass flow rate and discharge voltage. For ions with charge 1, the density is","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"rho_i = 2 times 10^17 m_i sqrtfracV_d300fracdotm5times10^-6left(1 + 5 expleft-left(fracz - z_0 - L_ch2L_ch3right)^2rightright)","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"For ions with charge Z, the density is assumed to scale as","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"rho_i_Z = fracrho_i _Z=1Z^2","category":"page"},{"location":"initialization/#Ion-velocities","page":"Initialization","title":"Ion velocities","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"Ions are initialized with the Bohm velocity at the anode. For an ion of charge Z, this is","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"u_i1 = -u_bohm =- sqrtfracZ eT_eV anodem_i","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"The maximum ion velocity is determined by the discharge voltage V_d:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"u_imathrmend = u_max = sqrtfrac2 Z e V_dm_i","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"The initial ion velocity profile between the cathode and the anode is then prescribed as:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"u_i(z) = begincases\r\n\tu_bohm + frac23(u_max - u_bohm)left(fracz - z_0L_chright)^2 z-z_0 L_ch \r\n\tfrac13left(u_bohm + u_maxright)left(1 - fracz - z_0 - L_chz_N - L_chright) + u_maxleft(fracz - z_0 - L_chz_N - L_chright) z - z_0 ge L_ch\r\nendcases","category":"page"},{"location":"initialization/#Neutral-density","page":"Initialization","title":"Neutral density","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"The neutral density at the anode is computed in the same way as during a simulation, namely:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"rho_n anode = fracdotmu_n A_ch - sum_s fracrho_is u_is_anodeu_n","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"The density at the cathode is assumed to be 1/100 that at the anode. In the domain, the neutral density has a sigmoid shape:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"rho_n(z) = frac12left(rho_nanode + rho_n cathode + (rho_n anode - rho_n cathode)tanhleft(fracz - z_0 - L_ch2L_ch 6right)right)","category":"page"},{"location":"initialization/#Electron-energy","page":"Initialization","title":"Electron energy","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"The number density is computed from the ion densities. The electron temperature is a Gaussian with height V_d 10 eV plus a linear baseline to make sure the boundary conditions are satisfied:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"T_e(z) = left(1 - fracz - z_0z_N - z_0right) T_e anode + left(fracz - z_0z_N - z_0right) T_e cathode + fracV_d10expleft-left(fracz - z_0 - L_chL_ch3right)^2right","category":"page"},{"location":"initialization/#Example","page":"Initialization","title":"Example","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"For a simulation of the SPT-100 with V_d= 500V, three ion charge states, a a mass flow rate of 3 mg/s, an anode electron temperature of 3 eV and a cathode electron temperature of 5 eV, the initial condition looks like:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"(Image: )","category":"page"},{"location":"initialization/#Custom-initial-conditions","page":"Initialization","title":"Custom initial conditions","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"You may define your own initial condition by creating subtypes of HallThruster.InitialCondition. Let's say for some reason we wanted to initialize every state variable in every cell to the z-location of its cell center. We might define our initialization as follows:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"using HallThruster\r\n\r\nstruct MyInitialCondition <: HallThruster.InitialCondition end;\r\n\r\n# output\r\n","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"We would then add a method to the initialize!(U, params, model) function as follows:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"import HallThruster.initialize!\r\n\r\nfunction HallThruster.initialize!(U, params, model::MyInitialCondition)\r\n\t(;z_cell) = params # Pull cell centers locations out of params\r\n nvars = size(U, 1)\r\n for (i, z) in enumerate(z_cell)\r\n \tfor j in 1:nvars\r\n \tU[j, i] = z_cell[i]\r\n end\r\n end\r\n return U # optional. Since U is modified. the return value is never used, but by Julia convention we also return the mutated object.\r\nend;\r\n\r\n# output\r\n","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"We can check the behavior of our new function:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"# Dummy config and params\r\nncells = 100\r\nnvars = 4\r\nconfig = (;initial_condition = MyInitialCondition())\r\nz_cell = range(0, 0.05, length = ncells)\r\nU = zeros(nvars, ncells)\r\nparams = (;config, z_cell)\r\n\r\n# Method of initialize! which dispatches to initialize!(U, params, config.initial_condition)\r\n# This is what HallThruster.jl calls when initializing a simulation\r\nHallThruster.initialize!(U, params)\r\n\r\nU[1, :] == U[2, :] == U[3, :] == U[4, :] == collect(z_cell)\r\n\r\n# output\r\n\r\ntrue","category":"page"},{"location":"fluxes/#Fluxes","page":"Fluxes","title":"Fluxes","text":"","category":"section"},{"location":"fluxes/","page":"Fluxes","title":"Fluxes","text":"HallThruster.jl uses the Finite Volume method, and as such the face values of the fluxes need to be reconstructed. See Numerics for more information.","category":"page"},{"location":"fluxes/","page":"Fluxes","title":"Fluxes","text":"The fluxes F__i+frac12 and F__i-frac12 are reconstructed at the cell interfaces, and for this flux reconstruction multiple options are available. These are set using the object HyperbolicScheme consisting of fields flux, limiter, and reconstruct. Three different flux approximations are available.","category":"page"},{"location":"fluxes/","page":"Fluxes","title":"Fluxes","text":"Flux Description\nupwind Simple first order accurate flux approximation, that as a results does not distinguish between cell centered and cell average values and adapts reconstruction according to sign of advection velocity. Very diffusive. No Riemann solver or approximation.\nHLLE Approximate Riemann solver. The Harten-Lax-van Leer-Einfeldt scheme approximates a Riemann problem with three constant states. see reference. The scheme is positively-conservative if stability bounds for maximum and minimum wavespeeds are met, which makes it useful in its application with HallThruster.jl. First order accurate in space. B. Einfeldt. On godunov-type methods for gas dynamics. Journal of Computational Physics, 25:294-318, 1988.\nrusanov Approximate Riemann solver. Also known as the local Lax-Friedrich flux. Has slighlty modified choice of wave speeds. Adds viscosity to a centered flux. More diffusive than HLLE. Chi-Wang Shu, Lecture Notes: Numerical Methods for Hyperbolic Conservation Laws (AM257)","category":"page"},{"location":"fluxes/","page":"Fluxes","title":"Fluxes","text":"These flux approximations are all first order accurate in space (piecewise constant recontruction), but can be extended to piecewise linear reconstruction within a cell. To satisfy stability bounds and keep the scheme total variation diminishing (TVD), it has to be coupled with a limiter. Many limiters have been proposed, the ones implemented in HallThruster.jl are the following: koren, minmod, osher, van_albada, van_leer. If the field reconstruction is set to true, the selected limiter will be used.","category":"page"},{"location":"collisions/#Collisions-and-Reactions","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"HallThruster.jl allows you to choose from a few different models for ionization, excitation and elastic scattering, or supply your own. This allows you to implement different propellants or more charge states for an existing propellant.","category":"page"},{"location":"collisions/#Background","page":"Collisions and Reactions","title":"Background","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Most collisions in HallThruster.jl are handled via the Reaction interface. This is an abstract type with three subtypes: IonizationReaction, ExcitationReaction, and ElasticScattering.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"The core of the ionization model in HallThruster.jl is the IonizationReaction struct. It has four fields: energy, reactant, product, and rate_coeff. The first is of type Float64 and is the ionization energy of the given reaction in eV. The next two are Species objects, while the last is an arbitrary function. This rate_coeff computes the ionization reaction rate coefficient (in m^3/s) provided the electron energy (in eV). It is used in heavy species source terms in order to compute the production or destruction of the reactant and product due to ionization, and in the electron energy equation in order to compute electron energy losses due to inelastic ionization collisions.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Excitation reactions are handled similarly. The ExcitationReaction struct has only three fields: energy, reactant and rate_coeff, with the same types as above. Since fluids of different excitation levels are not tracked explicitly, the choice of excitation model only affects the electron energy balance.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Elastic scattering (electron-neutral) collisions are implemented via the ElasticCollision struct, which has two fields: reactant and rate_coeff, as no energy is lost in such collisions. This affects the electron momentum balance and the cross-field transport.","category":"page"},{"location":"collisions/#Ionization","page":"Collisions and Reactions","title":"Ionization","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"HallThruster.jl provides two models out of the box. These are","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Model Supported species Maximum charge state Description\nIonizationLookup Xenon, Krypton (out of the box. With user-provided tables, can support any species) 3 Ionization look-up table for species provided with HallThruster.jl. By default, the tables are stored in the reactions subfolder of the HallThruster.jl directory, but the user may provide additional directories in which to look for tables.\nLandmarkIonizationLookup Xenon 1 Lookup table provided for the LANDMARK benchmark. Table is stored in the landmark subfolder of the HallThruster.jl directory.","category":"page"},{"location":"collisions/#IonizationLookup","page":"Collisions and Reactions","title":"IonizationLookup","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This is the default ionization model. To use the IonizationLookup model, initialize it as follows:","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"ionization_model = IonizationLookup([directories::Vector{AbstractString = String[]}])","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"If the optional argument directories is left empty or unprovided, the HallThruster.jl will only look in the reactions subfolder of the HallThruster.jl main directory. Otherwise, HallThruster.jl will preferentially look in directories before before falling back to the included tables. If two files in user-provided directories have the same name, HallThruster.jl will pick the one in the directory which comes first in directories.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Inside of the folders listed in directories, HallThruster.jl will look for rate coefficient files matching the desired propellant gas and maximum charge state. The rate coefficient files must be named as follows in order to be found.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"ionization_$(reactant.symbol)_$(product.symbol).dat","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"For example, for a reaction file containing rate coefficients for direct double ionization of Bismuth, you would name the file ionization_Bi_Bi2+.dat, or for Argon II being ionized to Argon III, it would be ionization_Ar2+_Ar3+.dat.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"The rate coefficient files must have the ionization energy in the first row, with a colon separating the descriptor and the number. It must next have a header row (which is skipped on load), followed by two tab-delimited columns. The first should have the electron energy (note: this is 3/2 Te) in eV, and the second should have the rate coefficient in m^3/s. The first few rows of the ionization_Kr_Kr+.dat folder thus reads","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Ionization energy (eV): 13.9996055\r\nEnergy (eV) Rate coefficient (m3/s)\r\n1.0 1.812780887933804e-23\r\n2.0\t6.784605416289418e-19\r\n3.0\t2.86241339516785e-17\r\n4.0\t2.0154931458303006e-16\r\n5.0\t6.77202352079487e-16\r\n6.0\t1.5567995341077301e-15\r\n7.0\t2.8667673314913722e-15\r\n8.0\t4.5818881444694e-15\r\n9.0\t6.650747725094247e-15","category":"page"},{"location":"collisions/#LandmarkIonizationLookup","page":"Collisions and Reactions","title":"LandmarkIonizationLookup","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This accounts for single ionization of Xenon only using the lookup table provided by test case 3 of the LANDMARK benchmark. It reads from the file landmark/landmark_rates.csv. Useful mostly for replicating the LANDMARK benchmark.","category":"page"},{"location":"collisions/#Excitation","page":"Collisions and Reactions","title":"Excitation","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"As with ionization, HallThruster.jl provides two models out of the box. These are","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Model Supported species Description\nExcitationLookup Xenon, Krypton (out of the box. With user-provided tables, can support any species) Excitation look-up table for species provided with HallThruster.jl. By default, the tables are stored in the reactions subfolder of the HallThruster.jl directory, but the user may provide additional directories in which to look for tables.\nLandmarkExcitationLookup Xenon Lookup table provided for the LANDMARK benchmark. Table is stored in the landmark subfolder of the HallThruster.jl directory.","category":"page"},{"location":"collisions/#ExcitationLookup","page":"Collisions and Reactions","title":"ExcitationLookup","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This is the default excitation model. To use the ExcitationLookup model, initialize it as follows:","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"excitation_model = ExcitationLookup([directories::Vector{AbstractString = String[]}])","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This functions nearly identically to the IonizationLookup, with the exception that, since excitation reactions do not change the charge state, the product is the same Species as the reactant and thus is not included in the filename. The filename for excitation reactions is thus:","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"excitation_$(reactant.symbol).dat","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"For example, for a reaction file containing excitation rate coefficients for neutral Argon would be called excitation_Ar.dat. Similarly, a file containing rates for excitation of triply-charged Xenon would be called excitation_Xe3+.dat.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"The rate coefficient files are formatted identically to the ionization rate files. Below are the first few lines of the included excitation_Xe.dat.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Excitation energy (eV): 8.32\r\nEnergy (eV)\tRate coefficient (m3/s)\r\n1.0\t2.909965013767145e-20\r\n2.0\t3.078734312855916e-17\r\n3.0\t4.1547515755380286e-16\r\n4.0\t1.6649256403317016e-15\r\n5.0\t3.9526948476759076e-15\r\n6.0\t7.124788357557455e-15\r\n7.0\t1.0908925177391674e-14\r\n8.0\t1.5042335588913955e-14\r\n9.0\t1.9316662863621785e-14","category":"page"},{"location":"collisions/#LandmarkIonizationLookup-2","page":"Collisions and Reactions","title":"LandmarkIonizationLookup","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This accounts for excitation of Xenon only using the lookup table provided by test case 3 of the LANDMARK benchmark. It reads from the file landmark/landmark_rates.csv. Useful mostly for replicating the LANDMARK benchmark. LANDMARK does explicitly provide excitation rates, and instead gives an energy loss coefficient. However, using the provided ionization rate coefficients, we can back out the excitation rate coefficients. These are then used to construct an ExcitationReaction.","category":"page"},{"location":"collisions/#Electron-neutral-elastic-scattering","page":"Collisions and Reactions","title":"Electron-neutral elastic scattering","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"These are ReactionModels of type ElectronNeutralModel. HallThruster.jl provides three models out of the box. These are","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Model Supported species Description\nElectronNeutralLookup Xenon, Krypton (out of the box. With user-provided tables, can support any species) Electron-neutral elastic scattering look-up table for species provided with HallThruster.jl. By default, the tables are stored in the reactions subfolder of the HallThruster.jl directory, but the user may provide additional directories in which to look for tables.\nLandmarkElectronNeutral Xenon Constant rate coefficient of 2.5e-13\nGKElectronNeutral Xenon Uses Eq. 36.13 on pg. 58 from Goebel and Katz to fit Xenon e-n cross section","category":"page"},{"location":"collisions/#ElectronNeutralLookup","page":"Collisions and Reactions","title":"ElectronNeutralLookup","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Like IonizationLookup and ExcitationLookup, this reads a table of reaction rate coefficient vs energy from a file either in the HallThruster.jl reactions directory or in a user-provided directory. The interface and usage is identical to that of the other two lookup models, with the exception that since these collisions do not have an electron energy loss associated with them, we do not need to supply an energy in the first line of the files. Thus, the first few lines of elastic_Kr.dat are:","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Energy (eV)\tRate coefficient (m3/s)\r\n1.0\t1.7652019589294465e-14\r\n2.0\t6.286806105711669e-14\r\n3.0\t1.260621740782443e-13\r\n4.0\t1.879916985413993e-13\r\n5.0\t2.421697883866546e-13\r\n6.0\t2.878523500134384e-13\r\n7.0\t3.2602160860803316e-13","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Naming is similarly simple, with HallThruster.jl looking for files named as follows","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"elastic_$(species).dat","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Since electron-ion collisions are not handled via the ReactionModel interface, species with charge states greater than 0, if provided, are ignored.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Once a rate coefficient k_en(epsilon) is computed, the electron-neutral collision frequency is simply","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"nu_en = n_n k_en(epsilon)","category":"page"},{"location":"collisions/#LandmarkElectronNeutral","page":"Collisions and Reactions","title":"LandmarkElectronNeutral","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"In this model, as in the LANDMARK benchmark, the electron-neutral collision rate coefficient has a constant value of k_en = 25times 10^-13.","category":"page"},{"location":"collisions/#GKElectronNeutral","page":"Collisions and Reactions","title":"GKElectronNeutral","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This uses a fit to the Xenon average collision cross section as a function of electron temperature taken from Goebel and Katz, Fundamentals of Electric Propulsion (page 58):","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"beginaligned\r\nnu_en = sigma_en(T_e) n_n sqrtfrac8 e T_epi m_e \r\nsigma_en(T_e) = 66times 10^-19 leftfracfracT_e4 - 011 + left(fracT_e4right)^16right textrmm^2\r\nendaligned","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Here, T_e is in eV.","category":"page"},{"location":"collisions/#Electron-ion-collisions","page":"Collisions and Reactions","title":"Electron-ion collisions","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Unlike the above types of collisions, electron-ion colulombic collisions are not strongly dependent on the type of gas, as the interaction distance is much larger than the atomic radius. They are thus handled via a simple Boolean flag in the Config struct: electron_ion_collisions = true or electron_ion_collisions = false. These are computed using the classical formulae (see NRL Plasma Formulary, pg. 33):","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"nu_ei = 29 times 10^-6 Z^2 n_e T_e^-32 lnLambda","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Here, Z is the ion charge state, n_e is the plasma density in m^-3 and T_e is the electron temperature in eV. In the above expression, lnLambda is the well-known Coulomb logarithm, given by","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"beginaligned\r\nlnLambda = 23 - frac12lnleft(10^-6 Z^2 n_e T_e^-3right) T_e 10 Z^2 textrm eV \r\nlnLambda = 24 - frac12lnleft(10^-6 n_e T_e^-2right) T_e 10 Z^2 textrm eV\r\nendaligned","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"For plasmas containing multiple charge states, we compute the number-averaged charge state langle Zrangle and use that in the above formula:","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"langle Zrangle equiv left(sum_s Z_s n_sright) n_e","category":"page"},{"location":"collisions/#Implementing-your-own-collisions","page":"Collisions and Reactions","title":"Implementing your own collisions","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"ElectronNeutralModel, ExcitationModel and IonizationModel are all subtypes of ReactionModel. Users may specify their own IonizationModel, ElectronNeutralModel, or ExcitationModel by implementing a few key functions required by the ReactionModel interface. Let's say we wanted to implement our own ionization model, called MyIonizationModel, we would first define our struct as a subtype of HallThruster.IonizationModel, along with any fields we might want:","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"struct MyIonizationModel <: HallThruster.IonizationModel\r\n\t# any fields you might want\r\nend","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"If we were defining an ExcitationModel, we would instead subtype HallThruster.ExcitationModel, and if we were defining a model for electron-neutral elastic scattering, we would subtype ElectronNeutralModel. Next, we need to define a few helper methods.","category":"page"},{"location":"collisions/#supported_gases(::ReactionModel)::Vector{Gas}","page":"Collisions and Reactions","title":"supported_gases(::ReactionModel)::Vector{Gas}","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This method must return a vector of Gas objects. If not overwritten, this method returns Gas[], which signifies that there are no restrictions on what type of gas works with this method. This is useful for IonizationLookup, which can in principle work for any gas, but not so much for LandmarkLookup, which is Xenon specific. Specifying which gases your model is valid for lets HallThruster.jl check at run time that user-provided propellant works with the provided model, preventing it from silently computing a bad result without the user's knowledge.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Let's say our model works exclusively with Bismuth","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"import HallThruster: supported_gases\r\n\r\nHallThruster.supported_gases(::MyIonizationModel) = [HallThruster.Bismuth]","category":"page"},{"location":"collisions/#maximum_charge_state(::ReactionModel)::Int","page":"Collisions and Reactions","title":"maximum_charge_state(::ReactionModel)::Int","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This method returns an integer corresponding to the maximum allowed charge state. By default, this is zero, indicating that our method can work with any charge state. However, to avoid mistakes down the line, it is best to define this, unless we're defining an ElectronNeutralModel. In our case, let's just work with singly-charged Bismuth.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"import HallThruster: maximum_charge_state\r\n\r\nmaximum_charge_state(::MyIonizationModel) = 1","category":"page"},{"location":"collisions/#load_reactions(model::ReactionModel,-species::Vector{Species})","page":"Collisions and Reactions","title":"load_reactions(model::ReactionModel, species::Vector{Species})","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This is the most important method to define. load_reactions takes our model along with a vector of Species (generated using the propellant and ncharge fields in the user-provided Config) and returns a vector of IonizationReaction{I} or ExcitationReaction{I}, where I is the type of the rate coefficient function. It is important that the Reactions all have the same type so that the returned vector will have a concrete type, which will prevent dynamic dispatch during runtime and prevent unnecessary slowdowns. This means that if you have multiple reactions with different rate coefficient functions, you should use something like FunctionWrappers.jl. Let's implement a simple ionization curve with the form","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"k_iz(epsilon) = 4times 10^-20 expleft(frac-73frac23 epsilonright)sqrtfrac8 (frac23epsilon)pi m_e","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"We would implement this as so:","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"using FunctionWrappers\r\nimport HallThruster: e, me, load_reactions\r\n\r\nkiz(ϵ) = 4e-20 * exp(-7.3 / (2/3 * ϵ)) * sqrt(8 * 2/3 * ϵ / pi / me)\r\n\r\nfunction load_reactions(model::MyIonizationModel, species)\r\n rxn = IonizationReaction(\r\n \tenergy = -7.3,\r\n #=\r\n Since we defined maximum_charge_state and supported_species, we know that\r\n species[1] will be Bi and species[2] will be Bi+. Otherwise, an error would have\r\n been thrown before this point. Without these methods, we would need have logic \t\t\t \thandling whichever species get passed to the function.\r\n =#\r\n reactant = species[1],\r\n product = species[2],\r\n # Use a function wrapper here, though not necessary with only one reaction\r\n rate_coeff = FunctionWrapper{Float64, Tuple{Float64}}(kiz)\r\n )\r\n return rxn\r\nend","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"The above advice works identically for defining your own ExcitationModel, with the sole exception that ExcitationReaction objects do not have a product field. Similarly, we can define our own ElectronNeutralModel, noting that ElasticCollisions do not have an energy field or a product field. We would also not need to define maximum_charge_state for an ElectronNeutralModel.","category":"page"},{"location":"propellants/#Propellants","page":"Propellants","title":"Propellants","text":"","category":"section"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"HallThruster implements several common Hall thruster propellants, and makes it easy to implement your own.","category":"page"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"note: Note\nHallThruster only supports monatomic gases at this time. Support for diatomic propellants, such as iodine, may come in a future release.","category":"page"},{"location":"propellants/#Provided-propellants","page":"Propellants","title":"Provided propellants","text":"","category":"section"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"Xenon\nKrypton\nArgon\nBismuth\nMercury","category":"page"},{"location":"propellants/#Implementing-your-own-propellant","page":"Propellants","title":"Implementing your own propellant","text":"","category":"section"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"Propellants in HallThruster are instances of the Gas struct, which contains information about the atomic and thermodynamic properties of a gaseous species. These are","category":"page"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"name::String Full name of gas (i.e. Xenon)\nshort_name::String Short name/symbol (i.e. Xe for Xenon)\nγ::Float64 Specific heat ratio / adiabatic index\nM::Float64 Molar mass (grams/mol) or atomic mass units\nm::Float64 Mass of atom in kg\ncp::Float64 Specific heat at constant pressure in J / kg / K\ncv::Float64 Specific heat at constant volume in J / kg / K\nR::Float64 Gas constant in J / kg / K","category":"page"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"Many of these properties are inter-dependent, so HallThruster provides a convenience constructor Gas(name, short_name, γ, M) which will compute the rest of the properties automatically. For example, we might want to define atomic Neon:","category":"page"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"using HallThruster: Gas\r\n\r\nNeon = HallThruster.Gas(\"Neon\", \"Ne\"; γ = 5/3, M = 20.1797)\r\n\r\n# output\r\n\r\nNeon","category":"page"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"If we then selected Neon as a propellant in our Config struct and used one of the lookup table models for ionization, HallThruster.jl would know to search for files beginning ionization_Ne....","category":"page"},{"location":"physics/#Physics-model","page":"Physics model","title":"Physics model","text":"","category":"section"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"HallThruster.jl solves the quasineutral plasma equations of motion for a Hall Thruster along the thruster's channel centerline (the z-axis). We solve seperate models for neutral particles, ions, and electrons. Neutrals are assumed to have constant velocity and temperature and are tracked by a single continuity equation. Ions are assumed isothermal and unmagnetized. Multiple ion species with different charge states are supported, and each is tracked by a continuity equation and a momentum equation. We employ the drift-diffusion approximation for electrons, which reduces the electron momentum equation to a generalized Ohm's law. Charge conservation is then used to solve for the electrostatic potential. The electron temperature is determined by solving an equation for the conservation of electron internal energy. The model is based upon the work presented in K. Hara, Non-oscillatory quasineutral fluid model of cross-field discharge plasmas, Physics of Plasmas 25, 123508, 2018. See Configuration for supported gases. Xenon is the standard, Krypton is fully supported and in theory any monoatomic gas can be used as propellant in the simulation.","category":"page"},{"location":"physics/#Neutrals","page":"Physics model","title":"Neutrals","text":"","category":"section"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"For neutrals, the continuity equation is solved:","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" fracpartial n_npartial t + fracpartialpartial z (n_n u_n) = dotn_n","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Here, n_n is the neutral number density in m^-3, mathbfu_n is the neutral velocity vector in m/s, and dotn_n is the rate of neutral depletion due to ionization in m^-3s^-1, which is given by","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" dotn_n = -sum_j = 1^3 n_e n_n k_nj(T_e)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"where n_e is the electron number density j represents the ion charge state (i.e. j = 1 represents singly-charged ions, and so on), T_e is the electron temperature, and k_nj is the rate coefficient of the ionization reaction","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"A + e^- rightarrow A^j+ + (j + 1) e^-","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"where A represents the gas species being simulated. Currently, the code is compatible with Xenon and Krypton. The reaction rate coefficients are generated as a function of electron temperature using the BOLSIG+ code. We read in a table of these rate coefficients with electron temperature and use the Interpolations.jl to generate transform this data into a continuous function. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The neutrals are assumed to have a constant velocity in the axial direction and a constant temperature, and are thus approximated monoenergetic and not Maxwellian. The neutral momentum and energy equations are not solved for. ","category":"page"},{"location":"physics/#Ions","page":"Physics model","title":"Ions","text":"","category":"section"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"We solve continuity and momentum for each ion species. We may have the option for an ion energy equation, but for now they are treated as isothermal. The ion continuity equation for ions with charge j is","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" fracpartial n_ijpartial t + fracpartialpartial z (n_ij u_ij) = dotn_ij","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Here n_ij, u_ij, and dotn_ij are the number density, velocity, and net rate of production of ions with charge state j. The production rate dotn_ij is given by:","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" dotn_ij = n_e n_n k_nj(Te) - sum_ell = j + 1^3 n_e n_ij k_jell(T_e)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The first term here represents the rate of production of ions with charge state j and the second term represents the rate at which these ions are further ionized to become ions of charge state ell. In all, the following six reactions are modelled:","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"beginaligned\r\n A + e^- rightarrow A^+ + 2 e^-\r\n A + e^- rightarrow A^2+ + 3 e^-\r\n A + e^- rightarrow A^3+ + 4 e^-\r\n A+ + e^- rightarrow A^2+ + 2 e^-\r\n A+ + e^- rightarrow A^3+ + 3 e^-\r\n A^2+ + e^- rightarrow A^3+ + 2 e^-\r\nendaligned","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The currently-specified model does not include ion losses to the radial walls, but this could be included at a later date. Likewise, we could also include momentum-transfer collisions between ions and neutrals and between ions of different charge states at a future date, but neglect these for now. Future updates may also add the ability to model molecular propellants, not just monatomic ones, in which case we would need to add significantly more reaction equations, species, and model rotational and vibrational modes.","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The one-dimensional momentum equation for ions of charge state j is obtained by assuming the ions are unmagentized and that the momentum transfer due to collisions is negligible. The momentum equation in conservative form is","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" fracpartialpartial t (n_ij u_ij) + fracpartialpartial z (n_ij u_ij^2 + fracp_ijm_i) = fracj em_i n_ij E_z","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In this equation, p_ij = n_ij k_B T_i is the partial pressure of ions with charge j, T_i is the ion temperature, e is the fundamental charge, m_i is the ion mass, and E_z is the axial electric field. ","category":"page"},{"location":"physics/#Electrons","page":"Physics model","title":"Electrons","text":"","category":"section"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"We assume that the plasma is quasineutral, which means that the local charge density is zero everywhere. This means that","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" n_e = sum_j=1^3 jn_ij","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In addition, the electrons are assumed to be massless. This yields a generalized Ohm's law, also known as the Quasineutral Drift Diffusion (QDD) model. The electron momentum equation becomes:","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" nu_e fracm_eemathbfj_e = e n_e mathbfE +nabla p_e - mathbfj_e times mathbfB","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Here, nu_e is the total electron momentum transfer collision frequency, mathbfj_e = -e n_e mathbfu_e is the electron current vector, p_e = n_e k_B T_e is the electron pressure, and B is the magnetic field. We want to model the electron velocity in both the axial (hatz) and azimuthal (theta) directions. Making the assumption that B is purely radial and that the plasma is axisymmetric, we arrive at the following two equations after some algebraic manipulations.","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"axial current equation","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" j_ez = frace^2 n_em_e nu_efrac11 + Omega_e^2left(E_z + frac1e n_efracpartial p_epartial zright)\r\n j_etheta = Omega_e j_ez","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In this expression, Omega_e = omega_cenu_e = e B m_e nu_e is the Hall parameter, or the ratio of the electron cyclotron frequency to the total electron momentum transfer collision frequency, and measures how well-magnetized the electrons are. Finally, we introduce the anomalous collision frequency (nu_AN):","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" nu_e = nu_c + nu_AN","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In Hall thrusters, the observed axial/cross-field electron current is significantly higher than that which would result from classical collisions alone (here, nu_c represents the classical electron momentum transfer collision frequency, see Collisions and Reactions). We model this enhanced transport in a fluid framework as an additional anomalous collision frequency, see Anomalous Transport. The purpose of this code is to facilitate the development and testing of models for this important parameter.","category":"page"},{"location":"physics/#Electrostatic-potential","page":"Physics model","title":"Electrostatic potential","text":"","category":"section"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The electrostatic potential is found by first computing the electric field. To determine the electric field we generally follow the method from V. Giannetti, et. al Numerical and experimental investigation of longitudinal oscillations in Hall thrusters, Aerospace 8, 148, 2021 but the main steps are outlined here. By writing the discharge current as fracI_dA_ch = j_e + j_i where A_ch is the channel area, plugging in Ohm's law for the electron current density, and integrating over the domain, we can write the discharge current as","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" I_d = fracDelta V + int_z_c^z_a frac1en_efracpartial p_epartial z + fracj_izen_emu_perp dzint_z_c^z_a en_e mu_perp A dz","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Where A is the cross section area of either the channel or plume, z_c and z_a are the cathode and anode positions, and Delta V j_iz and mu_perp are given by ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Delta V = V_d + V_s \r\nj_iz = Sigma_j=1^3 jn_ij u_ij \r\nmu_perp = fracem_e nu_e frac11+Omega_e^2","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"With the discharge current known, the axial electric field is computed locally as","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"E_z = fracI_den_emu_perpA_ch - frac1en_e fracpartial p_epartial z - fracj_izen_emu_perp ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"As the electric field is the negative gradient of the electrostatic potential, the potential is finally calculted by integrating the negative electric field using the trapezoid rule.","category":"page"},{"location":"physics/#Electron-energy-equation","page":"Physics model","title":"Electron energy equation","text":"","category":"section"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The electron internal energy equation in one dimension is","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" fracpartialpartial tleft(frac32 n_e k_B T_eright) + fracpartialpartial zleft(frac52 n_e k_B T_e u_ez + q_ezright) = \r\n n_e u_ez fracpartialphipartial z - W_loss - S_coll","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Here, q_ez is the electron heat conduction in one dimension and S_wall, see Wall Loss Models, represents the loss of electron energy to the thruster walls and S_coll, see Collisions and Reactions captures the loss of energy due to inelastic collisions. The heat conduction is defined by Fourier's Law:","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"beginaligned\r\n q_ez = -kappa_eperp nabla_perp T_e \r\nendaligned","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In this expression, kappa_eperp is the cross-field (axial) electron thermal conductivity, for which various forms exist. More details can be found on the Electron Thermal Conductivity page. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The heat transfer terms slightly change when considering the Landmark case study, while the different wall and inelastic collision loss models are described in Wall Loss Models and Collisions and Reactions. ","category":"page"},{"location":"physics/#Sheath-considerations","page":"Physics model","title":"Sheath considerations","text":"","category":"section"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"HallThruster.jl, being a fluid globally quasineutral model, is not designed to resolve plasma sheaths. However, the sheath and presheath are important to model Hall Thruster discharges accurately. As this is a 1D axial solver, we do not have any direct fluxes towards the walls, the energy losses can however be taken into account by a source term in the energy equation. This term and the boundary conditions implemented at the anode employ the following presheath approximations and assumptions. They are absolutely critical to replicate experimental Hall Thruster behaviour. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In the following, potential differences ephi are assumed to be on the order of the electron temperature k T_e. Furthermore, assume that cold ions fall through an arbitrary potential of phi_0 while they move towards the wall. Through conservation of energy, their arrival velocity at the sheath edge can be related to the potential difference. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"energy conservation","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" frac12 m_i v_0^2 = e phi_0","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Additionally, the ion flux during acceleration toward the wall is conserved. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" n_i v = n_0 v_0","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The relation for ion velocity as a function of position in the sheath can be written as ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"above expression","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" frac12 m_i v^2 = frac12 m_i v_0^2 - ephi (x)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Rewriting both energy conservation and above expression for v_0 and v, and dividing gives","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" fracv_0v = sqrtfracphi_0phi_0 - phi","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"which by applying flux conservation results in ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"the density equation","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" n_i = n_0 sqrtfracphi_0phi_0 - phi","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Close to the sheath edge the density equation can be expanded as a Taylor series, as phi is small compared to phi_0.","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"expanded ion density","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" n_i = n_0 left(1 - frac12fracphiphi_0 + right)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In one dimension, neglecting collisions with other species and assuming isentropic temperature and pressure terms, no convection and no electron inertia, the electrons can be described by the Boltzmann relation.","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Boltzmann relation","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" n_e = n_0 expleft(frace phik T_eright)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In this regime, the electron density is diffusion dominated and dictated by the electrostatic field. This assumption is generally valid along magnetic field lines and across weak magnetic fields with sufficient electron electron collisions. The Boltzmann relation can be expanded by assuming that the change in potential at the sheath edge is small compared to the electron temperature. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"expanded Boltzmann relation","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" n_e = n_0 left(1 - fracephik T_e + right)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Taking Poisson's equation of the form ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" nabla^2 phi = - fracek Te_0(n_i - n_e)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"and substituting expanded Boltzmann relation and expanded ion density leads after rearranging to ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" nabla^2 phi = frace n_0 phiepsilon_0left(frac12phi_0 - fracekT_eright)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"As the sheath is assumed to be ion attracting, it can by definition not slow or repell ions. As a result, the right hand side of \\autoref{eq:poissonsubexpanded} has to always be positive, which leads to the following requirement. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" phi_0 frackT_e2e","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"By substituting energy conservation equation, the ion Bohm speed can be recovered. This condition is applied to the anode boundary and will be discussed in the boundary conditions. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Bohm velocity","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" v_0 sqrtfrackT_em_i","category":"page"},{"location":"thrusters/#Thrusters","page":"Thrusters","title":"Thrusters","text":"","category":"section"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"Predefined thruster models are specified as a Thruster object. The struct has 4 self-explanatory fields: name of type string, geometry of type HallThruster.Geometry1D, magnetic_field of type B (which can be an arbitrary function of z), and shielded which is a Boolean. You can easily add your own thrusters. ","category":"page"},{"location":"thrusters/#SPT-100","page":"Thrusters","title":"SPT-100","text":"","category":"section"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"For example, the SPT-100 is defined in the following way:","category":"page"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"const SPT_100 = Thruster(\r\n name = \"SPT-100\",\r\n geometry = geometry_SPT_100,\r\n magnetic_field = B_field_SPT_100 $ (0.015, geometry_SPT_100.channel_length),\r\n shielded = false\r\n)","category":"page"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"while the geometry is defined here","category":"page"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"const geometry_SPT_100 = Geometry1D(\r\n inner_radius = 0.0345,\r\n outer_radius = 0.05,\r\n channel_length = 0.025\r\n)","category":"page"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"and the magnetic field profile is approximated as follows","category":"page"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"function B_field_SPT_100(B_max, L_ch, z)\r\n B = if z < L_ch\r\n B_max * exp(-0.5 * ((z - L_ch) / (0.011))^2) #for SPT_100\r\n else\r\n B_max * exp(-0.5 * ((z - L_ch) / (0.018))^2)\r\n end\r\n return B\r\nend","category":"page"},{"location":"thrusters/#Custom-thrusters","page":"Thrusters","title":"Custom thrusters","text":"","category":"section"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"You can add your own thruster models by defining the geometry, magnetic field profile and selecting shielded or not. Shielded thrusters are assumed to have lower electron energy losses to the walls, see Wall Loss Models. Note that since HallThruster.jl is a 1D code, the inner_radius and outer_radius merely used for computing the inlet neutral density and thetotal thrust and discharge current computations (from the specific values). Aside from these, they do not majorly effect the simulation results. ","category":"page"},{"location":"citation/#Citation","page":"Citation","title":"Citation","text":"","category":"section"},{"location":"citation/","page":"Citation","title":"Citation","text":"If you use the code in a published scientific paper, we request that you cite the code. We will have a DOI soon.","category":"page"},{"location":"grid/#Grid-generation","page":"Grid generation","title":"Grid generation","text":"","category":"section"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"HallThruster.jl supports both regular and irregular grids. Grids are passed to the run_simulation function via the grid keyword argument.","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"To create an evenly-spaced grid with ncells cells, we construct an EvenGrid object","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"grid = EvenGrid(ncells)","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"Alternatively, we could produce an irregular grid using the UnevenGrid object. By default, this type of grid includes twice as many cells inside the discharge channel as outside, with a smooth transition between the high-density and low-density regions.","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"If our domain is (0 cm, 8 cm) and the thruster channel length is 2.5 cm, these options produce the following grids.","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"(Image: )","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"We can also specify a custom density function. Suppose we wanted high density in the middle of our domain. Our density function might look like","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"function my_density(z, z0, z1, L)\n midpoint = (z0 + z1) / 2\n width = midpoint / 2\n base_density = 1\n return base_density + exp(-((z - midpoint) / (width))^2)\nend\n\nmy_grid = UnevenGrid(30, my_density)","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"HallThruster.jl expects a custom density function to take four arguments–-z (the axial location), z0 and z1 (the left and right edges of the domain, respectively, in meters), and L, the channel length. These are automatically populated based on the domain and thruster you pass to the configuration file. ","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"With the density function defined, we can then compare this to our other grids.","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"(Image: )","category":"page"},{"location":"background/#Background","page":"Background","title":"Background","text":"","category":"section"},{"location":"background/","page":"Background","title":"Background","text":"Hall thrusters are a widely-used class of spacecraft electric propulsion device. They are annular crossed-field devices in which a voltage drop is applied across a steady radial magnetic field. Electrons in the device become trapped in an strong azimuthal Hall current. They impact injected neutral atoms, ionizing them. These ions are then accelerated out of the channel by the electric field, which generates thrust.","category":"page"},{"location":"background/","page":"Background","title":"Background","text":"Hall thrusters offer moderate to high specific impulse and high thrust density compared to other electric propulsion systems, and can achieve total efficiencies higher than 50%. They are commonly used for in-space propulsion for commercial communications and surveillance satellites as well as increasingly for deep space missions.","category":"page"},{"location":"","page":"Home","title":"Home","text":"CurrentModule = HallThruster\r\nDocTestSetup = quote\r\n using HallThruster\r\nend","category":"page"},{"location":"#HallThruster.jl","page":"Home","title":"HallThruster.jl","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Repository link","category":"page"},{"location":"","page":"Home","title":"Home","text":"HallThruster.jl is an open-source, 1D fluid Hall thruster code written in Julia. It was initially developed by the University of Michigan's Plasmadynamics and Electric Propulsion Laboratory and is licensed under the MIT license. ","category":"page"},{"location":"#Installation","page":"Home","title":"Installation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"To install HallThruster.jl, you must first install Julia 1.7 or above from the official Julia site, or by using juliaup. We recommend using the latest Julia release when possible. Once installed, launch Julia and type","category":"page"},{"location":"","page":"Home","title":"Home","text":"julia> ]add https://github.com/UM-PEPL/HallThruster.jl","category":"page"},{"location":"","page":"Home","title":"Home","text":"This will install HallThruster.jl using Julia's package manager. For details on setting up and running Hall thruster simulations, see the official documentation. A Tutorial is available here.","category":"page"},{"location":"#Contribution","page":"Home","title":"Contribution","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Users are welcome to suggest and implement features for the code, as well as report bugs or numerical issues they encounter. Please feel free to open an issue on this repository describing your desired change or bug-fix. Pull requests are also welcome!","category":"page"}] +[{"location":"wall_loss_models/#Wall-Loss-Models","page":"Wall Loss Models","title":"Wall Loss Models","text":"","category":"section"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"HallThruster.jl allows you to choose from three different wall loss models. They approximate the electron energy lost to the thruster walls in radial direction. As the computational axis of the 1D code is axially in the thruster, the wall loss is not directly resolved by the fluid and applied in each cell as an electron energy loss term. ","category":"page"},{"location":"wall_loss_models/#Background","page":"Wall Loss Models","title":"Background","text":"","category":"section"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"The core of the wall loss models in HallThruster.jl is the abstract type WallLossModel. It has three children: NoWallLosses, ConstantSheathPotential, and WallSheath. ConstantSheathPotential has three fields. A wall sheath_potential to be set by the user, and an inner_loss_coeff and outer_loss_coeff which allow to scale the energy loss inside vs. outside the thruster channel. WallSheath has two field: material, which is of type WallMaterial and includes information about secondary electron emission yields, and α, which is a constant wall loss scaling coefficient (values around 0.1-0.2 are good usually, but this may need to be calibrated against some data).","category":"page"},{"location":"wall_loss_models/#Provided-wall-loss-models","page":"Wall Loss Models","title":"Provided wall loss models","text":"","category":"section"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"HallThruster.jl provides three models out of the box. These are","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"Model Supported species Description\nNoWallLosses Any Ignores electron energy losses to the walls. May cause numerical issues.\nConstantSheathPotential Any Employs a simple sheath energy loss model with constant sheath potential, based on the electron Boltzmann equation for electron density in the sheath as a function of electron temperature. Uses constants to scale losses inside and outside the thruster. See also JP Boeuf, Low frequency oscillations in a stationary plasma thruster, Journal of Applied Physics 84, 3541, 1998 and Landmark study\nWallSheath Any Conceputally similar loss model as ConstantSheathPotential, but evaluates constants and sheath potential given in the previously mentioned using approximations. We compute the power loss to the walls as","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":" P_w = nu_ew(2 T_ev - phi_s)","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"where nu_ew is the electron wall collision frequency, T_ev is the electron temperature in electron-volts, and phi_s is the wall sheath potential in volts. The sheath potential is computed as:","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"phi_w = T_ev lnleft(1 - gamma) sqrtfracm_i2pi m_eright","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"Here, gamma is the secondary electron emission coefficient, which is computed according to the choice of WallMaterial. For a plasma with only once charge state, the electron-wall collision frequency is:","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"nu_ew = fracalpha1 - gammasqrtfrace T_eVm_ifrac1R_o - R_i","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"where R_o and R_i are the channel inner radius and outer radii respectively. For multiply-charged plasmas, the ion currents of each species are first computed as:","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"j_iwZ = alpha Z e n_iZ sqrtfracZ e T_eVm_i","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"Then, the electron wall current minus the secondary electron current are equal to the total ion wall current:","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"(1 - gamma) j_ew = j_iw = sum_Z j_iw Z","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"Lastly, we compute the electron-wall collision frequency as","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"nu_ew = fracj_ewe n_e frac1R_o - R_i","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"The ion current of each species is also used to compute ion wall losses if ion_wall_losses is set to true in config. Ions are assumed to recombine at the walls and the flux is re-injected as neutrals.","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"dotn_iw Z = -fracj_iw Zefrac1R_o - R_i","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"dotn_nw Z = -sum_Z dotn_iw Z","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"If thruster.shielded is true, the electron temperature at the walls is assumed to be equal to the electron temperature at the anode, see Thrusters for the option.","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"The density relation in the WallSheath model is based upon the electron Boltzmann relation. Note that at this point the model does not differentiate between axial positions inside and outside the thruster. The same loss model is applied over the entire domain. This approximation seems to work ok when comparing to 2D simulations due to isothermal magnetic field lines. More fidelity will most likely be added. ","category":"page"},{"location":"wall_loss_models/#Impact-of-magnetic-shielding","page":"Wall Loss Models","title":"Impact of magnetic shielding","text":"","category":"section"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"The effect on magnetic shielding on the electron energy can be seen below. Compared are time-averaged electron energy profiles for a Xenon SPT-100 type thruster using Boron Nitride walls.","category":"page"},{"location":"wall_loss_models/","page":"Wall Loss Models","title":"Wall Loss Models","text":"(Image: unshielded_vs_shielded)","category":"page"},{"location":"contribution/#Contribution","page":"Contribution","title":"Contribution","text":"","category":"section"},{"location":"contribution/","page":"Contribution","title":"Contribution","text":"We welcome all contributions. If you would like a new feature added, please open an issue on the HallThruster.jl repo, and if you modify the code on your end, please consider opening a pull request and contributing back to the main repo.","category":"page"},{"location":"verification/#Verification","page":"Verification","title":"Verification","text":"","category":"section"},{"location":"verification/","page":"Verification","title":"Verification","text":"Tests can be found in the test folder, and are split in unit_tests and order_verification tests. The julia Test environment is used. We verify that the PDEs are discretized correctly using the Method of Manufactured Solutions and perform order verification studies in order to ensure that the actual order of accuracy matches the predicted order. For more details on the discretization, see Fluxes and Numerics.","category":"page"},{"location":"verification/#Landmark","page":"Verification","title":"Landmark","text":"","category":"section"},{"location":"verification/","page":"Verification","title":"Verification","text":"In addition to the MMS studies discussed above, we also compare the results to the Landmark test cases for 1D fluid Hall Thruster discharges. Below, we compare the time-averaged output of HallThruster.jl for each of the three test cases to the expected results from Landmark. The cases differ only in the amount of electron energy lost to to radial sheaths inside the thruster. For the purpose of verification, the boundary conditions, source terms, collision models and anomalous collision frequency has been set to match Landmark. The results shown are time-averaged, performed using 160 cells using the first-order Rusanov flux and without gradient reconstruction. ","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"Landmark energy loss term:","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":" W = nu_epsilon expleft(frac-20epsilonright)","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"where","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":" nu_epsilon=\n begincases\n alpha_1 times 10^7 z - z_0 leq L_ch \n alpha_2 times 10^7 z - z_0 L_ch\n endcases","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"and","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"epsilon = frac32 T_ev","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"In the above, L_ch refers to thruster channel length and z_0 is domain[1], or the z-location of the anode.","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"Case 1 alpha_1 = 10 alpha_2 = 10 (Image: Landmark1)","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"Case 2 alpha_1 = 05 alpha_2 = 10 (Image: Landmark2)","category":"page"},{"location":"verification/","page":"Verification","title":"Verification","text":"Case 3 alpha_1 = 04 alpha_2 = 10 (Image: Landmark3)","category":"page"},{"location":"config/#Configuration","page":"Configuration","title":"Configuration","text":"","category":"section"},{"location":"config/","page":"Configuration","title":"Configuration","text":"The Config struct contains all of the options you need to run a simulation. On this page, we will explain what options are available and what they do. Note that all arguments must be provided as keywords.","category":"page"},{"location":"config/","page":"Configuration","title":"Configuration","text":"There are four absolutely mandatory arguments. These are:","category":"page"},{"location":"config/","page":"Configuration","title":"Configuration","text":"discharge_voltage: The difference in potential between the anode and cathode, in Volts. This is used to set the left boundary condition. If the cathode potential is zero, then the anode potential is equal to the discharge voltage.\nthruster: This is a Thruster object containing important geometric and magnetic information about the thruster being simulated. See the page about Thrusters for more.\ndomain: This is a Tuple containing the locations of the left and right boundaries of the simulation domain, in meters. For instance, if your simulation domain starts at z = 0.0 and is 5 cm long, you would write domain = (0.0, 0.05).\nanode_mass_flow_rate: The propellant mass flow rate at the anode, in kg/s","category":"page"},{"location":"config/","page":"Configuration","title":"Configuration","text":"Aside from these arguments, all others have default values provided. These are detailed below:","category":"page"},{"location":"config/","page":"Configuration","title":"Configuration","text":"initial_condition: A function used for initializing the simulation. See the page about Initialization for more information.\nncharge: Number of charge states to simulate. Defaults to 1.\npropellant: Propellant gas. Defaults to Xenon. Other options are described on the Propellants page.\nscheme: Numerical scheme to employ for integrating the ion equations. This is a HyperbolicScheme struct with fields flux_function, limiter, and reconstruct. Defaults to HyperbolicScheme(flux_function = rusanov, limiter = minmod, reconstruct = false). For more information, see Fluxes.\ncathode_potential: The potential at the right boundary of the simulation. Defaults to 0.0\nanode_Te: The electron temperature at the anode, in eV. Acts as a Dirichlet boundary condition for the energy equation. Defaults to 3.0.\ncathode_Te: The electron temperature at the cathode, in eV. Acts as a Dirichlet boundary condition for the energy equation. Defaults to 3.0.\nwall_loss_model: How radial losses due to sheaths are computed. Defaults to ConstantSheathPotential(sheath_potential=-20.0, inner_loss_coeff = 1.0, outer_loss_coeff = 1.0), which is the loss term from LANDMARK case 1. Other wall loss models are described on the Wall Loss Models page.\nwall_collision_freq: Extra \"wall collisions\" to be added to the total electron momentum transfer collision frequency inside of the channel. Units of Hz. Defaults to 0.0.\nanom_model: Model for computing the anomalous collision frequency. Defaults to TwoZoneBohm(1/160, 1/16). Further details on the Anomalous Transport page.\nconductivity_model: Model for the perpendicular electron thermal conductivity. Defaults to Mitchner(). Further details can be found on the Electron Thermal Conductivity page.\nionization_model: Model for ionization. Defaults to IonizationLookup(), which uses a lookup table to compute ionization rate coefficients as a function of electron energy. Other options are described on the Collisions and Reactions page.\nexcitation_model: Model for excitation reactions. Defaults to ExcitationLookup(), which uses a lookup table to compute excitation rate coefficients as a function of electron energy.. Other models are described on the Collisions and Reactions page.\nelectron_neutral_model: Model for elastic scattering collisions between electrons and neutral atoms. Defaults to ElectronNeutralLookup(), which uses a lookup table to compute the elastic scattering rate coefficient. Other models are described on the Collisions and Reactions page.\nelectron_ion_collisions: Whether to include electron-ion collisions. Defaults to true. More information on the Collisions and Reactions page.\nneutral_velocity: Neutral velocity in m/s. Defaults to 300.0\nneutral_temperature: Neutral temperature in Kelvins. Defaults to 300.0.\nion_temperature: Ion temperature in Kelvins. Defaults to 100.0\nimplicit_energy: The degree to which the energy is solved implicitly. 0.0 is a fully-explicit forward Euler, 0.5 is Crank-Nicholson, and 1.0 is backward Euler. Defaults to 1.0.\nmin_number_density: Minimum allowable number density for any species. Defaults to 1e6\nmin_electron_temperature: Minimum allowable electron temperature. Defaults to 1.0.\nmagnetic_field_scale: Factor by which the magnetic field is increased or decreased compared to the one in the provided Thruster struct. Defaults to 1.0.\nsource_neutrals: Extra user-provided neutral source term. Can be an arbitrary function, but must take (U, params, i) as arguments. Defaults to Returns(0.0). See User-Provided Source Terms for more information.\nsource_ion_continuity: Vector of extra source terms for ion continuity, one for each charge state. Defaults to fill(Returns(0.0), ncharge) . See User-Provided Source Terms for more information.\nsource_ion_momentum: Vector of extra source terms for ion momentum, one for each charge state. Defaults to fill(Returns(0.0), ncharge) . See User-Provided Source Terms for more information.\nsource_potential: Extra source term for potential equation. Defaults to Returns(0.0). See User-Provided Source Terms for more information.\nsource_electron_energy: Extra source term for electron energy equation. Defaults to Returns(0.0). See User-Provided Source Terms for more information.\nLANDMARK: Whether we are using the LANDMARK physics model. This affects whether certain terms are included in the equations, such as electron and heavy species momentum transfer due to ionization and the form of the electron thermal conductivity. Also affects whether we use an anode sheath model. Defaults to false.\nion_wall_losses: Whether we model ion losses to the walls. Defaults to false.\nsolve_background_neutrals: Turns on an additional mass flow rate due to neutral ingestion\nbackground_pressure: The pressure of the background neutrals, in Pascals\nbackground_neutral_temperature: The temperature of the background neutrals, in K\nanode_boundary_condition: Can be either :sheath or :dirichlet\nanom_smoothing_iters: How many times to smooth the anomalous transport profile\nsolve_plume: Whether to solve for plume area variation and divergence losses\napply_thrust_divergence_correction: Whether the thrust output by HallThruster.jl should include a divergence correction factor of cos(δ)^2\nelectron_losses_in_plume: Whether electron radial/wall losses are applied in the plume region","category":"page"},{"location":"electron_thermal_conductivity/#Electron-Thermal-Conductivity","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"","category":"section"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"HallThruster has a few electron thermal conductivity models built in and allows users to define their own. This page describes these models and the process by which algebraic transport models can be added by the user.","category":"page"},{"location":"electron_thermal_conductivity/#Built-in-Models","page":"Electron Thermal Conductivity","title":"Built-in Models","text":"","category":"section"},{"location":"electron_thermal_conductivity/#Mitchner()","page":"Electron Thermal Conductivity","title":"Mitchner()","text":"","category":"section"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"HallThruster.jl's default electron thermal conductivity option. This model employs the form described in Mitchner & Kruger \"Partially Ionized Gases\" (1973). The thermal conductivity takes the form:","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"beginaligned\n kappa_eperp approx frac11+Omega_H^2 frac241+ fracnu_iesqrt2nu fracneTe (eV)nu m_e \n nu = nu_ei + nu_en + nu_AN \nendaligned","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"The model is initialized by default but can be explicitly enabled by including:","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"conductivity_model = Mitchner()","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"In the user-defined configuration","category":"page"},{"location":"electron_thermal_conductivity/#Braginskii()","page":"Electron Thermal Conductivity","title":"Braginskii()","text":"","category":"section"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"This form of the thermal conductivity follows the result of S. I. Braginskii, in Reviews of Plasma Physics, edited by M. A. Leontovich (Consultants Bureau, New York, 1965), Vol. 1, p. 205.:","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"\\begin{aligned} \\kappa{e\\perp} & \\approx C \\frac{neTe (eV) \\nu}{me \\omega{ce}^2} \\\n \\nu = \\nu{ei} + \\nu{en} + \\nu{AN} \\\n\\end{aligned}","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"Where C is a constant that is based on the value of the effective charge for multiple charge states and Table 1 of the Braginskii reference. A Braginskii model can be initialized in the user-defined configuration as:","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"conductivity_model = Braginskii()","category":"page"},{"location":"electron_thermal_conductivity/#Custom-thermal-conductivity-models","page":"Electron Thermal Conductivity","title":"Custom thermal conductivity models","text":"","category":"section"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"The procedure for adding additional thermal conductivity models generally follows that of adding anomalous transport models, as described on the Anomalous Transport page. The two main differences is that the model type is of 'ThermalConductivityModel' rather than 'AnomalousTransportModel' and that the function needs to return kappa rather than nu an. For demonstration pursposes however, let's say we wanted to implement the Braginskii model but without the anomalous collision frequency and a coefficient of 4.66 (singly charged ions only). We first define the type:","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"using HallThruster\n\nstruct Braginskii_Classical <: ThermalConductivityModel end","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"With the type defined, we then need to define the function that describes the model. This function should take two arguements, the vector of thermal conductivity values and the solver params.","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"function (model::Braginskii_Classical)(κ, params)\n\n me = HallThruster.me\n e = HallThruster.e\n B = params.cache.B\n ne = params.cache.ne\n Te = params.cache.Tev\n\n for i in eachindex(κ)\n ωce = e * B[i] / me\n κ[i] = 4.66 * ne * e * Te * params.cache.νc[i] / (me * ωce^2)\n end\n\n return κ\nend","category":"page"},{"location":"electron_thermal_conductivity/","page":"Electron Thermal Conductivity","title":"Electron Thermal Conductivity","text":"We could now employ this model by setting `conductivitymodel = BraginskiiClassical()' in the user-defined configuration. ","category":"page"},{"location":"run/#Tutorial:-running-and-analyzing-a-simulation","page":"Tutorial","title":"Tutorial: running and analyzing a simulation","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"This page will walk you through running a simulation and analyzing the output, in the process discussing many of the key features of HallThruster.jl. An interactive Jupyter notebook tutorial covering similar topics and convering the process of comparing the results of the code to an established benchmark is also available here.","category":"page"},{"location":"run/#Defining-geometry","page":"Tutorial","title":"Defining geometry","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"The first thing we need to simulate a Hall thruster is geometry. Let's invent a fictional Hall thruster with a channel length of 3 cm, inner channel radius of 5 cm, and outer channel radius of 6.5 cm. To define the geometry, we create a HallThruster.Geometry1D object:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"using HallThruster\n\n# All units are in meters!\nmy_geometry = HallThruster.Geometry1D(\n inner_radius = 0.05,\n outer_radius = 0.065,\n channel_length = 0.03\n)","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"For clarity and ease of readability, you may also input dimensional numbers from the lovely Unitful package as shown below:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"using HallThruster\nusing Unitful\n\n# Units will be correctly converted!\nmy_geometry = HallThruster.Geometry1D(\n inner_radius = 5.0u\"cm\",\n outer_radius = 6.5u\"cm\",\n channel_length = 3.0u\"cm\"\n)","category":"page"},{"location":"run/#Magnetic-field","page":"Tutorial","title":"Magnetic field","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"The next thing we need is a magnetic field function. This can by any callable object, so long as it takes in an axial location in meters and returns a magnetic field strength in Teslas. Let's use a magnetic field with a Gaussian shape and a peak radial magnetic field strength of 200 Gauss at the channel exit plane:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"function my_magnetic_field(z)\n if z < 0.03\n return 0.02 * exp(-((z - 0.03) / 0.02)^2)\n else\n return 0.02 * exp(-((z - 0.03) / 0.04)^2)\n end\nend","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"Alternatively, we may want to load in a magnetic field from a file. Suppose we have a magnetic field stored in a file my_bfield.csv which has the following first few lines:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"z(m),Br(T)\n0.0,0.0021079844912372868\n0.001,0.0024430133907998\n0.002,0.0028171684184209005\n0.003,0.0032324238493067863\n0.004,0.003690390479859787\n0.005,0.004192227743021959\n0.006,0.004738555173642436\n0.007,0.005329365956270483\n0.008,0.005963945588597749\n0.009,0.006640798906893217\n0.01,0.00735758882342885\n...","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"We could load this in using the DelimitedFiles package","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"my_magnetic_field_data, header = readdlm(\"my_bfield.csv\", ',', header=true)","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"We can then construct a function which interpolates the data (here a linear interpolation, but you can use more complex interpolations using the Interpolations.jl package):","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"z_data = my_magnetic_field_data[:, 1]\nBr_data = my_magnetic_field_data[:, 2]\nmy_magnetic_field_itp = HallThruster.LinearInterpolation(z_data, Br_data)","category":"page"},{"location":"run/#Creating-a-Thruster","page":"Tutorial","title":"Creating a Thruster","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"Once we have a geometry and a magnetic field, we can construct a Thruster:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"my_thruster = HallThruster.Thruster(\n\tname = \"My thruster\",\n magnetic_field = my_magnetic_field,\n geometry = my_geometry,\n shielded = false,\n)","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"In addition to a magnetic field and a geometry, we have also provided a name (optional) and designated whether the thruster is magnetically shielded or not. If true, then the electron temperature used for electron wall loss computations will be the anode temperature instead of the temperature on centerline. HallThruster.jl also includes a built-in definition for the widely-known SPT-100 thruster, accessible as HallThruster.SPT_100.","category":"page"},{"location":"run/#Defining-a-Config","page":"Tutorial","title":"Defining a Config","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"We can now define a Config. We will run a simulation using Xenon propellant and two ion charge states, with a discharge voltage of 300 V and a mass flow rate of 6 mg/s. For anomalous transport, we use a multi-zone Bohm-like transport model. Many more options than these can be tweaked. For more information and a list all possible options, see the Configuration page.","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"my_config = HallThruster.Config(\n ncharge = 2,\n discharge_voltage = 300u\"V\",\n thruster = my_thruster,\n domain = (0.0u\"cm\", 8.0u\"cm\"),\n anode_mass_flow_rate = 8.0u\"mg/s\",\n wall_loss_model = HallThruster.WallSheath(HallThruster.BoronNitride),\n anom_model = HallThruster.MultiLogBohm([0.02, 0.03, 0.04, 0.06, 0.006, 0.2]),\n propellant = Xenon,\n neutral_velocity = 500.0u\"m/s\",\n neutral_temperature = 500.0u\"K\",\n ion_temperature = 500.0u\"K\",\n cathode_Te = 2.5u\"eV\",\n anode_Te = 2.5u\"eV\",\n ion_wall_losses = true,\n)","category":"page"},{"location":"run/#Running-a-simulation","page":"Tutorial","title":"Running a simulation","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"Now we can run a simulation. To do this, we use the run_simulation function. In addition to the Config object we just created, we also pass in the grid we want to run the simulation with, the number of frames we want to save, the timestep, in seconds and the simulation duration (also in seconds).","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> @time my_solution = HallThruster.run_simulation(my_config; grid= EvenGrid(150), nsave=10000, dt=1e-8, duration=1e-3)\n 36.058672 seconds (783.66 k allocations: 519.964 MiB)\nHall thruster solution with 10000 saved frames\nRetcode: success\nEnd time: 0.001 seconds","category":"page"},{"location":"run/#Postprocessing-and-analysis","page":"Tutorial","title":"Postprocessing and analysis","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"Once you have run a Hall thruster simulation, you will want to analyze the results to see how your simulation performed. This section describes the utilities available for such tasks.","category":"page"},{"location":"run/#The-Solution-object","page":"Tutorial","title":"The Solution object","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"Running a simulation returns a HallThruster.Solution object, which has the following fields:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"t: A vector of times at which the simulation state is saved u: A vector of simulation state matrices saved at each of the times in t savevals: A Vector of NamedTuples containing saved derived plasma properties at each of the times in t retcode: A Symbol describing how the simulation finished. This should be :Success if the simulation succeeded, but may be :NaNDetected if the simulation failed. params: A NamedTuple containing simulation parameters, such as the Config the simulation was run with, the computational grid, and more. params.cache contains all of the variables not contained in u","category":"page"},{"location":"run/#Extracting-performance-metrics","page":"Tutorial","title":"Extracting performance metrics","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"After running a simulation, the two things we might care the most about are the predicted thrust and discharge current. These can be computed with the thrust and discharge_current functions, respectively.","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> HallThruster.thrust(my_solution) # Thrust in Newtons at every saved frame\n10000-element Vector{Float64}:\n 0.24759825170838257\n 0.23553180163085566\n ⋮\n 0.1677545384599781\n 0.1677545384591017\n\njulia> HallThruster.thrust(my_solution, 12) # Thrust in Newtons at the twelfth frame\n0.16887856098607704","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> HallThruster.discharge_current(my_solution) # Discharge current in A at every frame\n10000-element Vector{Float64}:\n 16.594260447976414\n 16.491449186956455\n ⋮\n 12.635410795570154\n 12.63541079552306\n\njulia> HallThruster.discharge_current(my_solution, 1999) # Discharge current in A at the 1999th frame\n12.137864749597252\n","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"We can plot the ion, electron, and total currents using our plotting package of choice. In this case, we use Plots","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"using Plots\ntime_us = my_solution.t .* 1_000_000 # Convert time from seconds to microseconds\nI_ion = ion_current(my_solution)\nI_total = discharge_current(my_solution)\nI_electron = I_total .- I_ion # we can also just type electron_current(my_solution)\n\np = plot(\n time_us, I_ion;\n label = \"Ion current\",\n xlabel = \"Time (microseconds)\",\n\tylabel = \"Current (A)\"\n)\nplot!(p, time_us, I_electron; label = \"Electron current\")\nplot!(p, time_us, I_total; label = \"Discharge current\", linewidth = 2)\n\ndisplay(p)\n","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"(Image: )","category":"page"},{"location":"run/#Time-averaging-results","page":"Tutorial","title":"Time averaging results","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"In the above case, the simulation settled to a steady state after 250 microseconds, so we could just look at the last frame to obtain our performance and plasma properties. However, Hall thrusters are often oscillatory. To see this, let's cut the minimum anomalous collision frequency in half and re-run the simulation. The new config is:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"my_config = HallThruster.Config(\n ncharge = 2,\n discharge_voltage = 300u\"V\",\n thruster = my_thruster,\n domain = (0.0u\"cm\", 8.0u\"cm\"),\n anode_mass_flow_rate = 8u\"mg/s\",\n wall_loss_model = HallThruster.WallSheath(HallThruster.BoronNitride),\n # change second to last number here from 0.006 to 0.003\n anom_model = HallThruster.MultiLogBohm([0.02, 0.03, 0.04, 0.06, 0.003, 0.2]),\n propellant = Xenon,\n neutral_velocity = 500.0u\"m/s\",\n neutral_temperature = 500.0u\"K\",\n ion_temperature = 500.0u\"K\",\n cathode_Te = 2.5u\"eV\",\n anode_Te = 2.5u\"eV\",\n ion_wall_losses = true,\n)","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"Plotting the current, we find that the solution now no longer converges to a steady value but instead oscillates strongly about a mean:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"(Image: )","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"To compute performance, we want to average over several of the oscillations. To do this, we employ the time_average function","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> my_time_average = time_average(my_solution)\nHall thruster solution with 1 saved frames\nRetcode: Success\nEnd time: 0.001 seconds","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"The time_average function returns another Solution object, just like my_solution, with a single saved frame holding the time-averaged simulation data. In the case of our oscillatory simulation above, the simulation doesn't settle into a stationary mode until about 100 microseconds have elapsed (about 1000 frames, since we saved 10000 total). If we want to only average the last 9000 frames, we would type","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> my_time_average = time_average(my_solution, 1000) # start averaging at frame 1000","category":"page"},{"location":"run/#Plotting","page":"Tutorial","title":"Plotting","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"HallThruster.jl includes plotting recipes to allow you to plot your simulation results if the Plots package is installed. To plot the last frame of the simulation, you can type:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"using Plots\n\nplot(my_solution)","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"(Image: )","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"To plot a different frame, you can do plot(my_solution, frame_you_want). You can also plot time averaged solutions, as they are no different from a standard solution. You can also plot certain parts on a log scale using the yaxis=:log argument, add labels using label = \"label\", and plot solutions over each other using plot!, just as normal using Plots.jl.","category":"page"},{"location":"run/#Computing-efficiencies","page":"Tutorial","title":"Computing efficiencies","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"There are several key efficiency metrics that are employed to judge how well a Hall thruster performs. The most common is the anode efficiency, defined as the ratio of thrust power to power put into the plasma:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"eta_a = frac12fracT^2dotm V_d I_d","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"We can compute this using the compute_anode_eff function, which returns the anode efficiency at every timestep:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> HallThruster.anode_eff(my_solution)\n10000-element Vector{Float64}:\n 0.769654845938557\n 0.7008079984180736\n ⋮\n 0.46399997114634145\n 0.46399997114322283","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"warning: Computing average efficiencies\nWhen computing time-averaged efficiencies, it is better to first time-average the simulation and then compute the efficiencies from the averaged plasma properties then it is to average the instantaneous efficiencies. For example,avg_eff = mean(HallThruster.anode_eff(my_solution)) # not ideal\navg_eff = HallThruster.anode_eff(time_average(my_solution)[] # better","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"The mass utilization efficiency is the ratio of the ion beam mass flow rate to the total anode input mass flow rate and is computed with compute_mass_eff:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> HallThruster.mass_eff(my_solution)\n10000-element Vector{Float64}:\n 1.3406882897286088\n 1.2966376960524595\n ⋮\n 1.0022667540786294\n 1.0022667540739632","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"The current utilization efficiency is the ratio of the ion current to the discharge current:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> HallThruster.current_eff(my_solution)\n10000-element Vector{Float64}:\n 0.599052550532874\n 0.58182111692138\n ⋮\n 0.552664262832069\n 0.5526642628312223","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"The voltage utilization efficiency is the ratio of the effective acceleration voltage to the discharge voltage:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> HallThruster.voltage_eff(my_solution)\n10000-element Vector{Float64}:\n 0.9962185160007747\n 0.9699301625865606\n ⋮\n 0.8856545575551746\n 0.8856545575546175","category":"page"},{"location":"run/#Extracting-plasma-properties","page":"Tutorial","title":"Extracting plasma properties","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"To access a plasma property, you index the solution by the symbol corresponding to that property. For example, to get the plasma density at every frame, I would type:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> ne = my_solution[:ne]\n10000-element Vector{Vector{Float64}}:\n...","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"This returns a Vector of Vectors containing the number density at every frame and every cell. To get the number density just in the 325th frame, I would type","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> ne_end = my_solution[:ne][325]\n152-element Vector{Float64}:\n 9.638776090165182e16\n 9.638776090165182e16\n 1.1364174787296864e17\n ⋮\n 2.568578735293536e17\n 2.532630941584664e17\n 2.532630941584664e17","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"This has 152 elements, one for each of the 150 interior cells and 2 for the left and right boundary. To get the axial locations of these cells in meters, we can access sol.params.z_cell.","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"For ion parameters (ion density and velocity), we specify which charge state we want to extract. For example, to get the velocity (in m/s) of doubly-charged Xenon at the 4900th frame, we would type:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> ui = my_solution[:ui, 2][4900]\n152-element Vector{Float64}:\n -1795.4362688519843\n -1724.298256534735\n -1647.858433966283\n ⋮\n 27654.42396859592\n 27735.77112807524\n 27735.756446024698","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"Here, indexing by [:ui, 2] means we want the velocity for doubly-charged ions. We could similarly index by [:ni, 1] for the density of singly-charged ions.","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"A list of parameters that support this sort of indexing can be found by calling HallThruster.saved_fields(). A few of these are:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"B: Magnetic field strength in Tesla\nωce: Cyclotron frequency in Hz\nνan: Anomalous collision frequency in Hz\nνe: Total electron collision frequency in Hz\nνc: Classical collision frequency in Hz\nνei: Electron-ion collision frequency in Hz\nνen: Electron-neutral collision frequency in Hz\nνex: Excitation collision frequency in Hz\nνiz: Ionization collision frequency in Hz\nradial_loss_frequency: Electron-wall collision frequency for wall loss calculation in Hz\nνew_momentum: Electron-wall collision frequency for mobility calculation in Hz\nμ: Electron mobility\nE: Electric field\nϕ: plasma potential at cell centers in V\nTev: Electron temperature in eV\npe: Electron pressure in eV/m^3\n∇pe: Electron pressure gradient\nnn: Neutral density\nni: Ion density (default 1st charge state, index by [:ni, Z] to get charge state Z)\nui: Ion velocity (default 1st charge state, index by [:ui, Z] to get charge state Z)","category":"page"},{"location":"run/#Saving-simulations-for-use-as-restarts","page":"Tutorial","title":"Saving simulations for use as restarts","text":"","category":"section"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"To save a simulation for later, you can use the write_restart function. We can then read it back with the read_restart function:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> HallThruster.write_restart(\"my_restart.jld2\", my_solution);\n\njulia> HallThruster.read_restart(\"my_restart.jld2\")\nHall thruster solution with 10000 saved frames\nRetcode: Success\nEnd time: 0.001 seconds","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"To use a restart as the initial condition for a simulation, you can use the restart keyword argument in the run_simulation function:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"julia> @time my_solution = HallThruster.run_simulation(my_config; ncells=150, nsave=10000, dt=1e-8, duration=1e-3, restart = \"my_restart.jld2\")\n 34.700016 seconds (7.27 M allocations: 1016.374 MiB, 0.79% gc time, 5.42% compilation time)\nHall thruster solution with 10000 saved frames\nRetcode: Success\nEnd time: 0.001 seconds","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"If we plot the currents, we see that the simulation remained at the steady state established in the initial run:","category":"page"},{"location":"run/","page":"Tutorial","title":"Tutorial","text":"(Image: )","category":"page"},{"location":"internals/","page":"Internals","title":"Internals","text":"CurrentModule = HallThruster","category":"page"},{"location":"internals/","page":"Internals","title":"Internals","text":"","category":"page"},{"location":"internals/","page":"Internals","title":"Internals","text":"Modules = [HallThruster]","category":"page"},{"location":"internals/#HallThruster.Air","page":"Internals","title":"HallThruster.Air","text":"Air::Gas\n\nEarth air at standard temperature and pressure\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.Argon","page":"Internals","title":"HallThruster.Argon","text":"Argon::Gas\n\nArgon gas\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.Bismuth","page":"Internals","title":"HallThruster.Bismuth","text":"Bismuth::Gas\n\nBismuth vapor\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.Electron","page":"Internals","title":"HallThruster.Electron","text":"Electron::Species\n\nElectron\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.Krypton","page":"Internals","title":"HallThruster.Krypton","text":"Krypton::Gas\n\nKrypton gas\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.LOOKUP_ZS","page":"Internals","title":"HallThruster.LOOKUP_ZS","text":"Lookup for thermal conductivity coefficients, from Table 1 of S. I. Braginskii, in Reviews of Plasma Physics (1965), Vol. 1, p. 205.\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.Mercury","page":"Internals","title":"HallThruster.Mercury","text":"Mercury::Gas\n\nMercury vapor\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.NA","page":"Internals","title":"HallThruster.NA","text":"NA\n\nNumber of atoms in a kg-mol (6.02214076e26 / kmol)\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.R0","page":"Internals","title":"HallThruster.R0","text":"R0\n\nUniversal gas constant (8314.46261815324 J / kmol K)\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.Xenon","page":"Internals","title":"HallThruster.Xenon","text":"Xenon::Gas\n\nXenon gas\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.e","page":"Internals","title":"HallThruster.e","text":"e\n\nElectron charge (1.602176634e-19 Coulomb)\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.kB","page":"Internals","title":"HallThruster.kB","text":"kB\n\nBoltzmann constant (1.380649e-23 J/K)\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.me","page":"Internals","title":"HallThruster.me","text":"me\n\nElectron mass (9.10938356e-31 kilograms)\n\n\n\n\n\n","category":"constant"},{"location":"internals/#HallThruster.AnomalousTransportModel","page":"Internals","title":"HallThruster.AnomalousTransportModel","text":"AnomalousTransportModel\n\nThe abstract supertype of all types of anomalous transport models. Subtype this to define your own model.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Bohm","page":"Internals","title":"HallThruster.Bohm","text":"Bohm(c) <: AnomalousTransportModel\n\nModel where the anomalous collision frequency scales with the electron cyclotron frequency ωce times some scaling factor c\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Braginskii","page":"Internals","title":"HallThruster.Braginskii","text":"Braginskii conductivity model for fully-ionized plasmasa\nS. I. Braginskii, in Reviews of Plasma Physics (1965), Vol. 1, p. 205.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Config","page":"Internals","title":"HallThruster.Config","text":"struct Config{A<:HallThruster.AnomalousTransportModel, TC<:HallThruster.ThermalConductivityModel, W<:HallThruster.WallLossModel, IZ<:HallThruster.IonizationModel, EX<:HallThruster.ExcitationModel, EN<:HallThruster.ElectronNeutralModel, HET<:HallThruster.Thruster, S_N, S_IC, S_IM, S_ϕ, S_E, T<:HallThruster.TransitionFunction, IC<:HallThruster.InitialCondition, HS<:HallThruster.HyperbolicScheme}\n\nHall thruster configuration struct. Only four mandatory fields: discharge_voltage, thruster, anode_mass_flow_rate, and domain.\n\nFields\n\ndischarge_voltage::Float64\ncathode_potential::Float64\nanode_Te::Float64\ncathode_Te::Float64\nwall_loss_model::HallThruster.WallLossModel\nneutral_velocity::Float64\nneutral_temperature::Float64\nimplicit_energy::Float64\npropellant::HallThruster.Gas\nncharge::Int64\nion_temperature::Float64\nanom_model::HallThruster.AnomalousTransportModel\nconductivity_model::HallThruster.ThermalConductivityModel\nionization_model::HallThruster.IonizationModel\nexcitation_model::HallThruster.ExcitationModel\nelectron_neutral_model::HallThruster.ElectronNeutralModel\nelectron_ion_collisions::Bool\nmin_number_density::Float64\nmin_electron_temperature::Float64\ntransition_function::HallThruster.TransitionFunction\ninitial_condition::HallThruster.InitialCondition\nmagnetic_field_scale::Float64\nsource_neutrals::Any\nsource_ion_continuity::Any\nsource_ion_momentum::Any\nsource_potential::Any\nsource_energy::Any\nscheme::HallThruster.HyperbolicScheme\nthruster::HallThruster.Thruster\ndomain::Tuple{Float64, Float64}\nLANDMARK::Bool\nanode_mass_flow_rate::Float64\nion_wall_losses::Bool\nsolve_background_neutrals::Bool\nbackground_pressure::Float64\nbackground_neutral_temperature::Float64\nanode_boundary_condition::Symbol\nanom_smoothing_iters::Int64\nsolve_plume::Bool\napply_thrust_divergence_correction::Bool\nelectron_plume_loss_scale::Float64\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.ExcitationLookup","page":"Internals","title":"HallThruster.ExcitationLookup","text":"ExcitationLookup(;[directories::Vector{String} = String[]])\n\nDefault excitation model for HallThruster.jl. Reads excitation rate coefficients from file. Looks (preferentially) in provided directories and in the reactions subfolder for rate coefficient files\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Gas","page":"Internals","title":"HallThruster.Gas","text":"Gas\n\nA chemical element in the gaseous state. Container for element properties used in fluid computations.\n\nFields\n\nname::String Full name of gas (i.e. Xenon)\n\nshort_name::String Short name/symbol (i.e. Xe for Xenon)\n\nγ::Float64 Specific heat ratio / adiabatic index\n\nM::Float64 Molar mass (grams/mol) or atomic mass units\n\nm::Float64 Mass of atom in kg\n\ncp::Float64 Specific heat at constant pressure in J / kg / K\n\ncv::Float64 Specific heat at constant volume in J / kg / K\n\nR::Float64 Gas constant in J / kg / K\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Gas-Tuple{Any, Any}","page":"Internals","title":"HallThruster.Gas","text":"Gas(name::String, short_name::String; γ::Float64, M::Float64)\n\nInstantiate a new Gas, providing a name, short name, the adiabatic index, and the molar mass. Other gas properties, including gas constant, specific heats at constant pressure/volume, and mass of atom/molecule in kg will are then computed.\n\njulia> Gas(\"Xenon\", \"Xe\", γ = 5/3, M = 83.798)\nXenon\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.Grid1D-Tuple{Any, Any}","page":"Internals","title":"HallThruster.Grid1D","text":"Grid1D(geometry, z_edge)\n\nGiven 1-D edge coordinates and thruster geometry, compute cell centers and cell volumes for grid\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.IonizationLookup","page":"Internals","title":"HallThruster.IonizationLookup","text":"IonizationLookup(;[directories::Vector{String} = String[]])\n\nDefault ionization model for HallThruster.jl. Reads ionization rate coefficients from file. Looks (preferentially) in provided directories and in the reactions subfolder for rate coefficient files\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.LANDMARK_conductivity","page":"Internals","title":"HallThruster.LANDMARK_conductivity","text":"LANDMARK, uses 10/9 μnϵ\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.LandmarkExcitationLookup","page":"Internals","title":"HallThruster.LandmarkExcitationLookup","text":"LandmarkExcitationLookup()\n\nExcitation model for the LANDMARK benchmark.\n\nReads excitation rate coefficients from the landmark/landmark_rates.csv file in the HallThruster.jl main directory. Supports only singly-charged Xenon.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.LandmarkIonizationLookup","page":"Internals","title":"HallThruster.LandmarkIonizationLookup","text":"LandmarkIonizationLookup()\n\nIonization model for the LANDMARK benchmark.\n\nReads ionization rate coefficients from the landmark/landmark_rates.csv file in the HallThruster.jl main directory. Supports only singly-charged Xenon.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Mitchner","page":"Internals","title":"HallThruster.Mitchner","text":"Mitchner-Kruger conductivity model for partially-ionized plasmas\nM. Mitchner and C. H. Kruger, Jr., Partially Ionized Gases (1973). Pg. 94\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.MultiLogBohm","page":"Internals","title":"HallThruster.MultiLogBohm","text":"MultiLogBohm(zs, cs) <: AnomalousTransportModel\n\nModel similar to that employed in Hall2De, where the mobility is Bohm-like (i.e. νan(z) = c(z) * ωce(z)) and z is in meters.\n\nThe function c(z) is defined by a sequence of nodes (z, c) provided by the user. At z = z[1], c(z) = c[1], and so forth.\n\nAt z[i] < z < z[i+1], log(c) is defined by linearly interpolating between log(c[i]) and log(c[i+1]).\n\nFor z < z[1], c = c[1] and for z > z[end], c(z) = c[end].\n\nThe user may also provide a single array of [z[1], z[2], ..., z[end], c[1], c[2], ..., c[end]]. The number of z values must be equal to the number of c values.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.NoAnom","page":"Internals","title":"HallThruster.NoAnom","text":"NoAnom <: AnomalousTransportModel\n\nNo anomalous collision frequency included in simulation\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.NoExcitation","page":"Internals","title":"HallThruster.NoExcitation","text":"NoExcitation <: ExcitationModel\n\nModel for neglecting excitation energy losses\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.ShiftedGaussianBohm","page":"Internals","title":"HallThruster.ShiftedGaussianBohm","text":"ShiftedGaussianBohm(trough_location, trough_width, trough_depth, z0, dz, alpha, pstar) <: AnomalousTransportModel\n\nModel in which the anomalous collision frequency is Bohm-like (νan ~ ωce), except in a Gaussian-shaped region defined by the parameters troughlocation, troughwidth, troughmax, and troughmin where the collision frequency is lower. The location of the trough is based on the background pressure and the user-provided coefficients.\n\nArguments\n\ntrough_location: the axial position (in meters) of the mean of the Gaussian trough\ntrough_width: the standard deviation (in meters) of the Gaussian trough\ntrough_min: the minimum Hall parameter\ntrough_max: the maximum Hall parameter\nz0: the furthest upstream displacement permitted at high back-pressures, relative to trough_location\ndz: the maximum allowable amount of axial displacement\npstar: the background pressure at which the shift upstream halts/plateaus\nalpha: the slope of the pressure response curve, with a higher value corresponding to a steeper pressure response\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.ShiftedMultiBohm","page":"Internals","title":"HallThruster.ShiftedMultiBohm","text":"ShiftedMultiBohm(zs, cs, z0, dz, alpha, pstar) <: AnomalousTransportModel\n\nA version of MultiLogBohm where the coefficients are shifted depending on the background pressure.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.ShiftedTwoZoneBohm","page":"Internals","title":"HallThruster.ShiftedTwoZoneBohm","text":"ShiftedTwoZoneBohm(coeffs, z0, dz, alpha, pstar) <: AnomalousTransportModel\n\nModel where the anomalous collision frequency has two values: c1 * ωce before some transition location and c2 * ωce after. Takes two arguments: c1 and c2. The transition between these values can be smoothed by the user-provided transition function. The location of the transition is based on the background pressure and the user-provided coefficients.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Species","page":"Internals","title":"HallThruster.Species","text":"Species\n\nRepresents a gas with a specific charge state. In a plasma, different ionization states of the same gas may coexist, so we need to be able to differentiate between these.\n\njulia> Species(Xenon, 0)\nXe\n\njulia> Species(Xenon, 1)\nXe+\n\njulia> Species(Xenon, 3)\nXe3+\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.ThermalConductivityModel","page":"Internals","title":"HallThruster.ThermalConductivityModel","text":"Thermal_Conductivity\n\nThe abstract supertype of all types of thermal conductivity models. Subtype this to define your own model.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.Thruster","page":"Internals","title":"HallThruster.Thruster","text":"Thruster\n\nStruct containing information about a Hall thruster. This includes a name, geometry (a Geometry1D object), magnetic_field (radial magnetic field along centerline, a function which takes z in meters and outputs B in Tesla), and a shielded (a flag indicating whether the thruster is magnetically-shielded).\n\nFields\n\nname::String\ngeometry::HallThruster.Geometry1D\nmagnetic_field::Any\nshielded::Bool\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.TwoZoneBohm","page":"Internals","title":"HallThruster.TwoZoneBohm","text":"TwoZoneBohm(c1, c2) <: AnomalousTransportModel\n\nModel where the anomalous collision frequency has two values: c1 * ωce inside the channel and c2 * ωce outside of the channel. Takes two arguments: c1 and c2. The transition between these values can be smoothed by the user-provided transition function.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.WallLossModel","page":"Internals","title":"HallThruster.WallLossModel","text":"abstract type WallLossModel\n\nAbstract type for wall loss models in the electron energy equation. Types included with HallThruster.jl are:\n\nNoWallLosses No electron energy losses to the wall.\nConstantSheathPotential(sheath_potential, inner_loss_coeff, outer_loss_coeff) Power to the walls scales with α * exp(-sheath_potential)), where α = inner_loss_coeff inside the channel and α = outer_loss_coeff outside.\nWallSheath(material::WallMaterial) Power to the walls is computed self-consistently using a sheath model, dependent on the secondary electron emission yield of the provided material. See WallMaterial for material options.\n\nUsers implementing their own WallLossModel will need to implement at least three methods 1) freq_electron_wall(model, U, params, i): Compute the electron-wall momentum transfer collision frequency in cell i 2) wall_power_loss(model, U, params, i): Compute the electron power lost to the walls\n\nA third method, wall_electron_current(model, U, params, i), will compute the electron current to the walls in cell i. If left unimplemented, it defaults to Ie,w = e ne νew Vcell where Vcell is the cell volume.\n\nA fourth method, wall_ion_current(model, U, params, i, Z), for computing the current of ions of charge Z to the walls in cell i, may also be implemented. If left unimplemented, it will default to computing the current assuming Ie,w = Ii,w.\n\n\n\n\n\n","category":"type"},{"location":"internals/#HallThruster.EvenGrid-Tuple{Any}","page":"Internals","title":"HallThruster.EvenGrid","text":"EvenGrid(n)\n\nConstruct an evenly-spaced grid with n cells.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.UnevenGrid","page":"Internals","title":"HallThruster.UnevenGrid","text":"UnevenGrid(n, density = HallThruster.default_density)\n\nConstruct an unevenly-spaced grid according to provided density function. Defaults to twice as many grids inside of channel than outside. Provided density functions must have a signature of (z, z0, z1, Lch) where z is the location, (z0, z1) are the extents of the domain and Lch is the channel length\n\n\n\n\n\n","category":"function"},{"location":"internals/#HallThruster.allocate_anom_variables-Tuple{HallThruster.AnomalousTransportModel, Any}","page":"Internals","title":"HallThruster.allocate_anom_variables","text":"allocate_anom_variables(::AnomalousTransportModel, ncells)\n\nAllocate arrays for anomalous transport state variables. ncells is the length of the arrays to be allocated. These anomalous transport variables are then stored in params.cache.anom_variables\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.backward_diff_coeffs-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.backward_diff_coeffs","text":"backward_diff_coeffs(x0, x1, x2)\n\nGenerate finite difference coefficients for a backward first derivative approximation at the point x2 on a three-point stencil at points x0, x1, and x2\n\njulia> backward_diff_coeffs(-2//1, -1//1, 0//1)\n(1//2, -2//1, 3//2)\njulia> backward_diff_coeffs(-3//2, -1//1, 0//1)\n(4//3, -3//1, 5//3)\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.backward_difference-NTuple{6, Any}","page":"Internals","title":"HallThruster.backward_difference","text":"backward_difference(f0, f1, f2, x0, x1, x2)\n\nGiven three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the derivative at x2\n\nf(x) = x^4\nx0, x1, x2 = 1.9999998, 1.9999999, 2\nbd = backward_difference(f(x0), f(x1), f(x2), x0, x1, x2)\nbd ≈ 32\n\n# output\n\ntrue\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.central_diff_coeffs-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.central_diff_coeffs","text":"central_diff_coeffs(x0, x1, x2)\n\nGenerate finite difference coefficients for a central first derivative approximation at the point x1 on a three-point stencil at points x0, x1, and x2\n\njulia> central_diff_coeffs(-1//1, 0//1, 1//1)\n(-1//2, 0//1, 1//2)\njulia> central_diff_coeffs(-1//2, 0//1, 1//1)\n(-4//3, 1//1, 1//3)\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.central_difference-NTuple{6, Any}","page":"Internals","title":"HallThruster.central_difference","text":"central_difference(f0, f1, f2, x0, x1, x2)\n\nGiven three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the derivative at x1\n\nf(x) = x^4\nx0, x1, x2 = 1.9999999, 2, 2.0000001\ncd = central_difference(f(x0), f(x1), f(x2), x0, x1, x2)\ncd ≈ 32\n\n# output\n\ntrue\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.channel_area-Tuple{Any, Any}","page":"Internals","title":"HallThruster.channel_area","text":"channel_area(outer_radius, inner_radius)\n\nCompute the cross-sectional area of a Hall thruster channel from its dimensions\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.channel_perimeter-Tuple{Any, Any}","page":"Internals","title":"HallThruster.channel_perimeter","text":"channel_perimeter(outer_radius, inner_radius)\n\nCompute the perimeteter of the thruster channel, equal to the sum of the inner and outer circumferences\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.channel_width-Tuple{Any, Any}","page":"Internals","title":"HallThruster.channel_width","text":"channel_width(outer_radius, inner_radius)\n\nCompute the thruster channel width\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.compute_current","page":"Internals","title":"HallThruster.compute_current","text":"compute_current(sol, location)\n\ncompute current at anode or cathode = outflow in 1D code.\n\n\n\n\n\n","category":"function"},{"location":"internals/#HallThruster.coulomb_logarithm","page":"Internals","title":"HallThruster.coulomb_logarithm","text":"coulomb_logarithm(ne, Tev, Z = 1)\n\ncalculate coulomb logarithm for electron-ion collisions as a function of ion charge state Z, electron number density in m^-3, and electron temperature in eV.\n\n\n\n\n\n","category":"function"},{"location":"internals/#HallThruster.downwind_diff_coeffs-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.downwind_diff_coeffs","text":"downwind_diff_coeffs(x0, x1, x2)\n\nGenerate finite difference coefficients for a downwind first derivative approximation at the point x2 on a three-point stencil at points x0, x1, and x2 (uses only points x1 and x2)\n\njulia> downwind_diff_coeffs(-1//1, 0//1, 2//1)\n(0//1, -1//2, 1//2)\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.electron_mobility-Tuple{Any, Any}","page":"Internals","title":"HallThruster.electron_mobility","text":"electron_mobility(νe, B)\n\ncalculates electron transport according to the generalized Ohm's law as a function of sum of the classical and anomalous collision frequencies and the magnetic field.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.forward_diff_coeffs-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.forward_diff_coeffs","text":"forward_diff_coeffs(x0, x1, x2)\n\nGenerate finite difference coefficients for a forward first derivative approximation at the point x0 on a three-point stencil at points x0, x1, and x2\n\njulia> forward_diff_coeffs(1.0, 2.0, 3.0)\n(-1.5, 2.0, -0.5)\njulia> forward_diff_coeffs(0//1, 1//2, 3//2)\n(-8//3, 3//1, -1//3)\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.forward_difference-NTuple{6, Any}","page":"Internals","title":"HallThruster.forward_difference","text":"forward_difference(f0, f1, f2, x0, x1, x2)\n\nGiven three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the derivative at x0\n\nf(x) = x^4\nx0, x1, x2 = 2.0, 2.000001, 2.000002\nfd = forward_difference(f(x0), f(x1), f(x2), x0, x1, x2)\nfd ≈ 32\n\n# output\n\ntrue\n\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.freq_electron_electron-Tuple{Number, Number}","page":"Internals","title":"HallThruster.freq_electron_electron","text":"freq_electron_electron(ne, Tev)\n\nEffective frequency at which electrons are scattered due to collisions with other electrons\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.freq_electron_ion-Tuple{Number, Number, Number}","page":"Internals","title":"HallThruster.freq_electron_ion","text":"freq_electron_ion(ne, Tev, Z)\n\nEffective frequency at which electrons are scattered due to collisions with ions\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.freq_electron_neutral-Union{Tuple{T}, Tuple{Array{HallThruster.ElasticCollision{T}, 1}, Number, Number}} where T","page":"Internals","title":"HallThruster.freq_electron_neutral","text":"freq_electron_neutral(model::ElectronNeutralModel, nn, Tev)\n\nEffective frequency of electron scattering caused by collisions with neutrals\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.generate_grid-Union{Tuple{F}, Tuple{Any, Any, HallThruster.HallThrusterGrid{F}}} where F","page":"Internals","title":"HallThruster.generate_grid","text":"generate_grid(geometry, ncells)\n\nGenerate a one-dimensional uniform grid on the domain specified in the geomety. Returns number of cells, coordinates of cell centers (plus ghost cells face coordinates), interface/edges and volume of a cell for number density calculations.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.interpolation_coeffs-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.interpolation_coeffs","text":"interpolation_coeffs(x, x0, x1, y0, y1)\n\nCompute the coefficients for interpolation between two points (x0, y0) and (x1, y1) such that y = c0 * y0 + c1 * y1 ```jldoctest;setup = :(using HallThruster: itpcoeffs, lerp) julia> c0, c1 = interpolationcoeffs(0.5, 0.0, 1.0, 0.0, 2.0) (0.5, 0.5) julia> c0 * 0.0 + c1 * 2.0 == lerp(0.5, 0.0, 1.0, 0.0, 2.0) true\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.lerp-NTuple{5, Any}","page":"Internals","title":"HallThruster.lerp","text":"lerp(x, x0, x1, y0, y1)\n\nInterpolate between two points (x0, y0) and (x1, y1) ```jldoctest;setup = :(using HallThruster: lerp) julia> lerp(0.5, 0.0, 1.0, 0.0, 2.0) 1.0\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.load_reactions-Tuple{HallThruster.ChargeExchangeFit, Any}","page":"Internals","title":"HallThruster.load_reactions","text":"Charge exchange fits from Hause, Prince and Bemish, 2013\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.load_reactions-Tuple{HallThruster.ReactionModel, Any}","page":"Internals","title":"HallThruster.load_reactions","text":"load_reactions(model::ReactionModel, species)::Vector{IonizationReaction}\n\nLoad ionization reactions for the provided species and ionization model\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.maximum_charge_state-Tuple{HallThruster.ReactionModel}","page":"Internals","title":"HallThruster.maximum_charge_state","text":"maximum_charge_state(model::ReactionModel)::Int\n\nReturn the maximum supported charge state for a given reaction model. If 0 is returned, then no charge state restriction is applied.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.nodes_from_density-NTuple{5, Any}","page":"Internals","title":"HallThruster.nodes_from_density","text":"nodes_from_density(density, x0, x1, N)\n\nGiven bounds x0, x1, a number of points N, and a density function density(x), generate N nodes betweeen x0 and x1 spaced according to the provided desity function using inverse CDF transformation.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.num_anom_variables-Tuple{HallThruster.AnomalousTransportModel}","page":"Internals","title":"HallThruster.num_anom_variables","text":"num_anom_variables(::AnomalousTransportModel)::Int\n\nThe number of variable arrays that should be allocated for the provided anomalous transport model. These arrays are used to save state beyond the anomalous collision frequency, and are useful for defining more complex anomalous transport models. If not defined by the user, this defaults to zero.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.read_restart-Tuple{AbstractString}","page":"Internals","title":"HallThruster.read_restart","text":"read_restart(path::AbstractString)\n\nLoad a JLD2 restart file from path.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.run_simulation-Tuple{HallThruster.Config}","page":"Internals","title":"HallThruster.run_simulation","text":"run_simulation(\n config;\n grid,\n ncells,\n dt,\n duration,\n nsave,\n restart,\n CFL,\n adaptive,\n control_current,\n target_current,\n Kp,\n Ti,\n Td,\n time_constant,\n dtmin,\n dtmax,\n verbose\n)\n\n\nRun a Hall thruster simulation using the provided Config object.\n\nArguments\n\nconfig: a Config containing simulation parameters.\ndt: The timestep, in seconds. Typical values are O(10 ns) (1e-8 seconds).\nduration: How long to run the simulation, in seconds (simulation time, not wall time). Typical runtimes are O(1 ms) (1e-3 seconds).\nncells: How many cells to use. Typical values are 100 - 1000 cells.\nnsave: How many frames to save.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.second_deriv_central_diff-NTuple{6, Any}","page":"Internals","title":"HallThruster.second_deriv_central_diff","text":"second_deriv_central_diff(f0, f1, f2, x0, x1, x2)\n\nGiven three points x0, x1, and x2, and the function values at those points, f0, f1, f2, compute the second-order approximation of the second derivative at x1\n\nf(x) = x^4\nx0, x1, x2 = 1.9999, 2.0, 2.0001\nsd = second_deriv_central_diff(f(x0), f(x1), f(x2), x0, x1, x2)\nsd ≈ 48\n\n# output\n\ntrue\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.second_deriv_coeffs-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.second_deriv_coeffs","text":"second_deriv_coeffs(x0, x1, x2)\n\nGenerate finite difference coefficients for a central second derivative approximation at the point x1 on a three-point stencil at points x0, x1, and x2\n\njulia> second_deriv_coeffs(-2//1, 0//1, 2//1)\n(1//4, -1//2, 1//4)\njulia> second_deriv_coeffs(-1//2, 0//1, 1//1)\n(8//3, -4//1, 4//3)\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.sheath_potential-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.sheath_potential","text":"sheath_potential(Tev, γ, mi))\n\ncompute wall sheath to be used for radiative losses and loss to wall. Goebel Katz equ. 7.3-29, 7.3-44. Assumed nₑuₑ/nᵢuᵢ ≈ 0.5 Sheath potentials are positive by convention in HallThruster.jl.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.supported_gases-Tuple{HallThruster.ReactionModel}","page":"Internals","title":"HallThruster.supported_gases","text":"supported_gases(model::ReactionModel)::Vector{HallThruster.Gas}\n\nCheck which gases are supported by a given reaction model. If an empty vector is provided, then there are no restrictions on what gases can be used.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.time_average","page":"Internals","title":"HallThruster.time_average","text":"time_average(sol, tstampstart)\n\ncompute time-averaged solution, input Solution type and the frame at which averaging starts. Returns a Solution object with a single frame.\n\n\n\n\n\n","category":"function"},{"location":"internals/#HallThruster.upwind_diff_coeffs-Tuple{Any, Any, Any}","page":"Internals","title":"HallThruster.upwind_diff_coeffs","text":"upwind_diff_coeffs(x0, x1, x2)\n\nGenerate finite difference coefficients for a upwind first derivative approximation at the point x2 on a three-point stencil at points x0, x1, and x2 (uses only points x0 and x1)\n\njulia> upwind_diff_coeffs(-3//1, 0//1, 2//1)\n(-1//3, 1//3, 0//1)\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.write_restart-Tuple{AbstractString, Any}","page":"Internals","title":"HallThruster.write_restart","text":"write_restart(path::AbstractString, sol)\n\nWrite a JLD2 restart file to path`.\n\nThis can be reloaded to resume a simulation.\n\n\n\n\n\n","category":"method"},{"location":"internals/#HallThruster.σ_en-Tuple{Any}","page":"Internals","title":"HallThruster.σ_en","text":"σ_en(Tev)\n\nElectron neutral collision cross section in m² as a function of electron temperature in eV. Eq. 3.6-13, from Fundamentals of Electric Propulsion, Goebel and Katz, 2008.\n\n\n\n\n\n","category":"method"},{"location":"boundary_conditions/#Boundary-Conditions","page":"Boundary Conditions","title":"Boundary Conditions","text":"","category":"section"},{"location":"boundary_conditions/","page":"Boundary Conditions","title":"Boundary Conditions","text":"HallThruster.jl solves fluid hyperbolic conservation laws. As such, boundary conditions on at least one side have to be specified. Dirichlet boundary conditions are applied on both sides in the potential equation. ","category":"page"},{"location":"boundary_conditions/#Background","page":"Boundary Conditions","title":"Background","text":"","category":"section"},{"location":"boundary_conditions/","page":"Boundary Conditions","title":"Boundary Conditions","text":"The outflow side, which in the 1D domain conincides with the cathode, is usually left unspecified, i.e. no boundary conditions are applied. On the left side, corresponding to the anode, the neutral mass inflow is fixed, while the ion velocity is forced to be at least the Bohm velocity. The anode mass flow rate can be set in the Configuration. The potential employs Dirichlet boundary conditions at both anode and cathode (subject to change once a more accurate anode sheath model has been implemented). Currently the cathode potential is set to zero, and the anode potential can be set using discharge_voltage in the Configuration. The electron energy uses Dirichlet boundaries as well on both the anode and cathode, usually fixed to 2 or 3 eV. Note that this does not correspond to Dirichlet boundaries on the internal energy equations, since this is solved for the product of internal energy and density. ","category":"page"},{"location":"numerics/#Numerics","page":"Numerics","title":"Numerics","text":"","category":"section"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"As described in Configuration and Initialization different flux options are available in HyperbolicScheme. Timemarching for the heavy species is handled using a second order strong-stability preserving Runge-Kutta scheme (SSPRK22). The left hand side of the electron energy equation is integrated implicitly using a Crank Nicolson Adams Bashforth (CNAB) scheme. This enables larger timessteps due to the severe restrictions due to the electron heat flux.","category":"page"},{"location":"numerics/#Spatial-discretization-for-heavy-species","page":"Numerics","title":"Spatial discretization for heavy species","text":"","category":"section"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"Neutrals and ions are considered heavy species (compared to electrons). HallThruster.jl uses the finite volume method (FVM). FVM has the advantage that it is by definition conservative, which is a useful property when solving hyperbolic conservation laws such as the Euler equations. Currently, only the continuity equation is solved for the neutrals and the isothermal Euler equations for the ion species. Possibly, the full Euler equations will be added in the future, its implementation has been verified using the Sod Shock tube. The following provides and example of the control volume approach applied to the continuity equation.","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"int_i-frac12^i+frac12 fracpartial n_npartial t dz + int_i-frac12^i+frac12 fracpartial n_n u_npartial z dz = int_i-frac12^i+frac12 dotn_n dz","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"The n_n u_n can be replaced by a generic flux term F(z) and generalized to any advection like equation. Treatment of the source term is described in Collisions and Reactions. Integration results in","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"hfracpartial n_npartial t + left(F__i+frac12 - F__i-frac12right) = h dotn_n","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"See Fluxes for the implemented fluxes, and possible limiters to be used in reconstruction to ensure a total variation diminishing scheme (TVD).","category":"page"},{"location":"numerics/#Time-discretization-of-heavy-species","page":"Numerics","title":"Time discretization of heavy species","text":"","category":"section"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"We employ a strong stability preserving second-order Runge Kutta schemes (SSPRK22) for timestepping","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"The user has the option to supply a fixed timestep, or a CFL number. In the former case, the user will need to select a timestep that obeys the CFL condition, defined as","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":" sigma = fracu_i Delta tDelta x 1","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"Using a maximum ion velocity of 22000 m/s, a domain length of 0.05m and 200 cells, results in Delta t leq 12 times 10^-8 s. In practice, it needs to be a bit lower in order to handle transients as the solution oscillates. This restriction is valid for the continuity and isothermal euler equations. Information on setting dt and selecting the integration scheme can be found in the Tutorial.","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"In most cases, it is better to let HallThruster.jl handle timestepping automatically using its adaptive timestepping option. If adaptive timestepping is enabled, the user-defined timestep is ignored in favor of a timestep based on the minimum of three conditions and a user-supplied CFL number. Mathematically the timstep is choosen as:","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":" Delta t = min(sigma fracDelta xmax(u_i + a_i u_i - a_i) sigma fracdotn_in_i sqrtfracsigma m_i Delta xq_i E)","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"Where a_i is the ion sound speed. Physically, these three conditions represent timestep limits imposed by the flux, ionization, and electrostatic acceleration. Keep in mind that due to stability limits imposed by the ionization condition, the CFL number cannot be higher than 0.799 to remain stable. This limit will be imposed by HallThruster.jl if the user-defined value is too high.","category":"page"},{"location":"numerics/#Electron-energy-equation-discretization","page":"Numerics","title":"Electron energy equation discretization","text":"","category":"section"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"While the ions can be explicitly solved with Delta t sim 10^-8s, the heat condution term in the electron energy equation adds additional constraints which would lower the timestep by about a factor of 10. In order to not further increase the timestepping restrictions and increase computation time, the electron energy equation is solved semi-implicitly in time using a backward Euler or Crank-Nicholson scheme. See Configuration for information on how to select which scheme is used.","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"The spatial discretization of the electron energy equation uses central finite differences in a manner similar to the potential solver (see below). This, combined with the semi-implicit timestepping, creates a tridiagonal linear system which can be efficiently solved using the Thomas algorithm.","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"If adaptive timestepping is enabled, the timestep used for the explicit terms is limited by:","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":" Delta t = absfrac3sigma n_eT_eW_loss + S_coll","category":"page"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"As this timestep may be significantly smaller than the timestep used for the heavy species, the electron energy equation is updated using a series of sub-steps with the Delta t enforced by the equation above until a total Delta t equal to that set by the heavy species is reached.","category":"page"},{"location":"numerics/#Evaluation-of-derivatives","page":"Numerics","title":"Evaluation of derivatives","text":"","category":"section"},{"location":"numerics/","page":"Numerics","title":"Numerics","text":"Some computations require the numerical approximation of derivatives, for example the evaluation of the electron velocity from the equation for electron current using the generalized Ohm's law, see Physics model. The derivatives are evaluated to second order using forward difference, central difference or backward difference depending on the location in the domain.","category":"page"},{"location":"source_terms/#User-Provided-Source-Terms","page":"User-Provided Source Terms","title":"User-Provided Source Terms","text":"","category":"section"},{"location":"source_terms/","page":"User-Provided Source Terms","title":"User-Provided Source Terms","text":"HallThruster allows users to provide additional source terms if they want. We make use of this function internally when we perform order verification studies (see Verification, as well as our order verification tests in /tests/order_verification.jl). This may also be useful when implementing additional physics. Users may provide seperate source terms for each of the solved equations. The corresponding fields in the Config struct are","category":"page"},{"location":"source_terms/","page":"User-Provided Source Terms","title":"User-Provided Source Terms","text":"source_neutrals\nsource_potential\nsource_electron_energy\nsource_ion_continuity\nsource_ion_momentum","category":"page"},{"location":"source_terms/","page":"User-Provided Source Terms","title":"User-Provided Source Terms","text":"The first three act similarly. HallThruster expects a function which takes (U, params, i) as an argument, where U is the state matrix, params is the NamedTuple of paramters, and i is the cell index. The source term should then return a scalar, which is added to the right-hand side of the corresponding equation.","category":"page"},{"location":"source_terms/","page":"User-Provided Source Terms","title":"User-Provided Source Terms","text":"As we allow for multiple ion charge states, source_ion_continuity and source_ion_momentum should be of type Tuple or Vector and contain one function for each charge state, with the same expected signature and return type as above.","category":"page"},{"location":"source_terms/","page":"User-Provided Source Terms","title":"User-Provided Source Terms","text":"warning: Concrete vs abstract types\nFor performance, it is important that Julia is able to infer the return type of your source term. Therefore, you must ensure that the values passed to source_ion_continuity and source_ion_momentum are concretely-typed. For example, this would not be ideal:source_ion_momentum = [\n (U, params, i) -> 2.0,\n (U, params, i) -> 3.0,\n (U, params, i) -> -1\n]because the type of this term is not concrete:julia> typeof(source_ion_momentum)\nVector{Function} (alias for Array{Function, 1})\n\njulia> isconcretetype(ans)\nfalseBetter would be to implement a callable type, as shown below:struct MySource\n number::Float64\nend\n\n(s::MySource)(U, params, i) = s.number\n\nsource_ion_momentum_concrete = [\n MySource(2.0),\n MySource(3.0),\n MySource(-1),\n]This has identical behavior to the first example, but is a concrete type:julia> typeof(source_ion_momentum_concrete)\nVector{MySource} (alias for Array{MySource, 1})\n\njulia> isconcretetype(ans)\ntrue","category":"page"},{"location":"anomalous_transport/#Anomalous-Transport","page":"Anomalous Transport","title":"Anomalous Transport","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"HallThruster has a few anomalous transport models built in and allows users to define their own. This page describes these models and the process by which algebraic and multi-equation transport models can be added by the user.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"warning: Interface not finalized\nThe AnomalousTransportModel interface is not yet finalized and subject to revision. Keep this in mind when using this feature.","category":"page"},{"location":"anomalous_transport/#Built-in-Models","page":"Anomalous Transport","title":"Built-in Models","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"!!! warning Incomplete documentation Some models (those relating to pressure-dependent effects) have not been finalized and are not represented in this documentation. Please see the source code for a complete listing.","category":"page"},{"location":"anomalous_transport/#NoAnom()","page":"Anomalous Transport","title":"NoAnom()","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Model for no anomalous transport (anomalous collision frequency = 0).","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"anom_model = NoAnom()","category":"page"},{"location":"anomalous_transport/#Bohm(c)","page":"Anomalous Transport","title":"Bohm(c)","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Model where the anomalous collision frequency scales with the electron cyclotron frequency ωce times some scaling factor c","category":"page"},{"location":"anomalous_transport/#TwoZoneBohm(c1,-c2)","page":"Anomalous Transport","title":"TwoZoneBohm(c1, c2)","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"HallThruster's default anomalous transport option. This is a standard model of anomalous transport frequently used in Hall thruster simulations. The anomalous collision frequency is defined as","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"beginaligned\n nu_AN = c_1 omega_ce quad z L_ch \n = c_2 omega_ce quad z L_ch\nendaligned","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"In the above expression, c_1 and c_2 are tunable coefficients, omega_ce = e B m_e is the electron cyclotron frequency, and L_ch is the channel length. A TwoZoneBohm model is initialized as follows","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"anom_model = TwoZoneBohm(c1, c2)","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"The transition between the zones is determined by the user-provided transition function. This defaults to a step function.","category":"page"},{"location":"anomalous_transport/#MultiLogBohm(z,-c)","page":"Anomalous Transport","title":"MultiLogBohm(z, c)","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Model similar to that employed in Hall2De, where the mobility is Bohm-like (i.e. νan(z) = c(z) * ωce(z)) and z is in meters.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"The function c(z) is defined by a sequence of nodes (z, c) provided by the user. At z = z[1], c(z) = c[1], and so forth.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"At z[i] < z < z[i+1], log(c) is defined by linearly interpolating between log(c[i]) and log(c[i+1]).","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"For z < z[1], c = c[1] and for z > z[end], c(z) = c[end].","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"The user may also provide a single array of [z[1], z[2], ..., z[end], c[1], c[2], ..., c[end]]. The number of zvalues must be equal to the number of c values.","category":"page"},{"location":"anomalous_transport/#The-AnomalousTransportModel-interface","page":"Anomalous Transport","title":"The AnomalousTransportModel interface","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Currently, HallThruster.jl expects all models to be written to be callable structs, taking arguments U, params, i, where U is the system state vector, params are the simulation parameters (including the cache of all variables), and i is the index of the cell.","category":"page"},{"location":"anomalous_transport/#Custom-anomalous-transport-models","page":"Anomalous Transport","title":"Custom anomalous transport models","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Users of HallThruster may define their own models by defining a custom subtype of AnomalousTransportModel. Suppose we want to implement nu_AN = beta omega_ce (classic Bohm diffusion). This is a fixed anomalous transport model and does not change as the simulation progresses. We would first define our type:","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"using HallThruster\n\nstruct BohmDiffusion <: AnomalousTransportModel\n β::Float64\nend","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"We then need to define the function which computes the anomalous transport in each cell. This is a mutating function which takes two arguments: the vector of anomalous collision frequency values to be updated, and the solver params.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"function (model::BohmDiffusion)(νan, params)\n\n e = HallThruster.e\n me = HallThruster.me\n B = params.cache.B\n\n for i in eachindex(νan)\n ωce = e * B[i] / me\n νan[i] = model.β * ωce\n end\n\n return νan\nend","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"We can now set anom_model = BohmDiffusion in our config struct (see Configuration) and the simulation will correctly compute the anomalous transport according to our model.","category":"page"},{"location":"anomalous_transport/#More-complex-anomalous-transport-models","page":"Anomalous Transport","title":"More complex anomalous transport models","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Up until now, we have only defined algebraic models of anomalous electron transport. For more high-fidelity models, we might need to solve multiple partial differential equations. Even if we don't want to do that, we still might want to compute other anomalous transport- related quantities at the same time that we update the anomalous transport. Lets see how we might do this.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"As a first example, let's compute an anomalous transport that depends on energy density of electrostatic waves in the plasma. This model derives from Lafleur, Chabert, and Balruud (2016) and has the following form:","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"beginaligned\n nu_AN = K fracnabla cdot mathbfu_i Wm_e n_e c_s v_de\nendaligned","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"In this expression, K is a tunable coefficient, u_i is the ion velocity, W = n_e k_B T_e is the wave energy density, m_e is the electron mass, n_e is the electron number density, c_s is the ion sound speed, and v_de is the electron azimuthal drift speed. Let's say we want to save the wave energy density in addition to the anomalous collision frequency. We begin by defining the model:","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":" struct LafleurModel <: AnomalousTransportModel\n K::Float64\n end","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Next, we add a method to the num_anom_variables function. Since we want to save the wave energy density, we need 1 additional anomalous transport variable.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":" num_anom_variables(::LafleurModel) = 1","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Now, we define the behavior of the model in a function. Since the model is based on assuming the wave energy convects with the ions, we will use upwind differencing for the gradient.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"function (model::LafleurModel)(νan, params)\n\n (;config, cache) = params\n mi = config.propellant.m\n K = model.K\n e = HallThruster.e\n me = HallThruster.me\n (;ne, Tev, ue, ui, νe, anom_variables) = cache\n\n ncells = length(νan)\n\n for i in 2:ncells-1\n\n W = e * ne[i] * Tev[i]\n Hall_param = e * B[i] / me / νe[i]\n vde = Hall_param * ue[i]\n cs = sqrt(e * Tev[i] / mi)\n\n # Upwind differencing of gradient term\n if ui > 0\n dz = params.z_cell[i] - params.z_cell[i-1]\n W_left = e * cache.ne[i-1] * cache.Te[i-1]\n grad_ui_W = (ui[1, i] * W[i] - cache.ui[1, i-1] * W_left) / dz\n else\n dz = params.z_cell[i+1] - params.z_cell[i]\n W_right = e * cache.ne[i+1] * cache.Te[i+1]\n grad_ui_W = (cache.ui[1, i+1] * W_right - ui[i] * W[i]) / dz\n end\n\n # Save W to cache.anom_variables[1]\n anom_variables[1][i] = W\n\n # Return anomalous collision frequency\n νan[i] = abs(K * grad_ui_W / (me * cs * vde * ne))\n end\n\n # Neumann BC anomalous transport\n anom_variables[1][1] = anom_variables[1][2]\n anom_variables[1][end] = anom_variables[1][end-1]\n νan[1] = νan[2]\n νan[end] = νan[end-1]\n\n return νan\nend","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"The saved value of the wave energy density can then be recovered as","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":" solution.savevals[frame].anom_variables[1]","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"where solution is the Solution object resulting from a call to run_simulation","category":"page"},{"location":"anomalous_transport/#Solving-arbitrary-PDEs-using-the-AnomalousTransportModel-interface","page":"Anomalous Transport","title":"Solving arbitrary PDEs using the AnomalousTransportModel interface","text":"","category":"section"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"We can use this basic interface to solve PDEs within HallThruster.jl. We demonstrate this by solving the scalar advection equation using first-order upwind differencing in space and forward Euler integration in time, with periodic boundary conditions. The scalar advection equation is given by:","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":" beginaligned\n fracpartial upartial t + a fracpartial upartial x = 0\n endaligned","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"To begin, we define the model struct and the number of variables we need.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"using HallThruster, Plots\n\nstruct ScalarAdvection{F} <: HallThruster.AnomalousTransportModel\n advection_velocity::Float64 # Advection advection_velocity\n initializer::F # Initialization function\nend\n\n# Save two auxilliary variables\n# 1) Advected quantity u\n# 2) gradient of advected quantity (du/dz)\nHallThruster.num_anom_variables(::ScalarAdvection) = 2","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"Next, we define the model function:","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"function (model::ScalarAdvection)(νan, params)\n\n ncells = length(νan)\n\n # Extract variables from params\n cache = params.cache\n z = params.z_cell\n u = cache.anom_variables[1]\n du_dz = cache.anom_variables[2]\n a = model.advection_velocity\n dt = params.dt\n\n if params.iteration[] < 1\n # Initialize\n model.initializer(u, z)\n else\n for i in eachindex(νan)\n # Setup for periodic boundary conditions\n if i == 1\n i_minus_1 = ncells\n dz_minus = z[2] - z[1]\n else\n i_minus_1 = i - 1\n dz_minus = z[i] - z[i-1]\n end\n\n if i == ncells\n i_plus_1 = 1\n dz_plus = z[2] - z[1]\n else\n i_plus_1 = i + 1\n dz_plus = z[i+1] - z[i]\n end\n\n # Update gradient\n if a > 0\n du_dz[i] = (u[i] - u[i_minus_1]) / dz_minus\n else\n du_dz[i] = (u[i_plus_1] - u[i]) / dz_plus\n end\n end\n\n # Update advected quantity\n for i in eachindex(νan)\n u[i] -= a * du_dz[i] * dt\n end\n end\n\n # Return a two-zone bohm anomalous transport result,\n # since we don't really care about the anomalous transport.\n return HallThruster.TwoZoneBohm(1/160, 1/16)(νan, params)\nend","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"And that's it! Now all there is to do is define our simulation parameters and run!","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"\n# Set up config\nadvection_velocity = 1e5\nL = 0.08\n\nconfig = HallThruster.Config(\n domain = (0.0, L),\n anom_model = ScalarAdvection(advection_velocity, initializer),\n thruster = HallThruster.SPT_100,\n discharge_voltage = 300.0,\n anode_mass_flow_rate = 5e-6\n)\n\n# Define dt such that CFL condition is obeyed\nncells = 200\ndx = L / ncells\nCFL = 0.9\ndt = min(1e-8, dx * CFL / advection_velocity)\nnsteps = 1000\n\n# Run simulation\nsolution = HallThruster.run_simulation(\n config;\n ncells,\n dt,\n duration = nsteps * dt,\n nsave = nsteps\n)\n\n# Extract variables from solution\nz = solution.params.z_cell\nu = [saveval.anom_variables[1] for saveval in solution.savevals]","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"We can now visualize the results to make sure everything worked well.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"using Plots\n\n# Time needed to transit the domain\nt_transit = L / advection_velocity\n\n# Number of periods\nnum_periods = floor(Int, nsteps * dt / t_transit)\n\n# Plot results\np = plot(; framestyle = :box, xlabel = \"x\", ylabel = \"u\", title = \"First order upwind for scalar advection\")\nfor i in 0:num_periods\n index = round(Int, i * t_transit / dt) + 1\n plot!(\n p, z, u[index], label = \"After $i periods\",\n linecolor = cgrad(:turbo, num_periods + 1, categorical = true)[i+1]\n )\nend\ndisplay(p)","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"(Image: )","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"This looks correct! In this case, we haven't coupled our PDE solution to the anomalous transport, but one could easily do this. In the same way, systems of two, three, or more coupled PDEs can be solved and related to the anomalous collision frequency.","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"The full script is reproduced below:","category":"page"},{"location":"anomalous_transport/","page":"Anomalous Transport","title":"Anomalous Transport","text":"using HallThruster\n\nstruct ScalarAdvection{F} <: HallThruster.AnomalousTransportModel\n advection_velocity::Float64 # Advection advection_velocity\n initializer::F # Initialization function\nend\n\n# Save two auxilliary variables\n# 1) Advected quantity u\n# 2) gradient of advected quantity (du/dz)\nHallThruster.num_anom_variables(::ScalarAdvection) = 2\n\nfunction (model::ScalarAdvection)(νan, params)\n\n ncells = length(νan)\n\n # Extract variables from params\n cache = params.cache\n z = params.z_cell\n u = cache.anom_variables[1]\n du_dz = cache.anom_variables[2]\n a = model.advection_velocity\n dt = params.dt\n\n if params.iteration[] < 1\n # Initialize\n model.initializer(u, z)\n else\n for i in eachindex(νan)\n # Setup for periodic boundary conditions\n if i == 1\n i_minus_1 = ncells\n dz_minus = z[2] - z[1]\n else\n i_minus_1 = i - 1\n dz_minus = z[i] - z[i-1]\n end\n\n if i == ncells\n i_plus_1 = 1\n dz_plus = z[2] - z[1]\n else\n i_plus_1 = i + 1\n dz_plus = z[i+1] - z[i]\n end\n\n # Update gradient\n if a > 0\n du_dz[i] = (u[i] - u[i_minus_1]) / dz_minus\n else\n du_dz[i] = (u[i_plus_1] - u[i]) / dz_plus\n end\n end\n\n # Update advected quantity\n for i in eachindex(νan)\n u[i] -= a * du_dz[i] * dt\n end\n end\n\n # Return a two-zone bohm anomalous transport result,\n # since we don't really care about the anomalous transport.\n return HallThruster.TwoZoneBohm(1/160, 1/16)(νan, params)\nend\n\n\n# Define initializer function, which is a step function\n# between z = 0.01 and z = 0.02\nfunction initializer(u, z)\n for i in eachindex(u)\n if 0.01 < z[i] < 0.02\n u[i] = 1.0\n else\n u[i] = 0.0\n end\n end\n return u\nend\n\n# Set up config\nadvection_velocity = 1e5\nL = 0.08\n\nconfig = HallThruster.Config(\n domain = (0.0, L),\n anom_model = ScalarAdvection(advection_velocity, initializer),\n thruster = HallThruster.SPT_100,\n discharge_voltage = 300.0,\n anode_mass_flow_rate = 5e-6\n)\n\n# Define dt such that CFL condition is obeyed\nncells = 200\ndx = L / ncells\nCFL = 0.9\ndt = min(1e-8, dx * CFL / advection_velocity)\nnsteps = 1000\n\n# Run simulation\nsolution = HallThruster.run_simulation(\n config;\n ncells,\n dt,\n duration = nsteps * dt,\n nsave = nsteps\n)\n\n# Extract variables from solution\nz = solution.params.z_cell\nu = [saveval.anom_variables[1] for saveval in solution.savevals]\n\nusing Plots\n\n# Time needed to transit the domain\nt_transit = L / advection_velocity\n\n# Number of periods\nnum_periods = floor(Int, nsteps * dt / t_transit)\n\n# Plot results\np = plot(; framestyle = :box, xlabel = \"x\", ylabel = \"u\", title = \"First order upwind for scalar advection\")\nfor i in 0:num_periods\n index = round(Int, i * t_transit / dt) + 1\n plot!(\n p, z, u[index], label = \"After $i periods\",\n linecolor = cgrad(:turbo, num_periods + 1, categorical = true)[i+1]\n )\nend\ndisplay(p)","category":"page"},{"location":"initialization/#Initialization","page":"Initialization","title":"Initialization","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"HallThruster.jl provides sensible defaults for simulation initialization, or allows you to specify your own initial condition.","category":"page"},{"location":"initialization/#Default","page":"Initialization","title":"Default","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"The default is DefaultInitialization(), which initializes the solution domain as described in the following sections. Below, z_0 and z_N are domain[1] and domain[2], as passed into the Config object (see Configuration), L_ch and A_ch are config.thruster.geometry.channel_length and config.thruster.geometry.channel_area, respectively, and dotm is config.anode_mass_flow_rate.","category":"page"},{"location":"initialization/#Ion-densities","page":"Initialization","title":"Ion densities","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"The ion densities are Gaussian with a constant offset and a scaling factor proportional to the mass flow rate and discharge voltage. For ions with charge 1, the density is","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"rho_i = 2 times 10^17 m_i sqrtfracV_d300fracdotm5times10^-6left(1 + 5 expleft-left(fracz - z_0 - L_ch2L_ch3right)^2rightright)","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"For ions with charge Z, the density is assumed to scale as","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"rho_i_Z = fracrho_i _Z=1Z^2","category":"page"},{"location":"initialization/#Ion-velocities","page":"Initialization","title":"Ion velocities","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"Ions are initialized with the Bohm velocity at the anode. For an ion of charge Z, this is","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"u_i1 = -u_bohm =- sqrtfracZ eT_eV anodem_i","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"The maximum ion velocity is determined by the discharge voltage V_d:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"u_imathrmend = u_max = sqrtfrac2 Z e V_dm_i","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"The initial ion velocity profile between the cathode and the anode is then prescribed as:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"u_i(z) = begincases\r\n\tu_bohm + frac23(u_max - u_bohm)left(fracz - z_0L_chright)^2 z-z_0 L_ch \r\n\tfrac13left(u_bohm + u_maxright)left(1 - fracz - z_0 - L_chz_N - L_chright) + u_maxleft(fracz - z_0 - L_chz_N - L_chright) z - z_0 ge L_ch\r\nendcases","category":"page"},{"location":"initialization/#Neutral-density","page":"Initialization","title":"Neutral density","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"The neutral density at the anode is computed in the same way as during a simulation, namely:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"rho_n anode = fracdotmu_n A_ch - sum_s fracrho_is u_is_anodeu_n","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"The density at the cathode is assumed to be 1/100 that at the anode. In the domain, the neutral density has a sigmoid shape:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"rho_n(z) = frac12left(rho_nanode + rho_n cathode + (rho_n anode - rho_n cathode)tanhleft(fracz - z_0 - L_ch2L_ch 6right)right)","category":"page"},{"location":"initialization/#Electron-energy","page":"Initialization","title":"Electron energy","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"The number density is computed from the ion densities. The electron temperature is a Gaussian with height V_d 10 eV plus a linear baseline to make sure the boundary conditions are satisfied:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"T_e(z) = left(1 - fracz - z_0z_N - z_0right) T_e anode + left(fracz - z_0z_N - z_0right) T_e cathode + fracV_d10expleft-left(fracz - z_0 - L_chL_ch3right)^2right","category":"page"},{"location":"initialization/#Example","page":"Initialization","title":"Example","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"For a simulation of the SPT-100 with V_d= 500V, three ion charge states, a a mass flow rate of 3 mg/s, an anode electron temperature of 3 eV and a cathode electron temperature of 5 eV, the initial condition looks like:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"(Image: )","category":"page"},{"location":"initialization/#Custom-initial-conditions","page":"Initialization","title":"Custom initial conditions","text":"","category":"section"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"You may define your own initial condition by creating subtypes of HallThruster.InitialCondition. Let's say for some reason we wanted to initialize every state variable in every cell to the z-location of its cell center. We might define our initialization as follows:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"using HallThruster\r\n\r\nstruct MyInitialCondition <: HallThruster.InitialCondition end;\r\n\r\n# output\r\n","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"We would then add a method to the initialize!(U, params, model) function as follows:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"import HallThruster.initialize!\r\n\r\nfunction HallThruster.initialize!(U, params, model::MyInitialCondition)\r\n\t(;z_cell) = params # Pull cell centers locations out of params\r\n nvars = size(U, 1)\r\n for (i, z) in enumerate(z_cell)\r\n \tfor j in 1:nvars\r\n \tU[j, i] = z_cell[i]\r\n end\r\n end\r\n return U # optional. Since U is modified. the return value is never used, but by Julia convention we also return the mutated object.\r\nend;\r\n\r\n# output\r\n","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"We can check the behavior of our new function:","category":"page"},{"location":"initialization/","page":"Initialization","title":"Initialization","text":"# Dummy config and params\r\nncells = 100\r\nnvars = 4\r\nconfig = (;initial_condition = MyInitialCondition())\r\nz_cell = range(0, 0.05, length = ncells)\r\nU = zeros(nvars, ncells)\r\nparams = (;config, z_cell)\r\n\r\n# Method of initialize! which dispatches to initialize!(U, params, config.initial_condition)\r\n# This is what HallThruster.jl calls when initializing a simulation\r\nHallThruster.initialize!(U, params)\r\n\r\nU[1, :] == U[2, :] == U[3, :] == U[4, :] == collect(z_cell)\r\n\r\n# output\r\n\r\ntrue","category":"page"},{"location":"fluxes/#Fluxes","page":"Fluxes","title":"Fluxes","text":"","category":"section"},{"location":"fluxes/","page":"Fluxes","title":"Fluxes","text":"HallThruster.jl uses the Finite Volume method, and as such the face values of the fluxes need to be reconstructed. See Numerics for more information.","category":"page"},{"location":"fluxes/","page":"Fluxes","title":"Fluxes","text":"The fluxes F__i+frac12 and F__i-frac12 are reconstructed at the cell interfaces, and for this flux reconstruction multiple options are available. These are set using the object HyperbolicScheme consisting of fields flux, limiter, and reconstruct. Three different flux approximations are available.","category":"page"},{"location":"fluxes/","page":"Fluxes","title":"Fluxes","text":"Flux Description\nupwind Simple first order accurate flux approximation, that as a results does not distinguish between cell centered and cell average values and adapts reconstruction according to sign of advection velocity. Very diffusive. No Riemann solver or approximation.\nHLLE Approximate Riemann solver. The Harten-Lax-van Leer-Einfeldt scheme approximates a Riemann problem with three constant states. see reference. The scheme is positively-conservative if stability bounds for maximum and minimum wavespeeds are met, which makes it useful in its application with HallThruster.jl. First order accurate in space. B. Einfeldt. On godunov-type methods for gas dynamics. Journal of Computational Physics, 25:294-318, 1988.\nrusanov Approximate Riemann solver. Also known as the local Lax-Friedrich flux. Has slighlty modified choice of wave speeds. Adds viscosity to a centered flux. More diffusive than HLLE. Chi-Wang Shu, Lecture Notes: Numerical Methods for Hyperbolic Conservation Laws (AM257)","category":"page"},{"location":"fluxes/","page":"Fluxes","title":"Fluxes","text":"These flux approximations are all first order accurate in space (piecewise constant recontruction), but can be extended to piecewise linear reconstruction within a cell. To satisfy stability bounds and keep the scheme total variation diminishing (TVD), it has to be coupled with a limiter. Many limiters have been proposed, the ones implemented in HallThruster.jl are the following: koren, minmod, osher, van_albada, van_leer. If the field reconstruction is set to true, the selected limiter will be used.","category":"page"},{"location":"collisions/#Collisions-and-Reactions","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"HallThruster.jl allows you to choose from a few different models for ionization, excitation and elastic scattering, or supply your own. This allows you to implement different propellants or more charge states for an existing propellant.","category":"page"},{"location":"collisions/#Background","page":"Collisions and Reactions","title":"Background","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Most collisions in HallThruster.jl are handled via the Reaction interface. This is an abstract type with three subtypes: IonizationReaction, ExcitationReaction, and ElasticScattering.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"The core of the ionization model in HallThruster.jl is the IonizationReaction struct. It has four fields: energy, reactant, product, and rate_coeff. The first is of type Float64 and is the ionization energy of the given reaction in eV. The next two are Species objects, while the last is an arbitrary function. This rate_coeff computes the ionization reaction rate coefficient (in m^3/s) provided the electron energy (in eV). It is used in heavy species source terms in order to compute the production or destruction of the reactant and product due to ionization, and in the electron energy equation in order to compute electron energy losses due to inelastic ionization collisions.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Excitation reactions are handled similarly. The ExcitationReaction struct has only three fields: energy, reactant and rate_coeff, with the same types as above. Since fluids of different excitation levels are not tracked explicitly, the choice of excitation model only affects the electron energy balance.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Elastic scattering (electron-neutral) collisions are implemented via the ElasticCollision struct, which has two fields: reactant and rate_coeff, as no energy is lost in such collisions. This affects the electron momentum balance and the cross-field transport.","category":"page"},{"location":"collisions/#Ionization","page":"Collisions and Reactions","title":"Ionization","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"HallThruster.jl provides two models out of the box. These are","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Model Supported species Maximum charge state Description\nIonizationLookup Xenon, Krypton (out of the box. With user-provided tables, can support any species) 3 Ionization look-up table for species provided with HallThruster.jl. By default, the tables are stored in the reactions subfolder of the HallThruster.jl directory, but the user may provide additional directories in which to look for tables.\nLandmarkIonizationLookup Xenon 1 Lookup table provided for the LANDMARK benchmark. Table is stored in the landmark subfolder of the HallThruster.jl directory.","category":"page"},{"location":"collisions/#IonizationLookup","page":"Collisions and Reactions","title":"IonizationLookup","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This is the default ionization model. To use the IonizationLookup model, initialize it as follows:","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"ionization_model = IonizationLookup([directories::Vector{AbstractString = String[]}])","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"If the optional argument directories is left empty or unprovided, the HallThruster.jl will only look in the reactions subfolder of the HallThruster.jl main directory. Otherwise, HallThruster.jl will preferentially look in directories before before falling back to the included tables. If two files in user-provided directories have the same name, HallThruster.jl will pick the one in the directory which comes first in directories.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Inside of the folders listed in directories, HallThruster.jl will look for rate coefficient files matching the desired propellant gas and maximum charge state. The rate coefficient files must be named as follows in order to be found.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"ionization_$(reactant.symbol)_$(product.symbol).dat","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"For example, for a reaction file containing rate coefficients for direct double ionization of Bismuth, you would name the file ionization_Bi_Bi2+.dat, or for Argon II being ionized to Argon III, it would be ionization_Ar2+_Ar3+.dat.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"The rate coefficient files must have the ionization energy in the first row, with a colon separating the descriptor and the number. It must next have a header row (which is skipped on load), followed by two tab-delimited columns. The first should have the electron energy (note: this is 3/2 Te) in eV, and the second should have the rate coefficient in m^3/s. The first few rows of the ionization_Kr_Kr+.dat folder thus reads","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Ionization energy (eV): 13.9996055\r\nEnergy (eV) Rate coefficient (m3/s)\r\n1.0 1.812780887933804e-23\r\n2.0\t6.784605416289418e-19\r\n3.0\t2.86241339516785e-17\r\n4.0\t2.0154931458303006e-16\r\n5.0\t6.77202352079487e-16\r\n6.0\t1.5567995341077301e-15\r\n7.0\t2.8667673314913722e-15\r\n8.0\t4.5818881444694e-15\r\n9.0\t6.650747725094247e-15","category":"page"},{"location":"collisions/#LandmarkIonizationLookup","page":"Collisions and Reactions","title":"LandmarkIonizationLookup","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This accounts for single ionization of Xenon only using the lookup table provided by test case 3 of the LANDMARK benchmark. It reads from the file landmark/landmark_rates.csv. Useful mostly for replicating the LANDMARK benchmark.","category":"page"},{"location":"collisions/#Excitation","page":"Collisions and Reactions","title":"Excitation","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"As with ionization, HallThruster.jl provides two models out of the box. These are","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Model Supported species Description\nExcitationLookup Xenon, Krypton (out of the box. With user-provided tables, can support any species) Excitation look-up table for species provided with HallThruster.jl. By default, the tables are stored in the reactions subfolder of the HallThruster.jl directory, but the user may provide additional directories in which to look for tables.\nLandmarkExcitationLookup Xenon Lookup table provided for the LANDMARK benchmark. Table is stored in the landmark subfolder of the HallThruster.jl directory.","category":"page"},{"location":"collisions/#ExcitationLookup","page":"Collisions and Reactions","title":"ExcitationLookup","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This is the default excitation model. To use the ExcitationLookup model, initialize it as follows:","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"excitation_model = ExcitationLookup([directories::Vector{AbstractString = String[]}])","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This functions nearly identically to the IonizationLookup, with the exception that, since excitation reactions do not change the charge state, the product is the same Species as the reactant and thus is not included in the filename. The filename for excitation reactions is thus:","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"excitation_$(reactant.symbol).dat","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"For example, for a reaction file containing excitation rate coefficients for neutral Argon would be called excitation_Ar.dat. Similarly, a file containing rates for excitation of triply-charged Xenon would be called excitation_Xe3+.dat.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"The rate coefficient files are formatted identically to the ionization rate files. Below are the first few lines of the included excitation_Xe.dat.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Excitation energy (eV): 8.32\r\nEnergy (eV)\tRate coefficient (m3/s)\r\n1.0\t2.909965013767145e-20\r\n2.0\t3.078734312855916e-17\r\n3.0\t4.1547515755380286e-16\r\n4.0\t1.6649256403317016e-15\r\n5.0\t3.9526948476759076e-15\r\n6.0\t7.124788357557455e-15\r\n7.0\t1.0908925177391674e-14\r\n8.0\t1.5042335588913955e-14\r\n9.0\t1.9316662863621785e-14","category":"page"},{"location":"collisions/#LandmarkIonizationLookup-2","page":"Collisions and Reactions","title":"LandmarkIonizationLookup","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This accounts for excitation of Xenon only using the lookup table provided by test case 3 of the LANDMARK benchmark. It reads from the file landmark/landmark_rates.csv. Useful mostly for replicating the LANDMARK benchmark. LANDMARK does explicitly provide excitation rates, and instead gives an energy loss coefficient. However, using the provided ionization rate coefficients, we can back out the excitation rate coefficients. These are then used to construct an ExcitationReaction.","category":"page"},{"location":"collisions/#Electron-neutral-elastic-scattering","page":"Collisions and Reactions","title":"Electron-neutral elastic scattering","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"These are ReactionModels of type ElectronNeutralModel. HallThruster.jl provides three models out of the box. These are","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Model Supported species Description\nElectronNeutralLookup Xenon, Krypton (out of the box. With user-provided tables, can support any species) Electron-neutral elastic scattering look-up table for species provided with HallThruster.jl. By default, the tables are stored in the reactions subfolder of the HallThruster.jl directory, but the user may provide additional directories in which to look for tables.\nLandmarkElectronNeutral Xenon Constant rate coefficient of 2.5e-13\nGKElectronNeutral Xenon Uses Eq. 36.13 on pg. 58 from Goebel and Katz to fit Xenon e-n cross section","category":"page"},{"location":"collisions/#ElectronNeutralLookup","page":"Collisions and Reactions","title":"ElectronNeutralLookup","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Like IonizationLookup and ExcitationLookup, this reads a table of reaction rate coefficient vs energy from a file either in the HallThruster.jl reactions directory or in a user-provided directory. The interface and usage is identical to that of the other two lookup models, with the exception that since these collisions do not have an electron energy loss associated with them, we do not need to supply an energy in the first line of the files. Thus, the first few lines of elastic_Kr.dat are:","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Energy (eV)\tRate coefficient (m3/s)\r\n1.0\t1.7652019589294465e-14\r\n2.0\t6.286806105711669e-14\r\n3.0\t1.260621740782443e-13\r\n4.0\t1.879916985413993e-13\r\n5.0\t2.421697883866546e-13\r\n6.0\t2.878523500134384e-13\r\n7.0\t3.2602160860803316e-13","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Naming is similarly simple, with HallThruster.jl looking for files named as follows","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"elastic_$(species).dat","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Since electron-ion collisions are not handled via the ReactionModel interface, species with charge states greater than 0, if provided, are ignored.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Once a rate coefficient k_en(epsilon) is computed, the electron-neutral collision frequency is simply","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"nu_en = n_n k_en(epsilon)","category":"page"},{"location":"collisions/#LandmarkElectronNeutral","page":"Collisions and Reactions","title":"LandmarkElectronNeutral","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"In this model, as in the LANDMARK benchmark, the electron-neutral collision rate coefficient has a constant value of k_en = 25times 10^-13.","category":"page"},{"location":"collisions/#GKElectronNeutral","page":"Collisions and Reactions","title":"GKElectronNeutral","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This uses a fit to the Xenon average collision cross section as a function of electron temperature taken from Goebel and Katz, Fundamentals of Electric Propulsion (page 58):","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"beginaligned\r\nnu_en = sigma_en(T_e) n_n sqrtfrac8 e T_epi m_e \r\nsigma_en(T_e) = 66times 10^-19 leftfracfracT_e4 - 011 + left(fracT_e4right)^16right textrmm^2\r\nendaligned","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Here, T_e is in eV.","category":"page"},{"location":"collisions/#Electron-ion-collisions","page":"Collisions and Reactions","title":"Electron-ion collisions","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Unlike the above types of collisions, electron-ion colulombic collisions are not strongly dependent on the type of gas, as the interaction distance is much larger than the atomic radius. They are thus handled via a simple Boolean flag in the Config struct: electron_ion_collisions = true or electron_ion_collisions = false. These are computed using the classical formulae (see NRL Plasma Formulary, pg. 33):","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"nu_ei = 29 times 10^-6 Z^2 n_e T_e^-32 lnLambda","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Here, Z is the ion charge state, n_e is the plasma density in m^-3 and T_e is the electron temperature in eV. In the above expression, lnLambda is the well-known Coulomb logarithm, given by","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"beginaligned\r\nlnLambda = 23 - frac12lnleft(10^-6 Z^2 n_e T_e^-3right) T_e 10 Z^2 textrm eV \r\nlnLambda = 24 - frac12lnleft(10^-6 n_e T_e^-2right) T_e 10 Z^2 textrm eV\r\nendaligned","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"For plasmas containing multiple charge states, we compute the number-averaged charge state langle Zrangle and use that in the above formula:","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"langle Zrangle equiv left(sum_s Z_s n_sright) n_e","category":"page"},{"location":"collisions/#Implementing-your-own-collisions","page":"Collisions and Reactions","title":"Implementing your own collisions","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"ElectronNeutralModel, ExcitationModel and IonizationModel are all subtypes of ReactionModel. Users may specify their own IonizationModel, ElectronNeutralModel, or ExcitationModel by implementing a few key functions required by the ReactionModel interface. Let's say we wanted to implement our own ionization model, called MyIonizationModel, we would first define our struct as a subtype of HallThruster.IonizationModel, along with any fields we might want:","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"struct MyIonizationModel <: HallThruster.IonizationModel\r\n\t# any fields you might want\r\nend","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"If we were defining an ExcitationModel, we would instead subtype HallThruster.ExcitationModel, and if we were defining a model for electron-neutral elastic scattering, we would subtype ElectronNeutralModel. Next, we need to define a few helper methods.","category":"page"},{"location":"collisions/#supported_gases(::ReactionModel)::Vector{Gas}","page":"Collisions and Reactions","title":"supported_gases(::ReactionModel)::Vector{Gas}","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This method must return a vector of Gas objects. If not overwritten, this method returns Gas[], which signifies that there are no restrictions on what type of gas works with this method. This is useful for IonizationLookup, which can in principle work for any gas, but not so much for LandmarkLookup, which is Xenon specific. Specifying which gases your model is valid for lets HallThruster.jl check at run time that user-provided propellant works with the provided model, preventing it from silently computing a bad result without the user's knowledge.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"Let's say our model works exclusively with Bismuth","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"import HallThruster: supported_gases\r\n\r\nHallThruster.supported_gases(::MyIonizationModel) = [HallThruster.Bismuth]","category":"page"},{"location":"collisions/#maximum_charge_state(::ReactionModel)::Int","page":"Collisions and Reactions","title":"maximum_charge_state(::ReactionModel)::Int","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This method returns an integer corresponding to the maximum allowed charge state. By default, this is zero, indicating that our method can work with any charge state. However, to avoid mistakes down the line, it is best to define this, unless we're defining an ElectronNeutralModel. In our case, let's just work with singly-charged Bismuth.","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"import HallThruster: maximum_charge_state\r\n\r\nmaximum_charge_state(::MyIonizationModel) = 1","category":"page"},{"location":"collisions/#load_reactions(model::ReactionModel,-species::Vector{Species})","page":"Collisions and Reactions","title":"load_reactions(model::ReactionModel, species::Vector{Species})","text":"","category":"section"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"This is the most important method to define. load_reactions takes our model along with a vector of Species (generated using the propellant and ncharge fields in the user-provided Config) and returns a vector of IonizationReaction{I} or ExcitationReaction{I}, where I is the type of the rate coefficient function. It is important that the Reactions all have the same type so that the returned vector will have a concrete type, which will prevent dynamic dispatch during runtime and prevent unnecessary slowdowns. This means that if you have multiple reactions with different rate coefficient functions, you should use something like FunctionWrappers.jl. Let's implement a simple ionization curve with the form","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"k_iz(epsilon) = 4times 10^-20 expleft(frac-73frac23 epsilonright)sqrtfrac8 (frac23epsilon)pi m_e","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"We would implement this as so:","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"using FunctionWrappers\r\nimport HallThruster: e, me, load_reactions\r\n\r\nkiz(ϵ) = 4e-20 * exp(-7.3 / (2/3 * ϵ)) * sqrt(8 * 2/3 * ϵ / pi / me)\r\n\r\nfunction load_reactions(model::MyIonizationModel, species)\r\n rxn = IonizationReaction(\r\n \tenergy = -7.3,\r\n #=\r\n Since we defined maximum_charge_state and supported_species, we know that\r\n species[1] will be Bi and species[2] will be Bi+. Otherwise, an error would have\r\n been thrown before this point. Without these methods, we would need have logic \t\t\t \thandling whichever species get passed to the function.\r\n =#\r\n reactant = species[1],\r\n product = species[2],\r\n # Use a function wrapper here, though not necessary with only one reaction\r\n rate_coeff = FunctionWrapper{Float64, Tuple{Float64}}(kiz)\r\n )\r\n return rxn\r\nend","category":"page"},{"location":"collisions/","page":"Collisions and Reactions","title":"Collisions and Reactions","text":"The above advice works identically for defining your own ExcitationModel, with the sole exception that ExcitationReaction objects do not have a product field. Similarly, we can define our own ElectronNeutralModel, noting that ElasticCollisions do not have an energy field or a product field. We would also not need to define maximum_charge_state for an ElectronNeutralModel.","category":"page"},{"location":"propellants/#Propellants","page":"Propellants","title":"Propellants","text":"","category":"section"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"HallThruster implements several common Hall thruster propellants, and makes it easy to implement your own.","category":"page"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"note: Note\nHallThruster only supports monatomic gases at this time. Support for diatomic propellants, such as iodine, may come in a future release.","category":"page"},{"location":"propellants/#Provided-propellants","page":"Propellants","title":"Provided propellants","text":"","category":"section"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"Xenon\nKrypton\nArgon\nBismuth\nMercury","category":"page"},{"location":"propellants/#Implementing-your-own-propellant","page":"Propellants","title":"Implementing your own propellant","text":"","category":"section"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"Propellants in HallThruster are instances of the Gas struct, which contains information about the atomic and thermodynamic properties of a gaseous species. These are","category":"page"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"name::String Full name of gas (i.e. Xenon)\nshort_name::String Short name/symbol (i.e. Xe for Xenon)\nγ::Float64 Specific heat ratio / adiabatic index\nM::Float64 Molar mass (grams/mol) or atomic mass units\nm::Float64 Mass of atom in kg\ncp::Float64 Specific heat at constant pressure in J / kg / K\ncv::Float64 Specific heat at constant volume in J / kg / K\nR::Float64 Gas constant in J / kg / K","category":"page"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"Many of these properties are inter-dependent, so HallThruster provides a convenience constructor Gas(name, short_name, γ, M) which will compute the rest of the properties automatically. For example, we might want to define atomic Neon:","category":"page"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"using HallThruster: Gas\r\n\r\nNeon = HallThruster.Gas(\"Neon\", \"Ne\"; γ = 5/3, M = 20.1797)\r\n\r\n# output\r\n\r\nNeon","category":"page"},{"location":"propellants/","page":"Propellants","title":"Propellants","text":"If we then selected Neon as a propellant in our Config struct and used one of the lookup table models for ionization, HallThruster.jl would know to search for files beginning ionization_Ne....","category":"page"},{"location":"physics/#Physics-model","page":"Physics model","title":"Physics model","text":"","category":"section"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"HallThruster.jl solves the quasineutral plasma equations of motion for a Hall Thruster along the thruster's channel centerline (the z-axis). We solve seperate models for neutral particles, ions, and electrons. Neutrals are assumed to have constant velocity and temperature and are tracked by a single continuity equation. Ions are assumed isothermal and unmagnetized. Multiple ion species with different charge states are supported, and each is tracked by a continuity equation and a momentum equation. We employ the drift-diffusion approximation for electrons, which reduces the electron momentum equation to a generalized Ohm's law. Charge conservation is then used to solve for the electrostatic potential. The electron temperature is determined by solving an equation for the conservation of electron internal energy. The model is based upon the work presented in K. Hara, Non-oscillatory quasineutral fluid model of cross-field discharge plasmas, Physics of Plasmas 25, 123508, 2018. See Configuration for supported gases. Xenon is the standard, Krypton is fully supported and in theory any monoatomic gas can be used as propellant in the simulation.","category":"page"},{"location":"physics/#Neutrals","page":"Physics model","title":"Neutrals","text":"","category":"section"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"For neutrals, the continuity equation is solved:","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" fracpartial n_npartial t + fracpartialpartial z (n_n u_n) = dotn_n","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Here, n_n is the neutral number density in m^-3, mathbfu_n is the neutral velocity vector in m/s, and dotn_n is the rate of neutral depletion due to ionization in m^-3s^-1, which is given by","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" dotn_n = -sum_j = 1^3 n_e n_n k_nj(T_e)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"where n_e is the electron number density j represents the ion charge state (i.e. j = 1 represents singly-charged ions, and so on), T_e is the electron temperature, and k_nj is the rate coefficient of the ionization reaction","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"A + e^- rightarrow A^j+ + (j + 1) e^-","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"where A represents the gas species being simulated. Currently, the code is compatible with Xenon and Krypton. The reaction rate coefficients are generated as a function of electron temperature using the BOLSIG+ code. We read in a table of these rate coefficients with electron temperature and use the Interpolations.jl to generate transform this data into a continuous function. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The neutrals are assumed to have a constant velocity in the axial direction and a constant temperature, and are thus approximated monoenergetic and not Maxwellian. The neutral momentum and energy equations are not solved for. ","category":"page"},{"location":"physics/#Ions","page":"Physics model","title":"Ions","text":"","category":"section"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"We solve continuity and momentum for each ion species. We may have the option for an ion energy equation, but for now they are treated as isothermal. The ion continuity equation for ions with charge j is","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" fracpartial n_ijpartial t + fracpartialpartial z (n_ij u_ij) = dotn_ij","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Here n_ij, u_ij, and dotn_ij are the number density, velocity, and net rate of production of ions with charge state j. The production rate dotn_ij is given by:","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" dotn_ij = n_e n_n k_nj(Te) - sum_ell = j + 1^3 n_e n_ij k_jell(T_e)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The first term here represents the rate of production of ions with charge state j and the second term represents the rate at which these ions are further ionized to become ions of charge state ell. In all, the following six reactions are modelled:","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"beginaligned\r\n A + e^- rightarrow A^+ + 2 e^-\r\n A + e^- rightarrow A^2+ + 3 e^-\r\n A + e^- rightarrow A^3+ + 4 e^-\r\n A+ + e^- rightarrow A^2+ + 2 e^-\r\n A+ + e^- rightarrow A^3+ + 3 e^-\r\n A^2+ + e^- rightarrow A^3+ + 2 e^-\r\nendaligned","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The currently-specified model does not include ion losses to the radial walls, but this could be included at a later date. Likewise, we could also include momentum-transfer collisions between ions and neutrals and between ions of different charge states at a future date, but neglect these for now. Future updates may also add the ability to model molecular propellants, not just monatomic ones, in which case we would need to add significantly more reaction equations, species, and model rotational and vibrational modes.","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The one-dimensional momentum equation for ions of charge state j is obtained by assuming the ions are unmagentized and that the momentum transfer due to collisions is negligible. The momentum equation in conservative form is","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" fracpartialpartial t (n_ij u_ij) + fracpartialpartial z (n_ij u_ij^2 + fracp_ijm_i) = fracj em_i n_ij E_z","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In this equation, p_ij = n_ij k_B T_i is the partial pressure of ions with charge j, T_i is the ion temperature, e is the fundamental charge, m_i is the ion mass, and E_z is the axial electric field. ","category":"page"},{"location":"physics/#Electrons","page":"Physics model","title":"Electrons","text":"","category":"section"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"We assume that the plasma is quasineutral, which means that the local charge density is zero everywhere. This means that","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" n_e = sum_j=1^3 jn_ij","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In addition, the electrons are assumed to be massless. This yields a generalized Ohm's law, also known as the Quasineutral Drift Diffusion (QDD) model. The electron momentum equation becomes:","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" nu_e fracm_eemathbfj_e = e n_e mathbfE +nabla p_e - mathbfj_e times mathbfB","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Here, nu_e is the total electron momentum transfer collision frequency, mathbfj_e = -e n_e mathbfu_e is the electron current vector, p_e = n_e k_B T_e is the electron pressure, and B is the magnetic field. We want to model the electron velocity in both the axial (hatz) and azimuthal (theta) directions. Making the assumption that B is purely radial and that the plasma is axisymmetric, we arrive at the following two equations after some algebraic manipulations.","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"axial current equation","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" j_ez = frace^2 n_em_e nu_efrac11 + Omega_e^2left(E_z + frac1e n_efracpartial p_epartial zright)\r\n j_etheta = Omega_e j_ez","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In this expression, Omega_e = omega_cenu_e = e B m_e nu_e is the Hall parameter, or the ratio of the electron cyclotron frequency to the total electron momentum transfer collision frequency, and measures how well-magnetized the electrons are. Finally, we introduce the anomalous collision frequency (nu_AN):","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" nu_e = nu_c + nu_AN","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In Hall thrusters, the observed axial/cross-field electron current is significantly higher than that which would result from classical collisions alone (here, nu_c represents the classical electron momentum transfer collision frequency, see Collisions and Reactions). We model this enhanced transport in a fluid framework as an additional anomalous collision frequency, see Anomalous Transport. The purpose of this code is to facilitate the development and testing of models for this important parameter.","category":"page"},{"location":"physics/#Electrostatic-potential","page":"Physics model","title":"Electrostatic potential","text":"","category":"section"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The electrostatic potential is found by first computing the electric field. To determine the electric field we generally follow the method from V. Giannetti, et. al Numerical and experimental investigation of longitudinal oscillations in Hall thrusters, Aerospace 8, 148, 2021 but the main steps are outlined here. By writing the discharge current as fracI_dA_ch = j_e + j_i where A_ch is the channel area, plugging in Ohm's law for the electron current density, and integrating over the domain, we can write the discharge current as","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" I_d = fracDelta V + int_z_c^z_a frac1en_efracpartial p_epartial z + fracj_izen_emu_perp dzint_z_c^z_a en_e mu_perp A dz","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Where A is the cross section area of either the channel or plume, z_c and z_a are the cathode and anode positions, and Delta V j_iz and mu_perp are given by ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Delta V = V_d + V_s \r\nj_iz = Sigma_j=1^3 jn_ij u_ij \r\nmu_perp = fracem_e nu_e frac11+Omega_e^2","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"With the discharge current known, the axial electric field is computed locally as","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"E_z = fracI_den_emu_perpA_ch - frac1en_e fracpartial p_epartial z - fracj_izen_emu_perp ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"As the electric field is the negative gradient of the electrostatic potential, the potential is finally calculted by integrating the negative electric field using the trapezoid rule.","category":"page"},{"location":"physics/#Electron-energy-equation","page":"Physics model","title":"Electron energy equation","text":"","category":"section"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The electron internal energy equation in one dimension is","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" fracpartialpartial tleft(frac32 n_e k_B T_eright) + fracpartialpartial zleft(frac52 n_e k_B T_e u_ez + q_ezright) = \r\n n_e u_ez fracpartialphipartial z - W_loss - S_coll","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Here, q_ez is the electron heat conduction in one dimension and S_wall, see Wall Loss Models, represents the loss of electron energy to the thruster walls and S_coll, see Collisions and Reactions captures the loss of energy due to inelastic collisions. The heat conduction is defined by Fourier's Law:","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"beginaligned\r\n q_ez = -kappa_eperp nabla_perp T_e \r\nendaligned","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In this expression, kappa_eperp is the cross-field (axial) electron thermal conductivity, for which various forms exist. More details can be found on the Electron Thermal Conductivity page. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The heat transfer terms slightly change when considering the Landmark case study, while the different wall and inelastic collision loss models are described in Wall Loss Models and Collisions and Reactions. ","category":"page"},{"location":"physics/#Sheath-considerations","page":"Physics model","title":"Sheath considerations","text":"","category":"section"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"HallThruster.jl, being a fluid globally quasineutral model, is not designed to resolve plasma sheaths. However, the sheath and presheath are important to model Hall Thruster discharges accurately. As this is a 1D axial solver, we do not have any direct fluxes towards the walls, the energy losses can however be taken into account by a source term in the energy equation. This term and the boundary conditions implemented at the anode employ the following presheath approximations and assumptions. They are absolutely critical to replicate experimental Hall Thruster behaviour. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In the following, potential differences ephi are assumed to be on the order of the electron temperature k T_e. Furthermore, assume that cold ions fall through an arbitrary potential of phi_0 while they move towards the wall. Through conservation of energy, their arrival velocity at the sheath edge can be related to the potential difference. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"energy conservation","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" frac12 m_i v_0^2 = e phi_0","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Additionally, the ion flux during acceleration toward the wall is conserved. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" n_i v = n_0 v_0","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"The relation for ion velocity as a function of position in the sheath can be written as ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"above expression","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" frac12 m_i v^2 = frac12 m_i v_0^2 - ephi (x)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Rewriting both energy conservation and above expression for v_0 and v, and dividing gives","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" fracv_0v = sqrtfracphi_0phi_0 - phi","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"which by applying flux conservation results in ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"the density equation","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" n_i = n_0 sqrtfracphi_0phi_0 - phi","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Close to the sheath edge the density equation can be expanded as a Taylor series, as phi is small compared to phi_0.","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"expanded ion density","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" n_i = n_0 left(1 - frac12fracphiphi_0 + right)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In one dimension, neglecting collisions with other species and assuming isentropic temperature and pressure terms, no convection and no electron inertia, the electrons can be described by the Boltzmann relation.","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Boltzmann relation","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" n_e = n_0 expleft(frace phik T_eright)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"In this regime, the electron density is diffusion dominated and dictated by the electrostatic field. This assumption is generally valid along magnetic field lines and across weak magnetic fields with sufficient electron electron collisions. The Boltzmann relation can be expanded by assuming that the change in potential at the sheath edge is small compared to the electron temperature. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"expanded Boltzmann relation","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" n_e = n_0 left(1 - fracephik T_e + right)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Taking Poisson's equation of the form ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" nabla^2 phi = - fracek Te_0(n_i - n_e)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"and substituting expanded Boltzmann relation and expanded ion density leads after rearranging to ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" nabla^2 phi = frace n_0 phiepsilon_0left(frac12phi_0 - fracekT_eright)","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"As the sheath is assumed to be ion attracting, it can by definition not slow or repell ions. As a result, the right hand side of \\autoref{eq:poissonsubexpanded} has to always be positive, which leads to the following requirement. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" phi_0 frackT_e2e","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"By substituting energy conservation equation, the ion Bohm speed can be recovered. This condition is applied to the anode boundary and will be discussed in the boundary conditions. ","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":"Bohm velocity","category":"page"},{"location":"physics/","page":"Physics model","title":"Physics model","text":" v_0 sqrtfrackT_em_i","category":"page"},{"location":"thrusters/#Thrusters","page":"Thrusters","title":"Thrusters","text":"","category":"section"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"Predefined thruster models are specified as a Thruster object. The struct has 4 self-explanatory fields: name of type string, geometry of type HallThruster.Geometry1D, magnetic_field of type B (which can be an arbitrary function of z), and shielded which is a Boolean. You can easily add your own thrusters. ","category":"page"},{"location":"thrusters/#SPT-100","page":"Thrusters","title":"SPT-100","text":"","category":"section"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"For example, the SPT-100 is defined in the following way:","category":"page"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"const SPT_100 = Thruster(\r\n name = \"SPT-100\",\r\n geometry = geometry_SPT_100,\r\n magnetic_field = B_field_SPT_100 $ (0.015, geometry_SPT_100.channel_length),\r\n shielded = false\r\n)","category":"page"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"while the geometry is defined here","category":"page"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"const geometry_SPT_100 = Geometry1D(\r\n inner_radius = 0.0345,\r\n outer_radius = 0.05,\r\n channel_length = 0.025\r\n)","category":"page"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"and the magnetic field profile is approximated as follows","category":"page"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"function B_field_SPT_100(B_max, L_ch, z)\r\n B = if z < L_ch\r\n B_max * exp(-0.5 * ((z - L_ch) / (0.011))^2) #for SPT_100\r\n else\r\n B_max * exp(-0.5 * ((z - L_ch) / (0.018))^2)\r\n end\r\n return B\r\nend","category":"page"},{"location":"thrusters/#Custom-thrusters","page":"Thrusters","title":"Custom thrusters","text":"","category":"section"},{"location":"thrusters/","page":"Thrusters","title":"Thrusters","text":"You can add your own thruster models by defining the geometry, magnetic field profile and selecting shielded or not. Shielded thrusters are assumed to have lower electron energy losses to the walls, see Wall Loss Models. Note that since HallThruster.jl is a 1D code, the inner_radius and outer_radius merely used for computing the inlet neutral density and thetotal thrust and discharge current computations (from the specific values). Aside from these, they do not majorly effect the simulation results. ","category":"page"},{"location":"citation/#Citation","page":"Citation","title":"Citation","text":"","category":"section"},{"location":"citation/","page":"Citation","title":"Citation","text":"If you use the code in a published scientific paper, we request that you cite the code. We will have a DOI soon.","category":"page"},{"location":"grid/#Grid-generation","page":"Grid generation","title":"Grid generation","text":"","category":"section"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"HallThruster.jl supports both regular and irregular grids. Grids are passed to the run_simulation function via the grid keyword argument.","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"To create an evenly-spaced grid with ncells cells, we construct an EvenGrid object","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"grid = EvenGrid(ncells)","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"Alternatively, we could produce an irregular grid using the UnevenGrid object. By default, this type of grid includes twice as many cells inside the discharge channel as outside, with a smooth transition between the high-density and low-density regions.","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"If our domain is (0 cm, 8 cm) and the thruster channel length is 2.5 cm, these options produce the following grids.","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"(Image: )","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"We can also specify a custom density function. Suppose we wanted high density in the middle of our domain. Our density function might look like","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"function my_density(z, z0, z1, L)\n midpoint = (z0 + z1) / 2\n width = midpoint / 2\n base_density = 1\n return base_density + exp(-((z - midpoint) / (width))^2)\nend\n\nmy_grid = UnevenGrid(30, my_density)","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"HallThruster.jl expects a custom density function to take four arguments–-z (the axial location), z0 and z1 (the left and right edges of the domain, respectively, in meters), and L, the channel length. These are automatically populated based on the domain and thruster you pass to the configuration file. ","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"With the density function defined, we can then compare this to our other grids.","category":"page"},{"location":"grid/","page":"Grid generation","title":"Grid generation","text":"(Image: )","category":"page"},{"location":"background/#Background","page":"Background","title":"Background","text":"","category":"section"},{"location":"background/","page":"Background","title":"Background","text":"Hall thrusters are a widely-used class of spacecraft electric propulsion device. They are annular crossed-field devices in which a voltage drop is applied across a steady radial magnetic field. Electrons in the device become trapped in an strong azimuthal Hall current. They impact injected neutral atoms, ionizing them. These ions are then accelerated out of the channel by the electric field, which generates thrust.","category":"page"},{"location":"background/","page":"Background","title":"Background","text":"Hall thrusters offer moderate to high specific impulse and high thrust density compared to other electric propulsion systems, and can achieve total efficiencies higher than 50%. They are commonly used for in-space propulsion for commercial communications and surveillance satellites as well as increasingly for deep space missions.","category":"page"},{"location":"","page":"Home","title":"Home","text":"CurrentModule = HallThruster\r\nDocTestSetup = quote\r\n using HallThruster\r\nend","category":"page"},{"location":"#HallThruster.jl","page":"Home","title":"HallThruster.jl","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Repository link","category":"page"},{"location":"","page":"Home","title":"Home","text":"HallThruster.jl is an open-source, 1D fluid Hall thruster code written in Julia. It was initially developed by the University of Michigan's Plasmadynamics and Electric Propulsion Laboratory and is licensed under the MIT license. ","category":"page"},{"location":"#Installation","page":"Home","title":"Installation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"To install HallThruster.jl, you must first install Julia 1.7 or above from the official Julia site, or by using juliaup. We recommend using the latest Julia release when possible. Once installed, launch Julia and type","category":"page"},{"location":"","page":"Home","title":"Home","text":"julia> ]add https://github.com/UM-PEPL/HallThruster.jl","category":"page"},{"location":"","page":"Home","title":"Home","text":"This will install HallThruster.jl using Julia's package manager. For details on setting up and running Hall thruster simulations, see the official documentation. A Tutorial is available here.","category":"page"},{"location":"#Contribution","page":"Home","title":"Contribution","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Users are welcome to suggest and implement features for the code, as well as report bugs or numerical issues they encounter. Please feel free to open an issue on this repository describing your desired change or bug-fix. Pull requests are also welcome!","category":"page"}] } diff --git a/dev/source_terms/index.html b/dev/source_terms/index.html index dd63916b..f49fa0da 100644 --- a/dev/source_terms/index.html +++ b/dev/source_terms/index.html @@ -21,4 +21,4 @@ Vector{MySource} (alias for Array{MySource, 1}) julia> isconcretetype(ans) -true +true diff --git a/dev/thrusters/index.html b/dev/thrusters/index.html index fff0ecd1..b6eab73f 100644 --- a/dev/thrusters/index.html +++ b/dev/thrusters/index.html @@ -15,4 +15,4 @@ B_max * exp(-0.5 * ((z - L_ch) / (0.018))^2) end return B -end

      Custom thrusters

      You can add your own thruster models by defining the geometry, magnetic field profile and selecting shielded or not. Shielded thrusters are assumed to have lower electron energy losses to the walls, see Wall Loss Models. Note that since HallThruster.jl is a 1D code, the inner_radius and outer_radius merely used for computing the inlet neutral density and thetotal thrust and discharge current computations (from the specific values). Aside from these, they do not majorly effect the simulation results.

      +end

      Custom thrusters

      You can add your own thruster models by defining the geometry, magnetic field profile and selecting shielded or not. Shielded thrusters are assumed to have lower electron energy losses to the walls, see Wall Loss Models. Note that since HallThruster.jl is a 1D code, the inner_radius and outer_radius merely used for computing the inlet neutral density and thetotal thrust and discharge current computations (from the specific values). Aside from these, they do not majorly effect the simulation results.

      diff --git a/dev/verification/index.html b/dev/verification/index.html index b361c2f2..3374ba32 100644 --- a/dev/verification/index.html +++ b/dev/verification/index.html @@ -3,4 +3,4 @@ \begin{cases} \alpha_1 \times 10^7 & z - z_0 \leq L_{ch} \\ \alpha_2 \times 10^7 & z - z_0 > L_{ch} - \end{cases}\]

      and

      \[\epsilon = \frac{3}{2} T_{ev}\]

      In the above, $L_{ch}$ refers to thruster channel length and $z_0$ is domain[1], or the z-location of the anode.

      Case 1 $\; \; \alpha_1 = 1.0, \alpha_2 = 1.0$ Landmark1

      Case 2 $\; \; \alpha_1 = 0.5, \alpha_2 = 1.0$ Landmark2

      Case 3 $\; \; \alpha_1 = 0.4, \alpha_2 = 1.0$ Landmark3

      + \end{cases}\]

      and

      \[\epsilon = \frac{3}{2} T_{ev}\]

      In the above, $L_{ch}$ refers to thruster channel length and $z_0$ is domain[1], or the z-location of the anode.

      Case 1 $\; \; \alpha_1 = 1.0, \alpha_2 = 1.0$ Landmark1

      Case 2 $\; \; \alpha_1 = 0.5, \alpha_2 = 1.0$ Landmark2

      Case 3 $\; \; \alpha_1 = 0.4, \alpha_2 = 1.0$ Landmark3

      diff --git a/dev/wall_loss_models/index.html b/dev/wall_loss_models/index.html index 1b426373..389972cd 100644 --- a/dev/wall_loss_models/index.html +++ b/dev/wall_loss_models/index.html @@ -1,2 +1,2 @@ -Wall Loss Models · HallThruster.jl

      Wall Loss Models

      HallThruster.jl allows you to choose from three different wall loss models. They approximate the electron energy lost to the thruster walls in radial direction. As the computational axis of the 1D code is axially in the thruster, the wall loss is not directly resolved by the fluid and applied in each cell as an electron energy loss term.

      Background

      The core of the wall loss models in HallThruster.jl is the abstract type WallLossModel. It has three children: NoWallLosses, ConstantSheathPotential, and WallSheath. ConstantSheathPotential has three fields. A wall sheath_potential to be set by the user, and an inner_loss_coeff and outer_loss_coeff which allow to scale the energy loss inside vs. outside the thruster channel. WallSheath has two field: material, which is of type WallMaterial and includes information about secondary electron emission yields, and α, which is a constant wall loss scaling coefficient (values around 0.1-0.2 are good usually, but this may need to be calibrated against some data).

      Provided wall loss models

      HallThruster.jl provides three models out of the box. These are

      ModelSupported speciesDescription
      NoWallLossesAnyIgnores electron energy losses to the walls. May cause numerical issues.
      ConstantSheathPotentialAnyEmploys a simple sheath energy loss model with constant sheath potential, based on the electron Boltzmann equation for electron density in the sheath as a function of electron temperature. Uses constants to scale losses inside and outside the thruster. See also JP Boeuf, Low frequency oscillations in a stationary plasma thruster, Journal of Applied Physics 84, 3541, 1998 and Landmark study
      WallSheathAnyConceputally similar loss model as ConstantSheathPotential, but evaluates constants and sheath potential given in the previously mentioned using approximations. We compute the power loss to the walls as

      \[ P_w = \nu_{ew}(2 T_{ev} - \phi_s)\]

      where $\nu_{ew}$ is the electron wall collision frequency, $T_{ev}$ is the electron temperature in electron-volts, and $\phi_s$ is the wall sheath potential in volts. The sheath potential is computed as:

      \[\phi_w = T_{ev} \ln{\left[(1 - \gamma) \sqrt{\frac{m_i}{2\pi m_e}}\right]}\]

      Here, $\gamma$ is the secondary electron emission coefficient, which is computed according to the choice of WallMaterial. For a plasma with only once charge state, the electron-wall collision frequency is:

      \[\nu_{ew} = \frac{\alpha}{1 - \gamma}\sqrt{\frac{e T_{eV}}{m_i}}\frac{1}{R_o - R_i},\]

      where $R_o$ and $R_i$ are the channel inner radius and outer radii respectively. For multiply-charged plasmas, the ion currents of each species are first computed as:

      \[j_{iw,Z} = \alpha Z e n_{i,Z} \sqrt{\frac{Z e T_{eV}}{m_i}}\]

      Then, the electron wall current minus the secondary electron current are equal to the total ion wall current:

      \[(1 - \gamma) j_{ew} = j_{iw} = \sum_{Z} j_{iw, Z}\]

      Lastly, we compute the electron-wall collision frequency as

      \[\nu_{ew} = \frac{j_{ew}}{e n_e} \frac{1}{R_o - R_i}\]

      The ion current of each species is also used to compute ion wall losses if ion_wall_losses is set to true in config. Ions are assumed to recombine at the walls and the flux is re-injected as neutrals.

      \[\dot{n}_{iw, Z} = -\frac{j_{iw, Z}}{e}\frac{1}{R_o - R_i}\]

      \[\dot{n}_{nw, Z} = -\sum_Z \dot{n}_{iw, Z}\]

      If thruster.shielded is true, the electron temperature at the walls is assumed to be equal to the electron temperature at the anode, see Thrusters for the option.

      The density relation in the WallSheath model is based upon the electron Boltzmann relation. Note that at this point the model does not differentiate between axial positions inside and outside the thruster. The same loss model is applied over the entire domain. This approximation seems to work ok when comparing to 2D simulations due to isothermal magnetic field lines. More fidelity will most likely be added.

      Impact of magnetic shielding

      The effect on magnetic shielding on the electron energy can be seen below. Compared are time-averaged electron energy profiles for a Xenon SPT-100 type thruster using Boron Nitride walls.

      unshielded_vs_shielded

      +Wall Loss Models · HallThruster.jl

      Wall Loss Models

      HallThruster.jl allows you to choose from three different wall loss models. They approximate the electron energy lost to the thruster walls in radial direction. As the computational axis of the 1D code is axially in the thruster, the wall loss is not directly resolved by the fluid and applied in each cell as an electron energy loss term.

      Background

      The core of the wall loss models in HallThruster.jl is the abstract type WallLossModel. It has three children: NoWallLosses, ConstantSheathPotential, and WallSheath. ConstantSheathPotential has three fields. A wall sheath_potential to be set by the user, and an inner_loss_coeff and outer_loss_coeff which allow to scale the energy loss inside vs. outside the thruster channel. WallSheath has two field: material, which is of type WallMaterial and includes information about secondary electron emission yields, and α, which is a constant wall loss scaling coefficient (values around 0.1-0.2 are good usually, but this may need to be calibrated against some data).

      Provided wall loss models

      HallThruster.jl provides three models out of the box. These are

      ModelSupported speciesDescription
      NoWallLossesAnyIgnores electron energy losses to the walls. May cause numerical issues.
      ConstantSheathPotentialAnyEmploys a simple sheath energy loss model with constant sheath potential, based on the electron Boltzmann equation for electron density in the sheath as a function of electron temperature. Uses constants to scale losses inside and outside the thruster. See also JP Boeuf, Low frequency oscillations in a stationary plasma thruster, Journal of Applied Physics 84, 3541, 1998 and Landmark study
      WallSheathAnyConceputally similar loss model as ConstantSheathPotential, but evaluates constants and sheath potential given in the previously mentioned using approximations. We compute the power loss to the walls as

      \[ P_w = \nu_{ew}(2 T_{ev} - \phi_s)\]

      where $\nu_{ew}$ is the electron wall collision frequency, $T_{ev}$ is the electron temperature in electron-volts, and $\phi_s$ is the wall sheath potential in volts. The sheath potential is computed as:

      \[\phi_w = T_{ev} \ln{\left[(1 - \gamma) \sqrt{\frac{m_i}{2\pi m_e}}\right]}\]

      Here, $\gamma$ is the secondary electron emission coefficient, which is computed according to the choice of WallMaterial. For a plasma with only once charge state, the electron-wall collision frequency is:

      \[\nu_{ew} = \frac{\alpha}{1 - \gamma}\sqrt{\frac{e T_{eV}}{m_i}}\frac{1}{R_o - R_i},\]

      where $R_o$ and $R_i$ are the channel inner radius and outer radii respectively. For multiply-charged plasmas, the ion currents of each species are first computed as:

      \[j_{iw,Z} = \alpha Z e n_{i,Z} \sqrt{\frac{Z e T_{eV}}{m_i}}\]

      Then, the electron wall current minus the secondary electron current are equal to the total ion wall current:

      \[(1 - \gamma) j_{ew} = j_{iw} = \sum_{Z} j_{iw, Z}\]

      Lastly, we compute the electron-wall collision frequency as

      \[\nu_{ew} = \frac{j_{ew}}{e n_e} \frac{1}{R_o - R_i}\]

      The ion current of each species is also used to compute ion wall losses if ion_wall_losses is set to true in config. Ions are assumed to recombine at the walls and the flux is re-injected as neutrals.

      \[\dot{n}_{iw, Z} = -\frac{j_{iw, Z}}{e}\frac{1}{R_o - R_i}\]

      \[\dot{n}_{nw, Z} = -\sum_Z \dot{n}_{iw, Z}\]

      If thruster.shielded is true, the electron temperature at the walls is assumed to be equal to the electron temperature at the anode, see Thrusters for the option.

      The density relation in the WallSheath model is based upon the electron Boltzmann relation. Note that at this point the model does not differentiate between axial positions inside and outside the thruster. The same loss model is applied over the entire domain. This approximation seems to work ok when comparing to 2D simulations due to isothermal magnetic field lines. More fidelity will most likely be added.

      Impact of magnetic shielding

      The effect on magnetic shielding on the electron energy can be seen below. Compared are time-averaged electron energy profiles for a Xenon SPT-100 type thruster using Boron Nitride walls.

      unshielded_vs_shielded