Skip to content

Commit b8308c6

Browse files
authoredMar 10, 2023
Merge pull request #95 from bendudson/paper-inputs
WIP: Inputs for Hermes-3 paper
2 parents bcd44cd + a776b8c commit b8308c6

39 files changed

+1506
-125
lines changed
 

‎docs/sphinx/components.rst

+95-3
Original file line numberDiff line numberDiff line change
@@ -650,10 +650,52 @@ term:
650650

651651
.. math::
652652
653-
Q_{ab,F} = - F_{ab} u_a
653+
Q_{ab,F} = \frac{m_b}{m_a + m_b} \left( u_b - u_a \right) F_{ab}
654+
655+
This term has some important properties:
656+
657+
1. It is always positive: Collisions of two species with the same
658+
temperature never leads to cooling.
659+
2. It is Galilean invariant: Shifting both species' velocity by the
660+
same amount leaves :math:`Q_{ab,F}` unchanged.
661+
3. If both species have the same mass, the thermal energy
662+
change due to slowing down is shared equally between them.
663+
4. If one species is much heavier than the other, for example
664+
electron-ion collisions, the lighter species is preferentially
665+
heated. This recovers e.g. Braginskii expressions for :math:`Q_{ei}`
666+
and :math:`Q_{ie}`.
667+
668+
This can be derived by considering the exchange of energy
669+
:math:`W_{ab,F}` between two species at the same temperature but
670+
different velocities. If the pressure is evolved then it contains
671+
a term that balances the change in kinetic energy due to changes
672+
in velocity:
654673

655-
Energy exchange, heat transferred to species `a` from species `b` due to temperature
656-
differences, is given by:
674+
.. math::
675+
676+
\begin{aligned}
677+
\frac{\partial}{\partial t}\left(m_a n_a u_a\right) =& \ldots + F_{ab} \\
678+
\frac{\partial}{\partial t}\left(\frac{3}{2}p_a\right) =& \ldots - F_{ab} u_a + W_{ab, F}
679+
\end{aligned}
680+
681+
For momentum and energy conservation we must have :math:`F_{ab}=-F_{ba}`
682+
and :math:`W_{ab,F} = -W_{ba,F}`. Comparing the above to the
683+
`Braginskii expression
684+
<https://farside.ph.utexas.edu/teaching/plasma/lectures/node35.html>`_
685+
we see that for ion-electron collisions the term :math:`- F_{ab}u_a + W_{ab, F}`
686+
goes to zero, so :math:`W_{ab, F} \sim u_aF_{ab}` for
687+
:math:`m_a \gg m_b`. An expression that has all these desired properties
688+
is
689+
690+
.. math::
691+
692+
W_{ab,F} = \left(\frac{m_a u_a + m_b u_a}{m_a + m_b}\right)F_{ab}
693+
694+
which is not Galilean invariant but when combined with the :math:`- F_{ab} u_a`
695+
term gives a change in pressure that is invariant, as required.
696+
697+
Thermal energy exchange, heat transferred to species :math:`a` from
698+
species :math:`b` due to temperature differences, is given by:
657699

658700
.. math::
659701
@@ -817,6 +859,56 @@ Notes:
817859
The reason for this convention is the existence of the inverse reactions:
818860
`t + d+ -> t+ + d` outputs diagnostics `Ftd+_cx` and `Fd+t_cx`.
819861

862+
2. Reactions typically convert species from one to another, leading to
863+
a transfer of mass momentum and energy. For a reaction converting
864+
species :math:`a` to species :math:`b` at rate :math:`R` (units
865+
of events per second per volume) we have transfers:
866+
867+
.. math::
868+
869+
\begin{aligned}
870+
\frac{\partial}{\partial t} n_a =& \ldots - R \\
871+
\frac{\partial}{\partial t} n_b =& \ldots + R \\
872+
\frac{\partial}{\partial t}\left( m n_a u_a\right) =& \ldots + F_{ab} \\
873+
\frac{\partial}{\partial t}\left( m n_a u_a\right) =& \ldots + F_{ba} \\
874+
\frac{\partial}{\partial t}\left( \frac{3}{2} p_a \right) =& \ldots - F_{ab}u_a + W_{ab} - \frac{1}{2}mRu_a^2 \\
875+
\frac{\partial}{\partial t}\left( \frac{3}{2} p_b \right) =& \ldots - F_{ba}u_b + W_{ba} + \frac{1}{2}mRu_b^2
876+
\end{aligned}
877+
878+
where both species have the same mass: :math:`m_a = m_b = m`. In the
879+
pressure equations the :math:`-F_{ab}u_a` comes from splitting the
880+
kinetic and thermal energies; :math:`W_{ab}=-W_{ba}` is the energy
881+
transfer term that we need to find; The final term balances the loss
882+
of kinetic energy at fixed momentum due to a particle source or
883+
sink.
884+
885+
The momentum transfer :math:`F_{ab}=-F{ba}` is the momentum carried
886+
by the converted ions: :math:`F_{ab}=-m R u_a`. To find
887+
:math:`W_{ab}` we note that for :math:`p_a = 0` the change in pressure
888+
must go to zero: :math:`-F_{ab}u_a + W_{ab} -\frac{1}{2}mRu_a^2 = 0`.
889+
890+
.. math::
891+
892+
\begin{aligned}
893+
W_{ab} =& F_{ab}u_a + \frac{1}{2}mRu_a^2 \\
894+
=& - mR u_a^2 + \frac{1}{2}mRu_a^2\\
895+
=& -\frac{1}{2}mRu_a^2
896+
\end{aligned}
897+
898+
Substituting into the above gives:
899+
900+
.. math::
901+
902+
\begin{aligned}
903+
\frac{\partial}{\partial t}\left( \frac{3}{2} p_b \right) =& \ldots - F_{ba}u_b + W_{ba} + \frac{1}{2}mRu_b^2 \\
904+
=& \ldots - mRu_au_b + \frac{1}{2}mRu_a^2 + \frac{1}{2}mRu_a^2 \\
905+
=& \ldots + \frac{1}{2}mR\left(u_a - u_b\right)^2
906+
\end{aligned}
907+
908+
This has the property that the change in pressure of both species is
909+
Galilean invariant. This transfer term is included in the Amjuel reactions
910+
and hydrogen charge exchange.
911+
820912
Hydrogen
821913
~~~~~~~~
822914

1.65 KB
Loading

‎examples/1D-recycling/BOUT.inp

+17-7
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313
# Does not include recombination
1414

1515

16-
nout = 200
17-
timestep = 2000
16+
nout = 400
17+
timestep = 5000
1818

1919
MXG = 0 # No guard cells in X
2020

2121
[mesh]
2222
nx = 1
23-
ny = 200 # Resolution along field-line
23+
ny = 400 # Resolution along field-line
2424
nz = 1
2525

2626
length = 30 # Length of the domain in meters
@@ -53,7 +53,13 @@ Bnorm = 1
5353
Tnorm = 100
5454

5555
[solver]
56-
mxstep = 100000
56+
type = beuler # Backward Euler steady-state solver
57+
snes_type = newtonls
58+
ksp_type = gmres
59+
max_nonlinear_iterations = 10
60+
61+
atol = 1e-7
62+
rtol = 1e-5
5763

5864
[sheath_boundary]
5965

@@ -77,13 +83,16 @@ charge = 1
7783
AA = 2
7884

7985
density_upstream = 1e19 # Upstream density [m^-3]
86+
density_source_positive = false # Force source to be > 0?
87+
density_controller_i = 5e-4
88+
density_controller_p = 1e-2
8089

8190
thermal_conduction = true # in evolve_pressure
8291

8392
diagnose = true
8493

8594
recycle_as = d
86-
recycle_multiplier = 0.99 # Recycling fraction
95+
recycle_multiplier = 1 # Recycling fraction
8796

8897
[Nd+]
8998

@@ -148,6 +157,7 @@ species = d+
148157

149158
[reactions]
150159
type = (
151-
d + e -> d+ + 2e, # Deuterium ionisation
152-
d + d+ -> d+ + d, # Charge exchange
160+
d + e -> d+ + 2e, # Deuterium ionisation
161+
d+ + e -> d, # Deuterium recombination
162+
d + d+ -> d+ + d, # Charge exchange
153163
)

‎examples/1D-recycling/makeplot.py

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646

4747
plt.title(f"Time {i}")
4848
plt.savefig(f"1d_recycling_{i:02d}.png")
49+
plt.savefig(f"1d_recycling_{i:02d}.pdf")
4950
plt.close()
5051

5152
os.system('convert -resize 50% -delay 20 -loop 0 *.png 1d_recycling.gif')
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Analyse convergence towards steady state
2+
3+
paths = [".", "pvode"]
4+
labels = ["NK", "PVODE"]
5+
linestyles = ["-", "--"]
6+
7+
import matplotlib.pyplot as plt
8+
import numpy as np
9+
10+
from boutdata import collect
11+
12+
cumulative_calls = []
13+
times = []
14+
source_mags = []
15+
16+
for path in paths:
17+
try:
18+
# Number of calls
19+
ncalls = collect("ncalls", path=path) # number of calls each output
20+
21+
cumulative_calls.append(np.cumsum(ncalls)) # Summed over outputs
22+
23+
t_array = collect("t_array", path=path)
24+
wci = collect("Omega_ci", path=path)
25+
times.append(t_array / wci) # Seconds
26+
27+
# density source
28+
m = collect("density_source_multiplier_d+", path=path)
29+
source_mags.append(np.abs(m + 1))
30+
except:
31+
break
32+
33+
for calls, source, label, linestyle in zip(cumulative_calls, source_mags, labels, linestyles):
34+
plt.plot(calls, source, label=label, linestyle=linestyle)
35+
36+
plt.yscale('log')
37+
plt.xlabel('RHS evaluations')
38+
plt.ylabel('Source magnitude [arb]')
39+
plt.legend()
40+
plt.savefig("source_rhsevals.pdf")
41+
plt.show()
42+
43+
for time, source, label, linestyle in zip(times, source_mags, labels, linestyles):
44+
plt.plot(time, source, label=label, linestyle=linestyle)
45+
plt.yscale('log')
46+
plt.xlabel('Time [s]')
47+
plt.ylabel('Source magnitude [arb]')
48+
plt.legend()
49+
plt.savefig("source_time.pdf")
50+
plt.show()
51+
52+
# Time derivatives
53+
54+
for path, calls, label, linestyle in zip(paths, cumulative_calls, labels, linestyles):
55+
for varname, color in [("ddt(Nd+)", 'k'), ("ddt(Pd+)", 'r'), ("ddt(NVd+)",'b')]:
56+
dv = collect(varname, path=path)
57+
dv_rms = np.sqrt(np.sum(dv[:,0,:,0]**2, axis=1))
58+
plt.plot(calls, dv_rms, label=label + " " + varname, linestyle=linestyle, color=color)
59+
plt.yscale('log')
60+
plt.ylabel("RMS time derivative over domain")
61+
plt.xlabel("RHS evaluations")
62+
plt.legend()
63+
plt.savefig("timederivs_rhsevals.pdf")
64+
plt.show()
65+

0 commit comments

Comments
 (0)
Please sign in to comment.