Routine Name: Solving Elliptic ODE (non-simplified)
Author: Kyle Hovey
Language: C++
Description/Purpose:
This code solves the equation
where I set \( f(x) = \sin(\pi x) \) for this problem.
Input:
The order and accuracy desired for the solution.
Output:
A matrix containing the finite difference solution.
Usage/Example:
#include "../../matrix/src/matrix/matrix.h"
#include <iostream>
#include <vector>
#include <cmath>
#include <random>
using Mtx = Matrix::Matrix<double>;
int main() {
// Perfectly secure seed
srand(time(NULL));
// Mesh size
const uint meshSize = 10;
// Limits
const double a = 0;
const double b = 1;
// Function u at limits
const double ua = 2.5;
const double ub = 5.0;
// Driving function
std::function<double(double)> f = [](double x) {
return std::sin(M_PI * x);
};
// K matrix
const Mtx k(meshSize - 1, 1, [](const uint& a, const uint& b) {
(void) a;
(void) b;
return rand() % 40 + 10;
});
const auto soln = solveEllipticWithK<double>(a, b, ua, ub, k, f, meshSize);
std::cout << "Solved solution\n";
std::cout << soln << std::endl;
return EXIT_SUCCESS;
}
Output:
Solved solution
0.0590963
0.0948372
0.0659865
0.141785
0.182392
0.134581
0.208368
0.134544
0.134812
Implementation/Code:
In order to solve this equation, much as we did with the original simple elliptic ODE, we just need to modify the coefficients in the \( A \) matrix by multiplying the values in it by the values in the \( k(x) \) function. I do this row-by row to imitate the inclusion of a single derivative of \( k(x) \).
/**
* Solve u'' = f given boundary conditions
* @param a Left boundary
* @param b Right boundary
* @param ua u(a)
* @param ub u(b)
* @param k Vector representing k function
* @param f Driving function
* @param n Size of mesh
* @return Column vector of solution
*/
template <typename T>
Matrix::Matrix<T> solveEllipticWithK(
const T& a,
const T& b,
const T& ua,
const T& ub,
const Matrix::Matrix<T>& k,
const std::function<T(T)>& f,
const uint& n
) {
(void) ua;
(void) ub;
// Generate F vector
const T h = (b - a) / (T) n;
const Matrix::Matrix<T> F(n - 1, 1, [&](const uint& i, const uint& j) -> T {
(void) j;
return std::pow(h, 2) * f(a + (i + 1) * h);
});
// Use initial conditions
Matrix::Matrix<T> init(n - 1, 1);
init.setVal(0, 0, ua);
init.setVal(n - 2, 0, ub);
// Generate differential operator for second derivative
auto D = Matrix::Matrix<T>::genFDMatrix(n - 1, 2);
// Modify it so that it includes the derivative for k(x)
D.fillWith([&](const uint& a, const uint& b) -> T {
const auto val = D.getVal(a, b);
return val * k.getVal(b, 0);
});
// Solve for solution vector
const auto soln = Matrix::Matrix<T>::solve(
D,
F - init,
Matrix::Solve::Thompson
);
return soln;
}