main 2d001455106e cached
126 files
3.7 MB
972.1k tokens
76 symbols
1 requests
Download .txt
Showing preview only (3,887K chars total). Download the full file or copy to clipboard to get everything.
Repository: Open-Astrophysics-Bookshelf/numerical_exercises
Branch: main
Commit: 2d001455106e
Files: 126
Total size: 3.7 MB

Directory structure:
gitextract_nerblykz/

├── .github/
│   └── workflows/
│       └── build-book.yml
├── .gitignore
├── ADDITIONS
├── CompHydroTutorial.tex
├── Euler/
│   ├── Euler-methods.tex
│   ├── Euler-theory.tex
│   ├── README
│   ├── axisymmetry.odg
│   └── main.tex
├── GNUmakefile
├── LICENSE
├── NOTES
├── README.md
├── TODO
├── advection/
│   ├── advection-basics.tex
│   ├── advection-higherorder.tex
│   ├── main.tex
│   └── old-scripts/
│       ├── fv.py
│       ├── simplegrid.py
│       └── simplegrid2.py
├── burgers/
│   └── burgers.tex
├── codes/
│   └── intro/
│       └── sin-converge.py
├── diffusion/
│   ├── GNUmakefile
│   └── diffusion.tex
├── figures/
│   ├── Euler/
│   │   ├── multiple_interfaces.py
│   │   ├── ppm-sequence.py
│   │   ├── ppm-trace.py
│   │   ├── ppm.py
│   │   ├── rarefaction_cartoon.py
│   │   ├── riemann-states-q.py
│   │   ├── riemann-states.py
│   │   ├── riemann-waves-jump.py
│   │   ├── riemann-waves.py
│   │   ├── riemann_cartoon.py
│   │   ├── states.py
│   │   └── update.sh
│   ├── advection/
│   │   ├── 2dFD.py
│   │   ├── 2dFV.py
│   │   ├── 2dgrid.py
│   │   ├── 2dgrid_hat.py
│   │   ├── 2dgrid_transverse.py
│   │   ├── characteristics.py
│   │   ├── domains.py
│   │   ├── fd_ghost.py
│   │   ├── fv_ghost.py
│   │   ├── generalgrid.py
│   │   ├── rea-limitex.py
│   │   ├── rea.py
│   │   ├── riemann.py
│   │   ├── riemann_bc.py
│   │   ├── riemann_mol.py
│   │   └── update.sh
│   ├── burgers/
│   │   ├── characteristics.py
│   │   ├── rh.py
│   │   └── update.sh
│   ├── finite-volume/
│   │   ├── ccfd.py
│   │   ├── discretizations.odg
│   │   ├── domain.py
│   │   ├── fd.py
│   │   ├── fv.py
│   │   ├── simplegrid2.py
│   │   ├── simplegrid_gc.py
│   │   └── update.sh
│   ├── gridFigs/
│   │   ├── fdrestrict.py
│   │   ├── fvprolong.py
│   │   ├── fvrestrict.py
│   │   └── nested.py
│   ├── incompressible/
│   │   ├── MAC-solve.py
│   │   └── MAC.py
│   ├── intro/
│   │   ├── fft_simple_examples.py
│   │   ├── integrals.py
│   │   ├── rk4_plot.py
│   │   └── update.sh
│   ├── multigrid/
│   │   ├── 2dgrid-mg.py
│   │   ├── fv-fd_bnd.py
│   │   ├── fvrestrict.py
│   │   ├── laplacian.py
│   │   ├── mgtower.py
│   │   ├── red_black.py
│   │   └── smooth-separate.py
│   └── weno/
│       └── weno.py
├── finite-volume/
│   ├── discretizations.eps
│   ├── finite-volume.tex
│   ├── main.tex
│   └── old-scripts/
│       ├── domain-1d.py
│       └── simplegrid.py
├── gravity/
│   └── gravity.tex
├── higher-order/
│   ├── higher-order-burgers.tex
│   ├── higher-order-euler.tex
│   └── weno-coefficients.ipynb
├── hydro-test-problems/
│   └── hydro-test-problems.tex
├── hydro1d/
│   └── hydro1d.tex
├── hydro_examples/
│   └── hydro_examples.tex
├── incompressible/
│   ├── GNUmakefile
│   ├── MAC.eps
│   ├── MAC_solve.eps
│   ├── incompressible.tex
│   └── main.tex
├── instabilities/
│   └── instabilities.tex
├── intro/
│   └── intro.tex
├── low_mach/
│   ├── low_mach.tex
│   ├── mg_vc_periodic_converge.eps
│   └── mg_vc_periodic_test.eps
├── multigrid/
│   ├── 2dgrid-prolong.eps
│   ├── GNUmakefile
│   ├── main.tex
│   ├── mg-converge.eps
│   ├── mg_error_vs_cycle.eps
│   ├── multigrid.tex
│   └── rb.eps
├── multiphysics/
│   └── multiphysics.tex
├── mysymbols.tex
├── pde-classes/
│   └── pde-classes.tex
├── preface/
│   └── preface.tex
├── public-codes/
│   └── NOTES
├── pyro/
│   └── pyro.tex
├── radiation/
│   ├── mg_general_inhomogeneous_converge.eps
│   ├── mg_general_inhomogeneous_test.eps
│   └── radiation.tex
├── reactive_flow/
│   ├── notes.txt
│   └── reactive_flow.tex
├── refs.bib
├── simulations/
│   └── simulations.tex
├── software-engineering/
│   ├── software-engineering.tex
│   └── topics.txt
└── symbols/
    └── symbols.tex

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/build-book.yml
================================================
name: build book

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  build-book:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Install dependencies
        run: |
          sudo apt-get update -y -qq
          sudo apt-get -qq -y install texlive texlive-latex-extra texlive-fonts-extra texlive-font-utils build-essential

      - name: Build
        run: |
          make
          mkdir out
          mv CompHydroTutorial.pdf out

      - name: Archive
        uses: actions/upload-artifact@v3
        with:
          name: book-pdf
          path: out/CompHydroTutorial.pdf

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./out
          keep_files: true



================================================
FILE: .gitignore
================================================
*.pyc
*~
\#*
.\#*


*.log
*.aux
*.dvi
*.bbl
*.blg
*-converted-to.pdf
*.lof
*.exc
*.toc
*.png
*.bcf
*.brf
CompHydroTutorial.out
CompHydroTutorial.pdf

figures/*/*.eps
figures/*/*.pdf


================================================
FILE: ADDITIONS
================================================
* convergence testing via Richardson extrapolation

  -- always test the convergence of the initial conditions

* PPM vis

* well-balancing


================================================
FILE: CompHydroTutorial.tex
================================================
\documentclass[11pt]{book}

%\usepackage{microtype}

\input conditional.tex
%\def\debugmode{}

% include figures
\usepackage{epsfig,wrapfig}

% rotating table in the appendix
\usepackage{rotating}

% prefer PDF to PNG
\DeclareGraphicsExtensions{%
  .pdf, .png}

% Bibliographic Package
\usepackage[numbers,sort&compress]{natbib}

% code listings
\usepackage[procnames]{listings}

\lstset{basicstyle=\ttfamily\small, 
        keywordstyle=\color{keywords},
        commentstyle=\color{comments},
        stringstyle=\color{red},
        showstringspaces=false,
        identifierstyle=\color{blue},
        procnamekeys={def,class}}

\graphicspath{{preface/}{intro/}{finite-volume/}{advection/}{burgers/}{diffusion/}{Euler/}{incompressible/}{multigrid/}{multiphysics/}{low_mach/}{radiation/}{pyro/}{higher-order/}}

\usepackage{longtable}

% AMS symbols
\usepackage{amsmath,amssymb}

% for forcing a figure to appear on a single page
% see http://tex.stackexchange.com/questions/109219/force-position-of-full-page-sized-figure
\usepackage{afterpage}

% cancel
\usepackage{cancel}

% Palatino font (and math symbols) -- looks nicer than the standard
% LaTeX font
\usepackage[osf]{mathpazo}
\linespread{1.05}        % Palatino needs more leading
%\usepackage[scaled]{helvet} % ss
\usepackage{raleway}
\normalfont
\usepackage[T1]{fontenc}

% URLs (special font for monospace)
\usepackage{inconsolata}
%\usepackage[T1]{fontenc}


% footnotes use symbols
\renewcommand*{\thefootnote}{\fnsymbol{footnote}}


% margins and paper size -- this needs to come before fncychap
% see http://stackoverflow.com/questions/3729099/latex-paper-size
\usepackage[top=0.75in,
            bottom=0.75in,
            inner=0.65in,
            outer=0.65in]{geometry}
\geometry{papersize={7.0in,10in}}

% crop marks (for printing)
%\usepackage[
%  noinfo,
%  cam,
%  cross,                % crosses as marks
%  width=7.25in,         % the width of the galley
%  height=10.25in,        % the height of the galley
%  center                % actual page is centered on the galley
%]{crop}


% this needs to be done before the fncychap style, since that will
% redo the chapter stuff
\usepackage{sectsty}
\allsectionsfont{\sffamily}


% chapter title styles
%\usepackage[Bjornstrup]{fncychap}
%\ChNumVar{\fontsize{76}{80}\usefont{OT1}{pzc}{m}{n}\selectfont}
%\ChTitleVar{\raggedleft\Large\sffamily\bfseries}

\usepackage[PetersLenny]{fncychap}
\ChNameVar{\fontsize{16}{16}\sffamily\selectfont}%usefont{OT1}{raleway}{m}{n}\selectfont}
\ChNumVar{\fontsize{60}{62}\sffamily\selectfont}%\fontsize{60}{62}}\usefont{OT1}{raleway}{m}{n}\selectfont}
\ChTitleVar{\Huge\bfseries\sffamily}
\ChRuleWidth{1pt}

% part page style
% see http://tex.stackexchange.com/questions/6609/problems-with-part-labels-using-titlesec
\usepackage{titlesec}

\titleformat{\part}[display]
   {\bfseries\sffamily\Huge\filcenter}
   {{\partname{}} \thepart}
   {0em}
   {\hrule}



% hyperlinks -- load after fncychap
\usepackage{hyperref}
\usepackage[hyperpageref]{backref}
\renewcommand*{\backref}[1]{}% for backref < 1.33 necessary
\renewcommand*{\backrefalt}[4]{%
\ifcase #1 %
  No citations.%
\or
  (Cited on page #2)%
\else
  (Cited on pages #2)%
\fi
}

% back references


% color package
\usepackage{xcolor}
\definecolor{mygray}{gray}{0.5}


% custom hrule for title page
\newcommand{\HRule}{\rule{\linewidth}{0.125mm}}

\newcommand{\pyro}{{\sf pyro}}
\newcommand{\hydrooned}{{\sf hydro1d}}
\newcommand{\git}{{\tt git}}


\usepackage{xfrac}
%% \newcommand{\sfrac}[2]{\mathchoice
%%   {\kern0em\raise.5ex\hbox{\the\scriptfont0 #1}\kern-.15em/
%%    \kern-.15em\lower.25ex\hbox{\the\scriptfont0 #2}}
%%   {\kern0em\raise.5ex\hbox{\the\scriptfont0 #1}\kern-.15em/
%%    \kern-.15em\lower.25ex\hbox{\the\scriptfont0 #2}}
%%   {\kern0em\raise.5ex\hbox{\the\scriptscriptfont0 #1}\kern-.2em/
%%    \kern-.15em\lower.25ex\hbox{\the\scriptscriptfont0 #2}}
%%   {#1\!/#2}}


\newcommand{\myhalf}{{\sfrac{1}{2}}}
\newcommand{\mythreehalf}{\sfrac{3}{2}}
\newcommand{\mydxh}{\sfrac{\Delta x}{2}}
\newcommand{\mydth}{\sfrac{\Delta t}{2}}


% footer
%% \usepackage{fancyhdr}
%% \pagestyle{fancy}
%% \fancyfoot[LO,LE]{\footnotesize \sffamily \color{mygray} M.\ Zingale---Notes on the Euler equations}
%% \fancyfoot[RO,RE]{\footnotesize \sffamily \color{mygray} (\today)}
%% \fancyfoot[CO,CE]{\thepage}
%% \fancyhead{}
%% \renewcommand{\headrulewidth}{0.0pt}
%% \renewcommand{\footrulewidth}{0.0pt}



% don't make the chapter/section headings uppercase.  See the fancyhdr
% documentation (section 9)
\usepackage{fancyhdr}
\renewcommand{\chaptermark}[1]{%
\markboth{\chaptername
\ \thechapter.\ #1}{}}

\renewcommand{\sectionmark}[1]{\markright{\thesection---#1}}


% don't put a header on blank pages, see
% http://www.latex-community.org/forum/viewtopic.php?f=4&p=51559
% change ``plain'' to ``empty'' to eliminate the page number
\makeatletter
\renewcommand*\cleardoublepage{\clearpage\if@twoside
\ifodd\c@page\else
\hbox{}
\thispagestyle{empty}
\newpage
\if@twocolumn\hbox{}\newpage\fi\fi\fi}
\makeatother


% no page number of the part page
% http://latex.org/forum/viewtopic.php?f=47&t=4293&p=16738
\makeatletter
\renewcommand\part{%
   \if@openright
     \cleardoublepage
   \else
     \clearpage
   \fi
   \thispagestyle{empty}%
   \if@twocolumn
     \onecolumn
     \@tempswatrue
   \else
     \@tempswafalse
   \fi
   \null\vfil
   \secdef\@part\@spart}
\makeatother




% skip a bit of space between paragraphs, to enhance readability
\usepackage{parskip}


% captions
\usepackage{caption}
\renewcommand{\captionfont}{\footnotesize}
\renewcommand{\captionlabelfont}{\footnotesize}
\setlength{\captionmargin}{3em}


%-----------------------------------------------------------------------------
% define a new environment for exercises
%\newcounter{exercise}    % simple way -- no TOC list
% toclot allows us to make a list of exercises
% the new environment stuff came from http://www.dickimaw-books.com/latex/novices/html/newenv.html
\usepackage{tocloft}
\newcommand{\listexercisename}{List of Exercises}

% the [chapter] argumenet here means that we reset the numbers each chapter
% exc is the short name we give to this new list
\newlistof[chapter]{exercise}{exc}{\listexercisename}
\usepackage{changepage}   % used to adjust the margins within the environment

% environment name, with optional argument for display in the list of
% exercises
\newenvironment{exercise}[1][]
{% begin code
  %
  % this indents our text from the left and right
  \begin{adjustwidth}{1.0cm}{1.0cm}%
  %
  % this skips a line before
  %\par\vspace{\baselineskip}\noindent
  %
  % this increments our counter
  \refstepcounter{exercise}%
  \begin{tcolorbox}[enhanced, breakable, title={\sffamily Exercise \theexercise}]
  %
  % this displays the exercise number and starts italics
  \begin{itshape}%
  %
  % this adds an entry to our custom List of Exercises
  \addcontentsline{exc}{exercise}{\protect\numberline{\theexercise}~~ #1}
}%
{% end code -- this is done at the end of the environment
  %
  % stop the italics
  \end{itshape}%
  %
  \end{tcolorbox}
  % this stops our custom margins
  \end{adjustwidth}%
  %
  % this skips a line at the end
  %\vspace{\baselineskip}\ignorespacesafterend
}

% this makes the List of Exercises have a line break before each chapter,
% just like in the main ToC.
%
% this has a bug -- it does not omit the space if the chapter has 0 exercises
\usepackage{etoolbox}
\preto\section{%
  \ifnum\value{chapter}=1{}\else   % don't skip before Ch 1
    \ifnum\value{section}=0\addtocontents{exc}{\vskip10pt}\fi
  \fi
}

% indent these the standard amount for a chaptered section
\setlength{\cftexerciseindent}{1.5em}

%-----------------------------------------------------------------------------

% license
\usepackage{ccicons}

% computer keyboard symbol
\usepackage{marvosym}

% for dotted lines in the matrics/arrays
\usepackage{arydshln}



% fonts for TOC, list of figures, etc
\renewcommand*\listfigurename{\bf\textsf{List of Figures}}
\renewcommand*\listexercisename{\bf\textsf{List of Exercises}}
\renewcommand*\contentsname{\bf\textsf{Table of Contents}}



% short table of contents
\usepackage{shorttoc}


% pack more figures on a page
\usepackage{float}
\renewcommand\floatpagefraction{.9}
\renewcommand\topfraction{.9}
\renewcommand\bottomfraction{.9}
\renewcommand\textfraction{.1}


\newcommand{\hydroex}{{\sf hydro\_examples}}
\newcommand{\hydroexdoit}[1]{{\color{red} \LARGE \Keyboard}\/ \hydroex: {\tt #1}}
\newcommand{\hydroexsymb}{{\color{red} \LARGE \Keyboard}}

\usepackage{multirow}


% MarginPars
\setlength{\marginparwidth}{0.75in}
\newcommand{\aMarginPar}[1]{\marginpar{\vskip-\baselineskip\raggedright\tiny\sffamily\hrule\smallskip{\color{red}#1}\par\smallskip\hrule}}
\newcommand{\MarginPar}[1]{\ifdefined\debugmode\aMarginPar{#1}\fi}

\usepackage{eso-pic}
\newcommand\BackgroundPic{%
\put(-0,-0){%
\parbox[b][\paperheight]{\paperwidth}{%
\vfill
\centering
\includegraphics[width=\paperwidth,%height=\paperheight,%
keepaspectratio]{images/crop_cover.png}%
\vfill
}}}


\usepackage[many]{tcolorbox}

\newtcolorbox{mybox}[1][]{
    width=\textwidth,
    arc=0mm,
    auto outer arc,
    boxsep=0.05cm,
    toprule=2pt,
    leftrule=2pt,
    bottomrule=2pt,
    rightrule=2pt,
    colframe=black,
    colback=white,
    fontupper=\centering\fontsize{28pt}{28pt}\sffamily,
    breakable,
    nobeforeafter,
    enhanced jigsaw,
    opacityframe=0.7,
    opacityback=0.75,
    title={\hfill\sffamily part of the open astrophysics bookshelf},
}

\pdfpageattr{/Group <</S /Transparency /I true /CS /DeviceRGB>>}


\input mysymbols

\begin{document}

\AddToShipoutPicture*{\BackgroundPic}

\frontmatter

\begin{titlepage}

\ \\[1.25in]

%% \HRule\\[0.5em]
%% {\Huge \textsf{{
%% Lecture Notes on\\[0.1em]
%% Computational Hydrodynamics\\[0.3em]
%% for Astrophysics}}
%% }
%% \HRule
%% \\[2em]
%
%% {\Large \sf  Michael Zingale} \\ {\sf Stony Brook University}
%
%% \begin{mybox}[]
%% \vskip 3mm
%% {Introduction to} \\%[-0.75em]
%% {Computational Hydrodynamics \\%[-0.75em]
%% for Astrophysics}
%% \vspace{0.5em}
%% \end{mybox}

{\sffamily \color{white}%
\begin{center}
\fontsize{22}{18}\selectfont
Introduction to \\
\fontsize{32}{26}\selectfont
Computational Astrophysical Hydrodynamics
\end{center}
}
\vspace{0.5em}

\vfill


{\color{red}\sffamily the Open Astrophysics Bookshelf \hfill\color{white} Michael Zingale}

\end{titlepage}

\pagestyle{plain}

\null \vfill

\noindent \ccCopy\ 2013, 2014, 2015, 2016, 2017 Michael Zingale \\
\noindent document git version: \input git_info.tex $\ldots$ \\
\noindent \today

\noindent the source for these notes are available online (via \git):\\
\url{https://github.com/Open-Astrophysics-Bookshelf/numerical_exercises}

\noindent \ccbyncsa \\
\noindent This work is licensed under the Creative Commons
Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA
4.0) license.


\clearpage


\shorttoc{Chapter Listing}{0}

\clearpage


\setcounter{tocdepth}{2}
\tableofcontents

\clearpage

\listoffigures
\addcontentsline{toc}{chapter}{list of figures}

\clearpage

\listofexercise
\addcontentsline{toc}{chapter}{list of exercises}

\clearpage

\chapter*{preface}
\chaptermark{preface}
\addcontentsline{toc}{chapter}{preface}

\input preface/preface.tex

\clearpage

\pagestyle{headings}

\renewcommand{\chaptermark}[1]{%
\markboth{\chaptername
\ \thechapter.\ #1}{}}

\renewcommand{\sectionmark}[1]{\markright{\thesection---#1}}

% put the git hash on the first page of each chapter -- see section
% 7 of the fancyhdr docs to see how to override the plain
% style
\fancypagestyle{plain}{%
\fancyhf{} % clear all header and footer fields
\fancyfoot[C]{\thepage} % except the center
\fancyfoot[L]{\scriptsize git version: \input git_info.tex $\ldots$}
\renewcommand{\headrulewidth}{0pt}
\renewcommand{\footrulewidth}{0pt}}


\mainmatter

\part{Basics}

\chapter{Simulation Overview}

\input intro/intro.tex


\chapter{Classification of PDEs}

\input pde-classes/pde-classes.tex


%\addtocontents{exc}{\protect\addvspace{10pt}}%
\chapter{Finite-Volume Grids}

\input finite-volume/finite-volume.tex

\part{Advection and Hydrodynamics}

%\addtocontents{exc}{\protect\addvspace{10pt}}%
\chapter{Advection Basics}

\input advection/advection-basics.tex

\chapter{Second- (and Higher-) Order Advection}

\input advection/advection-higherorder.tex

%\addtocontents{exc}{\protect\addvspace{10pt}}%
\chapter{Burgers' Equation}

\input burgers/burgers.tex

\input higher-order/higher-order-burgers.tex

%\addtocontents{exc}{\protect\addvspace{10pt}}%
\chapter{Euler Equations: Theory}

\input Euler/Euler-theory.tex


\chapter{Euler Equations: Numerical Methods}

\input Euler/Euler-methods.tex

\input higher-order/higher-order-euler.tex

\ifdefined\debugmode
\chapter{Hydrodynamics Test Problems}

\input hydro-test-problems/hydro-test-problems.tex


\chapter{Instabilities and Turbulence}

\input instabilities/instabilities.tex

\fi




\part{Elliptic and Parabolic Problems}


%\addtocontents{exc}{\protect\addvspace{10pt}}%
\chapter{Elliptic Equations and Multigrid}

\input multigrid/multigrid.tex

%\addtocontents{exc}{\protect\addvspace{10pt}}%
\chapter{Diffusion}

\input diffusion/diffusion.tex




\part{Multiphysics applications}

%\addtocontents{exc}{\protect\addvspace{10pt}}%
\chapter{Model Multiphysics Problems}

\input multiphysics/multiphysics.tex

\chapter{Reactive Flow}

\input reactive_flow/reactive_flow.tex

\ifdefined\debugmode
\chapter{Self-gravity}

\input gravity/gravity.tex
\fi

\chapter{Planning a Simulation}

\input simulations/simulations.tex




\part{Low Speed Hydrodynamics}

%\addtocontents{exc}{\protect\addvspace{10pt}}%
\chapter{Incompressible Flow and Projection Methods}

\input incompressible/incompressible.tex

\chapter{Low Mach Number Methods}

\input low_mach/low_mach.tex

\ifdefined\debugmode
\chapter{Radiation Hydrodynamics}

\input radiation/radiation.tex
\fi

\part{Code Descriptions}

\appendix

\chapter{Using \hydroex}

\input hydro_examples/hydro_examples.tex

\chapter{Using \pyro}

\input pyro/pyro.tex

\chapter{Using \hydrooned}

\input hydro1d/hydro1d.tex

%% \chapter{Software Engineering Practices}

%% \input software-engineering/software-engineering.tex

\backmatter

\addcontentsline{toc}{chapter}{References}
\bibliographystyle{plain}
\bibliography{refs}

\end{document}


================================================
FILE: Euler/Euler-methods.tex
================================================
\label{ch:compressible}

\section{Introduction}

\label{sec:eulermeth:intro}

The numerical methods we use for the Euler equations mirror those used
with advection in Ch.~\ref{ch:advection}.  The basic process is:
\begin{itemize}
\item Reconstruct the state variables to the interfaces.
\item Solve the Riemann problem (as described in
  \S~\ref{euler:sec:riemann}) and construct the fluxes through
  the interfaces.
\item Perform the conservative update on the state variables.
\end{itemize}
The Euler equations are much more complicated than linear
advection---we already saw this with the Riemann problem.  But we will
also see that in different parts of the algorithm we will use
conservative or primitive variables.  Additional physics can enter as
source terms, which we'll see how to add to both the interface states
and conservative update here.

%-----------------------------------------------------------------------------
\section{Reconstruction of interface states}

\label{sec:onedrecon}

We will solve the Euler equations using a high-order {\em Godunov
  method}---a finite volume method whereby the fluxes through the
interfaces are computed by solving the Riemann problem for our system.
The finite-volume update for our system appears as:
\begin{equation}
\Uc^{n+1}_i = \Uc^n_i + \frac{\Delta t}{\Delta x} \left ( \Fb_{i-\myhalf}^{n+\myhalf} - \Fb_{i+\myhalf}^{n+\myhalf} \right )
\end{equation}
This says that each of the conserved quantities in $\Uc$ change only due
to the flux of that quantity through the boundary of the cell.

Instead of approximating the flux itself on the interface, we find an
approximation to the state on the interface, $\Uc_{i-\myhalf}^{n+\myhalf}$ and
$\Uc_{i+\myhalf}^{n+\myhalf}$ and use this with the flux function to define the
flux through the interface:
\begin{align}
\Fb_{i-\myhalf}^{n+\myhalf} &= \Fb(\Uc_{i-\myhalf}^{n+\myhalf}) \\
\Fb_{i+\myhalf}^{n+\myhalf} &= \Fb(\Uc_{i+\myhalf}^{n+\myhalf})
\end{align}
To find this interface state, we predict left and right states at each
interface (centered in time), which are the input to the Riemann
solver.  The Riemann solver will then look at the characteristic wave
structure and determine the fluid state on the interface, which is
then used to compute the flux.  This is illustrated in
Figure~\ref{fig:riemann}.

Finally, although we use the conserved variables for the final update,
in constructing the interface states it is often easier to work with
the primitive variables.  These have a simpler characteristic
structure.  The interface states in terms of the primitive variables
can be converted into the interface states of the conserved variables
through a simple algebraic transformation,
\begin{equation}
\Uc_{i+\myhalf,L}^{n+\myhalf} = \Uc(\qb_{i+\myhalf,L}^{n+\myhalf})
\end{equation}

% figure made with figures/Euler/riemann-states.py
\begin{figure}[t]
\centering
\includegraphics[width=\linewidth]{riemann_comp}
\caption[The left and right states for the Riemann
  problem]{\label{fig:riemann} The left and right states at interface
  $i+\myhalf$.  The arrow indicates the flux through the interface, as
  computed by the Riemann solver using these states as input.}
\end{figure}

As we saw with linear advection in \S~\ref{ch:adv:sndorder},
at the start of a timestep, each zones contains cell-averages.
Consider a cell average quantity, $\qb_i$.
Constructing the interface states requires reconstructing the
cell-average data as a continuous function, $\qb(x)$, defined for
each cell.  This polynomial is only {\em piecewise} continuous, since
each cell has its own $\qb(x)$.  Standard choices are piecewise constant,
\begin{equation}
\qb(x) = \qb_i
\end{equation}
piecewise linear,
\begin{equation}
\qb(x) = \qb_i + \frac{\Delta \qb_i}{\Delta x}(x - x_i)
\end{equation}
or piecewise parabolic,
\begin{equation}
\qb(x) = \boldsymbol{\alpha} (x - x_i)^2 + \boldsymbol{\beta} (x - x_i) + \boldsymbol{\gamma}
\end{equation}
where in each case, the average of $\qb(x)$ over the cell gives $\qb_i$.
Most of the complexity of the method is then figuring out the coefficients
of the polynomial.

Characteristic tracing is then done under this polynomial to see how
much of each characteristic quantity comes to the interface over the
timestep.  The jump in the primitive variables is projected into the
characteristic variables, and only jumps moving toward the interface
are included in our reconstruction.  We look at several methods below
that build off of these ideas below.

\subsection{Piecewise constant}

The simplest possible reconstruction of the data is piecewise constant.
This is what was done in the original Godunov method~\cite{godunov:1959}.  For the interface
marked by $i+\myhalf$, the left and right states on the interface are simply:
\begin{align}
\Uc_{i+\myhalf,L} &= \Uc_i \\
\Uc_{i+\myhalf,R} &= \Uc_{i+1}
\end{align}
This does not take into account in any way how the state $\Uc$ may be changing
through the cell.  As a result, it is first-order accurate in space, and since
no attempt was made to center it in time, it is first-order accurate in time.

\subsection{Piecewise linear}

For higher-order reconstruction, we first convert from the conserved
variables, $\Uc$, to the primitive variables, $\qb$.  These have a simpler
characteristic structure, making them easier to work with.  Here we
consider piecewise linear reconstruction---the cell average data is
approximated by a line with non-zero slope within each cell.
Figure~\ref{fig:plm} shows the piecewise linear reconstruction of some
data.


% figure made with figures/Euler/ppm.py
\begin{figure}[t]
\centering
\includegraphics[width=\linewidth]{piecewise-linear}
\caption[Piecewise linear reconstruction of cell average
  data]{\label{fig:plm} Piecewise linear reconstruction of the cell
  averages.  The dotted line shows the unlimited center-difference
  slopes and the solid line shows the limited slopes.}
\end{figure}

Consider constructing the left state at the interface $i+\myhalf$ (see
Figure~\ref{fig:riemann}).  Just like for the advection equation, we
do a Taylor expansion through $\Delta x/2$ to bring us to the
interface, and $\Delta t/2$ to bring us to the midpoint in time.
Starting with $\qb_i$, the cell-centered primitive variable, expanding
to the right interface (to create the left state there) gives:
\begin{align}
\qb_{i+\myhalf,L}^{n+\myhalf} &= \qb_i^n +
    \left . \frac{\Delta x}{2} \frac{\partial \qb}{\partial x} \right |_i +
    \frac{\Delta t}{2} \underbrace{\left .\frac{\partial \qb}{\partial t} \right |_i}_{= -\Ab \partial \qb / \partial x} + \ldots \\
&= \qb_i^n + \frac{\Delta x}{2} \left . \frac{\partial \qb}{\partial x} \right |_i
          - \frac{\Delta t}{2} \left ( \Ab \frac{\partial \qb}{\partial x} \right )_i\\
&= \qb_i^n + \frac{1}{2} \left [ 1 - \frac{\Delta t}{\Delta x} \Ab_i \right ] \Delta \qb_i \label{eq:taylorstate}
\end{align}
where $\Delta \qb_i$ is the reconstructed slope of the primitive
variable in that cell (similar to how we compute it for the advection
equation).  We note that the terms truncated in the first line are
$O(\Delta x^2)$ and $O(\Delta t^2)$, so our method will be second-order
accurate in space and time.

As with the advection equation, we limit the slope such that no new minima
or maxima are introduced.  Any of the slope limiters used for linear advection
apply here as well.  We represent the limited slope as $\overline{\Delta \qb}_i$.

We can decompose $\Ab \Delta \qb$ in terms of the left and right
eigenvectors and sum over all the waves that move {\em toward} the
interface.  First, we recognize that $\Ab = R \Lambda L$ and recognizing
that the `$1$'
in Eq.~\ref{eq:taylorstate} is the identity, $I = LR$, we rewrite this
expression as:
\begin{equation}
\qb_{i+\myhalf,L}^{n+\myhalf} = \qb_i^n +
     \frac{1}{2} \left [ \Rb\Lb - \frac{\Delta t}{\Delta x} \Rb\Lambdab \Lb \right ]_i \overline{\Delta \qb}_i
\end{equation}
We see the common factor of $\Lb \Delta \qb$.  We now write this back in
component form.  Consider:
\begin{equation}
\renewcommand{\arraystretch}{1.5}
\Rb\Lambdab \Lb \overline{\Delta \qb} =
   \left ( \begin{array}{c:c:c}
             r_1^\evm & r_1^\evz & r_1^\evp \\
             r_2^\evm & r_2^\evz & r_2^\evp \\
             r_3^\evm & r_3^\evz & r_3^\evp \end{array} \right )
   \left ( \begin{array}{ccc}
             \lambda^\evm &              & \\
                          & \lambda^\evz & \\
                          &              & \lambda^\evp \end{array} \right )
   \left ( \begin{array}{ccc}
             l_1^\evm & l_2^\evm & l_3^\evm \\
             \hdashline
             l_1^\evz & l_2^\evz & l_3^\evz \\
             \hdashline
             l_1^\evp & l_2^\evp & l_3^\evp \end{array} \right )
   \left ( \begin{array}{c}
            \overline{\Delta \rho} \\
            \overline{\Delta u} \\
            \overline{\Delta p} \end{array} \right )
\renewcommand{\arraystretch}{1.0}
\end{equation}
Starting with $\Lb \overline{\Delta \qb}$, which is a vector with each component
the dot-product of a left eigenvalue with $\overline{\Delta \qb}$, we have
\begin{equation}
\renewcommand{\arraystretch}{1.5}
\Rb\Lambdab \Lb \overline{\Delta \qb} =
   \left ( \begin{array}{c:c:c}
             r_1^\evm & r_1^\evz & r_1^\evp \\
             r_2^\evm & r_2^\evz & r_2^\evp \\
             r_3^\evm & r_3^\evz & r_3^\evp \end{array} \right )
   \left ( \begin{array}{ccc}
             \lambda^\evm &              & \\
                          & \lambda^\evz & \\
                          &              & \lambda^\evp \end{array} \right )
   \left ( \begin{array}{c}
            \lb^\evm \cdot \overline{\Delta \qb} \\
            \lb^\evz \cdot \overline{\Delta \qb} \\
            \lb^\evp \cdot \overline{\Delta \qb} \end{array} \right )
\renewcommand{\arraystretch}{1.0}
\end{equation}
Next we see that multiplying this vector by $\Lambdab$ simply puts the
eigenvalue with its respective eigenvector in the resulting column vector:
\begin{equation}
\renewcommand{\arraystretch}{1.5}
\Rb\Lambdab \Lb \overline{\Delta \qb} =
   \left ( \begin{array}{c:c:c}
             r_1^\evm & r_1^\evz & r_1^\evp \\
             r_2^\evm & r_2^\evz & r_2^\evp \\
             r_3^\evm & r_3^\evz & r_3^\evp \end{array} \right )
   \left ( \begin{array}{c}
            \lambda^\evm \, \lb^\evm \cdot \overline{\Delta \qb} \\
            \lambda^\evz \, \lb^\evz \cdot \overline{\Delta \qb} \\
            \lambda^\evp \, \lb^\evp \cdot \overline{\Delta \qb} \end{array} \right )
\renewcommand{\arraystretch}{1.0}
\end{equation}
Finally, the last multiply results in a column vector:
\begin{equation}
\renewcommand{\arraystretch}{1.5}
R\Lambda L \overline{\Delta \qb} =
   \left ( \begin{array}{c}
            r_1^\evm \, \lambda^\evm \, \lb^\evm \cdot \overline{\Delta \qb} +
            r_1^\evz \, \lambda^\evz \, \lb^\evz \cdot \overline{\Delta \qb} +
            r_1^\evp \, \lambda^\evp \, \lb^\evp \cdot \overline{\Delta \qb} \\
%
            r_2^\evm \, \lambda^\evm \, \lb^\evm \cdot \overline{\Delta \qb} +
            r_2^\evz \, \lambda^\evz \, \lb^\evz \cdot \overline{\Delta \qb} +
            r_2^\evp \, \lambda^\evp \, \lb^\evp \cdot \overline{\Delta \qb} \\
%
            r_3^\evm \, \lambda^\evm \, \lb^\evm \cdot \overline{\Delta \qb} +
            r_3^\evz \, \lambda^\evz \, \lb^\evz \cdot \overline{\Delta \qb} +
            r_3^\evp \, \lambda^\evp \, \lb^\evp \cdot \overline{\Delta \qb} \\
   \end{array} \right )
\renewcommand{\arraystretch}{1.0}
\end{equation}
We can rewrite this compactly as:
\begin{equation}
\sum_\nu \lambda^{(\nu)} (\lb^{(\nu)} \cdot \overline{\Delta \qb}) \rb^{(\nu)}
\end{equation}
where we use $\nu$ to indicate which wave we are summing over.  A similar
expansion is used for $\Rb\Lb \overline{\Delta \qb}$.  In fact, any vector
can be decomposed in this fashion:
\begin{equation}
{\boldsymbol{\chi}} = {\bf I} {\boldsymbol{\chi}} = \Rb \Lb {\boldsymbol{\chi}} = 
   \sum_\nu (\lb^\enu \cdot {\boldsymbol{\chi}}) \rb^\enu
\end{equation}
And then it is easy to see that the above manipulations for $\Ab \Delta \qb$
can be expressed as:
\begin{equation}
\Ab \Delta \qb =  \Ab \sum_\nu (\lb^\enu \cdot \overline{\Delta \qb}) \rb^\enu = 
  \sum_\nu (\lb^\enu \cdot \overline{\Delta \qb}) \Ab \rb^\enu = 
  \sum_\nu (\lb^\enu \cdot \overline{\Delta \qb}) \lambda^\enu \rb^\enu
\end{equation}
where we used $\Ab \rb^\enu = \lambda^\enu \rb^\enu$.  The quantity $(\lb^\enu
\cdot \overline{\Delta \qb})$ that shows up here is the projection of
the vector $\overline{\Delta \qb}$ into the characteristic variable
carried by wave $\nu$.  This sum shows, as discussed earlier, that each wave
carries a jump in the characteristic variable, with the jump in the primitive
variables proportion to the right eigenvector, $\rb^\enu$.

The resulting vector
for the left state is:
\begin{equation}
\qb_{i+\myhalf,L}^{n+\myhalf} = \qb_i^n + \frac{1}{2} \sum_{\nu; \lambda^{(\nu)} \ge 0}
  \left [ 1 - \frac{\Delta t}{\Delta x} \lambda_i^{(\nu)} \right ] (\lb_i^{(\nu)} \cdot \overline{\Delta \qb}_i) \rb_i^{(\nu)}
\end{equation}
Note that we make a slight change here, and only include a term in the sum if
its wave is moving toward the interface ($\lambda^\enu \ge 0$).  The quantity
$\Delta t \lambda^\enu/\Delta x$ inside the brackets is simply the CFL
number for the wave $\nu$.

Starting with the data in the $i+1$ zone and expanding to the left, we can
find the right state on the $i+\myhalf$ interface:
\begin{equation}
\qb_{i+\myhalf,R}^{n+\myhalf} = \qb_{i+1}^n - \frac{1}{2} \sum_{\nu; \lambda^{(\nu)} \le 0}
  \left [ 1 + \frac{\Delta t}{\Delta x} \lambda_{i+1}^{(\nu)} \right ] (\lb_{i+1}^{(\nu)} \cdot \overline{\Delta \qb}_{i+1}) \rb_{i+1}^{(\nu)}
\end{equation}


A good discussion of this is in Miller \& Colella
\cite{millercolella:2002} (Eq.\ 85).  This expression is saying that
each wave carries a jump in $\rb^{(\nu)}$ and only those jumps moving
toward the interface contribute to our interface state.  This
restriction of only summing up the waves moving toward the interface
is sometimes called {\em characteristic tracing}.  This decomposition
in terms of the eigenvectors and eigenvalues is commonly called a {\em
  characteristic projection}.  In terms of an operator, $P$, it can be
expressed as:
\begin{equation}
P {\boldsymbol{\chi}} = \sum_\nu (\lb^{(\nu)} . {\boldsymbol{\chi}}) \rb^{(\nu)}
\end{equation}
\begin{exercise}[Characteristic projection]
{
Show that $P \qb = \qb$, using the eigenvectors corresponding to the primitive
 variable form of the Euler equations.}
\end{exercise}
In the literature, sometimes a `$>$' or `$<$' subscript on $P$ is used
to indicate the characteristic tracing.

We could stop here, but Colella \& Glaz~\cite{colellaglaz:1985}
(p.\ 278) argue that the act of decomposing $\Ab$ in terms of the left
and right eigenvectors is a linearization of the quasi-linear system,
and we should minimize the size of the quantities that are subjected
to this characteristic projection.  To accomplish this, they suggest
subtracting off a {\em reference state}.  Saltzman (Eq.\ 8) further
argues that since only jumps in the solution are used in constructing
the interface state, and that the characteristic decomposition simply adds
up all these jumps, we can subtract off the reference state and
project the result.  In other words, we can write:
\begin{equation}
\qb_{i+\myhalf,L}^{n+\myhalf} - \qb_\mathrm{ref} = \qb_i^n - \qb_\mathrm{ref} +
  \frac{1}{2} \left [ 1 - \frac{\Delta t}{\Delta x} \Ab_i \right ] \overline{\Delta \qb}_i
\label{eq:lin_decomp}
\end{equation}
Then we subject the RHS to the characteristic projection---this tells
us how much of the quantity $\qb_{i+\myhalf,L}^{n+\myhalf} - \qb_\mathrm{ref}$
reaches the interface.  Colella \& Glaz (p.\ 278) and Colella
(Eq.\ 2.11) suggest
\begin{equation}
\qb_\mathrm{ref} = \tilde{\qb}_{i,L} \equiv \qb_i^n +
   \frac{1}{2} \left [ 1 - \frac{\Delta t}{\Delta x}
 \max(\lambda_i^\evp, 0) \right ] \overline{\Delta \qb}_i \label{eq:qref}
\end{equation}
where $\lambda^\evp$ is the fastest eigenvalue, and thus will see
the largest portion of the linear profiles.  Physically, this
reference state represents the jump carried by the fastest wave
moving toward the interface.  Then,
\begin{equation}
\qb_{i+\myhalf,L}^{n+\myhalf} - \tilde{\qb}_{i,L} = \frac{1}{2} \frac{\Delta t}{\Delta x}
  \left [ \max(\lambda_i^\evp,0) - \Ab_i \right ] \overline{\Delta \qb}_i
\end{equation}
and projecting this RHS (see Colella \& Glaz Eq. 43; Miller \& Colella Eq. 87),
and isolating the interface state, we have
\begin{align}
\qb_{i+\myhalf,L}^{n+\myhalf} &= \tilde{\qb}_{i,L} + \frac{1}{2} \frac{\Delta t}{\Delta x}
       \sum_{\nu; \lambda^{(\nu)} \ge 0} \lb_i^{(\nu)} \cdot \left [ \max(\lambda_i^\evp,0) - \Ab_i \right ]
                                           \overline{\Delta \qb}_i \, \rb_i^{(\nu)} \\
                    &= \tilde{\qb}_{i,L} + \frac{1}{2} \frac{\Delta t}{\Delta x}
       \sum_{\nu; \lambda^{(\nu)} \ge 0} \left [ \max(\lambda_i^\evp,0) - \lambda_i^{(\nu)} \right ]
                                          (\lb_i^{(\nu)} \cdot \overline{\Delta \qb}_i) \, \rb_i^{(\nu)}
\end{align}
This is equivalent to the expression in Saltzman~\cite{saltzman:1994}
(p.\ 161, first column, second-to-last equation) and
Colella~\cite{colella:1990} (p.\ 191, the group of expressions at the
end)\footnote{Since the combination $\lb^\enu \cdot \Delta \qb$
  appears so frequently, some sources represent this as $\beta^\enu$
  and then write the interface states as a linear combination of the
  $\beta$'s.  Some variation in the literation, depending on whether $\rho$
  or $\tau = 1/\rho$ is used as a primitive variable}.  The corresponding
  state to the right of this interface is:
\begin{equation}
\qb_{i+\myhalf,R}^{n+\myhalf} = \tilde{\qb}_{i+1,R} + \frac{1}{2} \frac{\Delta t}{\Delta x}
       \sum_{\nu; \lambda^\enu \le 0}
       \left [ \min(\lambda_{i+1}^\evm,0) - \lambda_{i+1}^\enu \right ]
       (\lb_{i+1}^\enu \cdot \overline{\Delta \qb}_{i+1}) \, \rb_{i+1}^\enu
\end{equation}
where now the reference state captures the flow from the $i+1$ zone
moving to the {\em left} to this interface (hence the appearance of
$\lambda^\evm$, the leftmost eigenvalue):
\begin{equation}
\tilde{\qb}_{i+1,R} = \qb_{i+1} - \frac{1}{2} \left [ 1 + \frac{\Delta t}{\Delta x} \min(\lambda_{i+1}^\evm,0) \right ] \overline{\Delta \qb}_{i+1}
\end{equation}

Side note: the data in zone $i$ will be used to construct the right
state at $i-\myhalf$ (the left interface) and the left state at $i+\myhalf$
(the right interface) (see Figure~\ref{fig:states}).  For this reason,
codes usually compute the eigenvectors/eigenvalues for that zone and
then compute $\qb_{i-\myhalf,R}^{n+\myhalf}$ together with $\qb_{i+\myhalf,L}^{n+\myhalf}$
in a loop over the zone centers.

% figure made by figures/Euler/states.py
\begin{figure}
\centering
\includegraphics[width=3.5in]{states}
\caption[The two interface states derived from a cell-center quantity]{\label{fig:states} The two interface states that are constructed
using $\qb_i$ as the starting point.}
\end{figure}

\subsection{Piecewise parabolic}

\label{sec:hydro:ppm}

The piecewise parabolic method uses a parabolic reconstruction in each
cell.  This is more accurate than the linear reconstruction.
Figure~\ref{fig:ppm} shows the reconstructed parabolic profiles within
a few cells.  Since the original PPM
paper~\cite{colellawoodward:1984}, there have been many discussions of
the method, with many variations.  Here we focus on the presentation
by Miller \& Colella~\cite{millercolella:2002}, since that is the most
straightforward.  Note: even though a parabolic profile could be
third-order accurate, the temporal discretization and prediction in
this method is still only second-order.
%
% figure made by figures/Euler/ppm.py
\begin{figure}[t]
\centering
\includegraphics[width=\linewidth]{piecewise-parabolic}
\caption[Piecewise parabolic reconstruction of the cell
  averages]{\label{fig:ppm} Piecewise parabolic reconstruction of the
  cell averages.  The dotted line shows the unlimited parabolas---note
  how they touch at each interface, since the interface values come
  from the same interpolant initially.  The solid line shows the
  limited parabolas.}
\end{figure}


Miller \& Colella give an excellent description of how to take the
results for piecewise linear reconstruction and generalize it to the case of
PPM~\cite{colellawoodward:1984} (see Eqs.\ 88-90).  Starting with
Eq.~\ref{eq:lin_decomp}, we can write this (after the characteristic
projection) as
\begin{equation}
\qb_{i+\myhalf,L}^{n+\myhalf} = \tilde{\qb}_+ -
   \sum_{\nu;\lambda^{(\nu)}\ge 0} \lb_i^{(\nu)} \cdot \left \{
        \tilde{\qb}_+ - \left [ \qb_i^n +
            \frac{1}{2} \left ( 1 - \frac{\Delta t}{\Delta x} \lambda_i^{(\nu)} \right ) \overline{\Delta \qb}_i \right ]
       \right \} \rb_i^{(\nu)}
\end{equation}
Miller \& Colella rewrite the portion inside the $[\ldots]$
recognizing that (similar to M\&C Eq.\ 88, but for the $i+\myhalf,L$ interface):
\begin{equation}
  \qb_i^n + \frac{1}{2} \left (1 - \frac{\Delta t}{\Delta x} \lambda_i^{(\nu)} \right ) \overline{\Delta \qb}_i
  \approx \frac{1}{\lambda \Delta t} \int_{x_{i+\myhalf} - \lambda \Delta t}^{x_{i+\myhalf}}
           \qb(x) dx
\end{equation}
where $\qb(x)$ is the reconstructed functional form of $\qb$ in the zone.

\begin{exercise}[The average state reacting the interface]
{Show that this is exactly true for a linear reconstruction of $\qb(x)$, i.e.,
$\qb(x) = \qb_i + (\partial \qb/\partial x) (x - x_i)$.}
\end{exercise}

\noindent The integral on the right represents the average of $\qb$ that
can reach the right interface of the cell $i$ over timestep $\Delta
t$, moving at the wavespeed $\lambda$.  This suggests that we can
replace the linear reconstruction of $\qb$ with a parabolic one, and
keep our expressions for the interface states.

% figure made by figures/Euler/ppm-trace.py
\begin{figure}
\centering
\includegraphics[width=3.5in]{ppm-trace}
\caption[Integration under the parabola profile for to an
  interface]{\label{fig:ppm_trace} Integration under the parabolic
  profile.  For each of the waves, $\sigma^\enu$ is the fraction of
  the cell that they cross in a timestep, and $\sigma^\enu \Delta x =
  \lambda^\enu \Delta t$ is the distance they can travel.  Here we are
  integrating under the parabola to the right interface of cell $i$ to
  define $\Ic_+^\enu$ (this is indicated by the shaded
  region).  The $\Ic_+^\enu$ carried by this wave will be
  added to those carried by the other waves to form the left state at
  interface $i+\myhalf$.}
\end{figure}

In particular, we define
\begin{equation}
\Ic_+^{(\nu)}(\qb_i) = \frac{1}{\sigma^{(\nu)} \Delta x} \int _{x_{i+\myhalf} - \sigma^{(\nu)} \Delta x}^{x_{i+\myhalf}} \qb(x) dx
\end{equation}
with $\sigma^{(\nu)} = |\lambda^{(\nu)}|\Delta t / \Delta x$ (see Almgren et
al. Eq. 31)  (see Figure~\ref{fig:ppm_trace}).  Then
\begin{equation}
\qb_{i+\myhalf,L}^{n+\myhalf} = \tilde{\qb}_+ -
   \sum_{\nu;\lambda^{(\nu)}\ge 0} \lb_i^{(\nu)} \cdot \left (
        \tilde{\qb}_+ - \Ic_+^{(\nu)}(\qb_i)
       \right ) \rb_i^{(\nu)}  \label{eq:ppmtrace}
\end{equation}
Miller \& Colella choose the reference state as
\begin{equation}
\tilde{\qb}_+ = \left \{ \begin{array}{cc}
       \Ic_+^{(+)}(\qb_i) & \mathrm{if~} u + c > 0 \\
       \qb_i                    & \mathrm{otherwise}
\end{array}
\right .
\end{equation}
where the superscript $(+)$ on $\Ic$ indicates that the
fastest eigenvalue ($\lambda^\evp = u + c$) is used.  This is similar in
spirit to Eq.~\ref{eq:qref}.  Note: in the original PPM paper, if the
wave is not approaching the interface, instead of using the
cell-average, $\qb_i$, they use the limit of the quadratic interpolant.
In contrast to the above, the Castro paper~\cite{almgren:2010} just
uses $\qb_i$ for the reference state regardless of whether the wave is
moving toward or away from the interface.  Note that if the system
were linear, then the choice of reference state would not matter.

To finish the reconstruction, we need to know the parabolic form
of $\qb(x)$.  Here, we do the reconstruction from the original PPM
paper:
\begin{equation}
\qb(x) = \qb_{-} + \xi(x) \left ( \Delta \qb + \qb_6 (1 - \xi(x) ) \right )
\end{equation}
with $\Delta \qb = \qb_+ - \qb_-$, and $\qb_-$, $\qb_+$ the values of the polynomial
on the left and right edges, respectively, of the current cell, and
\begin{equation}
\qb_6 \equiv 6 \left [ \qb_i - \frac{1}{2} (\qb_- + \qb_+) \right ]
\end{equation}
and
\begin{equation}
\xi(x) = \frac{x - x_{i-\myhalf}}{\Delta x}
\end{equation}

To complete the description, we need to determine the parameters of
the parabola.  The values of $\qb_-$ and $\qb_+$ are computed and limited
as described in the original PPM paper.  With this definition, we can
do the integral $\Ic_+$:
\begin{equation}
\Ic_+^{(\nu)}(\qb_i) = \qb_{+,i} - \frac{\sigma_i^{(\nu)}}{2}
   \left [ \Delta \qb_i - \qb_{6,i} \left ( 1 - \frac{2}{3} \sigma_i^{(\nu)} \right ) \right ]
\end{equation}
Figure~\ref{fig:ppm_trace} illustrates the process of integrating under
the parabolic profile.


\begin{exercise}[Conservative interpolation]
{Show that $\qb(x)$ is a conservative interpolant.  That is
\begin{equation}
\frac{1}{\Delta x} \int_{x_{i-\myhalf}}^{x_{i+\myhalf}} \qb(x) dx = \qb_i
\end{equation}
You can also see that the average over the left half of the zone is
$\qb_i -\frac{1}{4}\Delta \qb$ and the average over the right half of the
zone is $\qb_i + \frac{1}{4}\Delta \qb$.  This means that there are equal
areas between the integral and zone average on the left and right
sides of the zone.  This can be seen by looking at
Figure~\ref{fig:ppm}.  }
\end{exercise}

\begin{quote}
\noindent\makebox[\linewidth]{\rule{0.9\textwidth}{1pt}}
{\em Aside}:
Note that this characteristic projection of $\tilde{\qb}_+ -
\Ic_+^{(\nu)}$ is discussed in the original PPM paper in the
paragraph following their Eq.~3.5.  They do not keep things in this form
however, and instead explicitly multiply out the $l\cdot [\ldots] r$
terms to arrive at their Eq.~3.6.  For example, starting with
Eq.~\ref{eq:ppmtrace},
we can write the left velocity state as (leaving off the $i$
subscripts on the vectors):
\begin{equation}
u_{i+\myhalf,L}^{n+\myhalf} =
  \tilde{u}_+ - \sum_\nu \lb^{(\nu)} \cdot
      ( \tilde{\qb}_+ -  \Ic_+^{(\nu)}(\qb) )
    \underbrace{\rb^{(\nu)}}_{\begin{smallmatrix}\mathrm{only~the}\\ u~\mathrm{`slot'} \end{smallmatrix}}
\end{equation}
(where, as above, the $\sim$ indicates the reference state).
Here the $r$ eigenvector on the end is representative---we only pick
the row corresponding to $u$ in the $\qb$ vector (in our case, the
second row).

Putting in the eigenvectors and writing out the sum, we have:
\begin{align}
 u_{i+\myhalf,L}^{n+\myhalf} =
     \tilde{u}_+ &-
       \left ( \begin{array}{ccc}
                  0 & -\frac{\rho}{2c} & \frac{1}{2c^2} \end{array}
       \right )
    \left ( \begin{array}{c}
           \tilde{\rho}_+ - \Ic_+^\evm(\rho) \\
           \tilde{u}_+ - \Ic_+^\evm(u) \\
           \tilde{p}_+ - \Ic_+^\evm(p)
            \end{array} \right )
    {\color{mygray} \left ( \begin{array}{c}
           1  \\
           {\color{black} -c/\rho} \\
           c^2
    \end{array} \right ) } \nonumber \\
%
     &-\left ( \begin{array}{ccc}
                  1 & 0 & -\frac{1}{c^2} \end{array}
       \right )
    \left ( \begin{array}{c}
           \tilde{\rho}_+ - \Ic_+^\evz(\rho) \\
           \tilde{u}_+ - \Ic_+^\evz(u) \\
           \tilde{p}_+ - \Ic_+^\evz(p)
            \end{array} \right )
    {\color{mygray} \left ( \begin{array}{c}
           1  \\
           {\color{black} 0} \\
           0
    \end{array} \right ) } \nonumber \\
%
    &-\left ( \begin{array}{ccc}
                  0 & \frac{\rho}{2c} & \frac{1}{2c^2} \end{array}
       \right )
    \left ( \begin{array}{c}
           \tilde{\rho}_+ - \Ic_+^\evp(\rho) \\
           \tilde{u}_+ - \Ic_+^\evp(u) \\
           \tilde{p}_+ - \Ic_+^\evp(p)
            \end{array} \right )
    {\color{mygray} \left ( \begin{array}{c}
           1  \\
           {\color{black} c/\rho} \\
           c^2
    \end{array} \right ) }
%
\end{align}
Here again we show the entire right eigenvector for illustration, but
only the element that comes into play is drawn in black.  This shows
that the second term is $0$---the contact wave does not carry a jump
in velocity.  Multiplying out $\lb^{(\nu)} \cdot (\tilde{\qb}_+ -
\Ic_+^{(\nu)})$ we have:
\begin{align}
u_{i+\myhalf,L}^{n+\myhalf} =
   \tilde{u}_+
  &- \frac{1}{2} \left [
      (\tilde{u}_+ - \Ic_+^\evm(u) ) -
       \frac{\tilde{p}_+ - \Ic_+^\evm(p)}{C} \right ] \nonumber \\
  &- \frac{1}{2} \left [
      (\tilde{u}_+ - \Ic_+^\evp(u) ) +
       \frac{\tilde{p}_+ - \Ic_+^\evp(p)}{C} \right ]
\label{eq:ufull}
\end{align}
where $C$ is the Lagrangian sound speed ($C = \sqrt{\gamma p \rho}$).
Defining
\begin{align}
\beta^\evp &= - \frac{1}{2C}
  \left [
      (\tilde{u}_+ - \Ic_+^\evp(u) ) +
       \frac{\tilde{p}_+ - \Ic_+^\evp(p)}{C} \right ] \\
%
\beta^\evm &= + \frac{1}{2C}
  \left [
      (\tilde{u}_+ - \Ic_+^\evm(u) ) -
       \frac{\tilde{p}_+ - \Ic_+^\evm(p)}{C} \right ]
\end{align}
we can write our left state as:
\begin{equation}
u_{i+\myhalf,L}^{n+\myhalf} =
   \tilde{u}_+ + C ( \beta^\evp - \beta^\evm)
\end{equation}
This is Eqs.~3.6 and 3.7 in the PPM paper.  Note that in their
construction appears to use the reference state in defining the
Lagrangian sound speed (in their $\beta$ expressions is written as
$\tilde{C}$).  This may follow from the comment before Eq.~3.6,
``modified slightly for the present application''.  Similarly,
the expressions for $\rho_L$ and $p_L$ can be written out. \\
\noindent\makebox[\linewidth]{\rule{0.9\textwidth}{1pt}}
\end{quote}

Similar expressions can be derived for the right state at the left interface
of the zone ($\qb_{i-\myhalf,R}^{n+\myhalf}$).  Here, the integral under the parabolic
reconstruction is done over the region of each wave that can reach the left
interface over our timestep:
\begin{equation}
\Ic_-^{(\nu)}(\qb) = \frac{1}{\sigma^{(\nu)} \Delta x}
  \int_{x_{i-\myhalf}}^{x_{i-\myhalf} + \sigma^{(\nu)} \Delta x} \qb(x) dx
\end{equation}
The right state at $i-\myhalf$ using zone $i$ data is:
\begin{equation}
\qb_{i-\myhalf,R}^{n+\myhalf} = \tilde{\qb}_- - \sum_{\nu; \lambda_\nu \le 0}
   \lb_i^{(\nu)} \cdot \left ( \tilde{\qb}_- - \Ic_-^{(\nu)}(\qb_i) \right ) \rb_i^{(\nu)}
\end{equation}
where the reference state is now:
\begin{equation}
\tilde{\qb}_- = \left \{ \begin{array}{cc}
   \Ic_-^{(-)}(\qb_i) & \mathrm{if~} u - c < 0 \\
    \qb_i                   & \mathrm{otherwise}
\end{array} \right .
\end{equation}
where the $(-)$ superscript on $\Ic$ indicates that the most
negative eigenvalue $(\lambda^- = u - c)$ is used.  The integral
$\Ic_-^{(\nu)}(\qb)$ can be computed analytically by
substituting in the parabolic interpolant, giving:
\begin{equation}
\Ic_-^{(\nu)}(\qb_i) = \qb_{-,i} + \frac{\sigma_i^{(\nu)}}{2}
   \left [ \Delta \qb_i + \qb_{6,i} \left ( 1 - \frac{2}{3} \sigma_i^{(\nu)} \right ) \right ]
\end{equation}
This is equivalent to Eq.~31b in the Castro paper.

\subsubsection{New PPM limiters}

Recent work \cite{colellasekora} has formulated improved limiters for
PPM that do not clip the profiles at extrema.  This only changes the
limiting process in defining $\qb_+$ and $\qb_-$, and does not affect the
subsequent parts of the algorithm.


\subsection{Flattening and contact steepening}

  Shocks are self-steepening (this is how we
  detect them in the Riemann solver---we look for converging characteristics).
  This can cause trouble with the methods here, because the shocks may become
  too steep.

  Flattening is a procedure to add additional dissipation at shocks,
  to ensure that they are smeared out over $\sim 2$ zones.  The
  flattening procedure is a multi-dimensional operation that looks at
  the pressure and velocity profiles and returns a coefficient, $\chi
  \in [0,1]$ that multiplies the limited slopes.  The convention most
  sources use is that $\chi = 1$ means no flattening (the slopes are
  unaltered), while $\chi = 0$ means complete flattening---the slopes
  are zeroed, dropping us to a first-order method.
  See for example in Saltzman~\cite{saltzman:1994}.  Once the flattening
  coefficient is determined, the interface state is blended with the
  cell-centered value via:
  \begin{equation}
  \qb_{i+\myhalf,\{L,R\}}^{n+\myhalf} \leftarrow (1 - \chi) \qb_i + \chi \qb_{i+\myhalf,\{L,R\}}^{n+\myhalf}
  \end{equation}

  Note that the flattening algorithm increases the stencil size of
  piecewise-linear and piecewise-parabolic reconstruction to 4 ghost cells
  on each side.  This is because the flattening procedure itself looks
  at the pressure 2 zones away, and we need to construct the flattening
  coefficient in both the first ghost cell (since we need the interface
  values there) and the second ghost cell (since the flattening procedure
  looks at the coefficients in its immediate upwinded neighbor).

  In contrast to shocks, contact waves
  do not steepen (they are associated with the middle characteristic
  wave, and the velocity does not change across that, meaning there
  cannot be any convergence).  The original PPM
  paper advocates a contact steepening method to artificially steepen
  contact waves.  While it shows good results in 1-d, it can be
  problematic in multi-dimensions.

  Overall, the community seems split over whether this term should be
  used.  Many people advocate that if you reach a situation where you
  think contact steepening may be necessary, it is more likely that
  the issue is that you do not have enough resolution.


\subsection{Limiting on characteristic variables}

Some authors (see for example, \cite{athena} Eqs.~37, 38) advocate
limiting on the characteristic variables rather than the primitive
variables.  The characteristic slopes for the quantity carried by the
wave $\nu$ can be found from the primitive variables
as: 
%
\begin{equation} 
\Delta w^{(\nu)} = \lb^{(\nu)} \cdot \Delta \qb 
\end{equation} 
%
any limiting would then be done to $\Delta w^{(\nu)}$ and the limited
primitive variables would be recovered as:
\begin{equation}
  \overline{\Delta \qb} = \sum_\nu \overline{\Delta w}^{(\nu)}
  \rb^{(\nu)} 
\end{equation} 
(here we use an overline to indicate limiting).

This is attractive because it is more in the spirit of the linear
advection equation and the formalism that was developed there.  A
potential downside is that when you limit on the characteristic
variables and convert back to the primitive, the primitive variables
may now fall outside of valid physical ranges (for example, negative
density).



%-----------------------------------------------------------------------------
\section{Riemann solvers}


Once the interface states are created, the Riemann solver is called.  This
returns the solution at the interface:
\begin{equation}
\qb_{i+\myhalf}^{n+\myhalf} = \mathcal{R}(\qb_{i+\myhalf,L}^{n+\myhalf}, \qb_{i+\myhalf,R}^{n+\myhalf})
\end{equation}
This is done for every interface, as illustrated in Figure~\ref{fig:euler:multiple_interfaces}.

% figure drawn with figures/Euler/multiple_interfaces.py
\begin{figure}
\centering
\includegraphics[width=\linewidth]{multiple_interfaces}
\caption[Riemann wave structure at each interface]{\label{fig:euler:multiple_interfaces}
  The Riemann wave structure resulting from the separate Riemann problems at each interface.  For each
  interface, we find the state on the interface and use this to evaluate the flux through the interface.} 
\end{figure}

As discussed in \S~\ref{Euler:riemann:solution}, we need to determine
which state is on our interface to compute the fluxes through the
interface.  The full solution of the Riemann problem can be quite expensive,
so in practice, approximate Riemann solvers are used to speed
the computation.  Different Riemann solvers
will have different approximations for finding the speeds of the left,
center, and right wave, and evaluating the star state.  In the `star'
region, only $\rho$ jumps across the middle (contact) wave, the
pressure and velocity are constant across that wave (see $\rb^\evz$).
We determine the state in the star region ($\rho_l^*, \rho_r^*, u^*,
p^*$) by using the jump conditions for the Euler equations or the
Riemann invariants, as shown in \S~\ref{Euler:riemann:starstate}.
Some approximate Riemann solvers assume that both waves are shocks or
both are rarefactions, aimplying the form of the equation that
must be solved to find $p_\star$.

Two-shock solvers, like the one in \cite{colellaglaz:1985} are quite
common in astrophyiscs.  Figure~\ref{fig:euler:riemann-2shock-curve}
shows the Hugoniot curves for the Sod problem under the 2-shock
assumption---they are quite close to those for the true solution.  To
further save on cost, approximate Riemann solvers for general
equations of state often include additional thermodynamic information
at the interfaces that overconstrains the system, but can remove the
need to call an expensive equation of state routine in solving for the
star state.


\begin{figure}[t]
\centering
\includegraphics[width=0.9\linewidth]{riemann-2shock-sod-phase}
\caption[The approximate (2-shock) Hugoniot curves corresponding to
  the Sod problem]{\label{fig:euler:riemann-2shock-curve} The
  approximate Hugoniot curves under the 2-shock approximation
  corresponding to the Sod problem.  Also shown as the gray dotted
  line is the exact Hugoniot curves (compare to
  Figure~\ref{fig:euler:riemann-curve}).  We see that the 2-shock
  approximation does a reasonable job near the intersection and only
  diverges significantly for small $p$ (which is where the solution
  should really be a
  rarefaction).\\ 
  \hydroexdoit{\href{https://github.com/zingale/hydro_examples/blob/master/compressible/riemann-2shock.py}{riemann-2shock.py}}}
\end{figure}

An additional approximation concerns rarefactions.  Recall that a
rarefaction involves diverging flow---it spreads out with time.
Special consideration needs to be taken if the rarefaction wave spans
the interface (a {\em transonic rarefaction},
\S~\ref{Euler:riemann:solution}).  In this case, most approximate
Riemann solvers simply linearly interpolate between the left or right
state and the appropriate star state instead of solving for the
structure inside the rarefaction.

With this approximate state, the fluxes are computed as:
\begin{equation}
\renewcommand{\arraystretch}{1.5}
\Fb_{i+\myhalf}^{n+\myhalf} = \left ( \begin{array}{c}
                             \rho_{i+\myhalf}^{n+\myhalf} u_{i+\myhalf}^{n+\myhalf} \\
                             \rho_{i+\myhalf}^{n+\myhalf} (u_{i+\myhalf}^{n+\myhalf})^2 + p_{i+\myhalf}^{n+\myhalf} \\
                             u_{i+\myhalf}^{n+\myhalf} p_{i+\myhalf}^{n+\myhalf} / (\gamma - 1)  +
                             \frac{1}{2} \rho_{i+\myhalf}^{n+\myhalf} (u_{i+\myhalf}^{n+\myhalf})^3 +
                             u_{i+\myhalf}^{n+\myhalf} p_{i+\myhalf}^{n+\myhalf}
                            \end{array} \right )
\renewcommand{\arraystretch}{1.0}
\end{equation}

A different class of approximate Riemann solvers (the HLL family)
approximate the fluxes directly instead of approximating the state
first.  These require estimates of the wave speeds, and care must be
taken to ensure those estimates are valid for a general equation of
state.  These wave speeds are then used together with the
Rankine-Hugoniot jump conditions to give the fluxes.


%-----------------------------------------------------------------------------
\section{Conservative update}

Once we have the fluxes, the conservative update is done as
\begin{equation}
\Uc^{n+1}_i = \Uc^n_i + \frac{\Delta t}{\Delta x} 
   \left ( \Fb_{i-\myhalf}^{n+\myhalf} - \Fb_{i+\myhalf}^{n+\myhalf} \right )
\end{equation}
The timestep, $\Delta t$ is determined by the time it takes for the
fastest wave to cross a single zone:
\begin{equation}
\Delta t < \min_d \left \{ \frac{\Delta x}{|\Ub \cdot {\bf e}_d| + c}\right \}
\end{equation}
(This is the limit for the CTU unsplit scheme here, but see the discussion
in \S~\ref{sec:adv:timestep}).

Often simulation codes will further restrict the timestep.  Commonly
used restrictions for pure hydrodynamics include a limit on the factor
by which a timestep can grow from one step to the next (a typical
value is $1.2$), and an initial scaling, say of 1/10, for the first
timestep.  Together, these will force the code to take a few initial
steps before working up to the CFL limit.

\subsection{Artificial viscosity}

Colella and Woodward argue that behind slow-moving shocks these
methods can have oscillations.  The fix they propose is to use some
artificial viscosity---this is additional dissipation that kicks in at
shocks.  (They argue that flattening alone is not enough).

We use a multidimensional analog of their artificial viscosity
(\cite{colellawoodward:1984}, Eq.\ 4.5) which modifies the fluxes.  By
design, it only kicks in for converging flows, such that you would
find around a shock.


%-----------------------------------------------------------------------------
\section{Boundary conditions}

Boundary conditions are implemented through ghost cells.  The following
are the most commonly used boundary conditions.  For the expressions
below, we use the subscript $\mathrm{lo}$ to denote the spatial index
of the first valid zone in the domain (just inside the left boundary).

\begin{itemize}

\item {\em Outflow}: the idea here is that the flow should gracefully
  leave the domain.  The simplest form is to simply give all variables
  a zero-gradient:
  \begin{equation}
  \left ( \begin{array}{c} \rho_{\mathrm{lo-1},j} \\
                           (\rho u)_{\mathrm{lo-1},j} \\
                           (\rho v)_{\mathrm{lo-1},j} \\
                           (\rho E)_{\mathrm{lo-1},j} \end{array} \right ) =
  \left ( \begin{array}{c} \rho_{\mathrm{lo},j} \\
                           (\rho u)_{\mathrm{lo},j} \\
                           (\rho v)_{\mathrm{lo},j} \\
                           (\rho E)_{\mathrm{lo},j} \end{array} \right )
  \end{equation}

  Note that these boundaries are not perfect.  At the boundary, one
  (or more) of the waves from the Riemann problem can still enter
  the domain.  Only for supersonic flow, do all waves point outward.


\item {\em Reflect}: this is appropriate at a solid wall or symmetry
  plane.  All variables are reflected across the boundary, with the
  normal velocity given the opposite sign.  At the $x$-boundary, the
  first ghost cell is:
  \begin{equation}
  \left ( \begin{array}{c} \rho_{\mathrm{lo-1},j} \\
                           (\rho u)_{\mathrm{lo-1},j} \\
                           (\rho v)_{\mathrm{lo-1},j} \\
                           (\rho E)_{\mathrm{lo-1},j} \end{array} \right ) =
  \left ( \begin{array}{c} \rho_{\mathrm{lo},j} \\
                           -(\rho u)_{\mathrm{lo},j} \\
                           (\rho v)_{\mathrm{lo},j} \\
                           (\rho E)_{\mathrm{lo},j} \end{array} \right )
  \end{equation}
  The next is:
  \begin{equation}
  \left ( \begin{array}{c} \rho_{\mathrm{lo-2},j} \\
                           (\rho u)_{\mathrm{lo-2},j} \\
                           (\rho v)_{\mathrm{lo-2},j} \\
                           (\rho E)_{\mathrm{lo-2},j} \end{array} \right ) =
  \left ( \begin{array}{c} \rho_{\mathrm{lo+1},j} \\
                           -(\rho u)_{\mathrm{lo+1},j} \\
                           (\rho v)_{\mathrm{lo+1},j} \\
                           (\rho E)_{\mathrm{lo+1},j} \end{array} \right )
  \end{equation}
  and so on $\ldots$


  \item {\em Inflow}: inflow boundary conditions specify the state
    directly on the boundary.  Technically, this state is on the
    boundary itself, not the cell-center.  This can be accounted for
    by modifying the stencils used in the reconstruction near inflow
    boundaries.

  \item {\em Hydrostatic}: a hydrostatic boundary can be used at the
    base of an atmosphere to provide the pressure support necessary to
    hold up the atmosphere against gravity while still letting
    acoustic waves pass through.  An example of this is described
    in \cite{hse}.

\end{itemize}


%-----------------------------------------------------------------------------
\section{Multidimensional problems}

The multidimensional case is very similar to the multidimensional
advection problem.  Our system of equations is now:
\begin{equation}
\Uc_t + [\Fb^{(x)}(\Uc)]_x + [\Fb^{(y)}(\Uc)]_y = 0
\end{equation}
with
\begin{equation}
\Uc = \left ( \begin{array}{c} \rho \\ \rho u \\ \rho v \\ \rho E \end{array} \right )
%
\qquad
%
\Fb^{(x)}(\Uc) = \left ( \begin{array}{c} \rho u \\ \rho uu + p \\ \rho v u \\ \rho u E + up \end{array} \right )
%
\qquad
\Fb^{(y)}(\Uc) = \left ( \begin{array}{c} \rho v \\ \rho vu     \\ \rho v v + p \\ \rho v E + vp \end{array} \right )
\end{equation}

We note that there is no transformation that can convert the multidimensional
system into characteristic variables, since we cannot simultaneously
diagonalize the Jacobians corresponding to $\Fb^{(x)}$ and $\Fb^{(y)}$.  Related
to this is that when limiting, we limit one-dimensional slopes instead of
doing a full multidimensional reconstruction and limiting (see \cite{BDS}
for a multidimensional limiting procedure for linear advection.  For
the Euler equations, since we cannot write the multidimensional system
in a characteristic form, we cannot use this type of method).

For a directionally-unsplit discretization, we predict the
cell-centered quantities to the edges by Taylor expanding the
conservative state, $\Uc$, in space and time.  Now, when replacing the
time derivative ($\partial \Uc/\partial t$) with the divergence of the
fluxes, we gain a transverse flux derivative term.  For example,
predicting to the upper $x$ edge of zone $i,j$, we have:
\begin{align}
\Uc_{i+\myhalf,j,L}^{n+\myhalf} &= \Uc_{i,j}^n + \frac{\Delta x}{2} \frac{\partial \Uc}{\partial x}
                            + \frac{\Delta t}{2} \frac{\partial \Uc}{\partial t} + \ldots \\
&= \Uc_{i,j}^n + \frac{\Delta x}{2} \frac{\partial \Uc}{\partial x}
                            - \frac{\Delta t}{2} \frac{\partial \Fb^{(x)}}{\partial x}
                            - \frac{\Delta t}{2} \frac{\partial \Fb^{(y)}}{\partial y} \\
&= \Uc_{i,j}^n + \frac{1}{2} \left [ 1 - \frac{\Delta t}{\Delta x} \Ab^{(x)}(\Uc) \right ] \Delta \Uc
                            - \frac{\Delta t}{2} \frac{\partial \Fb^{(y)}}{\partial y} \label{eq:Utaylorstate}
\end{align}
where $\Ab^{(x)}(\Uc) \equiv \partial \Fb^{(x)} / \partial \Uc$.  We decompose
this into a {\em normal state} and a {\em transverse flux difference}.
Adopting the notation from Colella (1990), we use $\hat{\Uc}$ to denote
the normal state:
\begin{align}
\hat{\Uc}_{i+\myhalf,j,L}^{n+\myhalf} &\equiv \Uc_{i,j}^n
      + \frac{1}{2} \left [ 1 - \frac{\Delta t}{\Delta x} \Ab^{(x)}(\Uc) \right ] \Delta \Uc \\
\Uc_{i+\myhalf,j,L}^{n+\myhalf} &= \hat{\Uc}_{i+\myhalf,j,L}^{n+\myhalf}
                            - \frac{\Delta t}{2} \frac{\partial \Fb^{(y)}}{\partial y}  \label{eq:fullleftstate}
\end{align}

The primitive variable form for this system is
\begin{equation}
\qb_t + \Ab^{(x)}(\qb) \qb_x + \Ab^{(y)}(\qb) \qb_y = 0
\end{equation}
where
\begin{equation}
\qb = \left ( \begin{array}{c} \rho \\ u \\ v \\ p \end{array} \right )
%
\qquad
\Ab^{(x)}(\qb) = \left ( \begin{array}{cccc} u  & \rho     & 0 &  0 \\
                                         0  &  u       & 0 &  1/\rho \\
                                         0  &  0       & u &  0 \\
                                         0  & \gamma p & 0 &  u \end{array} \right )
\qquad
\Ab^{(y)}(\qb) = \left ( \begin{array}{cccc} v  & 0 & \rho &  0 \\
                                         0  & v & 0    &  0 \\
                                         0  & 0 & v    &  1/\rho \\
                                         0  & 0 & \gamma p & v \end{array} \right )
\end{equation}
There are now 4 eigenvalues.  For $\Ab^{(x)}(\qb)$, they are $u-c$, $u$,
$u$, $u+c$.  If we just look at the system for the $x$ evolution, we
see that the transverse velocity (in this case, $v$) just advects with
velocity $u$, corresponding to the additional eigenvalue.
\begin{exercise}[Eigenvectors for the 2-d Euler equations]
{
Derive the form of $\Ab^{(x)}(\qb)$ and $\Ab^{(y)}(\qb)$ and find their left and right eigenvectors.}
\end{exercise}

We note here that $\hat{\Uc}_{i+\myhalf,j,L}^{n+\myhalf}$ is essentially
one-dimensional, since only the $x$-fluxes are involved (through
$\Ab^{(x)}(\Uc)$).  This means that we can compute this term using the
one-dimensional techniques developed in \S~\ref{sec:onedrecon}.  In
particular, Colella (1990) suggest that we switch to primitive variables
and compute this as:
\begin{equation}
\hat{\Uc}_{i+\myhalf,j,L}^{n+\myhalf} = \Uc(\hat{\qb}_{i+\myhalf,j,L}^{n+\myhalf})
\end{equation}
Similarly, we consider the system projected along the $y$-direction to
define the normal states on the $y$-edges, again using the one-dimensional
reconstruction on the primitive variables from \S~\ref{sec:onedrecon}:
\begin{equation}
\hat{\Uc}_{i,j+\myhalf,L}^{n+\myhalf} = \Uc(\hat{\qb}_{i,j+\myhalf,L}^{n+\myhalf})
\end{equation}

To compute the full interface state (Eq.~\ref{eq:fullleftstate}), we
need to include the transverse term.
Colella (1990) gives two different procedures for evaluating the
transverse fluxes.  The first is to simply use the cell-centered
$\Uc_{i,j}$ (Colella 1990,
Eq. 2.13); the second is to use the reconstructed normal states (the
$\hat{\Uc}$'s) (Eq. 2.15).  In both cases, we need to solve a {\em
  transverse Riemann problem} to find the true state on the transverse
interface.  This latter approach is what we prefer.  In particular,
for computing the full $x$-interface left state, $\Uc_{i+\myhalf,j,L}^{n+\myhalf}$, we need the
transverse ($y$) states, which we define as
\begin{align}
\Uc^T_{i,j+\myhalf} &= \mathcal{R}(\hat{\Uc}^{n+\myhalf}_{i,j+\myhalf,L},
                            \hat{\Uc}^{n+\myhalf}_{i,j+\myhalf,R}) \\
\Uc^T_{i,j-\myhalf} &= \mathcal{R}(\hat{\Uc}^{n+\myhalf}_{i,j-\myhalf,L},
                            \hat{\Uc}^{n+\myhalf}_{i,j-\myhalf,R})
\end{align}

Taken together, the full interface state is now:
\begin{equation}
\Uc_{i+\myhalf,j,L}^{n+\myhalf} = \Uc(\hat{\qb}_{i+\myhalf,j,L}^{n+\myhalf})
   - \frac{\Delta t}{2} \frac{\Fb^{(y)}(\Uc^T_{i,j+\myhalf}) - \Fb^{(y)}(\Uc^T_{i,j-\myhalf})}{\Delta y}
\end{equation}

The right state at the $i+\myhalf$ interface can be similarly computed (starting with the
data in zone $i+1,j$ and expanding to the left) as:
\begin{equation}
\Uc_{i+\myhalf,j,R}^{n+\myhalf} = \Uc(\hat{\qb}_{i+\myhalf,j,R}^{n+\myhalf})
   - \frac{\Delta t}{2} \frac{\Fb^{(y)}(\Uc^T_{i+1,j+\myhalf}) - \Fb^{(y)}(\Uc^T_{i+1,j-\myhalf})}{\Delta y}
\end{equation}
Note the indices on the transverse states---they are now to the right of the interface (since
we are dealing with the right state).

We then find the $x$-interface state by solving the Riemann problem
normal to our interface:
\begin{equation}
\Uc_{i+\myhalf,j}^{n+\myhalf} = \mathcal{R}(\Uc_{i+\myhalf,j,L}^{n+\myhalf}, \Uc_{i+\myhalf,j,R}^{n+\myhalf})
\end{equation}
Therefore, construction of the interface states now requires two
Riemann solves: a transverse and normal one.  The fluxes are then evaluated as:
\begin{equation}
\Fb^{(x),n+\myhalf}_{i+\myhalf,j} = \Fb^{(x)}(\Uc_{i+\myhalf,j}^{n+\myhalf})
\end{equation}
Note, for multi-dimensional problems, in the Riemann solver, the transverse
velocities are simply selected based on the speed of the contact, giving
either the left or right state.

The final conservative update is done as:
\begin{equation}
\Uc^{n+1}_{i,j} = \Uc^n_{i,j}
   + \frac{\Delta t}{\Delta x} \left ( \Fb^{(x),n+\myhalf}_{i-\myhalf,j} - \Fb^{(x),n+\myhalf}_{i+\myhalf,j} \right )
   + \frac{\Delta t}{\Delta y} \left ( \Fb^{(y),n+\myhalf}_{i,j-\myhalf} - \Fb^{(y),n+\myhalf}_{i,j+\myhalf} \right )
\end{equation}



\subsection{3-d unsplit}

The extension of the unsplit methodology to 3-d is described by
Saltzman~\cite{saltzman:1994}.  The basic idea is the same as in 2-d,
except now additional transverse Riemann solve are needed to fully
couple in the corners.


\section{Source terms}
\label{euler:sec:sourceterms}

Adding source terms is straightforward.  For
a system described by
\begin{equation}
\Uc_t + [\Fb^{(x)}(\Uc)]_x + [\Fb^{(y)}(\Uc)]_y = \Hb
\end{equation}
we predict to the edges in the same fashion as described above, but now
when we replace $\partial \Uc/\partial t$ with the divergence of the
fluxes, we also pick up the source term.  This appears as:
\begin{align}
\Uc_{i+\myhalf,j,L}^{n+\myhalf} &= \Uc_{i,j}^n
            + \frac{\Delta x}{2} \frac{\partial \Uc}{\partial x}
            + \frac{\Delta t}{2} \frac{\partial \Uc}{\partial t} + \ldots \\
&= \Uc_{i,j}^n + \frac{\Delta x}{2} \frac{\partial \Uc}{\partial x}
              - \frac{\Delta t}{2} \frac{\partial \Fb^{(x)}}{\partial x}
              - \frac{\Delta t}{2} \frac{\partial \Fb^{(y)}}{\partial y}
              + \frac{\Delta t}{2} \Hb_{i,j} \\
&= \Uc_{i,j}^n
 + \frac{1}{2} \left [1 -\frac{\Delta t}{\Delta x} \Ab^{(x)}(\Uc)\right ] \Delta \Uc
 - \frac{\Delta t}{2} \frac{\partial \Fb^{(y)}}{\partial y}
 + \frac{\Delta t}{2} \Hb_{i,j}
  \label{eq:Utaylorstatesource}
\end{align}
We can compute things as above, but simply add the source term to the
$\hat{\Uc}$'s and carry it through.

Note that the source here is cell-centered.  This expansion is
second-order accurate.  This is the approach outlined in Miller
\& Colella \cite{millercolella:2002}.  Also notice the 
similarity of this source term to a second-order Euler method
for integrating ODEs.

Alternately, we can include the source terms in the characteristic
tracing of the interface states.  This is the approach taken in, e.g.,
the original PPM paper.  To make things more concrete, let's consider just
gravity as the source.  Our primitive variable equations in this case are:
\begin{equation}
\qb_t + \Ab(\qb) \qb_x = \Gb
\end{equation}
where $\Gb = (0, g, 0)^T$---i.e. the gravitational source only affects
$u$, not $\rho$ or $p$\footnote{Note that in the PPM paper, they put $\Gb$ on
the lefthand side of the primitive variable equation, so our signs are
opposite.}.

First we construct a parabolic profile of $g$ in each zone and
integrate under that profile to determine the average $g$ carried by
each wave to the interface, we'll denote these as $\Ic^\enu_\pm(g)$.  Then we include the gravitational source
term in the characteristic projection itself.  Our projections are
now:
\begin{equation}
\sum_{\nu; \lambda^\enu \ge 0}\lb^\enu \cdot (\tilde{\qb} - \Ic^\enu_+(\qb) - \tfrac{\Delta t}{2} \Gb) \rb^\enu
\end{equation}
for the left state, and
\begin{equation}
\sum_{\nu; \lambda^\enu \le 0} \lb^\enu \cdot (\tilde{\qb} - \Ic^\enu_-(\qb) - \tfrac{\Delta t}{2} \Gb) \rb^\enu
\end{equation}
for the right state.  Since $\Gb$ is only non-zero for velocity, only
the velocity changes.  Writing out the sum (and performing the vector products), we
get:
\begin{align}
u_{i+\myhalf,L}^{n+\myhalf} =
   \tilde{u}_+
  &- \frac{1}{2} \left [
      \left (\tilde{u}_+ - \Ic_+^\evm(u) - \frac{\Delta t}{2} \Ic^\evm_+(g) \right ) -
       \frac{\tilde{p}_+ - \Ic_+^\evm(p)}{C} \right ] \nonumber \\
  &- \frac{1}{2} \left [
      \left (\tilde{u}_+ - \Ic_+^\evp(u) - \frac{\Delta t}{2} \Ic^\evp_+(g) \right ) +
       \frac{\tilde{p}_+ - \Ic_+^\evp(p)}{C} \right ]
\end{align}
where the only change from Eq.~\ref{eq:ufull} are the
$\Ic^\evm_+(g)$ and $\Ic^\evp_+(g)$ terms.
\footnote{These differ from the expression in the PPM paper, where $\Delta t \Gb$,
not $(\Delta t/2) \Gb$ is used in the projection, however this appears to
be a typo.  To see this, notice that if both waves are moving toward
the interface, then the source term that is added to the interface
state is $(\Delta t/4) (\Ic_+^\evm(g) +
\Ic_+^\evp(g))$ for the left state, which reduces to $(\Delta
t/2) g$ for constant g---this matches the result from the Taylor
expansion above (Eq.~\ref{eq:Utaylorstatesource}).}

Regardless of how the source term information is included in the
interface states, we also need to include it in the conservative
update.  To second-order, we need it to be time-centered, which
usually means averaging the time-level $n$ and $n+1$ sources:
\begin{align}
\Uc^{n+1}_{i,j} = \Uc^n_{i,j}
   &+ \frac{\Delta t}{\Delta x} \left ( \Fb^{(x),n+\myhalf}_{i-\myhalf,j} - \Fb^{(x),n+\myhalf}_{i+\myhalf,j} \right ) \nonumber \\
   &+ \frac{\Delta t}{\Delta y} \left ( \Fb^{(y),n+\myhalf}_{i,j-\myhalf} - \Fb^{(y),n+\myhalf}_{i,j+\myhalf} \right ) + \frac{\Delta t}{2} \left (\Hb(\Uc^n_{i,j}) + \Hb(\Uc^{n+1}_{i,j})\right )
\end{align}
As written, this appears to be an implicit update (since $\Uc^{n+1}$
depends on $\Hb^{n+1}$), but often, the form of the source terms allows
you to update the equations in sequence explicitly.  

Again, using a constant gravitational acceleration as an example, and
looking in 1-d for simplicity, $\Uc = (\rho, \rho u, \rho E)^\intercal$
and $\Hb = (0, \rho g, \rho u g)^\intercal$, so our update sequence is:
\begin{align}
\rho^{n+1}_i = \rho^n_i &+ \frac{\Delta t}{\Delta x} 
   \left [\rho_{i-\myhalf}^{n+\myhalf} u_{i-\myhalf}^{n+\myhalf} - 
          \rho_{i+\myhalf}^{n+\myhalf} u_{i+\myhalf}^{n+\myhalf} \right ] \\
(\rho u)^{n+1}_i = (\rho u)^n_i &+ \frac{\Delta t}{\Delta x} 
   \left [ \rho_{i-\myhalf}^{n+\myhalf} (u_{i-\myhalf}^{n+\myhalf})^2  - 
           \rho_{i+\myhalf}^{n+\myhalf} (u_{i+\myhalf}^{n+\myhalf})^2  \right ]
         + \frac{\Delta t}{\Delta x} \left ( p_{i-\myhalf}^{n+\myhalf} - 
                                              p_{i+\myhalf}^{n+\myhalf} \right ) \nonumber \\
       &+ \frac{\Delta t}{2}(\rho^n_i + \rho^{n+1}_i) g \\
(\rho E)^{n+1}_i = (\rho E)^n_i &+ \frac{\Delta t}{\Delta x} 
   \left [ \left (\rho_{i-\myhalf}^{n+\myhalf} E_{i-\myhalf}^{n+\myhalf}  + p_{i-\myhalf}^{n+\myhalf} \right ) u_{i-\myhalf}^{n+\myhalf} - \right . \nonumber \\
   &\phantom{+ \frac{\Delta t}{\Delta x} \left[ \right.}   \left .   \left (\rho_{i+\myhalf}^{n+\myhalf} E_{i+\myhalf}^{n+\myhalf}  + p_{i+\myhalf}^{n+\myhalf} \right ) u_{i+\myhalf}^{n+\myhalf} \right ]
    + \frac{\Delta t}{2} \left [ (\rho u)^n + (\rho u)^{n+1} \right] g
\end{align}
These updates can be done one after another without any implicit
coupling.  Other sources, like the Coriolis force, will involve an
implicit update, but even then, it is local to a single zone and can
be solved analytically.

%-----------------------------------------------------------------------------
\section{Simple geometries}
\label{ch:euler:geom}

So far we have been working only with Cartesian geometries, but it is
easy to extend these methods to simple non-Cartesian geometies, like
spherical and cylindrical.  These geometies allow us to capture 3-d
volume expansion effects in lower dimensions.

For a 1-d solver, a spherical geometry means that our coordinate is
the radius in the sphere, and as we move outward from the origin, the
volume of a zone (which is actually now a spherical shell) grows.
There are two places where we need to take the geometry into account:
the reconstruction of the interface states and the conservative update.

Our 1-d system in spherical coordinates appears as:
\begin{equation}
\ddt{\Uc} + \frac{1}{r^2} \ddr{r^2 \Fb} = 0
\end{equation}
The geometry factors that appear are from the spherical form of the
divergence.  Expanding out the radial derivative, we have:
\begin{equation}
\ddt{\Uc} + \ddr{\Fb} = -\frac{2\Fb}{r}
\end{equation}
Likewise, the primitive variable equations now have source terms:
\begin{align}
\ddt{\rho} + u \ddx{\rho} + \rho \ddx{u} &= -\frac{2\rho u}{r} \\
\ddt{u} + u \ddx{u} + \frac{1}{\rho} \ddx{p} &= 0 \\
\ddt{p} + u \ddx{p} + \Gamma_1 p \ddx{u} &= -\frac{2\Gamma_1 p u}{r}
\end{align}

\begin{exercise}[Spherical form of primitive variable equations]
{Derive the above system of 1-d spherical primitive variable equations
  starting from the conservative equations.  Be sure to include the
  geometry factors everywhere there is a divergence.}
\end{exercise}

For the prediction of the interface states, we now include these
geometric source terms as sources to the interface state, following
the same ideas as in \S~\ref{euler:sec:sourceterms}.

The conservative update now needs to include the geometry factors.  However,
it is complicated by the fact that in the momentum equation, the pressure 
term is a gradient, not a divergence, and therefore has different 
geometic factors.  The update of the system appears as:
\begin{align}
\rho^{n+1}_i = \rho^n_i &+ \frac{\Delta t}{V_i} 
   \left [A_{i-\myhalf} \rho_{i-\myhalf}^{n+\myhalf} u_{i-\myhalf}^{n+\myhalf} - 
          A_{i+\myhalf} \rho_{i+\myhalf}^{n+\myhalf} u_{i+\myhalf}^{n+\myhalf} \right ] \\
(\rho u)^{n+1}_i = (\rho u)^n_i &+ \frac{\Delta t}{V_i} 
   \left [ A_{i-\myhalf} \rho_{i-\myhalf}^{n+\myhalf} (u_{i-\myhalf}^{n+\myhalf})^2  - 
           A_{i+\myhalf} \rho_{i+\myhalf}^{n+\myhalf} (u_{i+\myhalf}^{n+\myhalf})^2  \right ]\nonumber \\
        & + \frac{\Delta t}{\Delta r} \left ( p_{i-\myhalf}^{n+\myhalf} - 
                                              p_{i+\myhalf}^{n+\myhalf} \right ) \\
(\rho E)^{n+1}_i = (\rho E)^n_i &+ \frac{\Delta t}{V_i} 
   \left [ A_{i-\myhalf} \left (\rho_{i-\myhalf}^{n+\myhalf} E_{i-\myhalf}^{n+\myhalf}  + p_{i-\myhalf}^{n+\myhalf} \right ) u_{i-\myhalf}^{n+\myhalf} - \right . \nonumber \\
   &\phantom{+ \frac{\Delta t}{V_i} \left[ \right.}   \left .   A_{i+\myhalf} \left (\rho_{i+\myhalf}^{n+\myhalf} E_{i+\myhalf}^{n+\myhalf}  + p_{i+\myhalf}^{n+\myhalf} \right ) u_{i+\myhalf}^{n+\myhalf} \right ]
\end{align}
Here, the geometry factors are:
\begin{align}
A_{i-\myhalf} &= (r_{i-\myhalf})^2\\
V_i &= (r_i)^2 \Delta r
\end{align}

\begin{figure}
\centering
\includegraphics[width=0.8\linewidth]{axisymmetry}
\caption[The axisymmetric computational domain]
{\label{fig:axisymmetri} The axisymmetric computational domain.  Here we
  imagine that the 2-d plane rotates through the cylindrical $\theta$ angle to
  create a volume.}
\end{figure}

It is also common to do 2-d axisymmetric models---here the $r$ and $z$
coordinates from a cylindrical geometry are modeled.  Again, this
appears Cartesian, except there is a volume factor implicit in the
divergence that must be accounted for.  Our system in axisymmetric
coordinates\footnote{Some sources will call this cylindrical
  coordinates, but note that the grid is not a polar grid---it is
  still Cartesian} is:
\begin{equation}
\frac{\partial \Uc}{\partial t}
  + \frac{1}{r}\frac{\partial r \Fb^{(r)}}{\partial r}
  + \frac{\partial \Fb^{(z)}}{\partial z} = 0
\end{equation}
Expanding out the $r$ derivative, we can write this as:
\begin{equation}
\frac{\partial \Uc}{\partial t}
  + \frac{\partial \Fb^{(r)}}{\partial r}
  + \frac{\partial \Fb^{(z)}}{\partial z} = -\frac{\Fb^{(r)}}{r}
\end{equation}
Again, the primitive variable version of this expanded form is used
for the interface state prediction.  The conservative update
follows the same idea as the 1-d spherical version.  The area
and volume factors only differ from their Cartesian counterparts
in the radial direction, and take the form:
\begin{align}
A_{i-\myhalf,j} &= r_{i-\myhalf} \Delta z \\
A_{i,j-\myhalf} &= r_i \Delta z\\
V_{i,j} &= r_i \Delta r \Delta z
\end{align}
These choices of geometric factors reproduce a discretized
form of the cylindrical divergence:
\begin{equation}
\nabla \cdot {\boldsymbol{\phi}} = \frac{1}{r} \ddr{(r\phi^{(r)})} + \ddz{\phi^{(z)}}
\end{equation}
Just as with the 1-d spherical case, the pressure term in the momentum
equation needs to be treated separately from the flux, since it enters
as a gradient and not a divergence.\footnote{It is common to see the divergence
term expressed as 
\begin{equation}
\nabla \cdot {\boldsymbol{\phi}} = \frac{1}{r^\alpha} \ddr{(r^\alpha \phi^{(r)})} + \ldots
\end{equation}
where $\alpha = 1$ for axisymmetric and $\alpha = 2$ for 1-d
spherical.  This allows for the geometry correction to be expressed
more concisely, as the source term takes the form $-\alpha F/r$.  }


%-----------------------------------------------------------------------------
\section{Some Test problems}

There are a large number of standard test problems that are used to
test out our methods.  Like we say with advection, it is best to have
a problem with an analytic solution.  Here we show just a few of the most
popular test problems.

\subsection{Shock tubes}
\label{sec:euler-methods:shocktubes}

Shock tubes are Riemann problems---consider the evolution of an
initial discontinuity in the domain.  The evolution with time will
just be the solution to the Riemann problem that we described
\S~\ref{euler:sec:riemann}.  The initial conditions can be varied to
produce any combination of shocks and rarefactions as the left and
right waves.  A popular initial condition is the Sod
problem~\cite{sod:1978} which results is a right moving shock and
contact and a left moving rarefaction.

Note: it is a good test of your code's ability to preserve symmetry to
flip the initial conditions left/right and rerun.  The results should
be the same to machine precision, but atleast to roundoff error.  A
common reason for breaking symmetry is using inequalities in your code
that are biases in a direction, e.g.,
\begin{lstlisting}
if u > 0:
   # positive velocity test case
else:
   # negative or zero velocity test case
\end{lstlisting}
This has a left-right bias, since we don't handle the case where $u =
0$ separately.  A better construction would test on $u < 0$ alone, and
then have a final {\em else} clause to catch $u = 0$.

Since these tests start out with a discontinuity, they are not the
best tests to use for convergence testing.  Wherever there is an
initiali discontinuity, the limiters will kick in and drop your
method to first-order accurate.

For a general equation of state, you can still solve the Riemann
problem exactly and define analogous test problems to those commonly
used for a gamma-law gas.  Some shock tube test problems for a stellar
equation of state are shown in \cite{zingalekatz}.

For the tests shown below, we use the \hydrooned\ code described in
Appendix~\ref{app:hydro1d}.

\subsubsection{Sod problem}

The initial conditions for the Sod problem \cite{sod:1978} are:
\begin{align}
\rho_l &= 1      &  \rho_r &= 1/8 \nonumber \\
u_l   &= 0       &  u_r    &= 0   \\
p_l    &= 1      &  p_r    &= 1/10 \nonumber
\end{align}
usually with $\gamma = 1.4$\MarginPar{double check}

These result in a left wave moving contact and rightward moving
contact and shock.  The shock is not particularly strong, but this
problem is a nice demonstration of the types of hydrodynamic waves.

\begin{figure}[t]
\centering
\includegraphics[width=0.7\linewidth]{hydro1d_god_sod}
\caption[Piecewise constant reconstruction Sod problem]{\label{fig:Euler:sod:god} Piecewise constant reconstruction
  with the Sod problem, using 128 zones, $\cfl = 0.8$, and the CGF
  Riemann solver.  This was run with \hydrooned\ using the {\tt sod}
  problem setup, setting {\tt godunov\_type=0} and visualized with the
  {\tt sod\_compare.py} script there.}
\end{figure}

\begin{figure}[t]
\centering
\includegraphics[width=0.7\linewidth]{hydro1d_ppm_sod}
\caption[Piecewise parabolic reconstruction Sod problem]{\label{fig:Euler:sod:ppm} Piecewise parabolic reconstruction
  with the Sod problem, using 128 zones, $\cfl = 0.8$, and the CGF
  Riemann solver.  This was run with \hydrooned\ using the {\tt sod}
  problem setup, setting {\tt godunov\_type=2} and visualized with the
  {\tt sod\_compare.py} script there.}
\end{figure}


\subsubsection{Double rarefaction}

The double rarefaction problem starts with initially diverging flow
that creates a vacuum state in the middle.  The initial conditions (as
given in \cite{toro:1997} are
\begin{align}
\rho_l &= 1      &  \rho_r &= 1 \nonumber \\
u_l    &= -2.0   &  u_r    &= 2.0   \\
p_l    &= 0.4    &  p_r    &= 0.4 \nonumber
\end{align}


\begin{figure}[t]
\centering
\includegraphics[width=0.7\linewidth]{hydro1d_god_double_rare}
\caption[Piecewise constant reconstruction double rarefaction problem]{\label{fig:Euler:doublerare:god} Piecewise constant
  reconstruction with the double rarefaction problem, using 128 zones,
  $\cfl = 0.8$, and the CGF Riemann solver.  This was run with
  \hydrooned\ using the {\tt sod} problem setup, setting {\tt
    godunov\_type=0} and visualized with the {\tt sod\_compare.py}
  script there.}
\end{figure}

\begin{figure}[t]
\centering
\includegraphics[width=0.7\linewidth]{hydro1d_ppm_double_rare}
\caption[Piecewise constant reconstruction double rarefaction problem]{\label{fig:Euler:doublerare:ppm} Piecewise parabolic
  reconstruction with the double rarefaction problem, using 128 zones,
  $\cfl = 0.8$, and the CGF Riemann solver.  This was run with
  \hydrooned\ using the {\tt sod} problem setup, setting {\tt
    godunov\_type=2} and visualized with the {\tt sod\_compare.py}
  script there.}
\end{figure}


\subsection{Sedov blast wave}

The Sedov (or Sedov-Taylor) blast wave~\cite{sedov:1959} is a point
explosion---energy, $\mathcal{E}_\mathrm{expl}$, is placed at a point
in a uniform domain.  A spherical shockwave propagates outward,
evacuating the region in the center.  The Sedov problem also has an
analytic solution\footnote{See \cite{timmes_sedov_code} for a nice
  code to general the solutions}, and this problem is a good way of
testing out the geometric factors for 1-d spherical and 2-d
axisymmetric geometries.

\begin{figure}[t]
\centering
\includegraphics[width=0.7\linewidth]{hydro1d_sedov_1dsph}
\caption[1-d spherical Sedov problem]{\label{fig:Euler:sedov1d} 1-d Sedov explosion with
  piecewise parabolic reconstruction, using 128 zones (on $r \in
  [0,1]$), $\cfl = 0.8$, and the CGF Riemann solver.  This was run
  with \hydrooned\ using the {\tt sedov} problem setup and visualized
  with the {\tt sedov\_compare.py} script there.  The 1-d spherical
  geometry used makes this act as if it were a sphere.}
\end{figure}

The major difficulty with initializing the Sedov problem is
representing a point, where all the energy desposited, on the grid.
If you just initialize a singe zone, then the size of the point
changes as you change resolution.  Additionally, in 2- or 3-d
Cartesian coordinates, the point will be squared off.  A standard way
of initializing this (see, e.g., \cite{omang:2006}) is to imagine the
energy deposition inflating a region of radius $r_\mathrm{init}$ like
a balloon, resulting in an energy density, $E =
\mathcal{E}_\mathrm{expl}/V_\mathrm{init}$, where $V_\mathrm{init} =
4\pi r_\mathrm{init}^3/3$ for a spherical blast wave and
$V_\mathrm{init} = \pi r_\mathrm{init}^2$ for a cylindrical blast
wave. Then the pressure is
\begin{equation}
p = \frac{\mathcal{E}_\mathrm{expl}}{V_\mathrm{init}} (\gamma - 1)
\end{equation}


Figure~\ref{fig:Euler:sedov1d} shows the solution to the Sedov problem
in 1-d in a spherical geometry.  This is compared to the spherical
Sedov solution (solid line). There is good agreement in the position of the
shock and density and velocity profiles.  The pressure behind the shock
is a little low---this is likely an artifact of the initialization process.

In 2-d, we run the problem in Cartesian coordinates---this produces a cylindrical
blast wave.  Figure~\ref{fig:Euler:sedov2d} shows the solution in 2-d.
\begin{figure}[t]
\centering
\includegraphics[width=0.85\linewidth]{sedov_pyro}
\caption[2-d cylindrical Sedov problem]{\label{fig:Euler:sedov2d} 2-d Sedov explosion with
  piecewise linear reconstruction, using 128$^2$ zones (on $r \in
  [0,1]\times[0,1]$), $\cfl = 0.8$, and the HLLC Riemann solver.  This was run
  with \pyro\ as {\tt ./pyro.py compressible sedov inputs.sedov}.  An initial
  perturbation size of $r_\mathrm{init} = 0.01$ was used.}
\end{figure}
The density and pressure look very symmetric.  In the velocity magnitude
plot, we see an imprint of the grid along coordinate axes, and likewise
in the internal energy.  The bump in internal energy near the origin arises
because of the error in defining $e$ from $E$ and $U$.  We can produce an angle-averaged
profile of this and compare to the analytic solution, shown in Figure~\ref{fig:Euler:sedov2d_compare}.

\begin{figure}[t]
\centering
\includegraphics[width=0.75\linewidth]{sedov_compare}
\caption[2-d cylindrical Sedov problem]{\label{fig:Euler:sedov2d_compare} Angle-average 
  profile for the 2-d Sedov explosion from Figure~\ref{fig:Euler:sedov2d} shown
  with the analytic solution.  This was constructed using the {\tt sedov\_compare.py}
  script in \pyro.}
\end{figure}


\subsection{Advection}

We can run a simple advection test analogous to the tests we used in
Ch.~\ref{ch:advection}.  However, because we are now doing hydrodynamics,
we need to suppress the dynamics.  This is accomplished by putting the 
profile we want to advect in the density field and then put it in
pressure equilibrium by adjusting the internal energy.  For example, consider
a Gaussian profile.  We initialize the density as:
\begin{equation}
\rho = (\rho_1 - \rho_0) e^{-(x - x_c)^2/\sigma^2} + \rho_0
\end{equation}
To advect the profile to the right, we choose a constant velocity,
\begin{equation}
u = u_0
\end{equation}
and to suppress dynamics, we make the pressure constant,
\begin{equation}
p = p_0
\end{equation}
Finally, we compute the total energy as
\begin{equation}
\rho E = \frac{p}{\gamma - 1} + \frac{1}{2}\rho u^2
\end{equation}

\begin{figure}[t]
\centering
\includegraphics[width=0.7\linewidth]{advect_hydro1d}
\caption[Simple advection test]{\label{fig:Euler:advect:1d} Piecewise
  parabolic reconstruction with an advection test, using 128 zones,
  $\cfl = 0.8$, and the CGF Riemann solver.  A Gaussian profile was
  advected for 10 periods.  This was run with \hydrooned\ using the
  {\tt advect} problem setup and
  visualized with the {\tt advect\_compare.py} script there.}
\end{figure}

Figure~\ref{fig:Euler:advect:1d} shows an example of a Gaussian
profile advected for 10 periods.  The initial conditions used $\rho_0
= 10^{-3}$, $\rho_1 = 1$, $p_0 = 10^{-6}$, $u_0 = 1$, and $\sigma =
0.1$ (these coincide with the choices used in \cite{flash}).  The
non-zero value for the ambient density, $\rho_0$, ensures that any
quantities that are derived by dividing by density remain
well-defined.  The result is similar to what we saw when we considered
pure advection---the shape is mostly preserved, but the peak of the
Gaussian is clipped.

\subsection{Slow moving shock}

Slow moving (or stationary) shocks can be difficult to model, as
oscillations can be setup behind the shock (this is discussed a little
in \cite{colellawoodward:1984,leveque:2002}).  We can produce a slow
moving shock as a shock tube, and we can use the jump conditions 
across a shock that were derived for the Riemann problem to find the
conditions to setup a stationary (or slow-moving) shock.  

The speed of a right-moving shock was found (see
Eq.~\ref{eq:euler:shockspeedjump}) as:
\begin{equation}
S = u_r + c_r \left [ \left ( \frac{p_\star}{p_r} \right ) \frac{\gamma+1}{2\gamma} + \frac{\gamma-1}{2\gamma} \right ]^{\myhalf}
\end{equation}
We want $S = 0$, which allows us to express the pre-shock velocity, $u_r$, as:
\begin{equation}
u_r = -c_r \left [ \left ( \frac{p_\star}{p_r} \right ) \frac{\gamma+1}{2\gamma} + \frac{\gamma-1}{2\gamma} \right ]^{\myhalf}
\end{equation}
We have the freedom to choose the density and pressure ahead of the
shock, $\rho_r$ and $p_r$, which in turn gives us $c_r$.  Next, we can
pick the strength of the shock by choosing the jump in pressure,
$p_\star/p_r$.  Together, this allows us to compute $u_r$, and thus we
know the entire pre-shock state.  We can compute the post-shock state
(which was the star state when we discussed the Riemann problem) using
the jump conditions, Eqs.~\ref{eq:euler:shockrhojump} and
\ref{eq:euler:shockujump}.\footnote{The script
  \href{https://github.com/zingale/hydro_examples/blob/master/compressible/slow_shock.py}{\tt
    slow\_shock.py} will find the initial conditions to generate a
  stationary shock.}

For a pressure jump of 100 across a shock, the following conditions will
generate a stationary right-facing shock (with $\gamma = 1.4$):
\begin{align}
\rho_l &= 5.6698      &  \rho_r &= 1 \nonumber \\
u_l   &= -1.9336      &  u_r    &= -10.9636   \\
p_l    &= 100         &  p_r    &= 1 \nonumber
\end{align}

By adjusting the velocity of both the left and right state, we can
produce a strong shock that moves slowly across the grid.  For
instance, a shock with $S = 0.4$ results from
\begin{align}
\rho_l &= 5.6698      &  \rho_r &= 1 \nonumber \\
u_l   &= -1.5336      &  u_r    &= -10.5636   \\
p_l    &= 100         &  p_r    &= 1 \nonumber
\end{align}

\begin{figure}[t]
\centering
\includegraphics[width=0.7\linewidth]{slowshock}
\caption[1-d spherical Sedov problem]{\label{fig:Euler:slowshock:ppm} 1-d slow moving shock
  problem with
  piecewise parabolic reconstruction, using 128 zones (on $r \in
  [0,1]$), $\cfl = 0.8$, and the CGF Riemann solver.  This was run
  with \hydrooned\ using the {\tt sod} problem setup and visualized
  with the {\tt sod\_compare.py} script there.}
\end{figure}


\subsection{Two-dimensional Riemann problems}

Several different 2-d Riemann problems were introduced in
\cite{hydro_test_quad}, to explore the multi-dimensional
interactive of the different hydrodynamic waves.  These
problems initialize the 4 quadrants of the domain with different
states, and watch the ensuing evolution.  There are some
analytic estimates that can be compared to, but also these
tests can provide a means of assessing the symmetry of 
a code in the presence of complex flows.  We use the setup
corresponding to {\em configuration 3} in that paper (this
same setup is used in \cite{leveque:1997}).

\begin{figure}[t]
\centering
\includegraphics[width=0.85\linewidth]{quad}
\caption{\label{fig:Euler:quad} Two-dimensional Riemann problem
from \cite{hydro_test_quad}.}
\end{figure}

\ifdefined \debugmode
\subsection{Odd-even decoupling}

\subsection{Gresho vortex}

The Gresho vortex is a vortex in with a stabilizing pressure gradient
designed such that the overall structure is unchanging in time.  It
has a nice feature in that it allows you to set the Mach number of
the flow as one of the parameters.


\subsection{Hydrostatic equilibrium}

Hydrodynamics codes can have a difficult time keeping an atmosphere in
hydrostatic equilibrium.  This is because any departure from $\nabla p
= \rho {\bf g}$ due to truncation error in the method will be seen as an
acceleration by the momentum equation:
\begin{equation}
\rho \DDt{\Ub} = \rho {\bf g} - \nabla p
\end{equation}
The result will be growing velocities in the atmosphere, which can
overwhelm any signal in the flow that you are interested in studying.
Since this acceleration is driven by truncation error, higher
resolution will result in lower velocities.

% top of the star

% scale height resolved -- do uniform T atmosphere


%\subsection{Rayleigh-Taylor instability}

\fi


%-----------------------------------------------------------------------------
\section{Method of lines integration and higher order}
\label{sec:comp:mol}
Just like we explored with linear advection (\S~\ref{adv:sec:mol_2d}),
instead of doing the characteristic tracing, we could rely on the
integrator to do the work for us.


Discretizing our system in space leads to the following system:
\begin{equation}
\frac{d\Uc_{i,j}}{dt} = -\frac{\Fb^{(x)}(\Uc_{i+\myhalf,j}) - \Fb^{(x)}(\Uc_{i-\myhalf,j})}{\Delta x}
                      -\frac{\Fb^{(y)}(\Uc_{i,j+\myhalf}) - \Fb^{(y)}(\Uc_{i,j-\myhalf})}{\Delta y}
\end{equation}
Note that there is no time superscript in the $\Uc$ used to evaluate the
fluxes on the righthand side---we have not done any time
discretization yet.  Now we can use an ODE integrator to solve this system.

Consider
second-order Runge-Kutta.  We evaluate two slopes,
\begin{alignat}{3}
{\bf k}_1 &= \Delta t \bigg [ &-&\frac{\Fb^{(x)}(\Uc^n_{i+\myhalf,j})
                               - \Fb^{(x)}(\Uc^n_{i-\myhalf,j})}{\Delta x} \nonumber \\
    &\,                 &-&\frac{\Fb^{(y)}(\Uc^n_{i,j+\myhalf})
                               - \Fb^{(y)}(\Uc^n_{i,j-\myhalf})}{\Delta y} \bigg ] \\
{\bf k}_2 &= \Delta t \bigg [ &-&\frac{\Fb^{(x)}([\Uc^n + {\bf k}_\myhalf]_{i+\myhalf,j})
                               - \Fb^{(x)}([\Uc^n + {\bf k}_\myhalf]_{i-\myhalf,j})}{\Delta x} \nonumber \\
    &\,                 &-&\frac{\Fb^{(y)}([\Uc^n + {\bf k}_\myhalf]_{i,j+\myhalf})
                               - \Fb^{(y)}([\Uc^n + {\bf k}_\myhalf]_{i,j-\myhalf})}{\Delta y} \bigg ]
\end{alignat}
and then
\begin{equation}
\Uc^{n+1}_{i,j} = \Uc^n_{i,j} + {\bf k}_2
\end{equation}
In the construction of the interface states, $\Uc^n_{i+\myhalf,j}$ or $[\Uc^n
+ {\bf k}_\myhalf]_{i+\myhalf,j}$, there is no explicit transverse term, since that
arose from Taylor expanding $\Uc^n_{i,j}$ in time through $\Delta t/2$.
Instead, we simply construct these interface states using a
one-dimensional reconstruction and solve a Riemann problem at each
interface.  The evaluation of the second slope, ${\bf k}_2$, implicitly
includes the transverse information since we add ${\bf k}_\myhalf$ to
$\Uc^n_{i,j}$ before doing the prediction to the interfaces.  Also note,
however, that in this construction of the interface states, there is
no characteristic projection, since that arises from predicting the
interface states forward in time.  Again, these interface states are
at a constant time, not predicted into the future.

Generally speaking we want the order of accuracy in time to match that
in space.  The fourth-order Runge-Kutta method is a popular method for
integrating ODEs, so it makes sense to couple this with a
fourth-order-in-space method.  However, going higher-order than
second-order is more challenging.  The key issue is that we can no
longer simply approximate the cell average as the cell-center value,
i.e., $\langle \phi\rangle_i \ne \phi_i$.  This comes into play, for
instance, in translating between the conserved and primitive variables.
A fully fourth-order method is presented in ~\cite{mccorquodalecolella}

Note that when using a Runge-Kutta method-of-lines integrator for the
time-discretization of a multidimensional system, the timestep is
actually more restrictive than the cases presented above that
predicted the interface states to the half-time and performed
characteristic tracing.  Titarev \& Toro \cite{titarevtoro} claim that
you need $0 < C < \myhalf$ for 2-d flows and $0 < C < 1/3$ for 3-d flows.

An additional complexity arises when doing multiphysics.  Often we
split the different physical processes up and treat them in turn.
There are standard methods to do this with second-order accuracy in time,
but higher-order is more tricky.





\section{Thermodynamic issues}

\subsection{Defining temperature}

  Although not needed for the pure
  Euler equations, it is sometimes desirable to define the temperature
  for source terms (like reactions) or complex equations of state.
  The temperature can typically be found from the equation of state
  given the internal energy:
  \begin{eqnarray}
  e &=& E - \frac{1}{2} u^2 \\
  T &=& T(e, \rho)
  \end{eqnarray}
  Trouble can arise when you are in a region of flow where the kinetic
  energy dominates (high Mach number flow).  In this case, the $e$ defined
  via subtraction can become negative due to truncation error in the
  evolution of $u$ compared to $E$.  In this instance, one must either
  impose a floor value for $e$ or find an alternate method of deriving
  it.

  In~\cite{bryan:1995}, an alternate formulation of the Euler equations
  is proposed.  Both the total energy equation {\em and} the internal
  energy equation are evolved in each zone.  When the flow is dominated
  by kinetic energy, then the internal energy from the internal energy
  evolution equation is used.  The cost of this is conservation---the
  internal energy is not a conserved quantity, and switching to it
  introduces conservation of energy errors.

\subsection{General equation of state}

The above methods were formulated with a constant gamma equation of
state.  A general equation of state (such as degenerate electrons)
requires a more complex method.  Most methods are designed to 
reduce the need to call a complex equation of state frequently,
and work by augmenting the vector of primitive variables with 
additional thermodynamic information.  There are two parts of the 
adaption to a general equation of state: the interface states and 
the Riemann problem. 

\subsubsection{Carrying $\gamma_e$}


The classic prescription for
extending this methodology is presented by Colella and
Glaz~\cite{colellaglaz:1985}.  They construct a thermodynamic index,
\begin{equation}
\gamma_e = \frac{p}{\rho e} + 1
\end{equation}
and derive an evolution equation for $\gamma_e$ (C\&G, Eq.\ 26).
We can derive a similar expression as
\begin{align}
\frac{D\gamma_e}{Dt} &= \frac{D}{Dt} \left ( \frac{p}{\rho e} + 1 \right )
   = - \frac{p}{(\rho e)^2} \frac{D(\rho e)}{Dt} + \frac{1}{\rho e} \frac{Dp}{Dt} \nonumber \\
   &= (\gamma_e - 1) (\gamma_e  - \Gamma_1) \nabla \cdot \Ub \label{eq:gammae}
\end{align}
where we used Eqs.~\ref{eq:euler:pgeneral} and \ref{eq:euler:econs}, and the definition
of the sound speed.

This evolution equation is used to predict $\gamma_e$ to interfaces,
and these interface values of $\gamma_e$ are used in the Riemann
solver presented there to find the fluxes through the interface.  A
different adiabatic index (they call $\Gamma$, we call $\Gamma_1$)
appears in the definition of the sound speed.  They argue that this
can be brought to interfaces in a piecewise constant fashion while
still making the overall method second order, since $\Gamma_1$ does
not explicitly appear in the fluxes (see the discussion at the top of
page 277).

We can derive the characteristic structure of this system for use
in the tracing in the construction of interface states%
\footnote{A {\sf Jupyter} notebook using {\sf SymPy} that derives these
eigenvectors is available here:
\hydroexdoit{\href{https://github.com/zingale/hydro_examples/blob/master/compressible/euler-generaleos.ipynb}{euler-generaleos.ipynb}}}.
If we write 
our system as
\begin{equation}
\qb = \left ( \begin{array}{c} \tau \\ u \\ p \\ \gamma_e \end{array} \right )
\end{equation}
(we use $\tau = 1/\rho$ here for consistency with CG), we have
\begin{equation}
\Ab = \left ( \begin{array}{cccc} u & -\tau    & 0      & 0 \\
                                0 & u        & \tau   & 0 \\
                                0 & c^2/\tau & u      & 0 \\
                                0 & -\alpha  & 0      & u
            \end{array} \right )
\end{equation}
where we define $\alpha = (\gamma_e - 1)(\gamma_e - \Gamma_1)$ for
convenience.  The right eigenvectors are:
\begin{equation}
\rb^\evm = \left( \begin{array}{c} 1\\ {c}/{\tau}\\ -{c^{2}}/{\tau^{2}}\\ {\alpha}/{\tau}\end{array}\right)
%
\qquad
\rb^\evz = \left( \begin{array}{c} 1\\0\\0\\0 \end{array}\right)
%
\qquad
\rb^\evzs{\gamma_e} = \left( \begin{array}{c} 0\\0\\0\\1\end{array}\right)
%
\qquad
\rb^\evp = \left( \begin{array}{c} 1\\ -{c}/{\tau}\\ -{c^{2}}/{\tau^{2}}\\ {\alpha}/{\tau} \end{array}\right )
\end{equation}
and corresponding left eigenvectors are:
\begin{align}
\lb^\evm &= \left( \begin{array}{cccc} 0 & \frac{\tau}{2 c} & - \frac{\tau^{2}}{2 c^{2}} & 0\end{array}\right) \\
%
\lb^\evz &= \left( \begin{array}{cccc} 0 & \frac{\tau}{2 c} & - \frac{\tau^{2}}{2 c^{2}} & 0\end{array}\right) \\
%
\lb^\evzs{\gamma_e} &= \left( \begin{array}{cccc} 0 & 0 & \frac{\alpha \tau}{c^{2}} & 1\end{array}\right) \\
%
\lb^\evp &= \left ( \begin{array}{cccc} 0 & - \frac{\tau}{2 c} & - \frac{\tau^{2}}{2 c^{2}} & 0\end{array}\right)
\end{align}

\subsubsection{Carrying $(\rho e)$}

Alternately, the Castro paper~\cite{almgren:2010} relies on an idea
from an unpublished manuscript by Colella, Glaz, and Ferguson that
predicts $\rho e$ to edges in addition to $\rho$, $u$, and $p$.  Since
$\rho e$ comes from a conservation-like equation
(Eq.~\ref{eq:euler:econs}), predicting it to the interface in the
unsplit formulation is straightforward.  This over-specifies the
thermodynamics, but eliminates the need for $\gamma_e$.


With the addition of $\rho e$, our system becomes:
\begin{equation}
\qb = \left ( \begin{array}{c} \rho \\ u \\ p \\ \rho e \end{array} \right )
%
\qquad
%
\Ab = \left ( \begin{array}{cccc} u & \rho     & 0      & 0 \\
                                0 & u        & 1/\rho & 0 \\
                                0 & \rho c^2 & u      & 0 \\
                                0 & \rho h   & 0      & u
            \end{array} \right )
\end{equation}
where $h = e + p/\rho$ is the specific enthalpy.  The eigenvalues of this
system are:
\begin{equation}
\lambda^\evm = u - c \qquad
\lambda^\evz = u  \qquad
\lambda^\evzs{\rho e} = u  \qquad
\lambda^\evp = u + c
\end{equation}
and the eigenvectors are:
\begin{equation}
\rb^\evm = \left ( \begin{array}{c} 1 \\ -c/\rho \\ c^2 \\ h \end{array} \right )
\qquad
\rb^\evz = \left ( \begin{array}{c} 1 \\ 0 \\ 0 \\ 0 \end{array} \right )
\qquad
\rb^\evzs{\rho e} = \left ( \begin{array}{c} 0 \\ 0 \\ 0 \\ 1 \end{array} \right )
\qquad
\rb^\evp = \left ( \begin{array}{c} 1 \\ c/\rho \\ c^2 \\ h \end{array} \right )
\end{equation}
and
\begin{eqnarray}
&&
\lb^\evm = ( \begin{array}{cccc} 0 & -\frac{\rho}{2c} & \frac{1}{2c^2} & 0
            \end{array} ) \nonumber \\
&&
\lb^\evz = ( \begin{array}{cccc} 1 & 0 & -\frac{1}{c^2} & 0
            \end{array} ) \nonumber \\
&&
\lb^\evzs{\rho e} = ( \begin{array}{cccc} 0 & 0 & -\frac{h}{c^2} & 1
            \end{array} ) \nonumber \\
&&
\lb^\evp = ( \begin{array}{cccc} 0 & \frac{\rho}{2c} & \frac{1}{2c^2} & 0
            \end{array} )
\end{eqnarray}
Remember that the state variables in the $\qb$ vector are mixed into the
other states by $\lb \cdot \qb$.  Since all $\lb^{(\nu)}$'s have $0$ in the
$\rho e$ `slot' (the last position) except for $\lb^\evzs{\rho e}$, and the
corresponding $\rb^\evzs{\rho e}$ is only non-zero in the $\rho e$ slot, this
means that $\rho e$ is not mixed into the other state variables.  This
is as expected, since $\rho e$ is not needed in the system.

Also recall that the jump carried by the wave $\nu$ is proportional
to $\rb^{(\nu)}$---since $\rb^\evm$, $\rb^\evzs{\rho e}$, and $\rb^\evp$ have
non-zero $\rho e$ elements, this means that $\rho e$ jumps across
these three waves.

Working through the sum for the $(\rho e)$ state, and using a $\sim$ to
denote the reference states, we arrive at:
\begin{align}
(\rho e)_{i+\myhalf,L}^{n+\myhalf} = \widetilde{(\rho e)} &-
   \frac{1}{2} \left [ -\frac{\rho}{c} \left (\tilde{u} - \Ic^{(1)}_+(u) \right )
                       +\frac{1}{c^2} \left (\tilde{p} - \Ic^{(1)}_+(p) \right )
               \right ] h \nonumber \\
  &-
    \left [ -\frac{h}{c^2} \left (\tilde{p} - \Ic^{(3)}_+(p) \right )
                       + \left (\widetilde{(\rho e)} - \Ic^{(3)}_+(\rho e) \right )
               \right ] \nonumber \\
  &-
   \frac{1}{2} \left [ \frac{\rho}{c} \left (\tilde{u} - \Ic^{(4)}_+(u) \right )
                       +\frac{1}{c^2} \left (\tilde{p} - \Ic^{(4)}_+(p) \right )
               \right ] h
\end{align}
This is the expression that is found in the Castro code.  If you are dealing with
a simple geometry, then the divergences have metric terms.  In 1-d, we then have:
\begin{equation}
 \ddt{(\rho e)} + \frac{1}{r^\alpha} \ddr{(r^\alpha \rho u e)} + p \frac{1}{r^\alpha} \ddr{(r^\alpha u)}
\end{equation}
Expanding out the derivatives gives use the equation in Cartesian form with a geometric source term:
\begin{equation}
 \ddt{(\rho e)} + \ddr{(\rho u e)} + p \ddr{u} = -\frac{\alpha \rho hu}{r}
\end{equation}
where $h$ is the specific enthalpy.  This can be accommodated using
the procedure described in \S~\ref{ch:euler:geom}.

All of these methods are designed to avoid EOS calls where possible,
since general equations of state can be expensive.

Extending these to an unsplit formulation requires carrying an additional
auxiliary variable from the primitive state back to the conserved state
and adding the transverse gradients to its interface state.  Castro
deals with a conserved state of $\Uc = (\rho, \rho \Ub, \rho E, p)$, and
explicitly adds the transverse terms found in the multi-dimensional form
of Eq.~\ref{eq:euler:pgeneral}
to the normal states of $p$.





================================================
FILE: Euler/Euler-theory.tex
================================================
\label{ch:compressible-theory}


%-----------------------------------------------------------------------------
\section{Euler equation properties}

The Euler equations\footnote{ We focus on the Euler equations, which
are the most commonly modeled set of fluid equations in astrophysics.
The more general equation set, the Navier-Stokes equations, includes
dissipative terms.  However, for astrophysical flows, the scales on
which these dissipative terms operate are usually much smaller than
the system of interest (equivalently, Reynolds numbers of
astrophysical flows are very large).} describe conservation of 
mass, momentum, and energy in the fluid approximation.  Their general
form, without any source terms, is:  \MarginPar{need to add a discussion of the N-S equations and dimensionless numbers}
\begin{align}
\ddt{\rho} + \nabla \cdot (\rho \Ub) &= 0 \\
\ddt{(\rho \Ub)} + \nabla \cdot (\rho \Ub \Ub) + \nabla p &= 0 \\
\ddt{(\rho E)} + \nabla \cdot (\rho E \Ub + p \Ub ) &= 0 
\end{align}
Here $\rho$ is the density, $\Ub$ is the velocity vector, $\Ub =
u\hat{x} + v\hat{y}$, $p$ is the pressure, and $E$ is the total energy
/ mass, and can be expressed in terms of the specific internal energy,
$e$, and kinetic energy as:
\begin{equation}
E = e + \frac{1}{2} |\Ub|^2
\end{equation}
The equations are closed with the addition of an equation of state.  A common
choice is the gamma-law EOS:
\begin{equation}
p = \rho e(\gamma - 1)
\end{equation}
where $\gamma$ is the ratio of specific heats for the gas/fluid (for
an ideal, monatomic gas, $\gamma = 5/3$), but any relation of the form:
\begin{equation}
p = p(\rho, e)
\end{equation}
will work.  For many astrophysical environments, we may not be able to
express this relation analytically, but instead will solve it via
numerical integration or by interpolating from tabulated results.

For a derivation of the equations of hydrodynamics using moments of
the Boltzmann equation see \cite{shu,choudhuri}.  For a
physically-motivated derivation from conservation, see
\cite{choudhuri,leveque:2002}.

In one dimension, they appear as\footnote{assuming Cartesian coordinates}:
\begin{align}
\frac{\partial \rho}{\partial t} +
    \frac{\partial (\rho u)}{\partial x} &= 0 \\
%
\frac{\partial(\rho u)}{\partial t} +
    \frac{\partial (\rho uu + p)}{\partial x} &= 0 \\
%
\frac{\partial(\rho E)}{\partial t} +
    \frac{\partial(\rho u E + u p)}{\partial x} &= 0
\end{align}

One thing that we can notice immediately is that there is no need for
temperature in this equation set, although often, when source terms
are present, we will need to obtain temperature from the equation of
state.

In this form, the equations are said to be in {\em conservative form},
i.e.\ they can be written as:
\begin{equation}
\Uc_t + \left [\Fb(\Uc) \right ]_x = 0
\end{equation}
with
\begin{equation}
\Uc = \left ( \begin{array}{c} \rho \\ \rho u \\ \rho E \end{array} \right )
%
\qquad
%
\Fb(\Uc) = \left ( \begin{array}{c} \rho u \\ \rho uu + p \\ \rho u E + up \end{array} \right )
\end{equation}
%
We can write this in {\em quasi-linear} form by first expressing the
flux vector in terms of the conserved variables directly.  Taking $m
\equiv \rho u$, $\mathcal{E} \equiv \rho E$, and assuming a gamma-law
EOS%
\footnote{we can relax this assumption by writing $p = p(\rho, e)$, and then
taking the derivatives of this as needed:  $\partial p/\partial \rho$, 
$\partial p/\partial m = \partial p /\partial e|_\rho \partial e/\partial m$,
and $\partial p/\partial \mathcal{E} = \partial p/\partial e|_\rho \partial e/\partial \mathcal{E}$,
with $e = (\mathcal{E} - \myhalf m^2/\rho)/\rho$.  But as we'll see, there are
simpler systems to work with.},
\begin{equation}
p = \rho e (\gamma-1) =  \left (\mathcal{E} - \frac{1}{2} \frac{m^2}{\rho}\right )(\gamma - 1)
\end{equation}
we have
\begin{equation}
\Fb(\Uc) = \left ( \begin{array}{c}
      m \\
      \frac{1}{2}\frac{m^2}{\rho} \left (3 - \gamma \right ) +
          \mathcal{E} (\gamma - 1) \\
      \frac{m\mathcal{E}}{\rho} \gamma -\frac{1}{2} \frac{m^3}{\rho^2} (\gamma -1) \end{array} \right )
\end{equation}
The Jacobian%
\footnote{
The Jacobian, ${\bf J}$ of a vector $\Fb(\Uc)$ with $\Fb = (f_1, f_2, \ldots, f_n)^\intercal$ and
$\Uc = (u_1, u_2, \ldots, u_n)^\intercal$ is 
\begin{equation*}
{\bf J} \equiv \frac{\partial \Fb}{\partial \Uc} = \left (
  \begin{array}{cccc}
     \partial f_1/\partial u_1 & \partial f_1/\partial u_2 & \ldots & \partial f_1/\partial u_n \\
     \partial f_2/\partial u_1 & \partial f_2/\partial u_2 & \ldots & \partial f_2/\partial u_n \\
     \vdots                    & \vdots                    & \ddots & \vdots \\
     \partial f_n/\partial u_1 & \partial f_n/\partial u_2 & \ldots & \partial f_n/\partial u_n 
  \end{array} \right )
\end{equation*}
}
of this flux vector can now be computed as $\Ab = \partial
\Fb/\partial \Uc$:
\begin{equation}
\Ab(\Uc) = \left ( \begin{array}{ccc}
   0  & 1 & 0 \\
   -\frac{1}{2}u^2(3 -\gamma) & u (3 -\gamma) & \gamma - 1 \\
   \frac{1}{2}(\gamma -2)u^3 - \frac{uc^2}{\gamma -1} &
       \frac{3-2\gamma}{2} u^2 + \frac{c^2}{\gamma -1} & u \gamma
  \end{array} \right )
\end{equation}\MarginPar{SymPy notebook?}
where the speed of sound is $c = \sqrt{\gamma p/\rho}$.   With this, our
system can be written as:
\begin{equation}
\Uc_t + \Ab(\Uc) \Uc_x = 0
\end{equation}
This matrix is quite complex and difficult to work with.  The
eigenvectors of this matrix can be found in a variety of sources
(e.g. \cite{toro:1997,athena}).


An alternate way to express these equations is using the {\em
  primitive variables}: $\rho, u, p$.
\begin{exercise}[Primitive variable form of the Euler equations]
{Show that the Euler equations in primitive form can
  be written as
\begin{align}
\ddt{\rho} + u \ddx{\rho} + \rho \ddx{u} &= 0 \\
\ddt{u} + u \ddx{u} + \frac{1}{\rho} \ddx{p} &= 0 \\
\ddt{p} + u \ddx{p} + \gamma p \ddx{u} &= 0 \label{eq:prim:p}
\end{align}
}
\end{exercise}
Notice that the velocity equation looks like Burgers' equation, and 
is nonlinear.  This nonlinearity will admit shock and rarefaction
solutions like we saw with Burgers' equation.

%
The primitive variable system can be written compactly as:
\begin{equation}
\qb_t + \Ab(\qb) \qb_x = 0
\end{equation}
where
\begin{equation}
\qb = \left ( \begin{array}{c} \rho \\ u \\ p \end{array} \right )
%
\qquad
\Ab(\qb) = \left ( \begin{array}{ccc} u  & \rho     & 0 \\
                                  0  &  u       & 1/\rho \\
                                  0  & \gamma p & u \end{array} \right )
\label{eq:primitivesystem}
\end{equation}



The eigenvalues of $\Ab$ can be found via $| \Ab - \lambda {\bf I} | = 0$,
where $|\ldots|$ indicates the determinant and $\lambda$ are the eigenvalues.
\begin{exercise}[The eigenvalues of the Euler system]
{
Show that the eigenvalues of $\Ab$ are $\lambda^\evm = u -c$, $\lambda^\evz = u$, $\lambda^\evp = u+c$.
}
\end{exercise}
Note that both the conserved Jacobian matrix, $\Ab(\Uc)$, and the
primitive variable matrix, $\Ab(\qb)$, have the same eigenvalues,
 since they represent the same physics.

In Eq.~\ref{eq:prim:p}, we used the algebraic gamma-law
equation of state to replace $e$ with $p$, however, for a general
equation of state, we can get the appropriate expression by writing $p
= p(\rho, s)$:
\begin{equation}
\label{eq:euler:presnosource}
\frac{Dp}{Dt} = \left . \frac{\partial p}{\partial \rho} \right |_s
     \frac{D\rho}{Dt} +
     \left . \frac{\partial p}{\partial s} \right |_\rho
     \cancelto{0}{\frac{Ds}{Dt}}
\end{equation}
where $Ds/Dt = 0$ when no entropy sources are present (we will relax this
assumption in \S~\ref{ch:lm:constraints}).  Recognizing
that $\Gamma_1 \equiv \partial \log p/\partial \log \rho |_s$, we have:
\begin{equation}
\frac{\partial p}{\partial t} + u \frac{\partial p}{\partial x}
  + \Gamma_1 p \frac{\partial u}{\partial x} = 0  \label{eq:euler:pgeneral}
\end{equation}
as the generalization of the pressure equation\footnote{$\Gamma_1$ is one of the
many adiabatic indices that describe the coupling between different
thermodynamic quantities under compression/expansion.  Any stellar structure
book should give a good background, e.g., \cite{HKT}.  Note that for an ideal gas, $\Gamma_1 = \gamma$}.
The sound speed is then $c^2 = \Gamma_1 p /\rho$.

These eigenvalues are the speeds at which information propagates
through the fluid.  Since the eigenvalues are real, this system (the
Euler equations) is said to be {\em hyperbolic}.  Additionally, since
$\Ab = \Ab(\qb)$, the system is said to be {\em quasi-linear}.  Note,
physically, these eigenvalues are telling us that information is
communicated at the speed of the fluid ($u$), as well as the speed of
sound moving with respect to the fluid ($u \pm c$).

We'll use the symbols $\{-,\circ,+\}$ to denote the eigenvalues and their
corresponding eigenvectors throughout these notes.
%
The right and left eigenvectors can be found via:
\begin{equation}
\Ab \, \rb^\enu = \lambda^\enu \rb^\enu \; ;
\qquad
\lb^\enu \, \Ab  = \lambda^\enu \lb^\enu
\end{equation}
where $\nu = \{-,\circ,+\}$ corresponding to the three waves, and
there is one right and one left eigenvector for each of the eigenvalues.
%
\begin{exercise}[Eigenvectors of the Euler system]
{
Show that the right eigenvectors are:
\begin{equation}
\label{eq:euler:primRevs}
\rb^\evm = \left ( \begin{array}{c} 1 \\ -c/\rho \\ c^2 \end{array} \right )
%
\qquad
\rb^\evz = \left ( \begin{array}{c} 1 \\ 0 \\ 0  \end{array} \right )
%
\qquad
\rb^\evp = \left ( \begin{array}{c} 1 \\ c/\rho \\ c^2 \end{array} \right )
\end{equation}
and the left eigenvectors are:
\begin{align}
\lb^\evm &= \left ( \begin{array}{ccc} 0 & -\frac{\rho}{2c} & \frac{1}{2c^2}
                  \end{array} \right ) \\
%
\qquad
\lb^\evz &= \left ( \begin{array}{ccc} 1 & 0 & -\frac{1}{c^2}  \end{array} \right ) \\
%
\qquad
\lb^\evp &= \left ( \begin{array}{ccc} 0 & \phantom{+}\frac{\rho}{2c} & \frac{1}{2c^2} \end{array} \right )
\end{align}
Note that in general, there can be an arbitrary constant in front of each
eigenvector.  Here they are normalized such that
$\lb^{(i)} \cdot \rb^{(j)} = \delta_{ij}$.
}
\end{exercise}
A {\sf Jupyter} notebook using {\sf SymPy} that derives these
eigenvectors is available:
\hydroexdoit{\href{https://github.com/zingale/hydro_examples/blob/master/compressible/euler.ipynb}{euler.ipynb}}
\footnote{if you don't have {\sf Jupyter}, you can view this rendered online via the github link.}

A final form of the equations is called the {\em characteristic form}.  Here,
we wish to diagonalize the matrix $\Ab$.  We take the matrix $\Rb$ to be the
matrix of right eigenvectors,
\begin{equation}
\Rb = (\rb^\evm | \rb^\evz | \rb^\evp )
\end{equation}
(i.e., $\Rb$ is a square matrix whose columns are the eigenvectors),
and $\Lb$
is the corresponding matrix of left eigenvectors:
\begin{equation}
\Lb = \left ( \begin{array}{c} \lb^\evm \\
                             \hdashline
                             \lb^\evz \\
                             \hdashline
                             \lb^\evp \end{array} \right )
\end{equation}
Note that $\Lb\, \Rb = {\bf I} = \Rb\, \Lb$, and $\Lb = \Rb^{-1}$.
\begin{exercise}[Characteristic form of the Euler equations]
{
Show that $\Lambdab = \Lb \Ab \Rb$ is a diagonal matrix with the diagonal elements
simply the 3 eigenvalues we found above:
\begin{equation}
\Lambdab =
   \left ( \begin{array}{ccc}
             \lambda^\evm &              & \\
                          & \lambda^\evz & \\
                          &              & \lambda^\evp \end{array} \right )
\end{equation}
}
\end{exercise}
To transform our primitive variable system into the characteristic form, we 
start by multiplying by $\Lb$:
\begin{equation}
\Lb\qb_t + \Lb \Ab \qb_x = 0
\end{equation}
Next, recalling that $\Rb\Lb = {\bf I}$ (we can insert
the identity matrix where we please), we can rewrite our system as:
\begin{equation}
\Lb\qb_t + \Lb \Ab \Rb \Lb \qb_x = 0
\end{equation}
Finally, defining $d\wb = \Lb d\qb$,
\begin{equation}
\wb_t + \Lambda \wb_x = 0
\end{equation}
Here, the $\wb$ are the {\em characteristic variables}.  Note that we cannot
in general integrate $d\wb = \Lb d\qb$ to write down the characteristic
quantities.  Since $\Lambdab$ is diagonal, this system is a set of
decoupled advection-like equations:
\begin{align}
w_t^\evm + \lambda^\evm w_x^\evm &= 0 \\
w_t^\evz + \lambda^\evz w_x^\evz &= 0 \\
w_t^\evp + \lambda^\evp w_x^\evp &= 0 
\end{align}

If the system were linear, then the solution to each would simply be
to advect the quantity $w^\enu$ at the wave speed $\lambda^\enu$.  We
could then get back the primitive variables as $d\qb = \Lb^{-1} d\wb = \Rb d\wb$.

The basic idea of hyperbolic systems of PDEs is that there is one wave
for each eigenvalue, and these define the characteristic curves,
$dx/dt = \lambda^\enu$.  As we discussed with linear advection
and Burgers' equation, along the characteristics the solution is
constant.  Across them, the solution jumps.  For a linear system, the
characteristics are straight lines.

Imagine initial conditions consisting of a jump in the primitive
variables, $\Delta \qb$.  The corresponding jumps in characteristic
variables are $\Delta \wb \sim \Lb \Delta \qb$ (where the $\sim$ accounts
for the fact that in a nonlinear system, $\Lb = \Lb(\qb)$).  The
characteristic form of the equations says that each of the waves will
carry its respective jump, $\Delta \wb$.  Since $d\qb = \Lb^{-1}d\wb = \Rb d\wb$,
the jump in the primitive variable across each wave is proportional to
the right-eigenvector associated with that wave.  So, for example,
since $\rb^\evz$ is only non-zero for the density element (see
Eq.~\ref{eq:euler:primRevs}), this then means that only density jumps
across the $\lambda^\evz = u$ wave---pressure and velocity are
constant across this wave (see for example, Toro~\cite{toro:1997},
Ch.\ 2, 3 or LeVeque~\cite{leveque:2002} for a thorough discussion).

Figure~\ref{fig:sod} shows the three waves emanating from an initial
discontinuity.  This is a classic problem called the Sod
problem~\cite{sod:1978}.  The initial conditions are
\begin{align}
\rho_l &= 1      &  \rho_r &= 1/8 \nonumber \\
u_l   &= 0       &  u_r    &= 0   \\
p_l    &= 1      &  p_r    &= 1/10 \nonumber
\end{align}
Here we see the three waves propagating away from the initial
discontinuity.  The left ($u-c$) wave is a rarefaction, the middle
($u$) is the contact discontinuity, and the right ($u+c$) is a
shock. Note that all 3 primitive variables jump across the left and
right waves, but only the density jumps across the middle wave.  This
reflects the right eigenvectors.  Also note that no waves have reached
the far left and far right yet, the conditions there are the same as
the initial conditions.  \MarginPar{we need a python version of the Riemann exact script}

\begin{figure}
\centering
\includegraphics[width=0.8\linewidth]{riemann-sod}
\caption[The Sod problem]{\label{fig:sod} Evolution following from an initial
  discontinuity at $x = 0.5$.  These particular conditions are called
  the {\em Sod problem}, and in general, a setup with two states
  separated by a discontinuity is called a shock-tube problem.  We see three
  waves carrying changes in the solution. \\
  \hydroexdoit{\href{https://github.com/zingale/hydro_examples/blob/master/compressible/riemann-sod.py}{riemann-sod.py}}}
\end{figure}






%-----------------------------------------------------------------------------
\section{The Riemann problem}

\label{euler:sec:riemann}

Just like with advection and Burgers' equation, we will need to solve
a Riemann problem.  However, as our system is nonlinear, and has 3
waves, the solution is considerably more complex, but the general
ideas are straightforward.  Here we review the basic outline of
operations, and refer to Toro~\cite{toro:1997} for full details on a
variety of methods for solving the Riemann problem.

The Riemann problem consists of a left and right state separated by an
interface.  For the Euler equations, there are three eigenvalues,
which are the speeds at which information propagates.  Each of these
correspond to a wave that will move out from the interface with time,
and each wave will carry with it a jump in the characteristic
variables.  Figure~\ref{fig:riemann:waves} shows the
three waves moving out from the interface, separating space into 4
regions, marked: $L$, $L_*$, $R_*$, and $R$.
\begin{figure}[h]
\centering
\includegraphics[width=\linewidth]{riemann-waves}
\caption[The Riemann problem wave structure for the Euler
  equations]{\label{fig:riemann:waves} The wave structure and 4
  distinct regions for the Riemann problem.  Time can be thought of as
  the vertical axis here, so we see the waves moving outward from the
  interface.}
\end{figure}
We typically work in terms of primitive variables.  The states in the
$L$ and $R$ regions are simply the left and right input states---the
waves have not had time to reach here, so they are unmodified.

Looking at the middle right eigenvector, $\rb^\evz$, we identify the
middle wave as a {\em contact discontinuity}.  There is neither
compression nor expansion across this wave (since the velocity does
not jump across it) and it simply separates two states.  We also know
from the eigenvectors that the pressure is constant across the
contact.

The left and right waves can be either a rarefaction or a shock.  It will
be a shock if the flow is compressing and a rarefaction otherwise.

We already see that the only unknowns are $u_\star$, $p_\star$, $\rho_{\star,L}$,
and $\rho_{\star,R}$.

\subsection{Rarefactions}

The conditions across a rarefaction can be understood by considering
a system where entropy replaces pressure, $\qb_s = (\rho, u, s)^\intercal$.
The entropy equation is simply $Ds/Dt = 0$.  We need to express the
pressure gradient in the velocity equation in terms of $\qb_s$.
\begin{equation}
\frac{\partial p(\rho, s)}{\partial x} =
  \left . \frac{\partial p}{\partial s} \right |_\rho \frac{\partial s}{\partial x} +
  \left . \frac{\partial p}{\partial \rho} \right |_s \frac{\partial \rho}{\partial x}
=
  \left . \frac{\partial p}{\partial s} \right |_\rho \frac{\partial s}{\partial x} +
  \frac{p\Gamma_1}{\rho} \frac{\partial \rho}{\partial x}
\end{equation}
giving
\begin{equation}
\frac{\partial u}{\partial t} + u \frac{\partial u}{\partial x} + \frac{1}{\rho} \left [
     \left . \frac{\partial p}{\partial s} \right |_\rho \frac{\partial s}{\partial x} +
          \frac{p\Gamma_1}{\rho} \frac{\partial \rho}{\partial x} \right ] = 0
\end{equation}
This gives a system:
\begin{equation}
{\qb_s}_t + \Ab_s(\qb_s) {\qb_s}_x = 0
\end{equation}
where
\begin{equation}
\Ab_s =
 \left ( \begin{array}{ccc} u & \rho & 0 \\
        c^2/\rho & u & \frac{1}{\rho} \left . \frac{\partial p}{\partial s}\right |_\rho \\
        0 & 0 & u \end{array} \right )
\end{equation}
The eigenvalues of $\Ab_s$ are again $u$, $u-c$, and $u+c$.  The right eigenvectors
are\footnote{Again, see the {\sf SymPy} {\sf Jupyter} notebook:
\hydroexdoit{\href{https://github.com/zingale/hydro_examples/blob/master/compressible/euler.ipynb}{euler.ipynb}}}
\begin{align}
\rb_s^\evm = \left ( \begin{array}{c} 1 \\ -c/\rho \\ 0 \end{array} \right )
%
\qquad
\rb_s^\evz = \left ( \begin{array}{c} 1 \\ 0 \\ -c^2/p_s  \end{array} \right )
%
\qquad
\rb_s^\evp = \left ( \begin{array}{c} 1 \\ c/\rho \\ 0 \end{array} \right )
\end{align}
Here, we define $p_s \equiv \partial p/\partial s |_\rho$.
Since the jump in $\qb_s$ is proportional to these eigenvectors, we see that
entropy does not change across the left, $(-)$, and right, $(+)$, waves.

Consider the $\evp$ wave, which moves at a speed $\lambda^\evp = u
+c$.  Across this wave, the characteristic variable $\wb^\evp$ will
jump, but the others will not.  Similarly, $\wb^\evp$ will be constant
across the $\evm$ wave.  So we can use this constancy to tell us how
the evolution behaves across that wave.  The constancy of the middle and right characteristic variables across the left
wave gives us the conditions (using our original primitive variable system):
\begin{align}
\lb^\evp \cdot d\qb &= 0 \\
\lb^\evz \cdot d\qb &= 0 
\end{align}
or 
\begin{equation}
\left ( \begin{array}{ccc} 0 & \frac{\rho}{2c} & \frac{1}{2c^2} \end{array} \right)
   \left ( \begin{array}{c} d\rho \\ du \\ dp \end{array} \right ) = 0
\qquad
%
\left ( \begin{array}{ccc} 1 & 0 & -\frac{1}{c^2} \end{array} \right)
   \left ( \begin{array}{c} d\rho \\ du \\ dp \end{array} \right ) = 0
\end{equation}
Expanding these, we have the system:
\begin{align}
du + \frac{1}{\rho c} dp &= 0 \\
d\rho - \frac{1}{c^2} dp &= 0 
\end{align}
Defining the {\em Lagrangian sound speed}, $C \equiv \rho c$, and the 
specific volume, $\tau = 1/\rho$, we can rewrite this system as:
\begin{equation}
du = -\frac{dp}{C} , \,\,\, d\tau = -\frac{dp}{C^2} \quad \mbox{across the left wave}
\end{equation}

Similar arguments would give the condition across the right wave as:
\begin{equation}
du = \frac{dp}{C} , \,\,\, d\tau = -\frac{dp}{C^2} \quad \mbox{across the right wave}
\end{equation}

These are completely general at this point.  Note that the condition
of the second wave, $d\tau/dp$ is essentially the definition of the
adiabatic index $\Gamma_1$, $dp/p - \Gamma_1 d\rho/\rho = 0$ for
constant entropy.  Finding the solution across the rarefaction then
involves integrating the system from $p_{l,r}$ to $p_\star$, where $l,
r$ is the original left or right state, depending on which wave you
are considering.  Coupled with this, we need our equation of state to
provide $C = C(\tau, p)$.  These solutions are called the {\em Riemann
  invariants}.

Considerable simplification can be made if we assume a gamma-law gas.
The eigensystem with entropy showed us that entropy is constant across
the solution.  This allows us to write our equation of state as:
\begin{equation}
p = K \rho^\gamma
\end{equation}
where $K$ is a constant that depends on the entropy, and do the 
integrals analytically.

\begin{exercise}[Riemann invariants for gamma-law gas]
Assume a gamma-law gas, then you only need to integrate a single
equation to find the solution across the left rarefaction:
\begin{equation}
u = - \int \frac{dp}{\rho c}
\end{equation}
where $c = \sqrt{\gamma p/\rho}$.  Using $p = K\rho^\gamma$, show that
\begin{equation}
u + \frac{2c}{\gamma - 1} = \mbox{constant} \quad \mbox{across the left rarefaction}
\end{equation}

This allows you to link the state to the left of the rarefaction to the star state:
\begin{equation}
u_L + \frac{2c_L}{\gamma - 1} = u_\star + \frac{2c_\star}{\gamma -1}
\end{equation}
and
\begin{equation}
\frac{p_L}{\rho_L^\gamma} = \frac{p_\star}{\rho_\star^\gamma}
\end{equation}
from our constant-entropy equation of state.  Together, show that this
gives:
\begin{equation}
u_{\star,L} = u_L + \frac{2c_L}{\gamma - 1} \left [ 1 - \left ( \frac{p_\star}{p_L}\right )^{(\gamma - 1)/2\gamma} \right ]
\end{equation}
A similar construction can be done for the right rarefaction, yielding:
\begin{equation}
u_{\star,R} = u_R - \frac{2c_R}{\gamma - 1} \left [ 1 - \left ( \frac{p_\star}{p_R}\right )^{(\gamma - 1)/2\gamma} \right ]
\end{equation}

\end{exercise}

For a general equation of state, there is not a closed form, but we would need
to integrate our system to get $u_\star = u(p_\star)$ and $\rho_{\star,s} = 1/\tau(p_\star)$.

We'll denote the solution across the left rarefaction as $u_\star =
u_L^{rare}(p_\star)$ and across the right rarefaction as $u_\star =
u_R^{rare}(p_\star)$.

\subsection{Shocks}

Entropy is not constant across a shock---there is dissipation, so we
need a different way to connect the states across the shock.  As with
Burgers' equation, we can understand the shock by looking at the
Rankine-Hugoniot jump conditions.  There will be one condition for
each of our conservation laws, and together they tell us the speed of
the shock and how density and pressure jump across
it.  

The Rankine-Hugoniot conditions are:
\begin{equation}
\frac{\Fb(\Uc_\star) - \Fb(\Uc_s)}{\Uc_\star - \Uc_s} = S
\end{equation}
where $S$ is the shock speed.  It is easiest to work in the frame of the shock.  If the shock speed
is $S$, then we define the velocity in the shock frame as:
\begin{align}
\hat{u}_s &= u_s - S  \\
\hat{u}_\star &= u_\star - S
\end{align}
and the Rankine-Hugoniot conditions become:
\begin{equation}
\frac{\Fb(\hat{\Uc}_\star) - \Fb(\hat{\Uc}_s)}{\hat{\Uc}_\star - \hat{\Uc}_s} = 0
\end{equation}

For the one-dimensional system of Euler equations, we have the conditions:
\begin{align}
\rho_\star \hat{u}_\star &= \rho_s \hat{u}_s \\
\rho_\star \hat{u}_\star^2 + p_\star &= \rho_s \hat{u}_s^2 + p_s \\
\rho_\star \hat{u}_\star e_\star + \frac{1}{2} \rho_\star \hat{u}_\star^3 + \hat{u}_\star p_\star &= 
  \rho_s \hat{u}_s e_s + \frac{1}{2} \rho_s \hat{u}_s^3 + \hat{u}_s p_s
\end{align}
Our goal is to find how each variable jumps across the shock.  We'll 
work this out for the general EOS case, following the ideas in \cite{colellaglaz:1985}.

Starting with the mass flux, we can express:
\begin{equation}
\hat{u}_\star = \frac{\rho_s}{\rho_\star} \hat{u}_s
\end{equation}
and then insert this into the momentum equation to get:
\begin{equation}
\rho_s^2 \left ( \frac{1}{\rho_s} - \frac{1}{\rho_\star} \right ) \hat{u}_s^2 = p_\star - p_s
\end{equation}
Introducing compact notation for the jump across the shock:
\begin{equation}
[q] \equiv q_\star - q
\end{equation}
we have:
\begin{equation}
-[\tau] = \frac{[p]}{\rho_s^2 \hat{u}_s^2}
\end{equation}

We now introduce the mass flux, $W_s$.  For a shock separating
$L$/$L\star$ (the 1-shock), mass will be moving through the shock to the
right, so, in the frame of the shock, the mass flux is
\begin{equation}
W_L \equiv \rho_L \hat{u}_L = \rho_\star \hat{u}_\star
\end{equation}
Likewise, for a shock separating $R$/$R\star$ (the 3-shock), mass will
move to the left passing through the shock, and in the frame of the
shock, the mass flux is
\begin{equation}
W_R \equiv -\rho_R \hat{u}_R = -\rho_\star \hat{u}_\star
\end{equation}

Thus, our first jump condition becomes
\begin{equation}
-[\tau] = \frac{[p]}{W_s^2}
\end{equation}

Next, going back to the momentum equation, we can substitute in the
mass flux.  For the left (1-shock), we have:
\begin{equation}
W_L \hat{u}_\star + p_\star = W_L \hat{u}_L + p_L
\end{equation}
giving
\begin{equation}
[u] = -\frac{[p]}{W_L}
\end{equation}
where we recognized that $\hat{u}_\star - \hat{u}_L = u_\star - u_L =
[u]$, since the shock speed is the same for $u_\star$ and $u$.

Likewise, for the right (3-shock), we have:
\begin{equation}
-W_R \hat{u}_\star + p_\star = -W_R \hat{u}_R + p_R
\end{equation}
giving
\begin{equation}
[u] = \frac{[p]}{W_R}
\end{equation}

The last jump condition is for energy.  Since all the terms in the 
energy equation are proportional to velocity, there will be no sign
difference between the left and right shock jump conditions.  
We start by introducing the mass flux:
\begin{equation}
W_s e_\star + \frac{1}{2} W_s \hat{u}_\star^2 + \frac{W_s}{\rho_\star} p_\star =
  W_s e_s + \frac{1}{2} W_s \hat{u}_s^2 + \frac{W_s}{\rho_s} p_s
\end{equation}
The mass flux cancels, leaving
\begin{equation}
[e] + \frac{p_\star}{\rho_\star} - \frac{p_s}{\rho_s} + \frac{1}{2} \left ( \hat{u}_\star^2 - \hat{u}_s^2 \right ) = 0
\end{equation}
getting rid of the velocities using $\hat{u}_\star^2 = W_s^2/\rho_\star^2$ and 
$\hat{u}_s^2 = W_s^2/\rho_s^2$, we have:
\begin{equation}
[e] + \frac{p_\star}{\rho_\star} - \frac{p_s}{\rho_s} + \frac{1}{2} W_s^2 \left ( \frac{1}{\rho_\star^2} - \frac{1}{\rho_s^2} \right ) = 0
\end{equation}
Then introducing $W_s^2 = -[p]/[\tau]$, and after a lot of algebra, we arrive at:
\begin{equation}
[e] = -\frac{p_\star + p_s}{2} [\tau]
\end{equation}
Some sources write $\bar{p} \equiv (p_\star + p_s)/2$.

To summarize, our jump conditions across the shock are:
\begin{align}
[\tau] &= -\frac{[p]}{W_s^2} \\
[u] &= \mp \frac{[p]}{W_s} \quad\mbox{`$-$' for left, `+' for right}\\
[e] &= - \frac{p_\star + p_s}{2} [\tau] \label{eq:euler:shock:ejump}
\end{align}

As with the rarefaction, the goal is to express this as a function, $u_\star
= u_s^\mathrm{shock}(p_\star)$.  The general solution procedure is starts with
a proposed value for $p_\star$, then:
\begin{enumerate}
\item root find to find $\rho_\star$ corresponding to the $p_\star$:
  \begin{enumerate}
  \item guess a value for $\rho_\star$
  \item using the equation of state, express $e_\star = e(p_\star, \rho_\star)$
  \item use Newton's method (or another technique) with $[e] = -\bar{p} [\tau]$
     to find a correction to $\rho_\star$
  \end{enumerate}
\item compute 
  \begin{equation}
    \frac{1}{W_s^2} = - \frac{[\tau]}{[p]}
  \end{equation}
\item find the star velocity:
  \begin{equation}
    u_\star = u_s \mp \frac{[p]}{W_s}
  \end{equation}
  where we use `$-$' for the left shock, and `+' for the right shock
\end{enumerate}

The one other piece of information we need is the shock speed.  We can
get this from the mass flux, $W_s$, definition, e.g., $W_L = \rho_L
\hat{u}_L = \rho_L (u_L - S)$,:
\begin{equation}
\label{eq:euler-theory:shockgeneral}
S = u_s \mp \frac{W_s}{\rho_s} \quad\mbox{`$-$' for left, `+' for right}\\
\end{equation}
This procedure gives us $\rho_{\star,s}$, $p_\star$, and $S$, the
shock speed.

Just as with the rarefaction, considerable simplification can be made
if we assume a gamma-law gas.

\begin{exercise}[Shock jump conditions for $\gamma$-law EOS]
{
Introducing 
\begin{equation}
e = \frac{p}{\rho} \frac{1}{\gamma -1}
\end{equation}
into the jump condition for energy, Eq.~\ref{eq:euler:shock:ejump},
show that we can express the jump in density in terms of the
ratio of pressure, $p_\star/p_s$, as:
\begin{equation}
\label{eq:euler:shockrhojump}
\rho_{\star,s} = \rho_s \left [ \frac{ \frac{p_\star}{p_s} (\gamma + 1) + (\gamma - 1)}
   {(\gamma + 1) + \frac{p_\star}{p_s} (\gamma -1)} \right ]
\end{equation}
}

Now, compute the mass flux, $W_s$ starting with
\begin{equation}
W_s^2 = -\frac{[p]}{[\tau]}
\end{equation}
use the $\gamma$-law equation of state and show that
\begin{equation}
W_s^2 = \frac{1}{2} p_s \rho_s \left [ \left(\frac{p_\star}{p_s}\right) (\gamma + 1) + (\gamma -1) \right ]
\end{equation}

With this, show that the star velocity is:
\begin{equation}
\label{eq:euler:shockujump}
u_\star = u_s \pm c \left [\frac{2}{\gamma(\gamma - 1)}\right]^{1/2} \frac{1 - \frac{p_\star}{p_s}}{\left ( \frac{p_\star}{p_s} \frac{\gamma + 1}{\gamma - 1} + 1\right)^{1/2}}
\end{equation}
with `+` for the left shock and `$-$` for the right shock.
Also show that the shock speed is:
\begin{equation}
\label{eq:euler:shockspeedjump}
S = u_s \mp c \left [ \left ( \frac{p_\star}{p_s} \right ) \frac{\gamma+1}{2\gamma} + \frac{\gamma-1}{2\gamma} \right ]^{1/2}
\end{equation}
with the `$-$' or the left shock and the `+' for the right shock.
\end{exercise}
  
\subsection{Finding the Star State}

\label{Euler:riemann:starstate}

The left and right states are connected to the state in the star
region by a Hugoniot curve---this is a curve in the $u$-$p$ plane that
shows all of the possible states one can reach from the current state
through either a shock or rarefaction.  There are two such curves, one
corresponding to the left and one to the right state:
\begin{equation}
u_{\star,L}(p) = \begin{cases}
   u_{\star,L}^\mathrm{shock}(p) & p > p_L \\
   u_{\star,L}^\mathrm{rare}(p) & p \le p_L 
   \end{cases}
\qquad
u_{\star,r}(p) = \begin{cases}
   u_{\star,R}^\mathrm{shock}(p) & p > p_R \\
   u_{\star,R}^\mathrm{rare}(p) & p \le p_R 
   \end{cases}
\end{equation}
The solution
to the Riemann problem is the point in the $u$-$p$ plane where these
two curves intersect, e.g., we solve for $p_\star$ in:
\begin{equation}
u_{\star,l}(p_\star) - u_{\star,r}(p_\star) = 0
\end{equation}
This is equivalent to saying that pressure and velocity do not jump
across the contact wave.

For a gamma-law equation of state, using the results from the
exercises, we have:
\begin{equation}
\renewcommand{\arraystretch}{1.5}
u_{\star,s}(p_\star) = \begin{cases}
  u_s \pm \frac{2c}{\gamma - 1} \left [ 1 - \left ( \frac{p_\star}{p_s}\right )^{(\gamma - 1)/2\gamma} \right ] & p_\star \le p_s \\
\\
%
  u_s \pm c \left [\frac{2}{\gamma(\gamma - 1)}\right]^{1/2} \frac{1 - \frac{p_\star}{p_s}}{\left ( \frac{p_\star}{p_s} \frac{\gamma + 1}{\gamma - 1} + 1\right)^{1/2}} & p_\star > p_s
\end{cases}
\renewcommand{\arraystretch}{1.0}
\end{equation}



Figure~\ref{fig:euler:riemann-curve} shows the Hugoniot curves for the
Sod problem.  Comparing to Figure~\ref{fig:sod}, we see that the right
state is linked to the star state with a shock while the left state is
linked to the star state with a rarefaction.

\begin{exercise}[Hugoniot curves]
Download the code demonstrated in Figure~\ref{fig:euler:riemann-curve}
and experiment with different initial conditions to see how the
solution changes based on the states.  Try to create initial states
that give rise to two rarefactions and a separate set of states that
give rise to two shocks.
\end{exercise}

\begin{figure}[t]
\centering
\includegraphics[width=0.9\linewidth]{riemann-phase}
\caption[The Hugoniot curves corresponding
to the Sod problem]{\label{fig:euler:riemann-curve} The Hugoniot
curves corresponding to the Sod problem.  The shock and rarefaction
curves are shown.  The solution to the Riemann problem is the point
where the curves intersect.  The line style of the curve indicates
where we are a shock or rarefaction.  Where $p > p_s$, where $s \in {L,R}$, we have a shock.\\
\hydroexdoit{\href{https://github.com/zingale/hydro_examples/blob/master/compressible/riemann-phase.py}{riemann-phase.py}}}
\end{figure}


\subsection{Complete Solution}

\label{Euler:riemann:solution}

To complete the solution, we need to find which of the 4 regions, $L,
L\star, R\star, R$ we fall in.  For hydrodynamics, we are usually
interested only in the solution on the interface, but we can look
along any ray in the $x$-$t$ plane by defining $\xi = (x -
x_\mathrm{interface})/t$.  If the initial discontinuity is on the
interface, then $\xi = 0$.

% figure from figures/Euler/riemann_cartoon.py
\begin{figure}
\centering
\includegraphics[width=0.49\linewidth]{riemann_waves_ifc_R}
\includegraphics[width=0.49\linewidth]{riemann_waves_ifc_Rstar} \\
\includegraphics[width=0.49\linewidth]{riemann_waves_ifc_Lstar}
\includegraphics[width=0.49\linewidth]{riemann_waves_ifc_L} 
\caption[Wave configuration for the Riemann problem]
        {\label{fig:euler:riemann_sample} An illustration of the 3
          waves emanating from an initial discontinuity (the origin of
          the axes).  The 4 cases show all possible cases of waves
          being to the left or right of the interface (corresponding
          to the choice $\xi = 0$).  In all cases, the middle wave is
          a contact and the left (1) and right (3) waves are either a
          shock or a rarefaction.  The state on the interface is: $R$
          (case a); $R\star$ (case b); $L\star$ (case c); $L$ (case
          d).}
\end{figure}

Figure~\ref{fig:euler:riemann_sample} shows the possible
configurations of the waves.  Note that the middle wave is always a
contact but the left (1) and right (3) waves can be either a shock or
rarefaction.  To find out which region the interface falls in, we simply
look at the speeds.  

The first speed to consider is the contact wave, that has a speed of
simply $S_c = u_\star$.  If $S_c < \xi$, then we are choosing between
$R$ and $R_\star$ states (cases a and b).  If $S_c > \xi$, then we are
choosing between the $L$ and $L_\star$ states (cases c and d in
Figure~\ref{fig:euler:riemann_sample})\footnote{for the special case
  where $S_c = 0$, we usually take the solution to be the average of
  the $L_\star$ and $R_\star$ states.  Testing for this explicitly
  rather than using $\ge$ in a check is important for maintaining
  symmetry (see \S~\ref{sec:euler-methods:shocktubes}).}.

The direction of the contact reduces the problem down to choosing
between just two regions, either $L$-$L_\star$ or $R$-$R_\star$.  This
leaves just a single wave to consider: the right wave for cases a and
b; and the left wave for cases c and d.  We need the wave speed for
this---it will depend on whether it is a shock or a rarefaction.  

For a shock, the wave speed is given by
Eq.~\ref{eq:euler-theory:shockgeneral}.  We do the same procedure as
before.  For example, for cases a and b, we look at $S_R$, the
right-moving shock speed for the 3-wave.  If $S_R > 0$, then the
interface is in the $R_\star$ state (case b), while if $S_R < 0$, then
the interface is in the $R$ state (case a).  A similar process
holds for the left-moving shock and cases c and d.

For a rarefaction, the
relevant speeds are the characteristic speeds on either side of the
rarefaction.  We usually talk about the leading part of the
rarefaction (the {\em head}) and trailing part (the {\em tail}).  The
corresponding wave speeds are:
\begin{itemize}
\item left (1) rarefaction:
  \begin{itemize} 
  \item $\lambda_\mathrm{head} = u_L - c_L$
  \item $\lambda_\mathrm{tail} = u_\star - c_\star$
  \end{itemize}
  
\item right (3) rarefaction:
  \begin{itemize} 
  \item $\lambda_\mathrm{head} = u_R + c_R$
  \item $\lambda_\mathrm{tail} = u_\star + c_\star$
  \end{itemize}
\end{itemize}
The nature of the rarefaction is such that it spreads out,
$|\lambda_\mathrm{head}| > |\lambda_\mathrm{tail}|$.  To determine
which state we are in, we look to see where both the head and tail are
with respect to the interface.
Figure~\ref{fig:euler:rarefaction_sample} shows the possibilities for
a left (1) rarefaction.  In case (a), $\lambda_\mathrm{head},
\lambda_\mathrm{tail} < 0$, so the $L_\star$ state is on the
interface.  In case (c), $\lambda_\mathrm{head}, \lambda_\mathrm{tail}
> 0$, so the $L$ state is on the interface.  Case (b) is more
complicated---we have $\lambda_\mathrm{head} <0, \lambda_\mathrm{tail}
> 0$, so the rarefaction spans the interface.  We need to therefore
solve for the state in the rarefaction itself.

To find the structure inside of a rarefaction, consider some point,
$(x, t)$, in the $x$-$t$ plane.  For an initial discontinuity at the
origin, we can imagine a line connecting this point and the origin,
which has the form:
\begin{equation}
\frac{x}{t} = u - c
\end{equation}

% figure from figures/Euler/rarefaction_cartoon.py
\begin{figure}
\centering
\includegraphics[width=0.6\linewidth]{rarefaction_left} \\
\includegraphics[width=0.6\linewidth]{rarefaction_center} \\
\includegraphics[width=0.6\linewidth]{rarefaction_right}
\caption[Rarefaction configuration for the Riemann problem]
        {\label{fig:euler:rarefaction_sample} An illustration of the 
          structure of the left rarefaction wave, for the case
          where the contact and right wave are to the right of the
          interface.  Here, we are choosing between states $L$ and $L_\star$.
          In (a), both the head and tail of the rarefaction are to the 
          left of the interface, so state $L_\star$ is on the interface.
          In (c), both the head and tail of the rarefaction are to the 
          right of the interface, so state $L$ is on the interface.
          Inbetween, case (b), shows a rarefaction that spans the 
          interface.  For this case, we need to integrate the Riemann
          invariants to find the state on the interface.}
\end{figure}


%-----------------------------------------------------------------------------
\section{Other thermodynamic equations}

\label{sec:euler:otherthermo}

At times we will want to use alternate forms of the energy equation.  The
internal energy is governed by the first law of thermodynamics.  In the
absence of any heat sources, we have:
\begin{equation}
dq = 0 = de + pd(1/\rho)
\end{equation}
where $e$ is the specific internal energy.
Applying this to a Lagrangian fluid element, we have:
\begin{align}
\DDt{e} + p \DDt{(1/\rho)} &= 0 \\
\DDt{e} - \frac{p}{\rho^2} \frac{D\rho}{Dt} &= 0 \\
\rho \frac{De}{Dt} + p \nabla \cdot \Ub &= 0
\end{align}
where we used the continuity equation in the last step to eliminate
$D\rho/Dt$.  This can be rewritten by adding $e \times$ the continuity
equation to give:
\begin{equation}
\ddt{(\rho e)} + \nabla \cdot (\rho \Ub e) + p \nabla \cdot \Ub = 0 \label{eq:euler:econs}
\end{equation}

Notice that internal energy, $(\rho e)$ is not a conserved quantity
(in particular, the $p\nabla \cdot \Ub$ term is not in conservative
form).  

Another energy-like quantity that we can consider is specific enthalpy,
\begin{equation}
h = e + \frac{p}{\rho}
\end{equation}
Differentiating this, and using the internal energy equation,
\begin{align}
\DDt{h} &= \DDt{e} - \frac{p}{\rho^2} \DDt{\rho} + \frac{1}{\rho} \DDt{p} \\
        &= \frac{p}{\rho^2}\DDt{\rho} - \frac{p}{\rho^2} \DDt{\rho} + \frac{1}{\rho} \DDt{p}
\end{align}
so
\begin{equation}
\rho \DDt{h} = \DDt{p}
\end{equation}

This form is useful for very subsonic flows (see,
e.g.~\cite{SNpaper}), where $Dp/Dt = 0$, which then shows that
enthalpy is conserved:
\begin{equation}
\ddt{(\rho h)} + \nabla \cdot (\rho h \Ub) = 0
\end{equation}
(here we added $h \times$ the continuity equation to transform from
the Lagrangian derivative to a conservation equation).


We can also look at the temperature evolution.  It is interesting to
approach this from both the internal energy and enthalpy equations.
Starting with internal energy, writing it as $e(\rho, T)$, we have:
\begin{equation}
\DDt{e} = \left . \frac{\partial e}{\partial \rho} \right |_T \DDt{\rho} +
          \left . \frac{\partial e}{\partial T} \right |_\rho \DDt{T} = -\frac{p}{\rho} \nabla \cdot \Ub
\end{equation}
The specific heat at constant volume is defined as $c_v = \partial
e/\partial T|_\rho$, allowing us to write:
\begin{equation}
c_v \DDt{T} = \left ( \left . \frac{\partial e}{\partial \rho} \right |_T - \frac{p}{\rho} \right ) \nabla \cdot \Ub
\end{equation}

If we alternately start with enthalpy, expressing it as $h = h(p, T)$,
we have:
\begin{equation}
\DDt{h} = \left . \frac{\partial h}{\partial p} \right |_T \DDt{p} +
          \left . \frac{\partial h}{\partial T} \right |_p \DDt{T} = \frac{1}{\rho} \DDt{p}
\end{equation}
The specific heat at constant pressure is defined as $c_p = \partial
h/\partial T|_p$, letting us write:
\begin{equation}
c_p \DDt{T} = \left ( \frac{1}{\rho} - \left . \frac{\partial h}{\partial p} \right |_T \right ) \DDt{p}
\end{equation}

These two temperature evolution equations are equivalent, but one
describes the evolution in terms of density and the other in terms of
pressure.  Later, we'll see how these can be useful when we
approximate the evolution of reactive flow under constant density or
constant pressure behaviors.

\if debug
\subsection{Eigensystem with temperature}

Here we illustrate how the eigensystem changes when we replace pressure with
temperature in our primitive variable system.

We write this set of variables as $\hat{\qb} = (\tau, u,
T)^\intercal$---note that we keep $\tau$ instead of $\rho$ here.  The
motivation for this comes from the fact that with temperature in the
mix, the temperature will jump across the contact wave.  Since
pressure should be constant across the contact, and, even with the
general EOS, a temperature jump needs a density drop for pressure to
remain constant, $\tau$ should counteract the behavior of $T$ across
the contact.

The temperature evolution equation appears as:
\begin{equation}
\frac{\partial T}{\partial t} = -u\ddx{T} +
  \frac{1}{\rho c_p} \left [ (1 - \rho h_p) \frac{Dp}{Dt} \right ]
\end{equation}
(see, e.g.\ \cite{ABRZ:I}) where $c_p$ is the specific heat at
constant pressure, $c_p = \partial h/\partial T|_p$ and $h_p \equiv
\partial h / \partial p |_T$, with $h = e + p/\rho$ the specific
enthalpy.  We can use the standard pressure evolution equation
(Eq.~\ref{eq:euler:pgeneral}) to eliminate the Lagrangian pressure term,
resulting in:
\begin{equation}
\frac{\partial T}{\partial t} = -u\ddx{T} - \eta \ddx{u}
\end{equation}
where we defined
\begin{equation}
\eta \equiv \frac{1 - \rho h_p}{c_p} c^2
\end{equation}

The density equation remains unchanged from the traditional primitive
variable formulation, but for the velocity, we need to write the
$\partial p/\partial x$ term in terms of $\hat{\qb}$.  We do this via
the chain rule.  We define $p_\rho \equiv {\partial p}/{\partial \rho}
|_T$ and $p_T \equiv {\partial p}/{\partial T} |_\rho$, then our
velocity equation is:
\begin{equation}
\frac{\partial u}{\partial t} + u \frac{\partial u}{\partial x} - \frac{p_\rho}{\tau} \frac{\partial \tau}{\partial x} + {\tau p_T} \frac{\partial T}{\partial x} = 0
\end{equation}
Note that here we neglected any composition dependence in the EOS.

Our primitive variable system in matrix form is then:
\begin{equation}
\hat{\qb}_t + \hat{\Ab} \hat{\qb}_x = 0
\end{equation}
with
\begin{equation}
\renewcommand{\arraystretch}{1.5}
\hat{\Ab}(\hat{\qb}) =
\left (
\begin{array}{ccc}
u                   & -\tau & 0 \\
-\dfrac{p_\rho}{\tau} & u    & \tau p_T \\
0                   & \eta & u
\end{array}
\right )
\end{equation}
The eigenvalues can be found through the characteristic polynomial,
$|\hat{\Ab} - \lambda I| = 0$:
\begin{equation}
(u - \lambda)^3 - (u -\lambda) \left ( {p_T \eta\tau} + p_\rho \right ) = 0
\end{equation}
We can simplify the last term in parenthesis:
\begin{equation}
{p_T \eta\tau} + p_\rho = \frac{p_T (1 - \rho h_p) c^2}{\rho c_p} + p_\rho
                               = \frac{c^2}{c_p}\left ( \frac{p p_T}{\rho^2 p_\rho} - \frac{p_T e_\rho}{p_\rho} \right ) + p_\rho \label{eq:step1}
\end{equation}
where we substituted in
\begin{equation}
h_p = \frac{1}{\rho} \left ( 1 - \frac{p}{\rho p_\rho} \right ) + \frac{e_\rho}{p_\rho}
\end{equation}
(see \cite{ABRZ:I}, appendix A) where $e_\rho = \partial e/\partial
\rho |_T$.  The term in parenthesis in Eq.~\ref{eq:step1} is simply
$c_p - c_v$ (\cite{cg}, Eq.~9.81) where $c_v$ is the specific heat
at constant volume, and Eq.~\ref{eq:step1} further reduces to:
\begin{equation}
{p_T \eta\tau} + p_\rho = \frac{c^2}{c_p} (c_p - c_v) + p_\rho
                               = c^2 - c^2 \frac{\chi_p}{\Gamma_1} + p_\rho = c^2
\end{equation}
where we used $c_v/c_p = \chi_p/\Gamma_1$ and $\chi_p = \rho p_\rho /
p$ (\cite{cg}, Eqs.~9.87, 9.82).  Putting this into our
characteristic polynomial, we see that the eigenvalues are, as expected,
$\lambda = u, u \pm c$.  It is also useful to note that
\begin{equation}
\eta = \frac{c^2 - p_\rho}{\tau p_T}
\end{equation}


We construct the left and right eigenvectors such that they are orthonormal,
and find:
\begin{equation}
\renewcommand{\arraystretch}{1.3}
\hat{R} = \left ( \begin{array}{ccc}
     1                       & 1                 & 1 \\
   c/\tau                    & 0                 & -c/\tau \\
  -(c^2 - p_\rho)/\tau^2 p_T & p_\rho/\tau^2 p_T & -(c^2 - p_\rho)/\tau^2 p_T
  \end{array} \right )
\end{equation}
and
\begin{equation}
\hat{L} = \left ( \begin{array}{ccc}
      {p_\rho}/{2 c^2}   & {\tau}/{2c}  & -{\tau^2 p_T}/{2 c^2} \\
      1 - {p_\rho}/{c^2} &0             & {\tau^2 p_T}/{c^2} \\
      {p_\rho}/{2 c^2}   & -{\tau}/{2c} & -{\tau^2 p_T}/{2 c^2} \end{array} \right )
\end{equation}
We note that all
thermodynamic derivatives are expressed in terms of $\rho$ or $T$ with
the other quantity held constant.  This is in the form we expect a
$(T, \rho)$-based EOS to return derivatives.  Notice also that the
temperature jumps across the $\evz$ wave (the contact discontinuity;
this is seen from the non-zero value in $\hat{r}^\evz$ for the
temperature).

We write:
\begin{eqnarray}
\hat{\beta}^\evm_s &\equiv& (\hat{l}^\evm \cdot \Delta \hat{\qb}^\evm ) =
   \frac{1}{2C} \left (\frac{\rho^2 p_\rho}{C} \Delta \tau^\evm
                        + \Delta u^\evm - \frac{p_T}{C}\Delta T^\evm \right ) \\
%
\hat{\beta}^\evz_s &\equiv& (\hat{l}^\evz \cdot \Delta \hat{\qb}^\evz ) =
    \Delta \tau^\evz +
        \frac{1}{C^2} \left (-\rho^2 p_\rho \Delta \tau^\evz
                        + {p_T}\Delta T^\evz \right ) \\
%
\hat{\beta}^\evp_s &\equiv& (\hat{l}^\evp \cdot \Delta \hat{\qb}^\evp ) =
   \frac{1}{2C} \left (\frac{\rho^2 p_\rho}{C} \Delta \tau^\evp
                        - \Delta u^\evp - \frac{p_T}{C}\Delta T^\evp \right )
\end{eqnarray}
Note that since $p_\tau = -\rho^2 p_\rho$, we can form a $\Delta p^\enu$ as
\begin{equation}
\Delta p^\enu = p_\tau \Delta \tau^\enu + p_T \Delta T^\enu
\end{equation}
and then we see that the $\hat{\beta}^\enu$'s above have the same
functional form as the $\mathring{\beta}^\enu$ from the $\mathring{\qb}
= (\tau, u, p, e)^\intercal$ eigensystem.  This is no surprise, since
the $l\cdot \Delta \qb$ are the characteristic variables of the Euler
equations.  The numerical values will differ though, because the
$\hat{\beta}^\enu$ and $\mathring{\beta}^\enu$ use different reference
states and reconstructed variables.

Finally, we can write out the interface states:
\begin{eqnarray}
\tau_s &=& \tilde{\tau} - (\hat{\beta}^\evm + \hat{\beta}^\evz + \hat{\beta}^\evp) \\
%
u_s &=& \tilde{u} - (C \hat{\beta}^\evm - C \hat{\beta}^\evp) \\
%
T_s &=& \tilde{T} - \frac{1}{p_T} \left \{
   \left [ -C^2 \hat{\beta}^\evm - C^2 \hat{\beta}^\evp \right ] +
   \rho^2 p_\rho \left [ \hat{\beta}^\evm + \hat{\beta}^\evz + \hat{\beta}^\evp \right ] \right \}
\end{eqnarray}
For $T_s$, we recognize the first quantity in the square brackets as
being the same as $-(p_s - \tilde{p})$ in the $\mathring{\qb}$ system, and the
second term in the square brackets being the same as $-(\tau_s - \tilde{\tau})$
in the $\mathring{\qb}$ system, then we see
\begin{equation}
p_T (T_s - \tilde{T} ) \approx (p_s - \tilde{p} ) - p_\tau (\tau_s - \tilde{\tau})
\end{equation}
which is what we would expect for jumps in $p$ when applying the chain
rule.  Note that this is not a strict equality, since the reference
states and interpolation between the two eigensystems are different.
Nevertheless, this demonstrates the connection between the two
methods.

The above did not consider variations in the composition of the fluid.
Multiple species complicate things---now the replacement of the
pressure gradient picks up a composition gradient term.
The eigensystem will change with this addition.  We don't explore this here at this
time.
\fi



================================================
FILE: Euler/README
================================================
sod.eps: made by hydro1d in the exact/ subdirector


================================================
FILE: Euler/main.tex
================================================
\documentclass[11pt]{article}

% margins
\usepackage[margin=0.75in]{geometry}

%
\usepackage{amsmath}

% figures
\usepackage{graphicx}

% font
\usepackage{mathpazo}

\usepackage{helvet}

% coloring
\usepackage{color}
\definecolor{mygray}{gray}{0.5}

% footer
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyfoot[LO,LE]{\footnotesize \sffamily \color{mygray} M.\ Zingale---Notes on the Euler equations}
\fancyfoot[RO,RE]{\footnotesize \sffamily \color{mygray} (\today)}
\fancyfoot[CO,CE]{\thepage}
\fancyhead{}
\renewcommand{\headrulewidth}{0.0pt}
\renewcommand{\footrulewidth}{0.0pt}

% captions
\usepackage{caption}
\renewcommand{\captionfont}{\footnotesize}
\renewcommand{\captionlabelfont}{\footnotesize}
\setlength{\captionmargin}{5em}

\newcommand{\evm}{{(-)}}
\newcommand{\evz}{{(\circ)}}
\newcommand{\evp}{{(+)}}
\newcommand{\enu}{{(\nu)}}

% for dotted lines in the matrics/arrays
\usepackage{arydshln}

\usepackage{sectsty}
\allsectionsfont{\sffamily}

\begin{document}

\begin{center}
{\LARGE \textsf{\textbf{
Notes on the Euler Equations}}
}
\end{center}

\input Euler

\bibliographystyle{plain}
\bibliography{../refs}

\end{document}


================================================
FILE: GNUmakefile
================================================
# by default, typing make will build the `production' version of the 
# Computational Hydrodynamics notes.
#
# if you instead for 'make DEBUG=t', then it will make the draft version.
# this will enable margin comments and build in any chapters that are
# not yet complete.

ALL: CompHydroTutorial.pdf

DEBUG := 

DIRS := preface \
        intro \
	pde-classes \
        finite-volume \
        advection \
        burgers \
        Euler \
        hydro-test-problems \
        multigrid \
        diffusion \
        multiphysics \
        incompressible \
        low_mach \
        pyro \
        hydro_examples \
        software-engineering \
        symbols \
        radiation

# dependencies
TEXS := $(foreach dir, $(DIRS), $(wildcard $(dir)/*.tex))
EPSS := $(foreach dir, $(DIRS), $(wildcard $(dir)/*.eps))

# for PDFs, pdflatex will automagically convert file.eps to
# file-converted-to.pdf at build time.  These lines create
# a variable, PDFS, that just contains the original PDF files
# as dependencies
tPDFS := $(foreach dir, $(DIRS), $(wildcard $(dir)/*.pdf))
cPDFS := $(foreach dir, $(DIRS), $(wildcard $(dir)/*converted-to.pdf))
PDFS := $(filter-out $(cPDFS), $(tPDFS)) 


conditional.tex:
ifdef DEBUG
	echo "\def\debugmode{}" > conditional.tex
else
	echo "" > conditional.tex
endif

CompHydroTutorial.pdf: CompHydroTutorial.tex conditional.tex $(TEXS) $(EPSS) $(PDFS) refs.bib
	git rev-parse --short=12 HEAD > git_info.tex
	pdflatex CompHydroTutorial  < /dev/null
	bibtex CompHydroTutorial.aux
	pdflatex CompHydroTutorial  < /dev/null
	pdflatex CompHydroTutorial  < /dev/null
	#pdflatex CompHydroTutorial  < /dev/null
	$(RM) git_info.tex
	$(RM) conditional.tex


clean:
	$(RM) *.aux *.log *.dvi *.bbl *.blg *.lof *.toc *.exc *.out *.brf
	$(RM) *~ conditional.tex

realclean: clean
	$(RM) CompHydroTutorial.pdf
	find . -name "*-converted-to.pdf" -exec $(RM) {} \;

.PHONY: clean


print-%: ; @echo $* is $($*)


================================================
FILE: LICENSE
================================================
Attribution-NonCommercial-ShareAlike 4.0 International

=======================================================================

Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.

Using Creative Commons Public Licenses

Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.

     Considerations for licensors: Our public licenses are
     intended for use by those authorized to give the public
     permission to use material in ways otherwise restricted by
     copyright and certain other rights. Our licenses are
     irrevocable. Licensors should read and understand the terms
     and conditions of the license they choose before applying it.
     Licensors should also secure all rights necessary before
     applying our licenses so that the public can reuse the
     material as expected. Licensors should clearly mark any
     material not subject to the license. This includes other CC-
     licensed material, or material used under an exception or
     limitation to copyright. More considerations for licensors:
	wiki.creativecommons.org/Considerations_for_licensors

     Considerations for the public: By using one of our public
     licenses, a licensor grants the public permission to use the
     licensed material under specified terms and conditions. If
     the licensor's permission is not necessary for any reason--for
     example, because of any applicable exception or limitation to
     copyright--then that use is not regulated by the license. Our
     licenses grant only permissions under copyright and certain
     other rights that a licensor has authority to grant. Use of
     the licensed material may still be restricted for other
     reasons, including because others have copyright or other
     rights in the material. A licensor may make special requests,
     such as asking that all changes be marked or described.
     Although not required by our licenses, you are encouraged to
     respect those requests where reasonable. More_considerations
     for the public: 
	wiki.creativecommons.org/Considerations_for_licensees

=======================================================================

Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
Public License

By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution-NonCommercial-ShareAlike 4.0 International Public License
("Public License"). To the extent this Public License may be
interpreted as a contract, You are granted the Licensed Rights in
consideration of Your acceptance of these terms and conditions, and the
Licensor grants You such rights in consideration of benefits the
Licensor receives from making the Licensed Material available under
these terms and conditions.


Section 1 -- Definitions.

  a. Adapted Material means material subject to Copyright and Similar
     Rights that is derived from or based upon the Licensed Material
     and in which the Licensed Material is translated, altered,
     arranged, transformed, or otherwise modified in a manner requiring
     permission under the Copyright and Similar Rights held by the
     Licensor. For purposes of this Public License, where the Licensed
     Material is a musical work, performance, or sound recording,
     Adapted Material is always produced where the Licensed Material is
     synched in timed relation with a moving image.

  b. Adapter's License means the license You apply to Your Copyright
     and Similar Rights in Your contributions to Adapted Material in
     accordance with the terms and conditions of this Public License.

  c. BY-NC-SA Compatible License means a license listed at
     creativecommons.org/compatiblelicenses, approved by Creative
     Commons as essentially the equivalent of this Public License.

  d. Copyright and Similar Rights means copyright and/or similar rights
     closely related to copyright including, without limitation,
     performance, broadcast, sound recording, and Sui Generis Database
     Rights, without regard to how the rights are labeled or
     categorized. For purposes of this Public License, the rights
     specified in Section 2(b)(1)-(2) are not Copyright and Similar
     Rights.

  e. Effective Technological Measures means those measures that, in the
     absence of proper authority, may not be circumvented under laws
     fulfilling obligations under Article 11 of the WIPO Copyright
     Treaty adopted on December 20, 1996, and/or similar international
     agreements.

  f. Exceptions and Limitations means fair use, fair dealing, and/or
     any other exception or limitation to Copyright and Similar Rights
     that applies to Your use of the Licensed Material.

  g. License Elements means the license attributes listed in the name
     of a Creative Commons Public License. The License Elements of this
     Public License are Attribution, NonCommercial, and ShareAlike.

  h. Licensed Material means the artistic or literary work, database,
     or other material to which the Licensor applied this Public
     License.

  i. Licensed Rights means the rights granted to You subject to the
     terms and conditions of this Public License, which are limited to
     all Copyright and Similar Rights that apply to Your use of the
     Licensed Material and that the Licensor has authority to license.

  j. Licensor means the individual(s) or entity(ies) granting rights
     under this Public License.

  k. NonCommercial means not primarily intended for or directed towards
     commercial advantage or monetary compensation. For purposes of
     this Public License, the exchange of the Licensed Material for
     other material subject to Copyright and Similar Rights by digital
     file-sharing or similar means is NonCommercial provided there is
     no payment of monetary compensation in connection with the
     exchange.

  l. Share means to provide material to the public by any means or
     process that requires permission under the Licensed Rights, such
     as reproduction, public display, public performance, distribution,
     dissemination, communication, or importation, and to make material
     available to the public including in ways that members of the
     public may access the material from a place and at a time
     individually chosen by them.

  m. Sui Generis Database Rights means rights other than copyright
     resulting from Directive 96/9/EC of the European Parliament and of
     the Council of 11 March 1996 on the legal protection of databases,
     as amended and/or succeeded, as well as other essentially
     equivalent rights anywhere in the world.

  n. You means the individual or entity exercising the Licensed Rights
     under this Public License. Your has a corresponding meaning.


Section 2 -- Scope.

  a. License grant.

       1. Subject to the terms and conditions of this Public License,
          the Licensor hereby grants You a worldwide, royalty-free,
          non-sublicensable, non-exclusive, irrevocable license to
          exercise the Licensed Rights in the Licensed Material to:

            a. reproduce and Share the Licensed Material, in whole or
               in part, for NonCommercial purposes only; and

            b. produce, reproduce, and Share Adapted Material for
               NonCommercial purposes only.

       2. Exceptions and Limitations. For the avoidance of doubt, where
          Exceptions and Limitations apply to Your use, this Public
          License does not apply, and You do not need to comply with
          its terms and conditions.

       3. Term. The term of this Public License is specified in Section
          6(a).

       4. Media and formats; technical modifications allowed. The
          Licensor authorizes You to exercise the Licensed Rights in
          all media and formats whether now known or hereafter created,
          and to make technical modifications necessary to do so. The
          Licensor waives and/or agrees not to assert any right or
          authority to forbid You from making technical modifications
          necessary to exercise the Licensed Rights, including
          technical modifications necessary to circumvent Effective
          Technological Measures. For purposes of this Public License,
          simply making modifications authorized by this Section 2(a)
          (4) never produces Adapted Material.

       5. Downstream recipients.

            a. Offer from the Licensor -- Licensed Material. Every
               recipient of the Licensed Material automatically
               receives an offer from the Licensor to exercise the
               Licensed Rights under the terms and conditions of this
               Public License.

            b. Additional offer from the Licensor -- Adapted Material.
               Every recipient of Adapted Material from You
               automatically receives an offer from the Licensor to
               exercise the Licensed Rights in the Adapted Material
               under the conditions of the Adapter's License You apply.

            c. No downstream restrictions. You may not offer or impose
               any additional or different terms or conditions on, or
               apply any Effective Technological Measures to, the
               Licensed Material if doing so restricts exercise of the
               Licensed Rights by any recipient of the Licensed
               Material.

       6. No endorsement. Nothing in this Public License constitutes or
          may be construed as permission to assert or imply that You
          are, or that Your use of the Licensed Material is, connected
          with, or sponsored, endorsed, or granted official status by,
          the Licensor or others designated to receive attribution as
          provided in Section 3(a)(1)(A)(i).

  b. Other rights.

       1. Moral rights, such as the right of integrity, are not
          licensed under this Public License, nor are publicity,
          privacy, and/or other similar personality rights; however, to
          the extent possible, the Licensor waives and/or agrees not to
          assert any such rights held by the Licensor to the limited
          extent necessary to allow You to exercise the Licensed
          Rights, but not otherwise.

       2. Patent and trademark rights are not licensed under this
          Public License.

       3. To the extent possible, the Licensor waives any right to
          collect royalties from You for the exercise of the Licensed
          Rights, whether directly or through a collecting society
          under any voluntary or waivable statutory or compulsory
          licensing scheme. In all other cases the Licensor expressly
          reserves any right to collect such royalties, including when
          the Licensed Material is used other than for NonCommercial
          purposes.


Section 3 -- License Conditions.

Your exercise of the Licensed Rights is expressly made subject to the
following conditions.

  a. Attribution.

       1. If You Share the Licensed Material (including in modified
          form), You must:

            a. retain the following if it is supplied by the Licensor
               with the Licensed Material:

                 i. identification of the creator(s) of the Licensed
                    Material and any others designated to receive
                    attribution, in any reasonable manner requested by
                    the Licensor (including by pseudonym if
                    designated);

                ii. a copyright notice;

               iii. a notice that refers to this Public License;

                iv. a notice that refers to the disclaimer of
                    warranties;

                 v. a URI or hyperlink to the Licensed Material to the
                    extent reasonably practicable;

            b. indicate if You modified the Licensed Material and
               retain an indication of any previous modifications; and

            c. indicate the Licensed Material is licensed under this
               Public License, and include the text of, or the URI or
               hyperlink to, this Public License.

       2. You may satisfy the conditions in Section 3(a)(1) in any
          reasonable manner based on the medium, means, and context in
          which You Share the Licensed Material. For example, it may be
          reasonable to satisfy the conditions by providing a URI or
          hyperlink to a resource that includes the required
          information.
       3. If requested by the Licensor, You must remove any of the
          information required by Section 3(a)(1)(A) to the extent
          reasonably practicable.

  b. ShareAlike.

     In addition to the conditions in Section 3(a), if You Share
     Adapted Material You produce, the following conditions also apply.

       1. The Adapter's License You apply must be a Creative Commons
          license with the same License Elements, this version or
          later, or a BY-NC-SA Compatible License.

       2. You must include the text of, or the URI or hyperlink to, the
          Adapter's License You apply. You may satisfy this condition
          in any reasonable manner based on the medium, means, and
          context in which You Share Adapted Material.

       3. You may not offer or impose any additional or different terms
          or conditions on, or apply any Effective Technological
          Measures to, Adapted Material that restrict exercise of the
          rights granted under the Adapter's License You apply.


Section 4 -- Sui Generis Database Rights.

Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:

  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
     to extract, reuse, reproduce, and Share all or a substantial
     portion of the contents of the database for NonCommercial purposes
     only;

  b. if You include all or a substantial portion of the database
     contents in a database in which You have Sui Generis Database
     Rights, then the database in which You have Sui Generis Database
     Rights (but not its individual contents) is Adapted Material,
     including for purposes of Section 3(b); and

  c. You must comply with the conditions in Section 3(a) if You Share
     all or a substantial portion of the contents of the database.

For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.


Section 5 -- Disclaimer of Warranties and Limitation of Liability.

  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.

  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.

  c. The disclaimer of warranties and limitation of liability provided
     above shall be interpreted in a manner that, to the extent
     possible, most closely approximates an absolute disclaimer and
     waiver of all liability.


Section 6 -- Term and Termination.

  a. This Public License applies for the term of the Copyright and
     Similar Rights licensed here. However, if You fail to comply with
     this Public License, then Your rights under this Public License
     terminate automatically.

  b. Where Your right to use the Licensed Material has terminated under
     Section 6(a), it reinstates:

       1. automatically as of the date the violation is cured, provided
          it is cured within 30 days of Your discovery of the
          violation; or

       2. upon express reinstatement by the Licensor.

     For the avoidance of doubt, this Section 6(b) does not affect any
     right the Licensor may have to seek remedies for Your violations
     of this Public License.

  c. For the avoidance of doubt, the Licensor may also offer the
     Licensed Material under separate terms or conditions or stop
     distributing the Licensed Material at any time; however, doing so
     will not terminate this Public License.

  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
     License.


Section 7 -- Other Terms and Conditions.

  a. The Licensor shall not be bound by any additional or different
     terms or conditions communicated by You unless expressly agreed.

  b. Any arrangements, understandings, or agreements regarding the
     Licensed Material not stated herein are separate from and
     independent of the terms and conditions of this Public License.


Section 8 -- Interpretation.

  a. For the avoidance of doubt, this Public License does not, and
     shall not be interpreted to, reduce, limit, restrict, or impose
     conditions on any use of the Licensed Material that could lawfully
     be made without permission under this Public License.

  b. To the extent possible, if any provision of this Public License is
     deemed unenforceable, it shall be automatically reformed to the
     minimum extent necessary to make it enforceable. If the provision
     cannot be reformed, it shall be severed from this Public License
     without affecting the enforceability of the remaining terms and
     conditions.

  c. No term or condition of this Public License will be waived and no
     failure to comply consented to unless expressly agreed to by the
     Licensor.

  d. Nothing in this Public License constitutes or may be interpreted
     as a limitation upon, or waiver of, any privileges and immunities
     that apply to the Licensor or You, including from the legal
     processes of any jurisdiction or authority.

=======================================================================

Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.

Creative Commons may be contacted at creativecommons.org.



================================================
FILE: NOTES
================================================
-- add to Ch 1 a review of numerical methods:

   . truncation vs. roundoff error
   . numerical differentiation and integration
   . ODEs
   . linear algebra

-- add section to each chapter: "Numerical Explorations"

   . create a separate, non-pyro git repo that has basic examples for all 
     of the methods in 1-d also add discussions from pyro.
   . start with simple grid class and BC discussion 
   . 1-d advection example


-- preface:

  "Each of the main chapters has 2 sections at the end: "Numerical
  Explorations" and "Going further".  The first guides the reader
  through some exercises using the codes in the git repo associated
  with these notes.  The latter briefly discusses some of the popular
  extensions done to the core algorithms discussed here, with pointers
  to the relevant papers in the literature.

-- burgers:

http://onlinelibrary.wiley.com/doi/10.1002/fld.1650030302/abstract

Generating exact solutions of the two-dimensional Burgers' equations
Clive A. J. Fletcher




================================================
FILE: README.md
================================================
# Computational Hydrodynamics for Astrophysics

*part of the Open Astrophysics Bookshelf*

Notes on numerical methods for computational astrophysical hydrodynamics.

These notes describe the way I think about the numerical methods commonly
used with grid-based codes in astrophysical hydrodynamics.  The notes
are written in LaTeX, and should build by typing 'make' in the main
directory.

Working implementations for all of the solvers are contained either in
the main pyro code or in the set of hydro examples, both referenced
below.

## Chapters

The following chapters are mostly written:

- Simulation Overview
- Finite-Volume Grids
- Advection
- Burgers' Equation
- Euler Equations: Theory
- Euler Equations: Numerical Methods
- Elliptic Equations and Multigrid
- Diffusion
- Model Multiphysics Problems
- Reactive Flow
- Planning a Simulation
- Incompressible Flow and Projection Methods
- Low Mach Number Methods

The following are things I'd like to add in the next 1-2 years:

- Fluid Instabilities
- Rotation and Self-gravity
- Radiation Hydrodynamics
- MHD
- AMR
- Mapped Grids

The following are things hopefully will eventually get written:

- Relativisitc Flows
- Higher-Order Methods
- Implicit Hydrodynamics


## Getting PDFs and Source

A PDF version of these notes is available at:

http://open-astrophysics-bookshelf.github.io/numerical_exercises/

(this PDF is automatically generated by a Github action each time changes are pushed to `main`.)

There are two sets of companion codes that go along with these notes:

 - *hydro_examples*: https://github.com/zingale/hydro_examples

   simple, standalone, 1-d solvers that illustrate the basic ideas.

 - *pyro*: https://github.com/python-hydro/pyro2

   pyro is a 2-d full simulation code designed with simplicity in
   mind that implements the core solvers described in these notes
   along with various test problems.






================================================
FILE: TODO
================================================
Add implementation details throughout, explaining how to translate stuff into code
   -- maybe in the margins with the Tufte class?

https://en.wikipedia.org/wiki/Shallow_water_equations#/media/File:Characteristics_saint-venant.svg

new chapters:

  -- self-gravity

  -- radiation hydro

  -- AMR

  -- mapped grids

     * general quadralateral grids

     * moving grids

       - 1-d moving grid showing 
     
  -- MHD

  -- relativisitc

  -- WENO

  -- higher-order

     o method of lines integration with RK3/4 and high-order reconstruction

  -- implicit hydro

  -- shallow water

  -- cosmological flows

  -- understanding simulations

     * convergence tests

     * sanity checks

     * parameter studies vs. hero calculations

  -- volume of fluid




sample of public codes

  -- Athena
  -- Castro
  -- Enzo
  -- Flash
  -- Maestro
  -- Pluto
  -- Zeus


=======================

Chapter 2:

 -- in "what is a simulation", add a discussion of DNS, LES, and ILES

 -- add BC and difference on a grid examples perhaps through a ipython
    notebook.



=======================

Chapter 4:

 -- add a notebook showing FTCS and upwind on a simple FV grid
 
 pyro exercises:

 -- try out different limiters


=======================

Chapter 5:


 -- exercise: notebook showing burgers' solution


=======================

Chapter 6/7:

 -- add a figure for section 5.2.1, showing piecewise constant
    reconstruction

 -- add a discussion (interlude) motivating how limiters are derived

 -- bulletted list on different Riemann solvers

 -- derive the jump conditions and the entropy conditions for the 
    Riemann problem and show the function we zero.

 -- implementation detail: for Riemann solvers, usually the godunov
    velocity is set to 0 at symmetry boundaries

 -- it is important to odd-reflect the gravitational acceleration 
    at reflecting boundaries

 examples:

   -- 1-d Riemann solver
   -- 1-d Godunov

 pyro...


=======================

Multigrid chapter:

 examples:

   -- 1-d relaxation
   -- 1-d MG


=======================

Diffusion chapter:


  examples:
    
    -- 1-d diffusion solver
    
  pyro


----

reference for the choice of epsilon in numerical derivatives as
\sqrt{machine epsilon} -- this gives some suggestions:
http://mathoverflow.net/questions/28463/optimum-small-number-for-numerical-differentiation


----

tcolorbox for exercises:

http://tex.stackexchange.com/questions/172475/how-can-i-define-a-custom-tcolorbox-environment-with-color-as-a-parameter


http://www.scriptscoop2.com/t/e6de0140d668/counters-for-chapter-and-section-environments-when-using-tcolorbox-for.html


http://tex.stackexchange.com/questions/254401/use-the-exercise-environment-from-legrand-book-template

http://www.latextemplates.com/template/the-legrand-orange-book



================================================
FILE: advection/advection-basics.tex
================================================
\label{ch:advection}


\section{The linear advection equation}

The linear advection equation is simply:
\begin{equation}
\label{eq:advect}
a_t + u a_x = 0
\end{equation}
where $a(x,t)$ is some scalar quantity and $u$ is the velocity at
which it is advected ($u > 0$ advects to the right).  The solution to
Eq.~\ref{eq:advect} is to simply take the initial data, $a(x,t=0)$,
and displace it to the right at a speed $u$.  The shape of the initial
data is preserved in the advection.  Many hyperbolic systems of PDEs,
e.g.\ the equations of hydrodynamics, can be written in a form that
looks like a system of (nonlinear) advection equations, so the
advection equation provides important insight into the methods used
for these systems.
%
\begin{exercise}[Linear advection analytic solution]
{Show via substitution that $a(x - ut)$ is a solution to
  Eq.~\ref{eq:advect} for any choice of a.  This means that
the solution is constant along the lines $x = u t$
(the curves along which the solution is constant are called the
characteristics).}
\end{exercise}

Figure~\ref{fig:advection_char} shows an initial profile, $a(x)$, and
the corresponding characteristics in the $t$-$x$ plane.  With time,
since the solution is constant along these characteristics, it simply
each point simply follows the characteristic curve, resulting in a
shift of the profile to the right.

An important concept that we will discuss shortly is {\em stability}.
Not every discretization that we write down will be well behaved.  For
some, our initial state will begin to ``blow-up'', and take on
obscenely large and unphysical values after just a few steps.  This is
the hallmark of a method that is unstable.  Some methods have
restrictions on the size of the timestep that result in a stable
methods as well.

% this figure is produced by figures/advection/characteristics.py
\begin{figure}[t]
\centering
\includegraphics[width=0.6\linewidth]{advection-characteristics}
\caption[Characteristics for linear advection]
{\label{fig:advection_char} (top) Initially sinusoidal
distribution (bottom) Characteristic
structure for the linear advection equation $u = 1$.  Note
that for this linear equation the characteristics are all parallel
(they have the same slope in the $t$-$x$ plane.}
\end{figure}

\section{First-order advection in 1-d and finite-differences}

To get a flavor of the methods for advection, we will use a simple
finite-difference discretization---here, the domain is divided into
a sequence of points where we store the solution.
We will solve
Eq.~\ref{eq:advect} numerically by discretizing the solution at
these points.  The index $i$ denotes the point's location, and $a_i$
denotes the discrete value of $a(x)$ in zone $i$.  The data in each
zone can be initialized as $a_i = a(x_i)$.  Figure~\ref{fig:fdgrid}
shows the grid.

We also need to discretize in time.  We denote the time-level of the
solution with a superscript, so $a_i^n = a(x_i,t^n)$.  For a fixed
$\Delta t$, time level $n$ corresponds to a time of $t = n\Delta t$.


A simple first-order accurate discretization is:
\begin{equation}
\frac{a_i^{n+1} - a_i^n}{\Delta t} = - u \frac{a_i^n - a_{i-1}^n}{\Delta x}
\label{eq:fo}
\end{equation}
This is an {\em explicit} method, since the new solution, $a_i^{n+1}$,
depends only on information at the old time level, $n$.  

Finally, we also need to specify a boundary condition for this.  Our
choice of spatial derivative is one-sided---it uses information from
the zone to the left of the zone we are updating.  This is because
information is flowing from left to right in this problem ($u > 0$).
This choice of the derivative is called {\em upwinding}---this choice
of derivative results in a stable method.
Notice that if we use Eq.~\ref{eq:fo} to update the data in the first
zone inside the boundary, we need data to the left of this
zone---outside of the domain.  This means that we need a single
{\em ghost point} to implement the boundary conditions for our method.  The
presence of the ghost points allow us to use the same update equation
(e.g.\ Eq.~\ref{eq:fo}) for all zones in the domain.


% figure created by figures/advection/fd-ghost.py
\begin{figure}[t]
\centering
\includegraphics[width=\linewidth]{fd_ghost}
\caption[A simple finite-difference grid]{\label{fig:fdgrid} A simple
  finite-difference grid.  The solution is stored at each of the
  labeled points.  The dotted lines show the ghost points used to
  extend our grid past the physical boundaries to accommodate boundary
  conditions.  Note that if we are periodic, then points $0$ and $N-1$
  are at the same physical point in space, so we would only need to
  update one of them.}
\end{figure}

The last piece of information needed to update the solution is the
timestep, $\Delta t$.  It can be shown that for the solution to be
{\em stable}, the timestep must be less than the time it takes information
to propagate across a single zone.  That is:
\begin{equation}
\Delta t \le \frac{\Delta x}{u} \enskip .
\end{equation}
This is called the {\em Courant-Friedrichs-Lewy} or {\em CFL}
condition.  A dimensionless quantity called the {\em CFL number} is 
defined as 
\begin{equation}
\cfl = \frac{\Delta t u }{\Delta x} 
\end{equation}
Stability requires $\cfl \le 1$.
%
We traditionally write the timestep as
\begin{equation}
\label{eq:timestep}
\Delta t = \cfl \frac{\Delta x}{u}
\end{equation}
and specify $\cfl$ as part of the problem (a typical value may be $\cfl = 0.7$).

\begin{exercise}[Perfect advection with a Courant number of 1]
{Show analytically that when you use $\cfl=1$ in the
  first-order differenced advection equation (Eq.~\ref{eq:fo}) that
  you advect the profile exactly, without any numerical error.}
\end{exercise}

Keep in mind that, in general, we will be solving a non-linear
system of equations, so it is not possible to run with $\cfl=1$, 
since $u$ (and therefore $\cfl$) will change from zone to zone.
Instead, one looks at the most restrictive timestep over all the
zones and uses that for the entire system.


\begin{exercise}[A 1-d finite-difference solver for linear advection]
{Write a code to solve the 1-d linear advection equation
  using the discretization of Eq.~\ref{eq:fo} on the domain $[0,1]$ with
  $u=1$ and periodic boundary conditions.  For initial conditions,
  try both a Gaussian profile and a top-hat:}
  \begin{equation}
  a = \left \{
      \begin{array}{lllll}0 & \mathit{~if~~} &         &x& < 1/3 \\
                          1 & \mathit{~if~~} & 1/3 \le &x& < 2/3 \\
                          0 & \mathit{~if~~} & 2/3 \le &x&
      \end{array}
      \right .
  \end{equation}

  \noindent Note: For a general treatment of boundary conditions, you would
    initialize the ghost points to their corresponding periodic data
    and apply the difference equations to zones $0, \ldots, N-1$.
    However, for periodic BCs on this grid, points $0$ and $N-1$ are
    identical, so you could do the update in this special case on
    points $1, \ldots, N-1$ without the need for ghost points and then
    set $a_0 = a_{N-1}$ after the update. \\

  \noindent Run you program for one or more periods (one period
    is $T=1/u$) with several different CFL numbers and notice that
    there is substantial numerical dissipation (see Figure~\ref{fig:fdadvect}).
\end{exercise}

\begin{figure}[t]
\centering
% figure generated by hydro_examples/advection/fdadvect.py
\includegraphics[width=0.8\linewidth]{fdadvect-upwind}
\caption[First-order finite-difference solution to linear advection]
{\label{fig:fdadvect} Finite-difference solution to the first-order
finite-difference upwind method for advection, using 65 points and
a variety of CFL numbers. \\
\hydroexdoit{\href{https://github.com/zingale/hydro_examples/blob/master/advection/fdadvect.py}{fdadvect.py}}}
\end{figure}
%
This method is first-order accurate.  


Ultimately we will want higher-order accurate methods.  The most obvious
change from our initial discretization is to try a higher-order spatial
derivative.

\begin{exercise}[FTCS and stability]
{You may think that using a centered-difference for
  the spatial derivative, $a_x \sim (a_{i+1} - a_{i-1})/(2 \Delta x)$
  would be more accurate.  This method is called FTCS (forward-time,
  centered-space).  Try this on the same test problems.}
\end{exercise}

\begin{figure}[t]
\centering
% figure generated by hydro_examples/advection/fdadvect.py
\includegraphics[width=0.48\linewidth]{fdadvect-FTCS-C0_1}
\includegraphics[width=0.48\linewidth]{fdadvect-FTCS-C0_5}
\caption[FTCS finite-difference solution to linear advection]
{\label{fig:fdadvect-ftcs} Finite-difference solution using the FTCS
finite-difference method for advection using 65 points, modeling for
only 1/10$^\mathrm{th}$ of a period.  The panel of the left is
with $\cfl = 0.1$ and the panel on the right is $\cfl = 0.5$.\\
\hydroexdoit{\href{https://github.com/zingale/hydro_examples/blob/master/advection/fdadvect.py}{fdadvect.py}}}
\end{figure}

You will find that no matter what value of $\cfl$ you choose with the
FTCS method, the solution is unconditionally {\em unstable} (see
Figure~\ref{fig:fdadvect-ftcs}).  If you continue to evolve the
equation with this method, you would find that the amplitude grows
without bound.  There is something about that discretization that
simply gets the physics wrong.


\section{Stability}

\MarginPar{add a discussion of domain of dependence}

The classic method for understanding stability is to consider the growth 
of a single Fourier mode in our discretization.  That is, substitute in
$a_i^n = A^n e^{Ii\theta}$, where $I = \sqrt{-1}$\footnote{our use of $i$ and $j$ as spatial indices presents an unfortunate cl
Download .txt
gitextract_nerblykz/

├── .github/
│   └── workflows/
│       └── build-book.yml
├── .gitignore
├── ADDITIONS
├── CompHydroTutorial.tex
├── Euler/
│   ├── Euler-methods.tex
│   ├── Euler-theory.tex
│   ├── README
│   ├── axisymmetry.odg
│   └── main.tex
├── GNUmakefile
├── LICENSE
├── NOTES
├── README.md
├── TODO
├── advection/
│   ├── advection-basics.tex
│   ├── advection-higherorder.tex
│   ├── main.tex
│   └── old-scripts/
│       ├── fv.py
│       ├── simplegrid.py
│       └── simplegrid2.py
├── burgers/
│   └── burgers.tex
├── codes/
│   └── intro/
│       └── sin-converge.py
├── diffusion/
│   ├── GNUmakefile
│   └── diffusion.tex
├── figures/
│   ├── Euler/
│   │   ├── multiple_interfaces.py
│   │   ├── ppm-sequence.py
│   │   ├── ppm-trace.py
│   │   ├── ppm.py
│   │   ├── rarefaction_cartoon.py
│   │   ├── riemann-states-q.py
│   │   ├── riemann-states.py
│   │   ├── riemann-waves-jump.py
│   │   ├── riemann-waves.py
│   │   ├── riemann_cartoon.py
│   │   ├── states.py
│   │   └── update.sh
│   ├── advection/
│   │   ├── 2dFD.py
│   │   ├── 2dFV.py
│   │   ├── 2dgrid.py
│   │   ├── 2dgrid_hat.py
│   │   ├── 2dgrid_transverse.py
│   │   ├── characteristics.py
│   │   ├── domains.py
│   │   ├── fd_ghost.py
│   │   ├── fv_ghost.py
│   │   ├── generalgrid.py
│   │   ├── rea-limitex.py
│   │   ├── rea.py
│   │   ├── riemann.py
│   │   ├── riemann_bc.py
│   │   ├── riemann_mol.py
│   │   └── update.sh
│   ├── burgers/
│   │   ├── characteristics.py
│   │   ├── rh.py
│   │   └── update.sh
│   ├── finite-volume/
│   │   ├── ccfd.py
│   │   ├── discretizations.odg
│   │   ├── domain.py
│   │   ├── fd.py
│   │   ├── fv.py
│   │   ├── simplegrid2.py
│   │   ├── simplegrid_gc.py
│   │   └── update.sh
│   ├── gridFigs/
│   │   ├── fdrestrict.py
│   │   ├── fvprolong.py
│   │   ├── fvrestrict.py
│   │   └── nested.py
│   ├── incompressible/
│   │   ├── MAC-solve.py
│   │   └── MAC.py
│   ├── intro/
│   │   ├── fft_simple_examples.py
│   │   ├── integrals.py
│   │   ├── rk4_plot.py
│   │   └── update.sh
│   ├── multigrid/
│   │   ├── 2dgrid-mg.py
│   │   ├── fv-fd_bnd.py
│   │   ├── fvrestrict.py
│   │   ├── laplacian.py
│   │   ├── mgtower.py
│   │   ├── red_black.py
│   │   └── smooth-separate.py
│   └── weno/
│       └── weno.py
├── finite-volume/
│   ├── discretizations.eps
│   ├── finite-volume.tex
│   ├── main.tex
│   └── old-scripts/
│       ├── domain-1d.py
│       └── simplegrid.py
├── gravity/
│   └── gravity.tex
├── higher-order/
│   ├── higher-order-burgers.tex
│   ├── higher-order-euler.tex
│   └── weno-coefficients.ipynb
├── hydro-test-problems/
│   └── hydro-test-problems.tex
├── hydro1d/
│   └── hydro1d.tex
├── hydro_examples/
│   └── hydro_examples.tex
├── incompressible/
│   ├── GNUmakefile
│   ├── MAC.eps
│   ├── MAC_solve.eps
│   ├── incompressible.tex
│   └── main.tex
├── instabilities/
│   └── instabilities.tex
├── intro/
│   └── intro.tex
├── low_mach/
│   ├── low_mach.tex
│   ├── mg_vc_periodic_converge.eps
│   └── mg_vc_periodic_test.eps
├── multigrid/
│   ├── 2dgrid-prolong.eps
│   ├── GNUmakefile
│   ├── main.tex
│   ├── mg-converge.eps
│   ├── mg_error_vs_cycle.eps
│   ├── multigrid.tex
│   └── rb.eps
├── multiphysics/
│   └── multiphysics.tex
├── mysymbols.tex
├── pde-classes/
│   └── pde-classes.tex
├── preface/
│   └── preface.tex
├── public-codes/
│   └── NOTES
├── pyro/
│   └── pyro.tex
├── radiation/
│   ├── mg_general_inhomogeneous_converge.eps
│   ├── mg_general_inhomogeneous_test.eps
│   └── radiation.tex
├── reactive_flow/
│   ├── notes.txt
│   └── reactive_flow.tex
├── refs.bib
├── simulations/
│   └── simulations.tex
├── software-engineering/
│   ├── software-engineering.tex
│   └── topics.txt
└── symbols/
    └── symbols.tex
Download .txt
SYMBOL INDEX (76 symbols across 39 files)

FILE: advection/old-scripts/simplegrid.py
  function simplegrid (line 5) | def simplegrid():

FILE: advection/old-scripts/simplegrid2.py
  function simplegrid (line 5) | def simplegrid():

FILE: figures/Euler/multiple_interfaces.py
  class RiemannWaves (line 17) | class RiemannWaves(object):
    method __init__ (line 20) | def __init__(self, x0, dx):
    method draw (line 51) | def draw(self, output="plot.png", label=None):

FILE: figures/Euler/ppm-sequence.py
  class RiemannProblem (line 7) | class RiemannProblem(object):
    method __init__ (line 8) | def __init__(self, q_l, q_r, gamma=5./3., N=3):
    method draw_cubic_points (line 41) | def draw_cubic_points(self, var, color="r"):
    method draw_parabola (line 48) | def draw_parabola(self, var):
    method draw_grid (line 53) | def draw_grid(self):
    method draw_var_avg (line 62) | def draw_var_avg(self, var, scale=1.0):

FILE: figures/Euler/rarefaction_cartoon.py
  class RiemannWaves (line 14) | class RiemannWaves(object):
    method __init__ (line 17) | def __init__(self, rpos=-1):
    method draw (line 46) | def draw(self, output="plot.png", label=None):

FILE: figures/Euler/riemann-states-q.py
  function riemann (line 5) | def riemann(with_time=True):

FILE: figures/Euler/riemann-states.py
  function riemann (line 5) | def riemann(with_time=True):

FILE: figures/Euler/riemann-waves-jump.py
  function simplegrid (line 4) | def simplegrid():

FILE: figures/Euler/riemann-waves.py
  function simplegrid (line 4) | def simplegrid():

FILE: figures/Euler/riemann_cartoon.py
  class RiemannWaves (line 14) | class RiemannWaves(object):
    method __init__ (line 17) | def __init__(self, left=-1, contact=-1, right=1):
    method draw (line 29) | def draw(self, output="plot.png", label=None):

FILE: figures/Euler/states.py
  function riemann (line 6) | def riemann():

FILE: figures/advection/2dFD.py
  function simplegrid (line 6) | def simplegrid():

FILE: figures/advection/2dFV.py
  function simplegrid (line 6) | def simplegrid():

FILE: figures/advection/2dgrid.py
  function simplegrid (line 5) | def simplegrid():

FILE: figures/advection/2dgrid_hat.py
  function simplegrid (line 5) | def simplegrid():

FILE: figures/advection/2dgrid_transverse.py
  function simplegrid (line 6) | def simplegrid():

FILE: figures/advection/characteristics.py
  function fun (line 9) | def fun(x):
  function funs (line 14) | def funs(x):

FILE: figures/advection/domains.py
  function domains (line 12) | def domains(method="FTCS"):

FILE: figures/advection/rea-limitex.py
  function evolve (line 10) | def evolve(pl, C, num, nolimit=1):

FILE: figures/advection/riemann.py
  function riemann (line 5) | def riemann(with_time=True):

FILE: figures/advection/riemann_bc.py
  function riemann (line 5) | def riemann():

FILE: figures/advection/riemann_mol.py
  function riemann (line 5) | def riemann():

FILE: figures/burgers/characteristics.py
  function fun (line 9) | def fun(x):
  function funs (line 14) | def funs(x):
  function funr (line 18) | def funr(x):
  function make_plot (line 23) | def make_plot(icfun=None, label=""):

FILE: figures/burgers/rh.py
  function rh (line 12) | def rh():

FILE: figures/finite-volume/domain.py
  function draw_box (line 3) | def draw_box(ll, uu, nx, ny, gridColor="0.5", ng=0):

FILE: figures/finite-volume/simplegrid2.py
  function simplegrid (line 6) | def simplegrid():

FILE: figures/finite-volume/simplegrid_gc.py
  function simplegrid (line 5) | def simplegrid():

FILE: figures/incompressible/MAC-solve.py
  class Grid2d (line 7) | class Grid2d:
    method __init__ (line 9) | def __init__(self, nx, ny,
    method draw_grid (line 35) | def draw_grid(self):
  function simplegrid (line 86) | def simplegrid():

FILE: figures/incompressible/MAC.py
  function simplegrid (line 5) | def simplegrid():

FILE: figures/intro/fft_simple_examples.py
  function single_freq_sine (line 29) | def single_freq_sine(npts, xmax, f_0):
  function single_freq_sine_plus_shift (line 37) | def single_freq_sine_plus_shift(npts, xmax, f_0):
  function two_freq_sine (line 44) | def two_freq_sine(npts, xmax, f_0, f_1):
  function single_freq_cosine (line 52) | def single_freq_cosine(npts, xmax, f_0):
  function plot_FFT (line 60) | def plot_FFT(xx, xmax, f, outfile):

FILE: figures/intro/integrals.py
  function f (line 10) | def f(x):
  function plot_base (line 22) | def plot_base(xp, fp, xfine, a, b, label_mid=False):
  function rectangle (line 56) | def rectangle(xp, fp, a, b):
  function trapezoid (line 79) | def trapezoid(xp, fp, a, b):
  function simpsons (line 101) | def simpsons(xp, fp, a, b):
  function main (line 147) | def main():

FILE: figures/intro/rk4_plot.py
  function rhs (line 15) | def rhs(y):
  function exact (line 19) | def exact(t):
  function start (line 34) | def start():

FILE: figures/multigrid/2dgrid-mg.py
  function simplegrid (line 5) | def simplegrid():

FILE: figures/multigrid/laplacian.py
  function laplace (line 5) | def laplace():

FILE: figures/multigrid/red_black.py
  class marker (line 8) | class marker:
    method __init__ (line 10) | def __init__(self, xc, yc, color):
  function RB (line 20) | def RB():

FILE: figures/multigrid/smooth-separate.py
  function true (line 24) | def true(x):
  function error (line 29) | def error(ilo, ihi, dx, r):
  function f (line 34) | def f(x):
  function compute_residual (line 39) | def compute_residual(ilo, ihi, dx, phi, frhs):
  function smooth_run (line 47) | def smooth_run(nx, method="GS"):

FILE: figures/weno/weno.py
  function stencil_5_pts (line 6) | def stencil_5_pts(q):
  function stencils_3_pts (line 29) | def stencils_3_pts(q):
  function weno3 (line 53) | def weno3(q):

FILE: finite-volume/old-scripts/domain-1d.py
  function drawBox (line 5) | def drawBox(ll, uu, nx, ny, gridColor="0.5", ng=0):

FILE: finite-volume/old-scripts/simplegrid.py
  function simplegrid (line 6) | def simplegrid():
Condensed preview — 126 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,977K chars).
[
  {
    "path": ".github/workflows/build-book.yml",
    "chars": 885,
    "preview": "name: build book\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n    branches:\n      - main\n\njobs:\n  build-book:"
  },
  {
    "path": ".gitignore",
    "chars": 182,
    "preview": "*.pyc\n*~\n\\#*\n.\\#*\n\n\n*.log\n*.aux\n*.dvi\n*.bbl\n*.blg\n*-converted-to.pdf\n*.lof\n*.exc\n*.toc\n*.png\n*.bcf\n*.brf\nCompHydroTutori"
  },
  {
    "path": "ADDITIONS",
    "chars": 140,
    "preview": "* convergence testing via Richardson extrapolation\n\n  -- always test the convergence of the initial conditions\n\n* PPM vi"
  },
  {
    "path": "CompHydroTutorial.tex",
    "chars": 14363,
    "preview": "\\documentclass[11pt]{book}\n\n%\\usepackage{microtype}\n\n\\input conditional.tex\n%\\def\\debugmode{}\n\n% include figures\n\\usepac"
  },
  {
    "path": "Euler/Euler-methods.tex",
    "chars": 92920,
    "preview": "\\label{ch:compressible}\n\n\\section{Introduction}\n\n\\label{sec:eulermeth:intro}\n\nThe numerical methods we use for the Euler"
  },
  {
    "path": "Euler/Euler-theory.tex",
    "chars": 50440,
    "preview": "\\label{ch:compressible-theory}\n\n\n%-----------------------------------------------------------------------------\n\\section"
  },
  {
    "path": "Euler/README",
    "chars": 51,
    "preview": "sod.eps: made by hydro1d in the exact/ subdirector\n"
  },
  {
    "path": "Euler/main.tex",
    "chars": 1144,
    "preview": "\\documentclass[11pt]{article}\n\n% margins\n\\usepackage[margin=0.75in]{geometry}\n\n%\n\\usepackage{amsmath}\n\n% figures\n\\usepac"
  },
  {
    "path": "GNUmakefile",
    "chars": 1927,
    "preview": "# by default, typing make will build the `production' version of the \n# Computational Hydrodynamics notes.\n#\n# if you in"
  },
  {
    "path": "LICENSE",
    "chars": 20841,
    "preview": "Attribution-NonCommercial-ShareAlike 4.0 International\n\n================================================================"
  },
  {
    "path": "NOTES",
    "chars": 1007,
    "preview": "-- add to Ch 1 a review of numerical methods:\n\n   . truncation vs. roundoff error\n   . numerical differentiation and int"
  },
  {
    "path": "README.md",
    "chars": 1894,
    "preview": "# Computational Hydrodynamics for Astrophysics\n\n*part of the Open Astrophysics Bookshelf*\n\nNotes on numerical methods fo"
  },
  {
    "path": "TODO",
    "chars": 2812,
    "preview": "Add implementation details throughout, explaining how to translate stuff into code\n   -- maybe in the margins with the T"
  },
  {
    "path": "advection/advection-basics.tex",
    "chars": 20043,
    "preview": "\\label{ch:advection}\n\n\n\\section{The linear advection equation}\n\nThe linear advection equation is simply:\n\\begin{equation"
  },
  {
    "path": "advection/advection-higherorder.tex",
    "chars": 68479,
    "preview": "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\\section{Advection and the finite-volume"
  },
  {
    "path": "advection/main.tex",
    "chars": 1370,
    "preview": "\\documentclass[11pt]{article}\n\n% margins\n\\usepackage[margin=0.75in]{geometry}\n\n% figures\n\\usepackage{graphicx}\n\n% font\n\\"
  },
  {
    "path": "advection/old-scripts/fv.py",
    "chars": 936,
    "preview": "import math\nimport numpy\nimport pylab\nimport grid_plot_util as gpu\n\n\nnzones = 5\n\n# data that lives on the grid\na = numpy"
  },
  {
    "path": "advection/old-scripts/simplegrid.py",
    "chars": 3534,
    "preview": "import math\nimport numpy\nimport pylab\n\ndef simplegrid():\n\n    # grid info\n    xmin = 0.0\n    xmax = 1.0\n\n    nzones = 7\n"
  },
  {
    "path": "advection/old-scripts/simplegrid2.py",
    "chars": 1975,
    "preview": "import math\nimport numpy\nimport pylab\n\ndef simplegrid():\n\n    xmin = 0.0\n    xmax = 1.0\n\n    nzones = 7\n\n    dx = (xmax "
  },
  {
    "path": "burgers/burgers.tex",
    "chars": 14757,
    "preview": "\\label{ch:burgers}\n\n\\section{Burgers' equation}\n\nThe inviscid Burgers' equation is the simplest {\\em nonlinear} hyperbol"
  },
  {
    "path": "codes/intro/sin-converge.py",
    "chars": 100,
    "preview": "import math\n\nX = [0.5, 0.25, 0.125, 0.0625]\n\nfor x in X:\n    print x, math.sin(x) - (x - x**3/6.0)\n\n"
  },
  {
    "path": "diffusion/GNUmakefile",
    "chars": 324,
    "preview": "EPStoPDF = epstopdf\n\nALL: diffusion.pdf\n\n\ndiffusion.pdf: main.tex diffusion.tex\n\tpdflatex -jobname=diffusion main.tex < "
  },
  {
    "path": "diffusion/diffusion.tex",
    "chars": 26779,
    "preview": "\\label{ch:diffusion}\n\n\\section{Diffusion}\n\n\\label{sec:diffusion}\n\nPhysically, a diffusive process obeys Fick's law---the"
  },
  {
    "path": "figures/Euler/multiple_interfaces.py",
    "chars": 3667,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport matplotlib as mpl\nimport random\n\nimport grid_plot as gp\n\nmpl.r"
  },
  {
    "path": "figures/Euler/ppm-sequence.py",
    "chars": 4303,
    "preview": "import math\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\nimport riemann\n\nclass RiemannProbl"
  },
  {
    "path": "figures/Euler/ppm-trace.py",
    "chars": 1485,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\n\n#-------------------------------------------"
  },
  {
    "path": "figures/Euler/ppm.py",
    "chars": 2397,
    "preview": "import math\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\n\n#-------------------------------"
  },
  {
    "path": "figures/Euler/rarefaction_cartoon.py",
    "chars": 3982,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport matplotlib as mpl\n\nmpl.rcParams['mathtext.fontset'] = 'cm'\nmpl"
  },
  {
    "path": "figures/Euler/riemann-states-q.py",
    "chars": 2124,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\ndef riemann(with_time=True):\n\n    # grid info"
  },
  {
    "path": "figures/Euler/riemann-states.py",
    "chars": 2158,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\ndef riemann(with_time=True):\n\n    # grid info"
  },
  {
    "path": "figures/Euler/riemann-waves-jump.py",
    "chars": 1622,
    "preview": "import matplotlib.pyplot as plt\nimport grid_plot as gp\n\ndef simplegrid():\n\n    # grid info\n    xmin = 0.0\n    xmax = 1.0"
  },
  {
    "path": "figures/Euler/riemann-waves.py",
    "chars": 2310,
    "preview": "import matplotlib.pyplot as plt\nimport grid_plot as gp\n\ndef simplegrid():\n\n    # grid info\n    xmin = 0.0\n    xmax = 1.0"
  },
  {
    "path": "figures/Euler/riemann_cartoon.py",
    "chars": 3436,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport matplotlib as mpl\n\nmpl.rcParams['mathtext.fontset'] = 'cm'\nmpl"
  },
  {
    "path": "figures/Euler/states.py",
    "chars": 1433,
    "preview": "import math\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\ndef riemann():\n\n    # grid info\n "
  },
  {
    "path": "figures/Euler/update.sh",
    "chars": 387,
    "preview": "#!/bin/sh\n\nDEST=../../Euler\n\n# riemann-states.py makes riemann_comp.pdf\npython3 riemann-states.py\ncp -f riemann_comp.pdf"
  },
  {
    "path": "figures/advection/2dFD.py",
    "chars": 1104,
    "preview": "import math\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\ndef simplegrid():\n\n    nzones = 5"
  },
  {
    "path": "figures/advection/2dFV.py",
    "chars": 1142,
    "preview": "import math\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\ndef simplegrid():\n\n    nzones = 5"
  },
  {
    "path": "figures/advection/2dgrid.py",
    "chars": 1634,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\ndef simplegrid():\n\n    nzones = 3\n    gr = gp"
  },
  {
    "path": "figures/advection/2dgrid_hat.py",
    "chars": 1742,
    "preview": "import numpy\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\ndef simplegrid():\n\n    nzones = 3\n    gr = gp.FVGri"
  },
  {
    "path": "figures/advection/2dgrid_transverse.py",
    "chars": 2307,
    "preview": "import math\nimport numpy\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\ndef simplegrid():\n\n    nzones = 3\n    g"
  },
  {
    "path": "figures/advection/characteristics.py",
    "chars": 1607,
    "preview": "import numpy as np\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\n\nmpl.rcParams['mathtext.fontset'] = 'cm'\nmpl"
  },
  {
    "path": "figures/advection/domains.py",
    "chars": 3390,
    "preview": "import numpy as np\nimport matplotlib.pylab as plt\nimport matplotlib as mpl\n\nmpl.rcParams['mathtext.fontset'] = 'cm'\nmpl."
  },
  {
    "path": "figures/advection/fd_ghost.py",
    "chars": 938,
    "preview": "import grid_plot as gp\nimport numpy as np\n\n# plot a simple finite-difference grid\n\n#------------------------------------"
  },
  {
    "path": "figures/advection/fv_ghost.py",
    "chars": 1414,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\n# plot a simple finite-difference grid\n\n#----"
  },
  {
    "path": "figures/advection/generalgrid.py",
    "chars": 902,
    "preview": "import math\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\n\nnzones = 7\n\n# data that lives on"
  },
  {
    "path": "figures/advection/rea-limitex.py",
    "chars": 5139,
    "preview": "# reconstruct - evolve - average: demonstrate what happens when we don't\n# limit\n\n\nimport numpy as np\nimport matplotlib."
  },
  {
    "path": "figures/advection/rea.py",
    "chars": 3472,
    "preview": "# reconstruct - evolve - average\n\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\n\n#---------"
  },
  {
    "path": "figures/advection/riemann.py",
    "chars": 1979,
    "preview": "import numpy as np\nimport matplotlib.pylab as plt\nimport grid_plot as gp\n\ndef riemann(with_time=True):\n\n    # grid info\n"
  },
  {
    "path": "figures/advection/riemann_bc.py",
    "chars": 2088,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\ndef riemann():\n\n    # grid info\n    xmin = 0."
  },
  {
    "path": "figures/advection/riemann_mol.py",
    "chars": 1889,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\ndef riemann():\n\n    # grid info\n    xmin = 0."
  },
  {
    "path": "figures/advection/update.sh",
    "chars": 1568,
    "preview": "#!/bin/sh\n\nDEST=../../advection\n\n# characteristics.py makes advection-characteristics.pdf\npython3 characteristics.py\ncp "
  },
  {
    "path": "figures/burgers/characteristics.py",
    "chars": 2017,
    "preview": "import numpy as np\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\n\nmpl.rcParams['mathtext.fontset'] = 'cm'\nmpl"
  },
  {
    "path": "figures/burgers/rh.py",
    "chars": 3000,
    "preview": "import numpy as np\nimport matplotlib.pylab as plt\nimport matplotlib as mpl\n\nmpl.rcParams['mathtext.fontset'] = 'cm'\nmpl."
  },
  {
    "path": "figures/burgers/update.sh",
    "chars": 295,
    "preview": "#!/bin/sh\n\nDEST=../../burgers\n\n# characteristics.py makes burgers-characteristics.pdf\npython3 characteristics.py\ncp -f b"
  },
  {
    "path": "figures/finite-volume/ccfd.py",
    "chars": 1022,
    "preview": "import math\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\n# plot a simple finite-difference"
  },
  {
    "path": "figures/finite-volume/domain.py",
    "chars": 1327,
    "preview": "import matplotlib.pyplot as plt\n\ndef draw_box(ll, uu, nx, ny, gridColor=\"0.5\", ng=0):\n\n    # draw the frame\n    plt.plot"
  },
  {
    "path": "figures/finite-volume/fd.py",
    "chars": 974,
    "preview": "\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport grid_plot as gp\n\n# plot a simple finite-difference grid\n\n#---"
  },
  {
    "path": "figures/finite-volume/fv.py",
    "chars": 1162,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\n\n\n# plot a simple finite-difference grid\n\n#--"
  },
  {
    "path": "figures/finite-volume/simplegrid2.py",
    "chars": 996,
    "preview": "import math\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport grid_plot as gp\n\ndef simplegrid():\n\n    nzones = 7"
  },
  {
    "path": "figures/finite-volume/simplegrid_gc.py",
    "chars": 1237,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\ndef simplegrid():\n\n    # grid info\n    nzones"
  },
  {
    "path": "figures/finite-volume/update.sh",
    "chars": 468,
    "preview": "#!/bin/sh\n\n# fd.py creates fd_grid.pdf\npython3 fd.py\ncp -f fd_grid.pdf ../../finite-volume/\n\n# ccfd.py creates ccfd_grid"
  },
  {
    "path": "figures/gridFigs/fdrestrict.py",
    "chars": 1464,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\n# plot two stacked fv grids of different (2x)"
  },
  {
    "path": "figures/gridFigs/fvprolong.py",
    "chars": 1303,
    "preview": "import matplotlib.pyplot as plt\nimport grid_plot as gp\n\n# plot two stacked fv grids of different (2x) resolution to show"
  },
  {
    "path": "figures/gridFigs/fvrestrict.py",
    "chars": 1323,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\n# plot two stacked fv grids of different (2x)"
  },
  {
    "path": "figures/gridFigs/nested.py",
    "chars": 4878,
    "preview": "import matplotlib.pyplot as plt\nimport grid_plot as gp\n\n# plot two stacked fv grids of different (2x) resolution to show"
  },
  {
    "path": "figures/incompressible/MAC-solve.py",
    "chars": 7476,
    "preview": "import math\nimport numpy\nimport pylab\n\n\n\nclass Grid2d:\n\n    def __init__(self, nx, ny,\n                 xmin=0.0, xmax=1"
  },
  {
    "path": "figures/incompressible/MAC.py",
    "chars": 5187,
    "preview": "import math\nimport numpy\nimport pylab\n\ndef simplegrid():\n\n    # grid info\n    xmin = 0.0\n    xmax = 1.0\n\n    ymin = 0.0\n"
  },
  {
    "path": "figures/intro/fft_simple_examples.py",
    "chars": 4252,
    "preview": "from __future__ import print_function\n\nimport matplotlib.pyplot as plt\nimport matplotlib as mpl\nimport numpy as np\nimpor"
  },
  {
    "path": "figures/intro/integrals.py",
    "chars": 4497,
    "preview": "import numpy as np\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\nfrom matplotlib.patches import Polygon\n\nmpl."
  },
  {
    "path": "figures/intro/rk4_plot.py",
    "chars": 5474,
    "preview": "# make a plot of what the 4th-order Runge-Kutta is doing using the\n# example dy/dt = -y (this comes from Garcia).\n\nfrom "
  },
  {
    "path": "figures/intro/update.sh",
    "chars": 277,
    "preview": "#!/bin/sh\n\n# integrals.py creates rectange.pdf trapezoid.pdf simpsons.pdf\npython3 integrals.py \ncp -f rectangle.pdf trap"
  },
  {
    "path": "figures/multigrid/2dgrid-mg.py",
    "chars": 5325,
    "preview": "import math\nimport numpy\nimport pylab\n\ndef simplegrid():\n\n    #---------------------------------------------------------"
  },
  {
    "path": "figures/multigrid/fv-fd_bnd.py",
    "chars": 3164,
    "preview": "import matplotlib.pyplot as plt\nimport numpy as np\nimport grid_plot as gp\n\n# plot a simple finite-difference grid showin"
  },
  {
    "path": "figures/multigrid/fvrestrict.py",
    "chars": 1340,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\n# plot two stacked fv grids of different (2x)"
  },
  {
    "path": "figures/multigrid/laplacian.py",
    "chars": 1386,
    "preview": "import numpy as np\nimport matplotlib.pyplot as plt\nimport grid_plot as gp\n\ndef laplace():\n\n    # grid info\n    xmin = 0."
  },
  {
    "path": "figures/multigrid/mgtower.py",
    "chars": 620,
    "preview": "import matplotlib.pyplot as plt\nimport grid_plot as gp\n\n# plot two stacked fv grids of different (2x) resolution to show"
  },
  {
    "path": "figures/multigrid/red_black.py",
    "chars": 1996,
    "preview": "import math\nimport numpy\nimport pylab\nimport random\n\n# red black gauss seidel pattern\n\nclass marker:\n\n    def __init__(s"
  },
  {
    "path": "figures/multigrid/smooth-separate.py",
    "chars": 3170,
    "preview": "#!/usr/bin/env python\n\n\"\"\"\n\nan example of solving Poisson's equation via smoothing only.  Here, we\nsolve\n\nu_xx = sin(x)\n"
  },
  {
    "path": "figures/weno/weno.py",
    "chars": 12345,
    "preview": "import numpy\nfrom matplotlib import pyplot\n\nng = 2\n\ndef stencil_5_pts(q):\n    \"\"\"\n    Do reconstruction to q_{i+1/2} usi"
  },
  {
    "path": "finite-volume/discretizations.eps",
    "chars": 107763,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0 \n%%BoundingBox: 0 0 792 612\n%%Pages: 0\n%%Creator: LibreOffice 3.6\n%%Title: none\n%%CreationDate: "
  },
  {
    "path": "finite-volume/finite-volume.tex",
    "chars": 20129,
    "preview": "\\label{ch:fv}\n\n\\section{Discretization}\n\nThe physical systems we model are described by continuous mathematical\nfunction"
  },
  {
    "path": "finite-volume/main.tex",
    "chars": 1342,
    "preview": "\\documentclass[11pt]{article}\n\n% margins\n\\usepackage[margin=0.75in]{geometry}\n\n% figures\n\\usepackage{graphicx}\n\n% font\n\\"
  },
  {
    "path": "finite-volume/old-scripts/domain-1d.py",
    "chars": 1450,
    "preview": "import pylab\nimport numpy\n\n\ndef drawBox(ll, uu, nx, ny, gridColor=\"0.5\", ng=0):\n\n    # draw the frame\n    pylab.plot([ll"
  },
  {
    "path": "finite-volume/old-scripts/simplegrid.py",
    "chars": 1277,
    "preview": "import math\nimport numpy\nimport pylab\nimport grid_plot_util as gpu\n\ndef simplegrid():\n\n    # grid info\n    nzones = 7\n  "
  },
  {
    "path": "gravity/gravity.tex",
    "chars": 377,
    "preview": "\\section{Self-gravity and hydrodynamics}\n\n\\section{Monopole approximation}\n\n -- radial sampling\n -- time-centering\n -- p"
  },
  {
    "path": "higher-order/higher-order-burgers.tex",
    "chars": 5793,
    "preview": "\n\\section{WENO methods, nonlinear equations, and flux-splitting}\n\\label{sec:weno-burgers-fvs}\n\n%\\todo{Also note that I h"
  },
  {
    "path": "higher-order/higher-order-euler.tex",
    "chars": 6985,
    "preview": "\n\\section{WENO methods for the Euler equations}\n\\label{sec:weno-euler}\n\nWhen dealing with nonlinear systems the flux spl"
  },
  {
    "path": "higher-order/weno-coefficients.ipynb",
    "chars": 139546,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# WENO coefficients\"\n   ]\n  },\n  {\n"
  },
  {
    "path": "hydro-test-problems/hydro-test-problems.tex",
    "chars": 2066,
    "preview": "\\section{Testing}\n\nThere are a large number of standard hydrodynamics test problems that\nshould be run on any implementa"
  },
  {
    "path": "hydro1d/hydro1d.tex",
    "chars": 2963,
    "preview": "\\label{app:hydro1d}\n\n%% \\begin{center}\n%% \\includegraphics[width=0.125\\linewidth]{pyro-sm}\n%% \\end{center}\n\n\\section{Int"
  },
  {
    "path": "hydro_examples/hydro_examples.tex",
    "chars": 7267,
    "preview": "\\label{app:hydroex}\n\n\\section{Introduction}\n\nThe \\hydroex\\ codes are simple 1-d solvers written in python that\nillustrat"
  },
  {
    "path": "incompressible/GNUmakefile",
    "chars": 359,
    "preview": "EPStoPDF = epstopdf\n\nALL: incompressible.pdf\n\n\nincompressible.pdf: main.tex incompressible.tex\n\tpdflatex -jobname=incomp"
  },
  {
    "path": "incompressible/MAC.eps",
    "chars": 24444,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0\n%%Title: MAC.eps\n%%Creator: matplotlib version 1.0.1, http://matplotlib.sourceforge.net/\n%%Creat"
  },
  {
    "path": "incompressible/MAC_solve.eps",
    "chars": 35799,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0\n%%Title: MAC_solve.eps\n%%Creator: matplotlib version 1.3.1, http://matplotlib.org/\n%%CreationDat"
  },
  {
    "path": "incompressible/incompressible.tex",
    "chars": 38250,
    "preview": "\\label{ch:incompressible}\n\n\\section{Incompressible flow}\n\nAs a fluid parcel advects through a domain, it compresses and "
  },
  {
    "path": "incompressible/main.tex",
    "chars": 1517,
    "preview": "\\documentclass[11pt]{article}\n\n% margins\n\\usepackage[margin=0.75in]{geometry}\n\n% figures\n\\usepackage{graphicx}\n\n% font\n\\"
  },
  {
    "path": "instabilities/instabilities.tex",
    "chars": 900,
    "preview": "\\section{Dimensionless numbers}\n\n\nRe\n\nRa\n\nM\n\nPr\n\nRossby\n\nTaylor\n\nAtwood\n\n\nTurbulence and instabilities are ubitiquous in"
  },
  {
    "path": "intro/intro.tex",
    "chars": 36295,
    "preview": "\\section{What is simulation?}\n\nAstronomy is an observational science.  Unlike in terrestrial physics,\nwe do not have the"
  },
  {
    "path": "low_mach/low_mach.tex",
    "chars": 21590,
    "preview": "\\newcommand{\\teta}{\\tilde{\\eta}}\n\nIncompressible flow represents the zero-Mach number limit of fluid\nflow---no compressi"
  },
  {
    "path": "low_mach/mg_vc_periodic_converge.eps",
    "chars": 30864,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0\n%%Title: mg_vc_periodic_converge.eps\n%%Creator: matplotlib version 1.3.1, http://matplotlib.org/"
  },
  {
    "path": "low_mach/mg_vc_periodic_test.eps",
    "chars": 1239193,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0\n%%Title: mg_vc_periodic_test.eps\n%%Creator: matplotlib version 1.3.1, http://matplotlib.org/\n%%C"
  },
  {
    "path": "multigrid/2dgrid-prolong.eps",
    "chars": 18009,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0\n%%Title: 2dgrid-prolong.eps\n%%Creator: matplotlib version 1.3.1, http://matplotlib.org/\n%%Creati"
  },
  {
    "path": "multigrid/GNUmakefile",
    "chars": 324,
    "preview": "EPStoPDF = epstopdf\n\nALL: multigrid.pdf\n\n\nmultigrid.pdf: main.tex multigrid.tex\n\tpdflatex -jobname=multigrid main.tex < "
  },
  {
    "path": "multigrid/main.tex",
    "chars": 937,
    "preview": "\\documentclass[11pt]{article}\n\n% margins\n\\usepackage[margin=0.75in]{geometry}\n\n% figures\n\\usepackage{graphicx}\n\n% font\n\\"
  },
  {
    "path": "multigrid/mg-converge.eps",
    "chars": 53199,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0\n%%Title: mg-converge.eps\n%%Creator: matplotlib version 1.3.1, http://matplotlib.org/\n%%CreationD"
  },
  {
    "path": "multigrid/mg_error_vs_cycle.eps",
    "chars": 46826,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0\n%%Title: mg_error_vs_cycle.eps\n%%Creator: matplotlib version 1.2.0, http://matplotlib.org/\n%%Cre"
  },
  {
    "path": "multigrid/multigrid.tex",
    "chars": 41273,
    "preview": "\\label{ch:multigrid}\n\n\\section{Elliptic equations}\n\nThe simplest elliptic PDE is {\\em Laplace's equation}:\n\\begin{equati"
  },
  {
    "path": "multigrid/rb.eps",
    "chars": 16946,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0\n%%Title: rb.eps\n%%Creator: matplotlib version 1.3.1, http://matplotlib.org/\n%%CreationDate: Fri "
  },
  {
    "path": "multiphysics/multiphysics.tex",
    "chars": 11195,
    "preview": "\n\\section{Integrating Multiphysics}\n\nConsider a system whose evolution depends on several different\nphysical processes, "
  },
  {
    "path": "mysymbols.tex",
    "chars": 1688,
    "preview": "\\newcommand{\\cfl}{{\\mathcal{C}}}\n\n% velocity\n\\newcommand{\\Ub}{{\\bf U}}\n\\newcommand{\\gb}{{\\bf g}}\n\\newcommand{\\Gb}{{\\bf G"
  },
  {
    "path": "pde-classes/pde-classes.tex",
    "chars": 3615,
    "preview": "\\section{Introduction}\n\nPartial differential equations (PDEs) are usually grouped into one of\nthree different classes: {"
  },
  {
    "path": "preface/preface.tex",
    "chars": 4940,
    "preview": "\nThis text started as a set of notes to help new students at Stony\nBrook University working on projects in computational"
  },
  {
    "path": "public-codes/NOTES",
    "chars": 310,
    "preview": "Describe the features of public codes:\n\n\nAthena\n\nCastro\n\nEnzo\n\nFlash\n\nMaestro\n\npyro\n\npluto\n\n\n\n\ngive details on:\n\n -- sol"
  },
  {
    "path": "pyro/pyro.tex",
    "chars": 8191,
    "preview": "\\label{app:pyro}\n\n%% \\begin{center}\n%% \\includegraphics[width=0.125\\linewidth]{pyro-sm}\n%% \\end{center}\n\n\n\\section{Intro"
  },
  {
    "path": "radiation/mg_general_inhomogeneous_converge.eps",
    "chars": 34274,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0\n%%Title: mg_general_inhomogeneous_converge.eps\n%%Creator: matplotlib version 1.3.1, http://matpl"
  },
  {
    "path": "radiation/mg_general_inhomogeneous_test.eps",
    "chars": 1352251,
    "preview": "%!PS-Adobe-3.0 EPSF-3.0\n%%Title: mg_general_inhomogeneous_test.eps\n%%Creator: matplotlib version 1.3.1, http://matplotli"
  },
  {
    "path": "radiation/radiation.tex",
    "chars": 5971,
    "preview": "\\label{ch:radiation}\n\n\\section{Equations of Radiation Hydrodynamics}\n\n\\subsection{Reference Frames}\n\n\\subsection{Angular"
  },
  {
    "path": "reactive_flow/notes.txt",
    "chars": 153,
    "preview": "-- mass fractions, partial density\n\n-- ODEs for reaction network\n\n-- number density\n\n-- coupling (Strang splitting vs. S"
  },
  {
    "path": "reactive_flow/reactive_flow.tex",
    "chars": 16898,
    "preview": "\n\\section{Introduction}\n\nMany astrophysical problems involve modeling nuclear (or chemical)\nreactions coupled with hydro"
  },
  {
    "path": "refs.bib",
    "chars": 38651,
    "preview": "@String{ JCP     = \"J Comput Phys\"}\n@String{ JAS     = \"J Atmos Sci\"}\n@String{ APJ     = \"Astrophys J\"}\n@String{ APJ:sup"
  },
  {
    "path": "simulations/simulations.tex",
    "chars": 11795,
    "preview": "\\section{How to setup a simulation?}\n\nWhen you perform a simulation, you are making a series of\napproximations.  The fir"
  },
  {
    "path": "software-engineering/software-engineering.tex",
    "chars": 1273,
    "preview": "\\section{Version control}\n\nVersion control gives you the ability to keep track of changes to your\nsource, interact with "
  },
  {
    "path": "software-engineering/topics.txt",
    "chars": 139,
    "preview": "\n\n-- git & github\n\n-- diff\n\n-- gnuplot\n\n-- awk\n\n-- grep / ack\n\n-- basic scripting (for i in ...  [ seq, *.png ]\n\n   . ba"
  },
  {
    "path": "symbols/symbols.tex",
    "chars": 3702,
    "preview": "\n\\renewcommand{\\arraystretch}{1.5}\n%\n\\begin{center}\n\\begin{longtable}{|l|p{3.25in}|l|}\n\\caption[Definition of symbols.]{"
  }
]

// ... and 2 more files (download for full content)

About this extraction

This page contains the full source code of the Open-Astrophysics-Bookshelf/numerical_exercises GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 126 files (3.7 MB), approximately 972.1k tokens, and a symbol index with 76 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!