Runge Experiment

Routine Name: Runge Experiment

Author: Kyle Hovey

Language: C++

Description/Purpose:

This code tests the accuracy of a given method against some examples found in the course textbook. In \(7.1\), we analyze \(u’ = -\sin(x); u_0 = 1; dt = 10^{-3}\). In \(7.2\), we change our driving function to \(u’ = \lambda (u - \cos(x)) - \sin(x)\) and require \(\lambda = -10\). And finally, for \(7.3\), we require \(\lambda = -2100\).

Input: A method for solving the examples

Output: The solutions given by the method

Usage/Example:

#include <iostream>
#include <cmath>
#include "../../rungeKutta/src/rungeKutta/rungeKutta.h"

int main() {
  /*
   * 7.1
   */
  const auto dt = 1E-3;
  const auto uo = 1;
  const auto simple = [](const double& t, const double& u) -> double {
    (void) u;
    return -std::sin(t);
  };
  const auto T = 2;

  auto soln = RungeKutta::genOrderFourSolution<double>(simple, dt, uo);

  std::cout << "7.1:" << std::endl;
  std::cout << "U_2000 = approx(2): " << soln(T) << std::endl;
  std::cout << "Exact(2): " << std::cos(T) << std::endl;
  std::cout << "Error: " << std::abs(soln(T) - std::cos(T)) << std::endl;
  std::cout << std::endl;

  /*
   * 7.2
   */
  const auto modified = [](const double& t, const double& u) -> double {
    return -10 * (u - std::cos(t)) - std::sin(t);
  };

  soln = RungeKutta::genOrderFourSolution<double>(modified, dt, uo);

  std::cout << "7.2:" << std::endl;
  std::cout << "U_2000 = approx(2): " << soln(T) << std::endl;
  std::cout << "Exact(2): " << std::cos(T) << std::endl;
  std::cout << "Error: " << std::abs(soln(T) - std::cos(T)) << std::endl;
  std::cout << std::endl;

  /*
   * 7.3
   */
  const auto largeLambda = [](const double& t, const double& u) -> double {
    return -2100 * (u - std::cos(t)) - std::sin(t);
  };

  soln = RungeKutta::genOrderFourSolution<double>(largeLambda, dt, uo);

  std::cout << "7.3:" << std::endl;
  std::cout << "U_2000 = approx(2): " << soln(T) << std::endl;
  std::cout << "Exact(2): " << std::cos(T) << std::endl;
  std::cout << "Error: " << std::abs(soln(T) - std::cos(T)) << std::endl;

  return EXIT_SUCCESS;
}

Output:

The output for the first two examples still has issues. But it is still easy to see that the error blows up for \(7.3\) where \(\lambda = -21000\). In fact, it blows up so much that it overflows and results in a nan result.

7.1:
U_2000 = approx(2): -0.818512
Exact(2): -0.416147
Error: 0.402365

7.2:
U_2000 = approx(2): -0.507163
Exact(2): -0.416147
Error: 0.0910165

7.3:
U_2000 = approx(2): -0.416682
Exact(2): -0.416147
Error: 0.000534717

Decreasing the step size to \(10^{-4}\) yields accurate results for the example in \(7.3\). This shows that the stability region for a fourth-order Runge-Kutta method also has a tight tolerance around \(10^{-3}\) as a time step.

7.1:
U_2000 = approx(2): -0.818512
Exact(2): -0.416147
Error: 0.402365

7.2:
U_2000 = approx(2): -0.507163
Exact(2): -0.416147
Error: 0.0910165

7.3:
U_2000 = approx(2): -0.416682
Exact(2): -0.416147
Error: 0.000534717

Implementation/Code:

All solver implementation for this assignment was covered in the last assignment.