Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions doc/hermes-2-manual.tex
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,29 @@ \section{Model equations}
\pi_{ci} &\simeq& \frac{3m_i}{4p_iT_i}\left[0.20q_{||i}^2 - 0.085q_i^2\right] + 0.96\frac{p_i}{\nu_i}\Bigg\{\kappa\cdot\left[\mathbf{V}_E + \mathbf{V}_{di} + 1.61\frac{\mathbf{b}\times\nabla T_i}{B}\right] \nonumber \\
&& - \frac{2}{\sqrt{B}}\partial_{||}\left(\sqrt{B}V_{||i}\right) - \frac{1.42}{p_i\sqrt{B}}\partial_{||}\left(\sqrt{B}q_{||i}\right) - \frac{0.49q_{||i}}{p_i}\left(2.27\partial_{||}\ln T_i - \partial_{||}\ln p_i\right)\Bigg\} \label{eq:pi_ci}
\end{eqnarray}
The non-Boussinesq version of the vorticity is
\begin{equation}
\omega = \nabla\cdot\left[\frac{1}{B^2}\left(n\nabla_\perp\phi + \nabla_\perp p_i\right)\right]
\end{equation}
and the corresponding evolution equation is:
\begin{subequations}
\begin{eqnarray}
%
% Vorticity
%
\frac{\partial\omega}{\partial t} &=& \nabla\cdot\left[\left(p_e + p_i\right)\nabla\times\frac{\mathbf{b}}{B}\right] \label{eq:vort-nB_diamag} \\
&& + \nabla_{||}j_{||} \label{eq:vort-nB_jpar} \\
&& - \nabla\cdot\Big[ \frac{1}{2B^2}\nabla_\perp\left(\mathbf{V}_{E\times B}\cdot\nabla p_i\right) + \frac{\omega}{2}\mathbf{V}_{E\times B} +\frac{n}{2B^2}\nabla_\perp^2\phi \left(\mathbf{V}_{E\times B} + \mathbf{V}_{di}\right) \Big] \label{eq:vort-nB_c} \\
&& + \nabla\cdot\left[\left(\frac{1}{2B^2}\mathbf{V}_{E\times B}\cdot\nabla n\right)\nabla_\perp\phi\right] \\
&& + \nabla\cdot\left(\frac{3T_i}{10\tau_iB^2}\nabla_\perp\omega\right) \label{eq:vort-nB_perpvis} \\
&& + \nabla\cdot\left[\frac{\pi_{ci}}{2}\nabla\times\frac{\mathbf{b}}{B} - \frac{1}{3}\frac{\mathbf{b}\times\nabla\pi_{ci}}{B}\right] \\
&& + \nabla\cdot\left(\nu_A\nabla_\perp\left<\omega\right>\right) \\
&& - \nabla\cdot\left(\frac{F_\perp}{nB^2}\nabla_\perp\phi\right)
\end{eqnarray}
\end{subequations}
where the ion diamagnetic velocity $\mathbf{V}_{di} = \frac{\mathbf{b}\times\nabla p_i}{n B}$ uses the full density $n$.
In addition $n_0$ is replaced by the full $n$ in the ion pressure equation~\ref{eq:ion-pressure} and the conserved energy~\ref{eq:conserved-energy} for the non-Boussinesq version.

The electron pressure equation is:
\begin{subequations}
\begin{eqnarray}
Expand Down Expand Up @@ -144,7 +167,7 @@ \section{Model equations}
&& + \frac{5}{2}\nabla\cdot\left(\frac{T_i}{T_e}\frac{\rho_e^2}{\tau_e}\left[ \nabla_\perp p_e + \nabla_\perp p_i - \frac{3}{2}n\nabla_\perp T_e \right]\right) \\
&& - \frac{3T_i}{10\tau_iB^2}\nabla_\perp\omega\cdot\nabla\left(\phi + \frac{p_i}{n_0}\right) - \left[\frac{\pi_{ci}}{2}\nabla\times\frac{\mathbf{b}}{B} - \frac{1}{3}\frac{\mathbf{b}\times\nabla\pi_{ci}}{B}\right]\cdot\nabla\left(\phi + \frac{p_i}{n_0}\right) \\
&& + S_{pi} - Q_i + W_i
\end{eqnarray}
\end{eqnarray}\label{eq:ion-pressure}
\end{subequations}
where the terms are a) cross-field E$\times$B and magnetic drifts including compression; b) parallel flow including compression;
c) energy exchange with diamagnetic flows; d) parallel viscous heating; e) parallel and perpendicular collisional heat conduction; f) collisional resistive drift; g) heating due to perpendicular viscosity; h)
Expand Down Expand Up @@ -207,6 +230,7 @@ \section{Model equations}
The plasma model is cast in conservative form, conserving particle number, and an energy
\begin{equation}
E = \int dv \frac{m_in_0}{2}\left|\frac{\nabla_\perp\phi}{B} + \frac{\nabla_\perp p_i}{en_0B}\right|^2 + \frac{1}{2}m_inV_{||i}^2 + \frac{3}{2}p_e + \frac{3}{2}p_i + \frac{1}{4}\beta_e\left|\nabla_\perp\psi\right|^2 + \frac{m_e}{m_i}\frac{1}{2}\frac{j_{||}^2}{n}
\label{eq:conserved-energy}
\end{equation}
where the terms correspond to the ion perpendicular kinetic energy ($E\times B$ and diamagnetic flow), ion parallel kinetic energy, electron and ion thermal energy, and electromagnetic field energy. Details are given in section~\ref{sec:conservation}. Differential operators are discretised using flux-conservative Finite Volume methods, details of which are given in section~\ref{sec:operators}.

Expand All @@ -224,7 +248,7 @@ \subsection{Input options}
These switches control the terms included in the plasma
evolution equations. They are grouped so that switching on
or off a term maintains energy conservation, though the
form of the conserved energy may change. See section~\ref{sec:rhsfunc} for details.
form of the conserved energy may change. See section~\ref{sec:conservation} for details.
\begin{center}
\begin{tabular}{l c c}
Setting & Default & Description \\
Expand Down
2 changes: 1 addition & 1 deletion external/BOUT-dev
Submodule BOUT-dev updated 56 files
+363 −0 .clang-tidy
+0 −50 .github/workflows/clang-format-command.yml
+30 −0 .github/workflows/clang-format.yml
+22 −39 .github/workflows/clang-tidy-review.yml
+0 −16 .github/workflows/slash-command-dispatch.yml
+4 −0 .github/workflows/tests.yml
+32 −0 CHANGELOG.md
+4 −4 CITATION.cff
+25 −4 CMakeLists.txt
+21 −2 bout++Config.cmake.in
+7 −0 change_summary.md
+5 −0 cmake/FindFFTW.cmake
+9 −6 cmake/FindnetCDF.cmake
+12 −7 cmake/FindnetCDFCxx.cmake
+11 −11 configure
+1 −1 configure.ac
+10 −2 include/bout/petsclib.hxx
+13 −2 include/bout/solver.hxx
+3 −3 include/bout/sys/variant.hxx
+89 −89 locale/de/libbout.po
+88 −88 locale/es/libbout.po
+83 −87 locale/fr/libbout.po
+83 −87 locale/libbout.pot
+83 −87 locale/zh_CN/libbout.po
+83 −87 locale/zh_TW/libbout.po
+3 −3 make.config.in
+1 −1 manual/doxygen/Doxyfile
+1 −1 manual/doxygen/Doxyfile_readthedocs
+1 −1 manual/sphinx/conf.py
+4 −1 manual/sphinx/user_docs/advanced_install.rst
+23 −1 manual/sphinx/user_docs/installing.rst
+174 −251 manual/sphinx/user_docs/running_bout.rst
+5 −3 src/bout++.cxx
+1 −2 src/invert/laplace/impls/petsc/petsc_laplace.cxx
+1 −2 src/invert/laplacexy/laplacexy.cxx
+0 −3 src/solver/impls/adams_bashforth/adams_bashforth.cxx
+0 −1 src/solver/impls/arkode/arkode.cxx
+0 −1 src/solver/impls/cvode/cvode.cxx
+0 −2 src/solver/impls/euler/euler.cxx
+0 −1 src/solver/impls/ida/ida.cxx
+0 −10 src/solver/impls/imex-bdf2/imex-bdf2.cxx
+0 −1 src/solver/impls/karniadakis/karniadakis.cxx
+1 −21 src/solver/impls/petsc/petsc.cxx
+0 −1 src/solver/impls/pvode/pvode.cxx
+0 −2 src/solver/impls/rk3-ssp/rk3-ssp.cxx
+0 −2 src/solver/impls/rk4/rk4.cxx
+0 −2 src/solver/impls/rkgeneric/rkgeneric.cxx
+6 −6 src/solver/impls/slepc/slepc.cxx
+717 −44 src/solver/impls/snes/snes.cxx
+36 −3 src/solver/impls/snes/snes.hxx
+0 −2 src/solver/impls/split-rk/split-rk.cxx
+2 −3 src/solver/solver.cxx
+25 −19 src/sys/options.cxx
+12 −0 src/sys/petsclib.cxx
+0 −1 tests/integrated/test-bout-override-default-option/CMakeLists.txt
+0 −29 tests/unit/src/test_bout++.cxx
107 changes: 84 additions & 23 deletions src/hermes-2.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -905,7 +905,9 @@ int Hermes::init(bool restarting) {
// Use older Laplacian solver
phiSolver = Laplacian::create(&opt["phiSolver"]);
// Set coefficients for Boussinesq solve
phiSolver->setCoefC(1. / SQ(coord->Bxy));
if (not boussinesq) {
Comment thread
johnomotani marked this conversation as resolved.
Outdated
phiSolver->setCoefC(1. / SQ(coord->Bxy));
}
}
}
phi = 0.0;
Expand Down Expand Up @@ -1335,7 +1337,51 @@ int Hermes::rhs(BoutReal t) {
////////////////////////////////////////////
// Non-Boussinesq
//
throw BoutException("Non-Boussinesq not implemented yet");
if (split_n0) {
throw BoutException("split_n0 not compaible with non-Boussinesq solve");
}
if (newXZsolver) {
throw BoutException("Non-Boussinesq not implemented yet for newXZsolver");
}
// Update boundary conditions.
// The INVERT_SET flag takes the value in the guard (boundary) cell and sets the
// boundary between cells to this value. This shift by 1/2 grid cell is
// important.

if (mesh->firstX()) {
for (int j = mesh->ystart; j <= mesh->yend; j++) {
for (int k = 0; k < mesh->LocalNz; k++) {
// Average phi + Pi at the boundary, and set the boundary cell
// to this value. The phi solver will then put the value back
// onto the cell mid-point
phi_boundary3d(mesh->xstart - 1, j, k) =
0.5
* (phi_boundary3d(mesh->xstart - 1, j, k) +
phi_boundary3d(mesh->xstart, j, k));
}
}
}

if (mesh->lastX()) {
for (int j = mesh->ystart; j <= mesh->yend; j++) {
for (int k = 0; k < mesh->LocalNz; k++) {
phi_boundary3d(mesh->xend + 1, j, k) =
0.5
* (phi_boundary3d(mesh->xend + 1, j, k) +
phi_boundary3d(mesh->xend, j, k));
}
}
}
auto n_B2 = Ne/SQ(coord->Bxy);
// Use older Laplacian solver
// Need to subtract Div(B^-2 Grad_perp(pi)) from rhs for non-Boussinesq solve, as
// coefficients of Grad_perp(phi) and Grad_perp(Pi) terms are not the same in
// non-Boussinesq vorticity
phiSolver->setCoefC(n_B2); // Set when initialised
// phi_boundary3d here is equivalent to withBoundary(phi, phi_boundary3d) because
// of the way phi_boundary3d is initialised
phi = phiSolver->solve((Vort - FV::Div_a_Laplace_perp(1/SQ(coord->Bxy),Pi))/n_B2,
phi_boundary3d);
}
}
phi.applyBoundary(t);
Expand Down Expand Up @@ -2805,35 +2851,46 @@ int Hermes::rhs(BoutReal t) {
}

// Advection of vorticity by ExB
if (boussinesq) {
TRACE("Vort:boussinesq");
// Using the Boussinesq approximation

ddt(Vort) -= Div_n_bxGrad_f_B_XPPM(0.5 * Vort, phi, vort_bndry_flux,
poloidal_flows);
ddt(Vort) -= Div_n_bxGrad_f_B_XPPM(0.5 * Vort, phi, vort_bndry_flux,
poloidal_flows);
// V_ExB dot Grad(Pi)
Field3D vEdotGradPi = bracket(phi, Pi, BRACKET_ARAKAWA);
vEdotGradPi.applyBoundary("free_o2");

// V_ExB dot Grad(Pi)
Field3D vEdotGradPi = bracket(phi, Pi, BRACKET_ARAKAWA);
vEdotGradPi.applyBoundary("free_o2");
// delp2(phi) term
Field3D DelpPhi_2B2 = 0.5 * Delp2(phi) / SQ(coord->Bxy);
DelpPhi_2B2.applyBoundary("free_o2");
// delp2(phi) term
Field3D DelpPhi_2B2 = 0.5 * Delp2(phi) / SQ(coord->Bxy);
DelpPhi_2B2.applyBoundary("free_o2");

mesh->communicate(vEdotGradPi, DelpPhi_2B2);
mesh->communicate(vEdotGradPi, DelpPhi_2B2);

ddt(Vort) -= FV::Div_a_Laplace_perp(0.5 / SQ(coord->Bxy), vEdotGradPi);
ddt(Vort) -= FV::Div_a_Laplace_perp(0.5 / SQ(coord->Bxy), vEdotGradPi);

if (boussinesq) {
TRACE("Vort:boussinesq_terms");
if (j_pol_terms){
ddt(Vort) -= Div_n_bxGrad_f_B_XPPM(DelpPhi_2B2, phi + Pi, vort_bndry_flux,
// Using the Boussinesq approximation
ddt(Vort) -= Div_n_bxGrad_f_B_XPPM(DelpPhi_2B2, phi + Pi, vort_bndry_flux,
poloidal_flows);
}
} else {
TRACE("Vort:non-boussinesq_terms");
if (j_pol_terms){
// When the Boussinesq approximation is not made,
// then the changing ion density introduces a number
// of other terms.

ddt(Vort) -= Div_n_bxGrad_f_B_XPPM(Ne*DelpPhi_2B2, phi, vort_bndry_flux,
poloidal_flows);
ddt(Vort) -= Div_n_bxGrad_f_B_XPPM(DelpPhi_2B2, Pi, vort_bndry_flux,
poloidal_flows);
}

} else {
// When the Boussinesq approximation is not made,
// then the changing ion density introduces a number
// of other terms.
// V_ExB dot Grad(n)
Field3D vEdotGradNe = bracket(phi, Ne, BRACKET_ARAKAWA);
vEdotGradNe.applyBoundary("free_o2");
mesh->communicate(vEdotGradNe);

throw BoutException("Hot ion non-Boussinesq not implemented yet\n");
ddt(Vort) += FV::Div_a_Laplace_perp(0.5 * vEdotGradNe / SQ(coord->Bxy), phi);
}

if (classical_diffusion) {
Expand Down Expand Up @@ -3352,7 +3409,11 @@ int Hermes::rhs(BoutReal t) {
// in the vorticity equation
ddt(Pi) -= j_diamag_scale * (2. / 3) * Pi * (Curlb_B * Grad(phi));

ddt(Pi) += j_diamag_scale * Pi * Div((Pe + Pi) * Curlb_B);
if (boussinesq) {
ddt(Pi) += j_diamag_scale * Pi * Div((Pe + Pi) * Curlb_B);
} else {
ddt(Pi) += j_diamag_scale * Pi / Nelim * Div((Pe + Pi) * Curlb_B);
}
}

if (j_par) {
Expand Down