<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Advection
We start our study with the scalar, linear hyperbolic PDE
Step1:  Characteristics
Notice that the solution is constant along the line $x-at=C$, for each value of $C$.  These are parallel, straight lines in the $x-t$ plane, with slope $1/a$, as shown in the figure below.
Step2:  We can think of the initial values $q_0(x)$ being transmitted along these lines; we sometimes say that information is transmitted along characteristics. 
The next figure shows how an initial hump propagates to the right along characteristics.
Step3:  For more complicated hyperbolic problems, we may have multiple sets of characteristics, they may not be parallel, and the solution may not be constant along them.  But it will still be the case that information is propagated along characteristics.  The idea that information propagates at finite speed is an essential property of hyperbolic PDEs.
The Riemann problem
The Riemann problem consists of a hyperbolic PDE, such as (\ref{adv
Step4:  Notice how the initial discontinuity follows the characteristic coming from $x=0$ at $t=0$.
In the live notebook, you can adjust the advection speed $a$ and see how this changes the solution.
Here's another way to look at the Riemann solution that will be very useful for more complicated equations.
<ASSISTANT_TASK:>
Python Code:
%matplotlib inline
%config InlineBackend.figure_format = 'svg'
from ipywidgets import interact
from exact_solvers import advection
Explanation: Advection
We start our study with the scalar, linear hyperbolic PDE: the advection equation. The solution to this equation simply consists of the initial condition propagating with constant velocity.  We first describe the physical origin of this equation and then investigate the solution of the corresponding Riemann problem. This equation is studied in more detail e.g. in Chapter 2 of <cite data-cite="fvmhp"><a href="riemann.html#fvmhp">(LeVeque, 2002)</a></cite>, for example.
To examine the Python code for this chapter, see:
exact_solvers/advection.py ...
   on github.
Conservation of mass
Imagine a fluid flowing in a long, narrow tube.  We'll use $q$ to indicate the density of the fluid and $u$ to indicate its velocity.  Both of these are functions of space and time: $q = q(x,t)$; $u=u(x,t)$.  The total mass in the section of tube $[x_1,x_2]$ is
\begin{equation}
\int_{x_1}^{x_2} q(x,t) dx.
\end{equation}
This total mass changes over time due to flow in or out of this section of the tube.  We call the rate of flow the flux, and denote it by $f(q)$.  Thus the net rate of flow of mass into (or out of) the interval $[x_1,x_2]$ at time $t$ is
$$f(q(x_1,t)) - f(q(x_2,t)).$$
We just said that this rate of flow must equal the time rate of change of total mass; i.e.
$$\frac{d}{dt} \int_{x_1}^{x_2} q(x,t) dx = f(q(x_1,t)) - f(q(x_2,t)).$$
Now since $\int_{x_1}^{x_2} \frac{\partial}{\partial x} f(q) dx = f(q(x_2,t)) - f(q(x_1,t))$, we can rewrite this as
$$\frac{d}{dt} \int_{x_1}^{x_2} q(x,t) dx = -\int_{x_1}^{x_2} \frac{\partial}{\partial x} f(q) dx.$$
If $q$ is sufficiently smooth, we can move the time derivative inside the integral.  We'll also put everything on the left side, to obtain
$$\int_{x_1}^{x_2} \left(\frac{\partial}{\partial t}q(x,t) + \frac{\partial}{\partial x} f(q)\right) dx = 0.$$
Since this integral vanishes for any choice of $x_1,x_2$, it must be that the integrand vanishes everywhere.  Therefore we can write the differential conservation law
$$q_t + f(q)_x = 0.$$
This equation expresses the fact that the total mass is conserved, since locally the mass can change only due to a net inflow or outflow.
Advection
In order to solve the conservation law above, we need an expression for the flux, $f$.  The rate of flow is just density times velocity: $f=u q$.  Thus we obtain the continuity equation
$$q_t + (uq)_x = 0.$$  
In general, we need another equation to determine the velocity $u(x,t)$.  In later chapters we'll examine models in which the velocity depends on the density (or other properties), but for now let's consider the simplest case, in which the flow is characterized by a single, constant velocity $u(x,t)=a$.  Then the continuity equation becomes the advection equation
\begin{align} \label{adv:advection}
    q_t + a q_x = 0.
\end{align}
This equation has a very simple solution.  Given the initial density $q(x,0)=q_0(x)$, the solution is simply
\begin{align} \label{adv:solution}
    q(x,t) = q_0(x-at).
\end{align}
End of explanation
interact(advection.characteristics);
Explanation: Characteristics
Notice that the solution is constant along the line $x-at=C$, for each value of $C$.  These are parallel, straight lines in the $x-t$ plane, with slope $1/a$, as shown in the figure below.
End of explanation
interact(advection.solution);
Explanation: We can think of the initial values $q_0(x)$ being transmitted along these lines; we sometimes say that information is transmitted along characteristics. 
The next figure shows how an initial hump propagates to the right along characteristics.
End of explanation
interact(advection.riemann_demo);
Explanation: For more complicated hyperbolic problems, we may have multiple sets of characteristics, they may not be parallel, and the solution may not be constant along them.  But it will still be the case that information is propagated along characteristics.  The idea that information propagates at finite speed is an essential property of hyperbolic PDEs.
The Riemann problem
The Riemann problem consists of a hyperbolic PDE, such as (\ref{adv:advection}), together with piecewise constant initial data consisting of two states.  For convenience, we place the interface (or jump) at $x=0$ and refer to the left state (for $x<0$) as $q_\ell$ and the right state (for $x>0$) as $q_r$.  We thus have
\begin{align}
    q_0(x) & = \begin{cases} q_\ell & x<0 \ q_r & x>0. \end{cases}
\end{align}
For the advection equation, the solution to the Riemann problem is immediately obvious; it is simply a special case of (\ref{adv:solution}).  The discontinuity initially at $x=0$ moves at speed $a$.  We have
\begin{align}
    q(x,t) & = \begin{cases} q_\ell & x-at<0 \ q_r & x-at>0. \end{cases}
\end{align}
End of explanation
q_l = 1.
q_r = 0.
advection.plot_riemann_solution(q_l, q_r, a=1.);
Explanation: Notice how the initial discontinuity follows the characteristic coming from $x=0$ at $t=0$.
In the live notebook, you can adjust the advection speed $a$ and see how this changes the solution.
Here's another way to look at the Riemann solution that will be very useful for more complicated equations.
End of explanation
<END_TASK>