apply format changes (LLVM)

This commit is contained in:
Max Lübke 2023-09-05 16:42:05 +02:00
parent 6e388f3d99
commit 7d05320f24

View File

@ -1,464 +1,487 @@
/** /**
* @file BTCSv2.cpp * @file BTCSv2.cpp
* @brief Implementation of heterogenous BTCS (backward time-centered space) solution * @brief Implementation of heterogenous BTCS (backward time-centered space)
* of diffusion equation in 1D and 2D space. Internally the alternating-direction * solution of diffusion equation in 1D and 2D space. Internally the
* implicit (ADI) method is used. Version 2, because Version 1 was an * alternating-direction implicit (ADI) method is used. Version 2, because
* implementation for the homogeneous BTCS solution. * Version 1 was an implementation for the homogeneous BTCS solution.
* *
*/ */
#include "FTCS.cpp" #include "FTCS.cpp"
#include <tug/Boundary.hpp>
#include <omp.h> #include <omp.h>
#include <tug/Boundary.hpp>
#ifdef WRITE_THOMAS_CSV #ifdef WRITE_THOMAS_CSV
#include<fstream> #include <fstream>
#include<string> #include <string>
#endif #endif
#define NUM_THREADS_BTCS 10 #define NUM_THREADS_BTCS 10
using namespace Eigen; using namespace Eigen;
// calculates coefficient for left boundary in constant case // calculates coefficient for left boundary in constant case
static tuple<double, double> calcLeftBoundaryCoeffConstant(MatrixXd &alpha, int rowIndex, double sx) { static tuple<double, double>
double centerCoeff; calcLeftBoundaryCoeffConstant(MatrixXd &alpha, int rowIndex, double sx) {
double rightCoeff; double centerCoeff;
double rightCoeff;
centerCoeff = 1 + sx * (calcAlphaIntercell(alpha(rowIndex,0), alpha(rowIndex,1)) centerCoeff =
+ 2 * alpha(rowIndex,0)); 1 + sx * (calcAlphaIntercell(alpha(rowIndex, 0), alpha(rowIndex, 1)) +
rightCoeff = -sx * calcAlphaIntercell(alpha(rowIndex,0), alpha(rowIndex,1)); 2 * alpha(rowIndex, 0));
rightCoeff = -sx * calcAlphaIntercell(alpha(rowIndex, 0), alpha(rowIndex, 1));
return {centerCoeff, rightCoeff}; return {centerCoeff, rightCoeff};
} }
// calculates coefficient for left boundary in closed case // calculates coefficient for left boundary in closed case
static tuple<double, double> calcLeftBoundaryCoeffClosed(MatrixXd &alpha, int rowIndex, double sx) { static tuple<double, double>
double centerCoeff; calcLeftBoundaryCoeffClosed(MatrixXd &alpha, int rowIndex, double sx) {
double rightCoeff; double centerCoeff;
double rightCoeff;
centerCoeff = 1 + sx * calcAlphaIntercell(alpha(rowIndex,0), alpha(rowIndex,1)); centerCoeff =
rightCoeff = -sx * calcAlphaIntercell(alpha(rowIndex,0), alpha(rowIndex,1)); 1 + sx * calcAlphaIntercell(alpha(rowIndex, 0), alpha(rowIndex, 1));
rightCoeff = -sx * calcAlphaIntercell(alpha(rowIndex, 0), alpha(rowIndex, 1));
return {centerCoeff, rightCoeff}; return {centerCoeff, rightCoeff};
} }
// calculates coefficient for right boundary in constant case // calculates coefficient for right boundary in constant case
static tuple<double, double> calcRightBoundaryCoeffConstant(MatrixXd &alpha, int rowIndex, int n, double sx) { static tuple<double, double> calcRightBoundaryCoeffConstant(MatrixXd &alpha,
double leftCoeff; int rowIndex, int n,
double centerCoeff; double sx) {
double leftCoeff;
double centerCoeff;
leftCoeff = -sx * calcAlphaIntercell(alpha(rowIndex,n-1), alpha(rowIndex,n)); leftCoeff =
centerCoeff = 1 + sx * (calcAlphaIntercell(alpha(rowIndex,n-1), alpha(rowIndex,n)) -sx * calcAlphaIntercell(alpha(rowIndex, n - 1), alpha(rowIndex, n));
+ 2 * alpha(rowIndex,n)); centerCoeff =
1 + sx * (calcAlphaIntercell(alpha(rowIndex, n - 1), alpha(rowIndex, n)) +
2 * alpha(rowIndex, n));
return {leftCoeff, centerCoeff}; return {leftCoeff, centerCoeff};
} }
// calculates coefficient for right boundary in closed case // calculates coefficient for right boundary in closed case
static tuple<double, double> calcRightBoundaryCoeffClosed(MatrixXd &alpha, int rowIndex, int n, double sx) { static tuple<double, double>
double leftCoeff; calcRightBoundaryCoeffClosed(MatrixXd &alpha, int rowIndex, int n, double sx) {
double centerCoeff; double leftCoeff;
double centerCoeff;
leftCoeff = -sx * calcAlphaIntercell(alpha(rowIndex,n-1), alpha(rowIndex,n)); leftCoeff =
centerCoeff = 1 + sx * calcAlphaIntercell(alpha(rowIndex,n-1), alpha(rowIndex,n)); -sx * calcAlphaIntercell(alpha(rowIndex, n - 1), alpha(rowIndex, n));
centerCoeff =
1 + sx * calcAlphaIntercell(alpha(rowIndex, n - 1), alpha(rowIndex, n));
return {leftCoeff, centerCoeff}; return {leftCoeff, centerCoeff};
} }
// creates coefficient matrix for next time step from alphas in x-direction // creates coefficient matrix for next time step from alphas in x-direction
static SparseMatrix<double> createCoeffMatrix(MatrixXd &alpha, vector<BoundaryElement> &bcLeft, vector<BoundaryElement> &bcRight, int numCols, int rowIndex, double sx) { static SparseMatrix<double> createCoeffMatrix(MatrixXd &alpha,
vector<BoundaryElement> &bcLeft,
vector<BoundaryElement> &bcRight,
int numCols, int rowIndex,
double sx) {
// square matrix of column^2 dimension for the coefficients // square matrix of column^2 dimension for the coefficients
SparseMatrix<double> cm(numCols, numCols); SparseMatrix<double> cm(numCols, numCols);
cm.reserve(VectorXi::Constant(numCols, 3)); cm.reserve(VectorXi::Constant(numCols, 3));
// left column // left column
BC_TYPE type = bcLeft[rowIndex].getType(); BC_TYPE type = bcLeft[rowIndex].getType();
if (type == BC_TYPE_CONSTANT) { if (type == BC_TYPE_CONSTANT) {
auto [centerCoeffTop, rightCoeffTop] = calcLeftBoundaryCoeffConstant(alpha, rowIndex, sx); auto [centerCoeffTop, rightCoeffTop] =
cm.insert(0,0) = centerCoeffTop; calcLeftBoundaryCoeffConstant(alpha, rowIndex, sx);
cm.insert(0,1) = rightCoeffTop; cm.insert(0, 0) = centerCoeffTop;
} else if (type == BC_TYPE_CLOSED) { cm.insert(0, 1) = rightCoeffTop;
auto [centerCoeffTop, rightCoeffTop] = calcLeftBoundaryCoeffClosed(alpha, rowIndex, sx); } else if (type == BC_TYPE_CLOSED) {
cm.insert(0,0) = centerCoeffTop; auto [centerCoeffTop, rightCoeffTop] =
cm.insert(0,1) = rightCoeffTop; calcLeftBoundaryCoeffClosed(alpha, rowIndex, sx);
} else { cm.insert(0, 0) = centerCoeffTop;
throw_invalid_argument("Undefined Boundary Condition Type somewhere on Left or Top!"); cm.insert(0, 1) = rightCoeffTop;
} } else {
throw_invalid_argument(
"Undefined Boundary Condition Type somewhere on Left or Top!");
}
// inner columns // inner columns
int n = numCols-1; int n = numCols - 1;
for (int i = 1; i < n; i++) { for (int i = 1; i < n; i++) {
cm.insert(i,i-1) = -sx * calcAlphaIntercell(alpha(rowIndex,i-1), alpha(rowIndex,i)); cm.insert(i, i - 1) =
cm.insert(i,i) = 1 + sx * ( -sx * calcAlphaIntercell(alpha(rowIndex, i - 1), alpha(rowIndex, i));
calcAlphaIntercell(alpha(rowIndex,i), alpha(rowIndex,i+1)) cm.insert(i, i) =
+ calcAlphaIntercell(alpha(rowIndex,i-1), alpha(rowIndex,i)) 1 +
) sx * (calcAlphaIntercell(alpha(rowIndex, i), alpha(rowIndex, i + 1)) +
; calcAlphaIntercell(alpha(rowIndex, i - 1), alpha(rowIndex, i)));
cm.insert(i,i+1) = -sx * calcAlphaIntercell(alpha(rowIndex,i), alpha(rowIndex,i+1)); cm.insert(i, i + 1) =
} -sx * calcAlphaIntercell(alpha(rowIndex, i), alpha(rowIndex, i + 1));
}
// right column // right column
type = bcRight[rowIndex].getType(); type = bcRight[rowIndex].getType();
if (type == BC_TYPE_CONSTANT) { if (type == BC_TYPE_CONSTANT) {
auto [leftCoeffBottom, centerCoeffBottom] = calcRightBoundaryCoeffConstant(alpha, rowIndex, n, sx); auto [leftCoeffBottom, centerCoeffBottom] =
cm.insert(n,n-1) = leftCoeffBottom; calcRightBoundaryCoeffConstant(alpha, rowIndex, n, sx);
cm.insert(n,n) = centerCoeffBottom; cm.insert(n, n - 1) = leftCoeffBottom;
} else if (type == BC_TYPE_CLOSED) { cm.insert(n, n) = centerCoeffBottom;
auto [leftCoeffBottom, centerCoeffBottom] = calcRightBoundaryCoeffClosed(alpha, rowIndex, n, sx); } else if (type == BC_TYPE_CLOSED) {
cm.insert(n,n-1) = leftCoeffBottom; auto [leftCoeffBottom, centerCoeffBottom] =
cm.insert(n,n) = centerCoeffBottom; calcRightBoundaryCoeffClosed(alpha, rowIndex, n, sx);
} else { cm.insert(n, n - 1) = leftCoeffBottom;
throw_invalid_argument("Undefined Boundary Condition Type somewhere on Right or Bottom!"); cm.insert(n, n) = centerCoeffBottom;
} } else {
throw_invalid_argument(
"Undefined Boundary Condition Type somewhere on Right or Bottom!");
}
cm.makeCompressed(); // important for Eigen solver cm.makeCompressed(); // important for Eigen solver
return cm; return cm;
} }
// calculates explicity concentration at top boundary in constant case // calculates explicity concentration at top boundary in constant case
static double calcExplicitConcentrationsTopBoundaryConstant(MatrixXd &concentrations, static double calcExplicitConcentrationsTopBoundaryConstant(
MatrixXd &alpha, vector<BoundaryElement> &bcTop, int rowIndex, int i, double sy) { MatrixXd &concentrations, MatrixXd &alpha, vector<BoundaryElement> &bcTop,
double c; int rowIndex, int i, double sy) {
double c;
c = sy * calcAlphaIntercell(alpha(rowIndex,i), alpha(rowIndex+1,i)) c = sy * calcAlphaIntercell(alpha(rowIndex, i), alpha(rowIndex + 1, i)) *
* concentrations(rowIndex,i) concentrations(rowIndex, i) +
+ ( (1 -
1 - sy * ( sy * (calcAlphaIntercell(alpha(rowIndex, i), alpha(rowIndex + 1, i)) +
calcAlphaIntercell(alpha(rowIndex,i), alpha(rowIndex+1,i)) 2 * alpha(rowIndex, i))) *
+ 2 * alpha(rowIndex,i) concentrations(rowIndex, i) +
) sy * alpha(rowIndex, i) * bcTop[i].getValue();
) * concentrations(rowIndex,i)
+ sy * alpha(rowIndex,i) * bcTop[i].getValue();
return c; return c;
} }
// calculates explicit concentration at top boundary in closed case // calculates explicit concentration at top boundary in closed case
static double calcExplicitConcentrationsTopBoundaryClosed(MatrixXd &concentrations, static double calcExplicitConcentrationsTopBoundaryClosed(
MatrixXd &alpha, int rowIndex, int i, double sy) { MatrixXd &concentrations, MatrixXd &alpha, int rowIndex, int i, double sy) {
double c; double c;
c = sy * calcAlphaIntercell(alpha(rowIndex,i), alpha(rowIndex+1,i)) c = sy * calcAlphaIntercell(alpha(rowIndex, i), alpha(rowIndex + 1, i)) *
* concentrations(rowIndex,i) concentrations(rowIndex, i) +
+ ( (1 -
1 - sy * ( sy * (calcAlphaIntercell(alpha(rowIndex, i), alpha(rowIndex + 1, i)))) *
calcAlphaIntercell(alpha(rowIndex,i), alpha(rowIndex+1,i)) concentrations(rowIndex, i);
)
) * concentrations(rowIndex,i);
return c; return c;
} }
// calculates explicit concentration at bottom boundary in constant case // calculates explicit concentration at bottom boundary in constant case
static double calcExplicitConcentrationsBottomBoundaryConstant(MatrixXd &concentrations, static double calcExplicitConcentrationsBottomBoundaryConstant(
MatrixXd &alpha, vector<BoundaryElement> &bcBottom, int rowIndex, int i, double sy) { MatrixXd &concentrations, MatrixXd &alpha,
double c; vector<BoundaryElement> &bcBottom, int rowIndex, int i, double sy) {
double c;
c = sy * alpha(rowIndex,i) * bcBottom[i].getValue() c = sy * alpha(rowIndex, i) * bcBottom[i].getValue() +
+ ( (1 -
1 - sy * ( sy * (2 * alpha(rowIndex, i) +
2 * alpha(rowIndex,i) calcAlphaIntercell(alpha(rowIndex - 1, i), alpha(rowIndex, i)))) *
+ calcAlphaIntercell(alpha(rowIndex-1,i), alpha(rowIndex,i)) concentrations(rowIndex, i) +
) sy * calcAlphaIntercell(alpha(rowIndex - 1, i), alpha(rowIndex, i)) *
) * concentrations(rowIndex,i) concentrations(rowIndex - 1, i);
+ sy * calcAlphaIntercell(alpha(rowIndex-1,i), alpha(rowIndex,i))
* concentrations(rowIndex-1,i);
return c; return c;
} }
// calculates explicit concentration at bottom boundary in closed case // calculates explicit concentration at bottom boundary in closed case
static double calcExplicitConcentrationsBottomBoundaryClosed(MatrixXd &concentrations, static double calcExplicitConcentrationsBottomBoundaryClosed(
MatrixXd &alpha, int rowIndex, int i, double sy) { MatrixXd &concentrations, MatrixXd &alpha, int rowIndex, int i, double sy) {
double c; double c;
c = ( c = (1 -
1 - sy * ( sy * (+calcAlphaIntercell(alpha(rowIndex - 1, i), alpha(rowIndex, i)))) *
+ calcAlphaIntercell(alpha(rowIndex-1,i), alpha(rowIndex,i)) concentrations(rowIndex, i) +
) sy * calcAlphaIntercell(alpha(rowIndex - 1, i), alpha(rowIndex, i)) *
) * concentrations(rowIndex,i) concentrations(rowIndex - 1, i);
+ sy * calcAlphaIntercell(alpha(rowIndex-1,i), alpha(rowIndex,i))
* concentrations(rowIndex-1,i);
return c; return c;
} }
// creates a solution vector for next time step from the current state of
// concentrations
static VectorXd createSolutionVector(
MatrixXd &concentrations, MatrixXd &alphaX, MatrixXd &alphaY,
vector<BoundaryElement> &bcLeft, vector<BoundaryElement> &bcRight,
vector<BoundaryElement> &bcTop, vector<BoundaryElement> &bcBottom,
int length, int rowIndex, double sx, double sy) {
// creates a solution vector for next time step from the current state of concentrations VectorXd sv(length);
static VectorXd createSolutionVector(MatrixXd &concentrations, MatrixXd &alphaX, MatrixXd &alphaY, int numRows = concentrations.rows();
vector<BoundaryElement> &bcLeft, vector<BoundaryElement> &bcRight, BC_TYPE type;
vector<BoundaryElement> &bcTop, vector<BoundaryElement> &bcBottom,
int length, int rowIndex, double sx, double sy) {
VectorXd sv(length); // inner rows
int numRows = concentrations.rows(); if (rowIndex > 0 && rowIndex < numRows - 1) {
BC_TYPE type; for (int i = 0; i < length; i++) {
sv(i) =
// inner rows sy *
if (rowIndex > 0 && rowIndex < numRows-1) { calcAlphaIntercell(alphaY(rowIndex, i), alphaY(rowIndex + 1, i)) *
for (int i = 0; i < length; i++) { concentrations(rowIndex + 1, i) +
sv(i) = sy * calcAlphaIntercell(alphaY(rowIndex,i), alphaY(rowIndex+1,i)) (1 - sy * (calcAlphaIntercell(alphaY(rowIndex, i),
* concentrations(rowIndex+1,i) alphaY(rowIndex + 1, i)) +
+ ( calcAlphaIntercell(alphaY(rowIndex - 1, i),
1 - sy * ( alphaY(rowIndex, i)))) *
calcAlphaIntercell(alphaY(rowIndex,i), alphaY(rowIndex+1,i)) concentrations(rowIndex, i) +
+ calcAlphaIntercell(alphaY(rowIndex-1,i), alphaY(rowIndex,i)) sy *
) calcAlphaIntercell(alphaY(rowIndex - 1, i), alphaY(rowIndex, i)) *
) * concentrations(rowIndex,i) concentrations(rowIndex - 1, i);
+ sy * calcAlphaIntercell(alphaY(rowIndex-1,i), alphaY(rowIndex,i))
* concentrations(rowIndex-1,i)
;
}
} }
}
// first row // first row
else if (rowIndex == 0) { else if (rowIndex == 0) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
type = bcTop[i].getType(); type = bcTop[i].getType();
if (type == BC_TYPE_CONSTANT) { if (type == BC_TYPE_CONSTANT) {
sv(i) = calcExplicitConcentrationsTopBoundaryConstant(concentrations, alphaY, bcTop, rowIndex, i, sy); sv(i) = calcExplicitConcentrationsTopBoundaryConstant(
} else if (type == BC_TYPE_CLOSED) { concentrations, alphaY, bcTop, rowIndex, i, sy);
sv(i) = calcExplicitConcentrationsTopBoundaryClosed(concentrations, alphaY, rowIndex, i, sy); } else if (type == BC_TYPE_CLOSED) {
} else { sv(i) = calcExplicitConcentrationsTopBoundaryClosed(
throw_invalid_argument("Undefined Boundary Condition Type somewhere on Left or Top!"); concentrations, alphaY, rowIndex, i, sy);
} } else {
} throw_invalid_argument(
"Undefined Boundary Condition Type somewhere on Left or Top!");
}
} }
}
// last row // last row
else if (rowIndex == numRows-1) { else if (rowIndex == numRows - 1) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
type = bcBottom[i].getType(); type = bcBottom[i].getType();
if (type == BC_TYPE_CONSTANT) { if (type == BC_TYPE_CONSTANT) {
sv(i) = calcExplicitConcentrationsBottomBoundaryConstant(concentrations, alphaY, bcBottom, rowIndex, i, sy); sv(i) = calcExplicitConcentrationsBottomBoundaryConstant(
} else if (type == BC_TYPE_CLOSED) { concentrations, alphaY, bcBottom, rowIndex, i, sy);
sv(i) = calcExplicitConcentrationsBottomBoundaryClosed(concentrations, alphaY, rowIndex, i, sy); } else if (type == BC_TYPE_CLOSED) {
} else { sv(i) = calcExplicitConcentrationsBottomBoundaryClosed(
throw_invalid_argument("Undefined Boundary Condition Type somewhere on Right or Bottom!"); concentrations, alphaY, rowIndex, i, sy);
} } else {
} throw_invalid_argument(
"Undefined Boundary Condition Type somewhere on Right or Bottom!");
}
} }
}
// first column -> additional fixed concentration change from perpendicular dimension in constant bc case // first column -> additional fixed concentration change from perpendicular
if (bcLeft[rowIndex].getType() == BC_TYPE_CONSTANT) { // dimension in constant bc case
sv(0) += 2 * sx * alphaX(rowIndex,0) * bcLeft[rowIndex].getValue(); if (bcLeft[rowIndex].getType() == BC_TYPE_CONSTANT) {
} sv(0) += 2 * sx * alphaX(rowIndex, 0) * bcLeft[rowIndex].getValue();
}
// last column -> additional fixed concentration change from perpendicular dimension in constant bc case // last column -> additional fixed concentration change from perpendicular
if (bcRight[rowIndex].getType() == BC_TYPE_CONSTANT) { // dimension in constant bc case
sv(length-1) += 2 * sx * alphaX(rowIndex,length-1) * bcRight[rowIndex].getValue(); if (bcRight[rowIndex].getType() == BC_TYPE_CONSTANT) {
} sv(length - 1) +=
2 * sx * alphaX(rowIndex, length - 1) * bcRight[rowIndex].getValue();
}
return sv; return sv;
} }
// solver for linear equation system; A corresponds to coefficient matrix, // solver for linear equation system; A corresponds to coefficient matrix,
// b to the solution vector // b to the solution vector
// use of EigenLU solver // use of EigenLU solver
static VectorXd EigenLUAlgorithm(SparseMatrix<double> &A, VectorXd &b) { static VectorXd EigenLUAlgorithm(SparseMatrix<double> &A, VectorXd &b) {
SparseLU<SparseMatrix<double>> solver; SparseLU<SparseMatrix<double>> solver;
solver.analyzePattern(A); solver.analyzePattern(A);
solver.factorize(A); solver.factorize(A);
return solver.solve(b); return solver.solve(b);
} }
// solver for linear equation system; A corresponds to coefficient matrix, // solver for linear equation system; A corresponds to coefficient matrix,
// b to the solution vector // b to the solution vector
// implementation of Thomas Algorithm // implementation of Thomas Algorithm
static VectorXd ThomasAlgorithm(SparseMatrix<double> &A, VectorXd &b) { static VectorXd ThomasAlgorithm(SparseMatrix<double> &A, VectorXd &b) {
uint32_t n = b.size(); uint32_t n = b.size();
Eigen::VectorXd a_diag(n); Eigen::VectorXd a_diag(n);
Eigen::VectorXd b_diag(n); Eigen::VectorXd b_diag(n);
Eigen::VectorXd c_diag(n); Eigen::VectorXd c_diag(n);
Eigen::VectorXd x_vec = b; Eigen::VectorXd x_vec = b;
// Fill diagonals vectors // Fill diagonals vectors
b_diag[0] = A.coeff(0, 0); b_diag[0] = A.coeff(0, 0);
c_diag[0] = A.coeff(0, 1); c_diag[0] = A.coeff(0, 1);
for (int i = 1; i < n - 1; i++) { for (int i = 1; i < n - 1; i++) {
a_diag[i] = A.coeff(i, i - 1); a_diag[i] = A.coeff(i, i - 1);
b_diag[i] = A.coeff(i, i); b_diag[i] = A.coeff(i, i);
c_diag[i] = A.coeff(i, i + 1); c_diag[i] = A.coeff(i, i + 1);
} }
a_diag[n - 1] = A.coeff(n - 1, n - 2); a_diag[n - 1] = A.coeff(n - 1, n - 2);
b_diag[n - 1] = A.coeff(n - 1, n - 1); b_diag[n - 1] = A.coeff(n - 1, n - 1);
// HACK: write CSV to file // HACK: write CSV to file
#ifdef WRITE_THOMAS_CSV #ifdef WRITE_THOMAS_CSV
#include<fstream> #include <fstream>
#include<string> #include <string>
static std::uint32_t file_index = 0; static std::uint32_t file_index = 0;
std::string file_name = "Thomas_" + std::to_string(file_index++) + ".csv"; std::string file_name = "Thomas_" + std::to_string(file_index++) + ".csv";
std::ofstream out_file; std::ofstream out_file;
out_file.open(file_name, std::ofstream::trunc | std::ofstream::out); out_file.open(file_name, std::ofstream::trunc | std::ofstream::out);
// print header // print header
out_file << "Aa, Ab, Ac, b\n"; out_file << "Aa, Ab, Ac, b\n";
// iterate through all elements // iterate through all elements
for (std::size_t i = 0; i < n; i++) { for (std::size_t i = 0; i < n; i++) {
out_file << a_diag[i] << ", " << b_diag[i] << ", " << c_diag[i] << ", " << b[i] << "\n"; out_file << a_diag[i] << ", " << b_diag[i] << ", " << c_diag[i] << ", "
} << b[i] << "\n";
}
out_file.close(); out_file.close();
#endif #endif
// start solving - c_diag and x_vec are overwritten // start solving - c_diag and x_vec are overwritten
n--; n--;
c_diag[0] /= b_diag[0]; c_diag[0] /= b_diag[0];
x_vec[0] /= b_diag[0]; x_vec[0] /= b_diag[0];
for (int i = 1; i < n; i++) { for (int i = 1; i < n; i++) {
c_diag[i] /= b_diag[i] - a_diag[i] * c_diag[i - 1]; c_diag[i] /= b_diag[i] - a_diag[i] * c_diag[i - 1];
x_vec[i] = (x_vec[i] - a_diag[i] * x_vec[i - 1]) / x_vec[i] = (x_vec[i] - a_diag[i] * x_vec[i - 1]) /
(b_diag[i] - a_diag[i] * c_diag[i - 1]); (b_diag[i] - a_diag[i] * c_diag[i - 1]);
} }
x_vec[n] = (x_vec[n] - a_diag[n] * x_vec[n - 1]) / x_vec[n] = (x_vec[n] - a_diag[n] * x_vec[n - 1]) /
(b_diag[n] - a_diag[n] * c_diag[n - 1]); (b_diag[n] - a_diag[n] * c_diag[n - 1]);
for (int i = n; i-- > 0;) { for (int i = n; i-- > 0;) {
x_vec[i] -= c_diag[i] * x_vec[i + 1]; x_vec[i] -= c_diag[i] * x_vec[i + 1];
} }
return x_vec; return x_vec;
} }
// BTCS solution for 1D grid
static void BTCS_1D(Grid &grid, Boundary &bc, double timestep,
VectorXd (*solverFunc)(SparseMatrix<double> &A,
VectorXd &b)) {
int length = grid.getLength();
double sx = timestep / (grid.getDelta() * grid.getDelta());
// BTCS solution for 1D grid VectorXd concentrations_t1(length);
static void BTCS_1D(Grid &grid, Boundary &bc, double timestep, VectorXd (*solverFunc) (SparseMatrix<double> &A, VectorXd &b)) {
int length = grid.getLength();
double sx = timestep / (grid.getDelta() * grid.getDelta());
VectorXd concentrations_t1(length); SparseMatrix<double> A;
VectorXd b(length);
SparseMatrix<double> A; MatrixXd alpha = grid.getAlpha();
VectorXd b(length); vector<BoundaryElement> bcLeft = bc.getBoundarySide(BC_SIDE_LEFT);
vector<BoundaryElement> bcRight = bc.getBoundarySide(BC_SIDE_RIGHT);
MatrixXd alpha = grid.getAlpha(); MatrixXd concentrations = grid.getConcentrations();
vector<BoundaryElement> bcLeft = bc.getBoundarySide(BC_SIDE_LEFT); int rowIndex = 0;
vector<BoundaryElement> bcRight = bc.getBoundarySide(BC_SIDE_RIGHT); A = createCoeffMatrix(alpha, bcLeft, bcRight, length, rowIndex,
sx); // this is exactly same as in 2D
for (int i = 0; i < length; i++) {
b(i) = concentrations(0, i);
}
if (bc.getBoundaryElementType(BC_SIDE_LEFT, 0) == BC_TYPE_CONSTANT) {
b(0) += 2 * sx * alpha(0, 0) * bcLeft[0].getValue();
}
if (bc.getBoundaryElementType(BC_SIDE_RIGHT, 0) == BC_TYPE_CONSTANT) {
b(length - 1) += 2 * sx * alpha(0, length - 1) * bcRight[0].getValue();
}
MatrixXd concentrations = grid.getConcentrations(); concentrations_t1 = solverFunc(A, b);
int rowIndex = 0;
A = createCoeffMatrix(alpha, bcLeft, bcRight, length, rowIndex, sx); // this is exactly same as in 2D
for (int i = 0; i < length; i++) {
b(i) = concentrations(0,i);
}
if (bc.getBoundaryElementType(BC_SIDE_LEFT, 0) == BC_TYPE_CONSTANT) {
b(0) += 2 * sx * alpha(0,0) * bcLeft[0].getValue();
}
if (bc.getBoundaryElementType(BC_SIDE_RIGHT, 0) == BC_TYPE_CONSTANT) {
b(length-1) += 2 * sx * alpha(0,length-1) * bcRight[0].getValue();
}
concentrations_t1 = solverFunc(A, b); for (int j = 0; j < length; j++) {
concentrations(0, j) = concentrations_t1(j);
}
for (int j = 0; j < length; j++) { grid.setConcentrations(concentrations);
concentrations(0,j) = concentrations_t1(j);
}
grid.setConcentrations(concentrations);
} }
// BTCS solution for 2D grid // BTCS solution for 2D grid
static void BTCS_2D(Grid &grid, Boundary &bc, double timestep, VectorXd (*solverFunc) (SparseMatrix<double> &A, VectorXd &b), int numThreads) { static void BTCS_2D(Grid &grid, Boundary &bc, double timestep,
int rowMax = grid.getRow(); VectorXd (*solverFunc)(SparseMatrix<double> &A,
int colMax = grid.getCol(); VectorXd &b),
double sx = timestep / (2 * grid.getDeltaCol() * grid.getDeltaCol()); int numThreads) {
double sy = timestep / (2 * grid.getDeltaRow() * grid.getDeltaRow()); int rowMax = grid.getRow();
int colMax = grid.getCol();
double sx = timestep / (2 * grid.getDeltaCol() * grid.getDeltaCol());
double sy = timestep / (2 * grid.getDeltaRow() * grid.getDeltaRow());
MatrixXd concentrations_t1 = MatrixXd::Constant(rowMax, colMax, 0); MatrixXd concentrations_t1 = MatrixXd::Constant(rowMax, colMax, 0);
VectorXd row_t1(colMax); VectorXd row_t1(colMax);
SparseMatrix<double> A; SparseMatrix<double> A;
VectorXd b; VectorXd b;
MatrixXd alphaX = grid.getAlphaX(); MatrixXd alphaX = grid.getAlphaX();
MatrixXd alphaY = grid.getAlphaY(); MatrixXd alphaY = grid.getAlphaY();
vector<BoundaryElement> bcLeft = bc.getBoundarySide(BC_SIDE_LEFT); vector<BoundaryElement> bcLeft = bc.getBoundarySide(BC_SIDE_LEFT);
vector<BoundaryElement> bcRight = bc.getBoundarySide(BC_SIDE_RIGHT); vector<BoundaryElement> bcRight = bc.getBoundarySide(BC_SIDE_RIGHT);
vector<BoundaryElement> bcTop = bc.getBoundarySide(BC_SIDE_TOP); vector<BoundaryElement> bcTop = bc.getBoundarySide(BC_SIDE_TOP);
vector<BoundaryElement> bcBottom = bc.getBoundarySide(BC_SIDE_BOTTOM); vector<BoundaryElement> bcBottom = bc.getBoundarySide(BC_SIDE_BOTTOM);
MatrixXd concentrations = grid.getConcentrations(); MatrixXd concentrations = grid.getConcentrations();
#pragma omp parallel for num_threads(numThreads) private(A, b, row_t1) #pragma omp parallel for num_threads(numThreads) private(A, b, row_t1)
for (int i = 0; i < rowMax; i++) { for (int i = 0; i < rowMax; i++) {
A = createCoeffMatrix(alphaX, bcLeft, bcRight, colMax, i, sx);
b = createSolutionVector(concentrations, alphaX, alphaY, bcLeft, bcRight,
bcTop, bcBottom, colMax, i, sx, sy);
SparseLU<SparseMatrix<double>> solver;
row_t1 = solverFunc(A, b); A = createCoeffMatrix(alphaX, bcLeft, bcRight, colMax, i, sx);
b = createSolutionVector(concentrations, alphaX, alphaY, bcLeft, bcRight,
concentrations_t1.row(i) = row_t1; bcTop, bcBottom, colMax, i, sx, sy);
}
concentrations_t1.transposeInPlace();
concentrations.transposeInPlace();
alphaX.transposeInPlace();
alphaY.transposeInPlace();
#pragma omp parallel for num_threads(numThreads) private(A, b, row_t1)
for (int i = 0; i < colMax; i++) {
// swap alphas, boundary conditions and sx/sy for column-wise calculation
A = createCoeffMatrix(alphaY, bcTop, bcBottom, rowMax, i, sy);
b = createSolutionVector(concentrations_t1, alphaY, alphaX, bcTop, bcBottom,
bcLeft, bcRight, rowMax, i, sy, sx);
row_t1 = solverFunc(A, b);
concentrations.row(i) = row_t1; SparseLU<SparseMatrix<double>> solver;
}
concentrations.transposeInPlace();
grid.setConcentrations(concentrations); row_t1 = solverFunc(A, b);
concentrations_t1.row(i) = row_t1;
}
concentrations_t1.transposeInPlace();
concentrations.transposeInPlace();
alphaX.transposeInPlace();
alphaY.transposeInPlace();
#pragma omp parallel for num_threads(numThreads) private(A, b, row_t1)
for (int i = 0; i < colMax; i++) {
// swap alphas, boundary conditions and sx/sy for column-wise calculation
A = createCoeffMatrix(alphaY, bcTop, bcBottom, rowMax, i, sy);
b = createSolutionVector(concentrations_t1, alphaY, alphaX, bcTop, bcBottom,
bcLeft, bcRight, rowMax, i, sy, sx);
row_t1 = solverFunc(A, b);
concentrations.row(i) = row_t1;
}
concentrations.transposeInPlace();
grid.setConcentrations(concentrations);
} }
// entry point for EigenLU solver; differentiate between 1D and 2D grid // entry point for EigenLU solver; differentiate between 1D and 2D grid
static void BTCS_LU(Grid &grid, Boundary &bc, double timestep, int numThreads) { static void BTCS_LU(Grid &grid, Boundary &bc, double timestep, int numThreads) {
if (grid.getDim() == 1) { if (grid.getDim() == 1) {
BTCS_1D(grid, bc, timestep, EigenLUAlgorithm); BTCS_1D(grid, bc, timestep, EigenLUAlgorithm);
} else if (grid.getDim() == 2) { } else if (grid.getDim() == 2) {
BTCS_2D(grid, bc, timestep, EigenLUAlgorithm, numThreads); BTCS_2D(grid, bc, timestep, EigenLUAlgorithm, numThreads);
} else { } else {
throw_invalid_argument("Error: Only 1- and 2-dimensional grids are defined!"); throw_invalid_argument(
} "Error: Only 1- and 2-dimensional grids are defined!");
}
} }
// entry point for Thomas algorithm solver; differentiate 1D and 2D grid // entry point for Thomas algorithm solver; differentiate 1D and 2D grid
static void BTCS_Thomas(Grid &grid, Boundary &bc, double timestep, int numThreads) { static void BTCS_Thomas(Grid &grid, Boundary &bc, double timestep,
if (grid.getDim() == 1) { int numThreads) {
BTCS_1D(grid, bc, timestep, ThomasAlgorithm); if (grid.getDim() == 1) {
} else if (grid.getDim() == 2) { BTCS_1D(grid, bc, timestep, ThomasAlgorithm);
BTCS_2D(grid, bc, timestep, ThomasAlgorithm, numThreads); } else if (grid.getDim() == 2) {
} else { BTCS_2D(grid, bc, timestep, ThomasAlgorithm, numThreads);
throw_invalid_argument("Error: Only 1- and 2-dimensional grids are defined!"); } else {
} throw_invalid_argument(
} "Error: Only 1- and 2-dimensional grids are defined!");
}
}