diff --git a/Snakefile b/Snakefile
index 9a4e7911895b3eadf9025bdc537510b1230771e0..8252eea6e3d394955c568a8f0ba5653d0630af49 100644
--- a/Snakefile
+++ b/Snakefile
@@ -9,8 +9,6 @@ TODO: Contemplate separating cell average and reconstruction calculations
 TODO: Contemplate removing Methods section from class docstring
 TODO: Contemplate containing the quadrature application for plots in Mesh
 TODO: Contemplate containing coarse mesh generation in Mesh
-TODO: Contemplate extracting boundary condition from InitialCondition
-TODO: Contemplate containing boundary condition in Mesh
 TODO: Ask whether all quadratures depend on freely chosen num_nodes
 TODO: Contemplate saving training data for each IC separately
 TODO: Contemplate removing TrainingDataGenerator class
@@ -24,16 +22,34 @@ TODO: Contemplate using lambdify for basis
 TODO: Contemplate allowing vector input for ICs
 TODO: Discuss how wavelet details should be plotted
 
+TODO: Ask after reasoning behind plotting approx for this specific Burgers case
+TODO: Ask what derivative basis represents
+TODO: Ask after Dirichlet boundary setup
+TODO: Ask after exact solution for different equations
+TODO: Ask where Euler 1D exact solution comes from
+TODO: Discuss first calculating plotting data and then plotting in separate
+    step
+TODO: Ask whether the option of multiple ghost cells has any potential use
+    cases
+TODO: Discuss necessary object dependencies
+TODO: Contemplate extracting boundary condition from InitialCondition
+TODO: Contemplate containing boundary condition in Mesh
+TODO: Discuss extracting all objects from UpdateScheme and giving equation as
+    input instead
+
 Urgent:
-TODO: Check whether 'projection' is always a ndarray
-TODO: Check whether ghost cells are handled/set correctly
-TODO: Make sure that the cell indices are the same over all TCDs
-TODO: Make sure TCs are reported as ndarray
-TODO: Extract equation-related functionality into LinearAdvection class
-TODO: Use cfl_number for updating, not just time (equation-related?)
+TODO: Check whether 'projection' is always a ndarray -> Done
+TODO: Add property attribute for num_ghost_cells -> Done
+TODO: Ensure compatibility with arbitrary number of ghost cells -> Done
+TODO: Move 'do_initial_projection()' to 'projection_utils.py' -> Done
+TODO: Extract equation-related functionality into LinearAdvection class -> Done
+TODO: Enforce num_ghost_cells to be positive integer for DG (not training)
 TODO: Add Burger class
+TODO: Use cfl_number for updating, not just time (equation-related?)
 
 Critical, but not urgent:
+TODO: Make sure TCs are reported as ndarray
+TODO: Make sure that the cell indices are the same over all TCDs
 TODO: Combine ANN workflows if feasible
 TODO: Check whether all instance variables are sensible
 TODO: Check whether all ValueError are set (correctly)
@@ -49,6 +65,7 @@ TODO: Enforce even number of ghost cells on each side on fine mesh (?)
 TODO: Create g-mesh with Mesh class
 TODO: Add images to report
 TODO: Add verbose output
+TODO: Add tests for all functions
 
 Not feasible yet or doc-related:
 TODO: Move plot_approximation_results() into plotting script
diff --git a/scripts/approximate_solution.py b/scripts/approximate_solution.py
index bbda5a4d0bebe7ed6c75bcc7b99047349f4c1499..d1c6c28d48561a569c097a9eac01cd80101b0867 100644
--- a/scripts/approximate_solution.py
+++ b/scripts/approximate_solution.py
@@ -14,6 +14,7 @@ from tcd import Update_Scheme
 from tcd.Basis_Function import OrthonormalLegendre
 from tcd.DG_Approximation import DGScheme
 from tcd.Mesh import Mesh
+from tcd.Equation import LinearAdvection
 
 
 def main() -> None:
@@ -57,15 +58,6 @@ def main() -> None:
             config=detector_config,
             mesh=mesh, basis=basis)
 
-        # Initialize update scheme after checking its legitimacy
-        scheme_name = params.pop('update_scheme', 'SSPRK3')
-        wave_speed = params.pop('wave_speed', 1)
-        if not hasattr(Update_Scheme, scheme_name):
-            raise ValueError('Invalid update scheme: "%s"' % scheme_name)
-        update_scheme = getattr(Update_Scheme, scheme_name)(
-            polynomial_degree=basis.polynomial_degree, mesh=mesh,
-            detector=detector, limiter=limiter, wave_speed=wave_speed)
-
         # Initialize quadrature after checking its legitimacy
         quadrature_name = params.pop('quadrature', 'Gauss')
         quadrature_config = params.pop('quadrature_config', {})
@@ -82,10 +74,25 @@ def main() -> None:
                              % init_name)
         init_cond = getattr(Initial_Condition, init_name)(config=init_config)
 
-        dg_scheme = DGScheme(detector=detector, quadrature=quadrature,
-                             init_cond=init_cond, update_scheme=update_scheme,
-                             mesh=mesh, basis=basis, wave_speed=wave_speed,
-                             **params)
+        # Initialize linear advection equation
+        wave_speed = params.pop('wave_speed', 1)
+        final_time = params.pop('final_time', 1)
+        cfl_number = params.pop('cfl_number', 0.2)
+        equation = LinearAdvection(final_time=final_time,
+                                   cfl_number=cfl_number,
+                                   basis=basis, init_cond=init_cond,
+                                   quadrature=quadrature,
+                                   mesh=mesh, wave_speed=wave_speed)
+
+        # Initialize update scheme after checking its legitimacy
+        scheme_name = params.pop('update_scheme', 'SSPRK3')
+        if not hasattr(Update_Scheme, scheme_name):
+            raise ValueError('Invalid update scheme: "%s"' % scheme_name)
+        update_scheme = getattr(Update_Scheme, scheme_name)(
+            detector=detector, limiter=limiter, equation=equation)
+
+        dg_scheme = DGScheme(detector=detector, update_scheme=update_scheme,
+                             equation=equation, **params)
 
         dg_scheme.approximate(
             data_file=snakemake.params['plot_dir'] + '/' +
diff --git a/scripts/tcd/DG_Approximation.py b/scripts/tcd/DG_Approximation.py
index a4cf1df3f853e6af8aa3ca26f05bb7d8eb994ff2..5f38c2649e03f8a3cb3f920c848ccdc6eadee4ba 100644
--- a/scripts/tcd/DG_Approximation.py
+++ b/scripts/tcd/DG_Approximation.py
@@ -6,12 +6,8 @@
 import json
 import math
 
-from .Basis_Function import Basis
 from .encoding_utils import encode_ndarray
-from .Initial_Condition import InitialCondition
-from .Mesh import Mesh
-from .projection_utils import do_initial_projection
-from .Quadrature import Quadrature
+from .Equation import Equation
 from .Troubled_Cell_Detector import TroubledCellDetector
 from .Update_Scheme import UpdateScheme
 
@@ -33,34 +29,20 @@ class DGScheme:
 
     """
     def __init__(self, detector: TroubledCellDetector,
-                 quadrature: Quadrature, init_cond: InitialCondition,
-                 update_scheme: UpdateScheme, mesh: Mesh, basis: Basis,
-                 wave_speed, **kwargs):
+                 update_scheme: UpdateScheme, equation: Equation, **kwargs):
         """Initializes DGScheme.
 
         Parameters
         ----------
         detector : TroubledCellDetector object
             Troubled cell detector.
-        quadrature : Quadrature object
-            Quadrature for evaluation.
-        init_cond : InitialCondition object
-            Initial condition for evaluation.
         update_scheme : UpdateScheme object
             Update scheme for evaluation.
-        mesh : Mesh object
-            Mesh for calculation.
-        basis : Basis object
-            Basis for calculation.
-        wave_speed : float, optional
-            Speed of wave in rightward direction.
+        equation : Equation object
+            Equation to approximate.
 
         Other Parameters
         ----------------
-        cfl_number : float, optional
-            CFL number to ensure stability. Default: 0.2.
-        final_time : float, optional
-            Final time for which approximation is calculated. Default: 1.
         verbose : bool, optional
             Flag whether commentary in console is wanted. Default: False.
         history_threshold : float, optional
@@ -69,19 +51,13 @@ class DGScheme:
 
         """
         self._detector = detector
-        self._quadrature = quadrature
-        self._init_cond = init_cond
         self._update_scheme = update_scheme
-        self._mesh = mesh
-        self._basis = basis
-        self._wave_speed = wave_speed
+        self._equation = equation
 
         # Unpack keyword arguments
-        self._cfl_number = kwargs.pop('cfl_number', 0.2)
-        self._final_time = kwargs.pop('final_time', 1)
         self._verbose = kwargs.pop('verbose', False)
-        self._history_threshold = kwargs.pop('history_threshold',
-                                             math.ceil(0.2/self._cfl_number))
+        self._history_threshold = kwargs.pop(
+            'history_threshold', math.ceil(0.2/self._equation.cfl_number))
 
         # Throw an error if there are extra keyword arguments
         if len(kwargs) > 0:
@@ -103,23 +79,14 @@ class DGScheme:
             Path to file in which data will be saved.
 
         """
-        projection = do_initial_projection(
-            init_cond=self._init_cond, mesh=self._mesh,
-            basis=self._basis, quadrature=self._quadrature)
-
-        time_step = abs(self._cfl_number * self._mesh.cell_len /
-                        self._wave_speed)
-
+        time_step, projection = self._equation.initialize_approximation()
         current_time = 0
         iteration = 0
         troubled_cell_history = []
         time_history = []
-        while current_time < self._final_time:
-            # Adjust for last cell
-            cfl_number = self._cfl_number
-            if current_time+time_step > self._final_time:
-                time_step = self._final_time-current_time
-                cfl_number = self._wave_speed * time_step / self._mesh.cell_len
+        while current_time < self._equation.final_time:
+            cfl_number, time_step = self._equation.update_time_step(
+                current_time=current_time, time_step=time_step)
 
             # Update projection
             projection, troubled_cells = self._update_scheme.step(projection,
@@ -136,8 +103,8 @@ class DGScheme:
         approx_stats = self._detector.create_data_dict(projection)
 
         # Save approximation results in dictionary
-        approx_stats['wave_speed'] = self._wave_speed
-        approx_stats['final_time'] = self._final_time
+        approx_stats['wave_speed'] = self._equation.wave_speed
+        approx_stats['final_time'] = self._equation.final_time
         approx_stats['time_history'] = time_history
         approx_stats['troubled_cell_history'] = troubled_cell_history
 
diff --git a/scripts/tcd/Equation.py b/scripts/tcd/Equation.py
new file mode 100644
index 0000000000000000000000000000000000000000..e0e7c21cfcc19befeb0ee50dff89d14b70908485
--- /dev/null
+++ b/scripts/tcd/Equation.py
@@ -0,0 +1,347 @@
+# -*- coding: utf-8 -*-
+"""Module for equation class.
+
+@author: Laura C. Kühle
+"""
+from typing import Tuple
+from abc import ABC, abstractmethod
+import numpy as np
+from numpy import ndarray
+
+from .Basis_Function import Basis
+from .Initial_Condition import InitialCondition
+from .Mesh import Mesh
+from .projection_utils import do_initial_projection
+from .Quadrature import Quadrature
+
+
+class Equation(ABC):
+    """Abstract class for equation.
+
+    Methods
+    -------
+    initialize_approximation()
+        Initialize projection and time step for approximation.
+    update_time_step(current_time, time_step)
+        Update time step.
+    solve_exactly(mesh)
+        Calculate exact solution.
+    enforce_boundary_condition(projection)
+        Enforce boundary condition.
+    update_right_hand_side(projection)
+        Update right-hand side.
+    """
+
+    def __init__(self, quadrature: Quadrature, init_cond: InitialCondition,
+                 basis: Basis, mesh: Mesh, final_time: float,
+                 wave_speed: float, cfl_number: float) -> None:
+        """Initialize equation class.
+
+        Parameters
+        ----------
+        quadrature : Quadrature object
+            Quadrature for evaluation.
+        init_cond : InitialCondition object
+            Initial condition for evaluation.
+        basis : Basis object
+            Basis for calculation.
+        mesh : Mesh object
+            Mesh for calculation.
+        final_time : float
+            Final time for which approximation is calculated.
+        wave_speed : float
+            Speed of wave in rightward direction.
+        cfl_number : float
+            CFL number to ensure stability.
+
+        """
+        self._quadrature = quadrature
+        self._init_cond = init_cond
+        self._basis = basis
+        self._mesh = mesh
+        self._final_time = final_time
+        self._wave_speed = wave_speed
+        self._cfl_number = cfl_number
+
+        self._reset()
+
+    @property
+    def final_time(self) -> float:
+        """Return final time."""
+        return self._final_time
+
+    @property
+    def wave_speed(self) -> float:
+        """Return wave speed."""
+        return self._wave_speed
+
+    @property
+    def cfl_number(self) -> float:
+        """Return CFL number."""
+        return self._cfl_number
+
+    def _reset(self) -> None:
+        """Reset instance variables."""
+        pass
+
+    def initialize_approximation(self) -> Tuple[float, ndarray]:
+        """Initialize projection and time step for approximation."""
+        return self._initialize_time_step(), self._initialize_projection()
+
+    def _initialize_time_step(self):
+        """Initialize time step."""
+        return abs(self._cfl_number * self._mesh.cell_len / self._wave_speed)
+
+    @abstractmethod
+    def _initialize_projection(self) -> ndarray:
+        """Initialize projection."""
+        pass
+
+    @abstractmethod
+    def update_time_step(self, current_time: float,
+                         time_step: float) -> Tuple[float, float]:
+        """Update time step.
+
+        Parameters
+        ----------
+        current_time : float
+            Current time during approximation.
+        time_step : float
+            Length of time step during approximation.
+        Returns
+        -------
+        cfl_number : float
+            Updated CFL number to ensure stability.
+        time_step : float
+            Updated time step for approximation.
+
+        """
+        pass
+
+    @abstractmethod
+    def solve_exactly(self, mesh: Mesh) -> Tuple[ndarray, ndarray]:
+        """Calculate exact solution.
+
+        Parameters
+        ----------
+        mesh : Mesh
+            Mesh for evaluation.
+
+        Returns
+        -------
+        grid : ndarray
+            Array containing evaluation grid for a function.
+        exact : ndarray
+            Array containing exact evaluation of a function.
+
+        """
+        pass
+
+    @abstractmethod
+    def enforce_boundary_condition(self, projection: ndarray) -> ndarray:
+        """Enforce boundary condition.
+
+        Adjust ghost cells to ensure periodic boundary condition.
+
+        Parameters
+        ----------
+        projection : ndarray
+            Matrix of projection for each polynomial degree.
+
+        Returns
+        -------
+        projection : ndarray
+            Matrix of projection for each polynomial degree.
+
+        """
+        pass
+
+    @abstractmethod
+    def update_right_hand_side(self, projection: ndarray) -> ndarray:
+        """Update right-hand side.
+
+        Parameter
+        ---------
+        projection : ndarray
+            Matrix of projection for each polynomial degree.
+
+        Returns
+        -------
+        ndarray
+            Matrix of right-hand side.
+
+        """
+        pass
+
+
+class LinearAdvection(Equation):
+    """Class for linear advection equation.
+
+    Attributes
+    ----------
+    stiffness_matrix : ndarray
+        Stiffness matrix.
+    boundary_matrix : ndarray
+        Boundary matrix.
+
+    Methods
+    -------
+    update_right_hand_side(projection)
+        Update right-hand side.
+    enforce_boundary_condition(projection)
+        Enforce boundary condition.
+
+    Notes
+    -----
+    .. math:: u_t + u_x = 0
+
+    """
+
+    def _reset(self) -> None:
+        """Reset instance variables."""
+        matrix_shape = (self._basis.polynomial_degree+1,
+                        self._basis.polynomial_degree+1)
+        root_vector = np.array([np.sqrt(degree+0.5) for degree in range(
+            self._basis.polynomial_degree+1)])
+        degree_matrix = np.matmul(root_vector[:, np.newaxis],
+                                  root_vector[:, np.newaxis].T)
+
+        # Set stiffness matrix
+        matrix = np.ones(matrix_shape)
+        if self._wave_speed > 0:
+            matrix[np.fromfunction(
+                lambda i, j: (j >= i) | ((i+j) % 2 == 0), matrix_shape)] = -1.0
+        else:
+            matrix[np.fromfunction(
+                lambda i, j: (j > i) & ((i+j) % 2 == 1), matrix_shape)] = -1.0
+        self._stiffness_matrix = matrix * degree_matrix
+
+        # Set boundary matrix
+        matrix = np.fromfunction(lambda i, j: (-1.0)**i, matrix_shape) \
+            if self._wave_speed > 0 \
+            else np.fromfunction(lambda i, j: (-1.0)**j, matrix_shape)
+        self._boundary_matrix = matrix * degree_matrix
+
+    def _initialize_projection(self) -> ndarray:
+        """Initialize projection."""
+        return do_initial_projection(init_cond=self._init_cond,
+                                     mesh=self._mesh, basis=self._basis,
+                                     quadrature=self._quadrature)
+
+    def update_time_step(self, current_time: float,
+                         time_step: float) -> Tuple[float, float]:
+        """Update time step.
+
+        Parameters
+        ----------
+        current_time : float
+            Current time during approximation.
+        time_step : float
+            Length of time step during approximation.
+        Returns
+        -------
+        cfl_number : float
+            Updated CFL number to ensure stability.
+        time_step : float
+            Updated time step for approximation.
+
+        """
+        cfl_number = self._cfl_number
+        if current_time+time_step > self.final_time:
+            time_step = self.final_time-current_time
+            cfl_number = self.wave_speed * time_step / self._mesh.cell_len
+        return cfl_number, time_step
+
+    def solve_exactly(self, mesh: Mesh) -> Tuple[ndarray, ndarray]:
+        """Calculate exact solution.
+
+        Parameters
+        ----------
+        mesh : Mesh
+            Mesh for evaluation.
+
+        Returns
+        -------
+        grid : ndarray
+            Array containing evaluation grid for a function.
+        exact : ndarray
+            Array containing exact evaluation of a function.
+
+        """
+        num_periods = np.floor(self.wave_speed * self.final_time /
+                               mesh.interval_len)
+
+        grid = np.repeat(mesh.non_ghost_cells, self._quadrature.num_nodes) + \
+            mesh.cell_len / 2 * np.tile(self._quadrature.nodes, mesh.num_cells)
+        exact = np.array([self._init_cond.calculate(
+            mesh=mesh, x=point-self.wave_speed * self.final_time+num_periods *
+                         mesh.interval_len)
+            for point in grid])
+
+        grid = np.reshape(grid, (1, grid.size))
+        exact = np.reshape(exact, (1, exact.size))
+
+        return grid, exact
+
+    def enforce_boundary_condition(self, projection: ndarray) -> ndarray:
+        """Enforce boundary condition.
+
+        Adjust ghost cells to ensure periodic boundary condition.
+
+        Parameters
+        ----------
+        projection : ndarray
+            Matrix of projection for each polynomial degree.
+
+        Returns
+        -------
+        projection : ndarray
+            Matrix of projection for each polynomial degree.
+
+        """
+        projection[:, :self._mesh.num_ghost_cells] = projection[
+            :, -2*self._mesh.num_ghost_cells:-self._mesh.num_ghost_cells]
+        projection[:, -self._mesh.num_ghost_cells:] = projection[
+            :, self._mesh.num_ghost_cells:2*self._mesh.num_ghost_cells]
+        return projection
+
+    def update_right_hand_side(self, projection: ndarray) -> ndarray:
+        """Update right-hand side.
+
+        Parameter
+        ---------
+        projection : ndarray
+            Matrix of projection for each polynomial degree.
+
+        Returns
+        -------
+        ndarray
+            Matrix of right-hand side.
+
+        """
+        right_hand_side = np.zeros_like(projection)
+        if self._wave_speed > 0:
+            right_hand_side[:, self._mesh.num_ghost_cells:
+                            -self._mesh.num_ghost_cells] = \
+                2 * (self._boundary_matrix @
+                     projection[:, self._mesh.num_ghost_cells-1:
+                                -self._mesh.num_ghost_cells-1] +
+                     self._stiffness_matrix @
+                     projection[:, self._mesh.num_ghost_cells:
+                                -self._mesh.num_ghost_cells])
+        else:
+            right_hand_side[:, self._mesh.num_ghost_cells:
+                            -self._mesh.num_ghost_cells] = \
+                2 * (self._boundary_matrix @
+                     projection[:, self._mesh.num_ghost_cells+1:] +
+                     self._stiffness_matrix @
+                     projection[:, self._mesh.num_ghost_cells:
+                                -self._mesh.num_ghost_cells])
+
+        # Set ghost cells to respective value
+        right_hand_side[:, :self._mesh.num_ghost_cells] = right_hand_side[
+            :, -2*self._mesh.num_ghost_cells:-self._mesh.num_ghost_cells]
+        right_hand_side[:, -self._mesh.num_ghost_cells:] = right_hand_side[
+            :, self._mesh.num_ghost_cells:2*self._mesh.num_ghost_cells]
+
+        return right_hand_side
diff --git a/scripts/tcd/Update_Scheme.py b/scripts/tcd/Update_Scheme.py
index 19cd20165f8e365ee44350e2b901a3d6aecab55b..e7c9122b13803a0d41fecd91bfac7177ebd21abe 100644
--- a/scripts/tcd/Update_Scheme.py
+++ b/scripts/tcd/Update_Scheme.py
@@ -4,20 +4,14 @@
 
 """
 from abc import ABC, abstractmethod
-import numpy as np
 import time
 
+from .Equation import Equation
+
 
 class UpdateScheme(ABC):
     """Abstract class for updating projections at a time step.
 
-    Attributes
-    ----------
-    stiffness_matrix : ndarray
-        Matrix
-    boundary_matrix : ndarray
-        Matrix
-
     Methods
     -------
     get_name()
@@ -26,56 +20,28 @@ class UpdateScheme(ABC):
         Performs time step.
 
     """
-    def __init__(self, polynomial_degree, mesh, detector, limiter,
-                 wave_speed):
+    def __init__(self, detector, limiter, equation):
         """Initializes UpdateScheme.
 
         Parameters
         ----------
-        polynomial_degree : int
-            Polynomial degree.
-        mesh : Mesh
-            Mesh for calculation.
         detector : TroubledCellDetector object
             Troubled cell detector for evaluation.
         limiter : Limiter object
             Limiter for evaluation.
-        wave_speed : float
-            Speed of wave in rightward direction.
+        equation: Equation
+            Equation.
 
         """
         # Unpack positional arguments
-        self._polynomial_degree = polynomial_degree
-        self._mesh = mesh
         self._detector = detector
         self._limiter = limiter
-        self._wave_speed = wave_speed
+        self._equation = equation
 
         self._reset()
 
     def _reset(self):
         """Resets instance variables."""
-        matrix_shape = (self._polynomial_degree+1, self._polynomial_degree+1)
-        root_vector = np.array([np.sqrt(degree+0.5) for degree in range(
-            self._polynomial_degree+1)])
-        degree_matrix = np.matmul(root_vector[:, np.newaxis],
-                                  root_vector[:, np.newaxis].T)
-
-        # Set stiffness matrix
-        matrix = np.ones(matrix_shape)
-        if self._wave_speed > 0:
-            matrix[np.fromfunction(
-                lambda i, j: (j >= i) | ((i+j) % 2 == 0), matrix_shape)] = -1.0
-        else:
-            matrix[np.fromfunction(
-                lambda i, j: (j > i) & ((i+j) % 2 == 1), matrix_shape)] = -1.0
-        self._stiffness_matrix = matrix * degree_matrix
-
-        # Set boundary matrix
-        matrix = np.fromfunction(lambda i, j: (-1.0)**i, matrix_shape) \
-            if self._wave_speed > 0 \
-            else np.fromfunction(lambda i, j: (-1.0)**j, matrix_shape)
-        self._boundary_matrix = matrix * degree_matrix
 
     def get_name(self):
         """Returns string of class name."""
@@ -150,32 +116,6 @@ class UpdateScheme(ABC):
 
         return new_projection, troubled_cells
 
-    def _enforce_boundary_condition(self, current_projection):
-        """Enforces boundary condition.
-
-        Adjusts ghost cells to ensure periodic boundary condition.
-
-        Parameters
-        ----------
-        current_projection : ndarray
-            Matrix of projection of current update step for each polynomial
-            degree.
-
-        Returns
-        -------
-        current_projection : ndarray
-            Matrix of projection of current update step for each polynomial
-            degree.
-
-        """
-        current_projection[:, :self._mesh.num_ghost_cells] = \
-            current_projection[
-            :, -2*self._mesh.num_ghost_cells:-self._mesh.num_ghost_cells]
-        current_projection[:, -self._mesh.num_ghost_cells:] = \
-            current_projection[
-            :, self._mesh.num_ghost_cells:2*self._mesh.num_ghost_cells]
-        return current_projection
-
 
 class SSPRK3(UpdateScheme):
     """Class for strong stability-preserving Runge Kutta of order 3.
@@ -210,14 +150,14 @@ class SSPRK3(UpdateScheme):
         current_projection = self._apply_first_step(original_projection,
                                                     cfl_number)
         current_projection, __ = self._apply_limiter(current_projection)
-        current_projection = self._enforce_boundary_condition(
+        current_projection = self._equation.enforce_boundary_condition(
             current_projection)
 
         current_projection = self._apply_second_step(original_projection,
                                                      current_projection,
                                                      cfl_number)
         current_projection, __ = self._apply_limiter(current_projection)
-        current_projection = self._enforce_boundary_condition(
+        current_projection = self._equation.enforce_boundary_condition(
             current_projection)
 
         current_projection = self._apply_third_step(original_projection,
@@ -225,7 +165,7 @@ class SSPRK3(UpdateScheme):
                                                     cfl_number)
         current_projection, troubled_cells = self._apply_limiter(
             current_projection)
-        current_projection = self._enforce_boundary_condition(
+        current_projection = self._equation.enforce_boundary_condition(
             current_projection)
 
         return current_projection, troubled_cells
@@ -246,7 +186,8 @@ class SSPRK3(UpdateScheme):
             Matrix of updated projection for each polynomial degree.
 
         """
-        right_hand_side = self._update_right_hand_side(original_projection)
+        right_hand_side = self._equation.update_right_hand_side(
+            original_projection)
         return original_projection + (cfl_number*right_hand_side)
 
     def _apply_second_step(self, original_projection, current_projection,
@@ -269,7 +210,8 @@ class SSPRK3(UpdateScheme):
             Matrix of updated projection for each polynomial degree.
 
         """
-        right_hand_side = self._update_right_hand_side(current_projection)
+        right_hand_side = self._equation.update_right_hand_side(
+            current_projection)
         return 1/4 * (3*original_projection
                       + (current_projection + cfl_number*right_hand_side))
 
@@ -293,48 +235,7 @@ class SSPRK3(UpdateScheme):
             Matrix of updated projection for each polynomial degree.
 
         """
-        right_hand_side = self._update_right_hand_side(current_projection)
+        right_hand_side = self._equation.update_right_hand_side(
+            current_projection)
         return 1/3 * (original_projection
                       + 2*(current_projection + cfl_number*right_hand_side))
-
-    def _update_right_hand_side(self, current_projection):
-        """Updates right-hand side.
-
-        Parameter
-        ---------
-        current_projection : ndarray
-            Matrix of projection of current update step for each polynomial
-            degree.
-
-        Returns
-        -------
-        ndarray
-            Matrix of right-hand side.
-
-        """
-        right_hand_side = np.zeros_like(current_projection)
-        if self._wave_speed > 0:
-            right_hand_side[:, self._mesh.num_ghost_cells:
-                            -self._mesh.num_ghost_cells] = \
-                2 * (self._boundary_matrix @
-                     current_projection[:, self._mesh.num_ghost_cells-1:
-                                        -self._mesh.num_ghost_cells-1] +
-                     self._stiffness_matrix @
-                     current_projection[:, self._mesh.num_ghost_cells:
-                                        -self._mesh.num_ghost_cells])
-        else:
-            right_hand_side[:, self._mesh.num_ghost_cells:
-                            -self._mesh.num_ghost_cells] = \
-                2 * (self._boundary_matrix @
-                     current_projection[:, self._mesh.num_ghost_cells+1:] +
-                     self._stiffness_matrix @
-                     current_projection[:, self._mesh.num_ghost_cells:
-                                        -self._mesh.num_ghost_cells])
-
-        # Set ghost cells to respective value
-        right_hand_side[:, :self._mesh.num_ghost_cells] = right_hand_side[
-            :, -2*self._mesh.num_ghost_cells:-self._mesh.num_ghost_cells]
-        right_hand_side[:, -self._mesh.num_ghost_cells:] = right_hand_side[
-            :, self._mesh.num_ghost_cells:2*self._mesh.num_ghost_cells]
-
-        return right_hand_side