mirror of
https://git.gfz-potsdam.de/naaice/tug.git
synced 2025-12-15 18:38:23 +01:00
added Thomas Solver with option to choose solver and cleaned up the repository
This commit is contained in:
parent
27829a1463
commit
32b05a8a87
@ -1,24 +1,17 @@
|
|||||||
add_executable(first_example first_example.cpp)
|
|
||||||
add_executable(second_example second_example.cpp)
|
|
||||||
add_executable(boundary_example1D boundary_example1D.cpp)
|
|
||||||
add_executable(FTCS_1D_proto_example FTCS_1D_proto_example.cpp)
|
add_executable(FTCS_1D_proto_example FTCS_1D_proto_example.cpp)
|
||||||
add_executable(FTCS_2D_proto_example FTCS_2D_proto_example.cpp)
|
add_executable(FTCS_2D_proto_example FTCS_2D_proto_example.cpp)
|
||||||
add_executable(BTCS_1D_proto_example BTCS_1D_proto_example.cpp)
|
add_executable(BTCS_1D_proto_example BTCS_1D_proto_example.cpp)
|
||||||
add_executable(BTCS_2D_proto_example BTCS_2D_proto_example.cpp)
|
add_executable(BTCS_2D_proto_example BTCS_2D_proto_example.cpp)
|
||||||
add_executable(FTCS_2D_proto_example_mdl FTCS_2D_proto_example_mdl.cpp)
|
|
||||||
add_executable(reference-FTCS_2D_closed reference-FTCS_2D_closed.cpp)
|
add_executable(reference-FTCS_2D_closed reference-FTCS_2D_closed.cpp)
|
||||||
add_executable(meeting_example meeting_example.cpp)
|
add_executable(profiling_openmp profiling_openmp.cpp)
|
||||||
target_link_libraries(first_example tug)
|
|
||||||
target_link_libraries(second_example tug)
|
|
||||||
target_link_libraries(boundary_example1D tug)
|
|
||||||
target_link_libraries(FTCS_1D_proto_example tug)
|
target_link_libraries(FTCS_1D_proto_example tug)
|
||||||
target_link_libraries(FTCS_2D_proto_example tug)
|
target_link_libraries(FTCS_2D_proto_example tug)
|
||||||
target_link_libraries(BTCS_1D_proto_example tug)
|
target_link_libraries(BTCS_1D_proto_example tug)
|
||||||
target_link_libraries(BTCS_2D_proto_example tug)
|
target_link_libraries(BTCS_2D_proto_example tug)
|
||||||
target_link_libraries(FTCS_2D_proto_example_mdl tug)
|
|
||||||
target_link_libraries(reference-FTCS_2D_closed tug)
|
target_link_libraries(reference-FTCS_2D_closed tug)
|
||||||
target_link_libraries(meeting_example tug)
|
target_link_libraries(profiling_openmp tug)
|
||||||
# target_link_libraries(FTCS_2D_proto_example easy_profiler)
|
|
||||||
|
|
||||||
|
add_executable(FTCS_2D_proto_example_mdl FTCS_2D_proto_example_mdl.cpp)
|
||||||
add_executable(FTCS_2D_proto_closed_mdl FTCS_2D_proto_closed_mdl.cpp)
|
add_executable(FTCS_2D_proto_closed_mdl FTCS_2D_proto_closed_mdl.cpp)
|
||||||
target_link_libraries(FTCS_2D_proto_closed_mdl tug)
|
target_link_libraries(FTCS_2D_proto_closed_mdl tug)
|
||||||
|
target_link_libraries(FTCS_2D_proto_example_mdl tug)
|
||||||
|
|||||||
@ -1,59 +0,0 @@
|
|||||||
#include "../include/diffusion/BTCSDiffusion.hpp"
|
|
||||||
#include "../include/diffusion/BoundaryCondition.hpp"
|
|
||||||
#include <algorithm> // for copy, max
|
|
||||||
#include <cmath>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <iostream> // for std
|
|
||||||
#include <vector> // for vector
|
|
||||||
#include <Rcpp.h>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace Diffusion;
|
|
||||||
using namespace Rcpp;
|
|
||||||
//using namespace Eigen;
|
|
||||||
|
|
||||||
// [[Rcpp::depends(RcppEigen)]]
|
|
||||||
// [[Rcpp::plugins("cpp11")]]
|
|
||||||
// [[Rcpp::export]]
|
|
||||||
std::vector<double> & diff1D(int n,
|
|
||||||
double length,
|
|
||||||
std::vector<double> & field,
|
|
||||||
std::vector<double> & alpha,
|
|
||||||
double timestep,
|
|
||||||
double bc_left,
|
|
||||||
double bc_right,
|
|
||||||
int iterations) {
|
|
||||||
// dimension of grid
|
|
||||||
int dim = 1;
|
|
||||||
|
|
||||||
// create input + diffusion coefficients for each grid cell
|
|
||||||
// std::vector<double> alpha(n, 1 * pow(10, -1));
|
|
||||||
// std::vector<double> field(n, 1 * std::pow(10, -6));
|
|
||||||
std::vector<boundary_condition> bc(n, {0,0});
|
|
||||||
|
|
||||||
// create instance of diffusion module
|
|
||||||
BTCSDiffusion diffu(dim);
|
|
||||||
|
|
||||||
diffu.setXDimensions(length, n);
|
|
||||||
|
|
||||||
// set the boundary condition for the left ghost cell to dirichlet
|
|
||||||
bc[0] = {Diffusion::BC_CONSTANT, bc_left};
|
|
||||||
bc[n-1] = {Diffusion::BC_CONSTANT, bc_right};
|
|
||||||
|
|
||||||
// set timestep for simulation to 1 second
|
|
||||||
diffu.setTimestep(timestep);
|
|
||||||
|
|
||||||
//cout << setprecision(12);
|
|
||||||
|
|
||||||
// loop 100 times
|
|
||||||
// output is currently generated by the method itself
|
|
||||||
for (int i = 0; i < iterations; i++) {
|
|
||||||
diffu.simulate(field.data(), alpha.data(), bc.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
// for (auto & cell : field) {
|
|
||||||
// Rcout << cell << "\n";
|
|
||||||
// }
|
|
||||||
|
|
||||||
return(field);
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
#include "../include/diffusion/BTCSDiffusion.hpp"
|
|
||||||
#include "../include/diffusion/BoundaryCondition.hpp"
|
|
||||||
#include <algorithm> // for copy, max
|
|
||||||
#include <cmath>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <iostream> // for std
|
|
||||||
#include <vector> // for vector
|
|
||||||
#include <Rcpp.h>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace Diffusion;
|
|
||||||
using namespace Rcpp;
|
|
||||||
//using namespace Eigen;
|
|
||||||
|
|
||||||
// [[Rcpp::depends(RcppEigen)]]
|
|
||||||
// [[Rcpp::plugins("cpp11")]]
|
|
||||||
// [[Rcpp::export]]
|
|
||||||
std::vector<double> & diff2D(int nx,
|
|
||||||
int ny,
|
|
||||||
double lenx,
|
|
||||||
double leny,
|
|
||||||
std::vector<double> & field,
|
|
||||||
std::vector<double> & alpha,
|
|
||||||
double timestep,
|
|
||||||
int iterations)
|
|
||||||
{
|
|
||||||
// problem dimensionality
|
|
||||||
int dim = 2;
|
|
||||||
// total number of grid cells
|
|
||||||
int n = nx*ny;
|
|
||||||
|
|
||||||
std::vector<boundary_condition> bc(n, {0,0});
|
|
||||||
|
|
||||||
// create instance of diffusion module
|
|
||||||
BTCSDiffusion diffu(dim);
|
|
||||||
|
|
||||||
diffu.setXDimensions(lenx, nx);
|
|
||||||
diffu.setXDimensions(leny, ny);
|
|
||||||
|
|
||||||
// set the boundary condition for the left ghost cell to dirichlet
|
|
||||||
// bc[0] = {Diffusion::BC_CONSTANT, bc_left};
|
|
||||||
// bc[n-1] = {Diffusion::BC_CONSTANT, bc_right};
|
|
||||||
|
|
||||||
// set timestep for simulation to 1 second
|
|
||||||
diffu.setTimestep(timestep);
|
|
||||||
|
|
||||||
//cout << setprecision(12);
|
|
||||||
|
|
||||||
// loop 100 times
|
|
||||||
// output is currently generated by the method itself
|
|
||||||
for (int i = 0; i < iterations; i++) {
|
|
||||||
diffu.simulate(field.data(), alpha.data(), bc.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
// for (auto & cell : field) {
|
|
||||||
// Rcout << cell << "\n";
|
|
||||||
// }
|
|
||||||
|
|
||||||
return(field);
|
|
||||||
}
|
|
||||||
@ -1,159 +0,0 @@
|
|||||||
## Time-stamp: "Last modified 2022-03-16 14:01:11 delucia"
|
|
||||||
library(Rcpp)
|
|
||||||
library(RcppEigen)
|
|
||||||
library(ReacTran)
|
|
||||||
library(deSolve)
|
|
||||||
|
|
||||||
options(width=110)
|
|
||||||
|
|
||||||
setwd("app")
|
|
||||||
|
|
||||||
## This creates the "diff1D" function with our BTCSdiffusion code
|
|
||||||
sourceCpp("Rcpp-BTCS-1d.cpp")
|
|
||||||
|
|
||||||
### FTCS explicit (same name)
|
|
||||||
sourceCpp("RcppFTCS.cpp")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Grid 101
|
|
||||||
## Set initial conditions
|
|
||||||
N <- 1001
|
|
||||||
D.coeff <- 1E-3
|
|
||||||
C0 <- 1 ## Initial concentration (mg/L)
|
|
||||||
X0 <- 0 ## Location of initial concentration (m)
|
|
||||||
## Yini <- c(C0, rep(0,N-1))
|
|
||||||
|
|
||||||
## Ode1d solution
|
|
||||||
xgrid <- setup.grid.1D(x.up = 0, x.down = 1, N = N)
|
|
||||||
x <- xgrid$x.mid
|
|
||||||
Diffusion <- function (t, Y, parms){
|
|
||||||
tran <- tran.1D(C = Y, C.up = 0, C.down = 0, D = parms$D, dx = xgrid)
|
|
||||||
return(list(tran$dC))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
## gaussian pulse as initial condition
|
|
||||||
sigma <- 0.02
|
|
||||||
Yini <- 0.5*exp(-0.5*((x-1/2.0)**2)/sigma**2)
|
|
||||||
|
|
||||||
## plot(x, Yini, type="l")
|
|
||||||
|
|
||||||
parms1 <- list(D=D.coeff)
|
|
||||||
# 1 timestep, 10 s
|
|
||||||
times <- seq(from = 0, to = 1, by = 0.1)
|
|
||||||
|
|
||||||
system.time({
|
|
||||||
out1 <- ode.1D(y = Yini, times = times, func = Diffusion,
|
|
||||||
parms = parms1, dimens = N)[11,-1]
|
|
||||||
})
|
|
||||||
|
|
||||||
## Now with BTCS
|
|
||||||
alpha <- rep(D.coeff, N)
|
|
||||||
|
|
||||||
system.time({
|
|
||||||
out2 <- diff1D(n=N, length=1, field=Yini, alpha=alpha, timestep = 0.1, 0, 0, iterations = 10)
|
|
||||||
})
|
|
||||||
|
|
||||||
## plot(out1, out2)
|
|
||||||
## abline(0,1)
|
|
||||||
|
|
||||||
## matplot(cbind(out1,out2),type="l", col=c("black","red"),lty="solid", lwd=2,
|
|
||||||
## xlab="grid element", ylab="Concentration", las=1)
|
|
||||||
## legend("topright", c("ReacTran ode1D", "BTCS 1d"), text.col=c("black","red"), bty = "n")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
system.time({
|
|
||||||
out3 <- RcppFTCS(n=N, length=1, field=Yini, alpha=1E-3, bc_left = 0, bc_right = 0, timestep = 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
## Poor man's
|
|
||||||
mm <- colMeans(rbind(out2,out3))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
matplot(cbind(Yini,out1, out2, out3, mm),type="l", col=c("grey","black","red","blue","green4"), lty="solid", lwd=2,
|
|
||||||
xlab="grid element", ylab="Concentration", las=1)
|
|
||||||
legend("topright", c("init","ReacTran ode1D", "BTCS 1d", "FTCS", "poor man's CN"), text.col=c("grey","black","red","blue","green4"), bty = "n")
|
|
||||||
|
|
||||||
|
|
||||||
sum(Yini)
|
|
||||||
sum(out1)
|
|
||||||
sum(out2)
|
|
||||||
sum(out3)
|
|
||||||
sum(mm)
|
|
||||||
|
|
||||||
## Yini <- 0.2*sin(pi/0.1*x)+0.2
|
|
||||||
## plot(Yini)
|
|
||||||
|
|
||||||
## plot(out3)
|
|
||||||
|
|
||||||
Fun <- function(dx) {
|
|
||||||
tmp <- diff1D(n=N, length=1, field=Yini, alpha=alpha, timestep = dx, 0, 0, iterations = floor(1/dx))
|
|
||||||
sqrt(sum({out1-tmp}^2))
|
|
||||||
}
|
|
||||||
|
|
||||||
reso <- optimise(f=Fun, interval=c(1E-5, 1E-1), maximum = FALSE)
|
|
||||||
|
|
||||||
|
|
||||||
dx <- 0.0006038284
|
|
||||||
floor(1/dx)
|
|
||||||
|
|
||||||
1/dx
|
|
||||||
|
|
||||||
system.time({
|
|
||||||
out2o <- diff1D(n=N, length=1, field=Yini, alpha=alpha, timestep = dx, 0, 0, iterations = 1656)
|
|
||||||
})
|
|
||||||
|
|
||||||
matplot(cbind(out1, out2o),type="l", col=c("black","red"), lty="solid", lwd=2,
|
|
||||||
xlab="grid element", ylab="Concentration", las=1)
|
|
||||||
legend("topright", c("ReacTran ode1D", "BTCS 1d dx=0.0006"), text.col=c("black","red"), bty = "n")
|
|
||||||
|
|
||||||
|
|
||||||
dx <- 0.05
|
|
||||||
|
|
||||||
system.time({
|
|
||||||
out2o <- diff1D(n=N, length=1, field=Yini, alpha=alpha, timestep = dx, 0, 0, iterations = 1/dx)
|
|
||||||
})
|
|
||||||
|
|
||||||
matplot(cbind(out1, out2o),type="l", col=c("black","red"), lty="solid", lwd=2,
|
|
||||||
xlab="grid element", ylab="Concentration", las=1)
|
|
||||||
legend("topright", c("ReacTran ode1D", "BTCS 1d dx=0.0006"), text.col=c("black","red"), bty = "n")
|
|
||||||
|
|
||||||
Matplot
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## This creates the "diff1D" function with our BTCSdiffusion code
|
|
||||||
sourceCpp("Rcpp-BTCS-2d.cpp")
|
|
||||||
|
|
||||||
n <- 256
|
|
||||||
a2d <- rep(1E-3, n^2)
|
|
||||||
|
|
||||||
init2d <- readRDS("gs1.rds")
|
|
||||||
|
|
||||||
ll <- {init2d - min(init2d)}/diff(range(init2d))
|
|
||||||
|
|
||||||
system.time({
|
|
||||||
res1 <- diff2D(nx=N, ny=N, lenx=1, leny=1, field=ll, alpha=a2d, timestep = 0.1, iterations = 10)
|
|
||||||
})
|
|
||||||
|
|
||||||
hist(ll,32)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
#include "../include/diffusion/BTCSDiffusion.hpp"
|
|
||||||
#include "../include/diffusion/BoundaryCondition.hpp"
|
|
||||||
#include <algorithm> // for copy, max
|
|
||||||
#include <cmath>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <iostream> // for std
|
|
||||||
#include <vector> // for vector
|
|
||||||
#include <Rcpp.h>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace Diffusion;
|
|
||||||
using namespace Rcpp;
|
|
||||||
//using namespace Eigen;
|
|
||||||
|
|
||||||
// [[Rcpp::depends(RcppEigen)]]
|
|
||||||
// [[Rcpp::plugins("cpp11")]]
|
|
||||||
// [[Rcpp::export]]
|
|
||||||
std::vector<double> & diff1D(int n,
|
|
||||||
double length,
|
|
||||||
std::vector<double> & field,
|
|
||||||
std::vector<double> & alpha,
|
|
||||||
double timestep,
|
|
||||||
double bc_left,
|
|
||||||
double bc_right,
|
|
||||||
int iterations) {
|
|
||||||
// dimension of grid
|
|
||||||
int dim = 1;
|
|
||||||
|
|
||||||
// create input + diffusion coefficients for each grid cell
|
|
||||||
// std::vector<double> alpha(n, 1 * pow(10, -1));
|
|
||||||
// std::vector<double> field(n, 1 * std::pow(10, -6));
|
|
||||||
std::vector<boundary_condition> bc(n, {0,0});
|
|
||||||
|
|
||||||
// create instance of diffusion module
|
|
||||||
BTCSDiffusion diffu(dim);
|
|
||||||
|
|
||||||
diffu.setXDimensions(length, n);
|
|
||||||
|
|
||||||
// set the boundary condition for the left ghost cell to dirichlet
|
|
||||||
bc[0] = {Diffusion::BC_CONSTANT, bc_left};
|
|
||||||
bc[n-1] = {Diffusion::BC_CONSTANT, bc_right};
|
|
||||||
|
|
||||||
// set timestep for simulation to 1 second
|
|
||||||
diffu.setTimestep(timestep);
|
|
||||||
|
|
||||||
//cout << setprecision(12);
|
|
||||||
|
|
||||||
// loop 100 times
|
|
||||||
// output is currently generated by the method itself
|
|
||||||
for (int i = 0; i < iterations; i++) {
|
|
||||||
diffu.simulate(field.data(), alpha.data(), bc.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
// for (auto & cell : field) {
|
|
||||||
// Rcout << cell << "\n";
|
|
||||||
// }
|
|
||||||
|
|
||||||
return(field);
|
|
||||||
}
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
// Time-stamp: "Last modified 2022-03-15 18:15:39 delucia"
|
|
||||||
#include <Rcpp.h>
|
|
||||||
#include <iostream> // for std
|
|
||||||
#include <vector> // for vector
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace Rcpp;
|
|
||||||
|
|
||||||
// [[Rcpp::plugins("cpp11")]]
|
|
||||||
// [[Rcpp::export]]
|
|
||||||
NumericVector RcppFTCS(int n,
|
|
||||||
double length,
|
|
||||||
NumericVector & field,
|
|
||||||
double alpha,
|
|
||||||
double bc_left,
|
|
||||||
double bc_right,
|
|
||||||
double timestep)
|
|
||||||
{
|
|
||||||
// dimension of grid
|
|
||||||
NumericVector ext (clone(field));
|
|
||||||
double dx = length / ((double) n - 1.);
|
|
||||||
double dt = 0.25*dx*dx/alpha;
|
|
||||||
|
|
||||||
|
|
||||||
double afac = alpha*dt/dx/dx;
|
|
||||||
int iter = (int) (timestep/dt);
|
|
||||||
|
|
||||||
Rcout << "dt: " << dt << "; inner iterations: " << iter << endl;
|
|
||||||
|
|
||||||
|
|
||||||
for (int it = 0; it < iter; it++){
|
|
||||||
for (int i = 1; i < ext.size()-1; i++) {
|
|
||||||
ext[i] = (1. - 2*afac)*ext[i] + afac*(ext[i+1]+ext[i-1]);
|
|
||||||
}
|
|
||||||
ext[0] = bc_left;
|
|
||||||
ext[n-1] = bc_right;
|
|
||||||
}
|
|
||||||
return(ext);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
#include <algorithm>
|
|
||||||
#include <tug/BoundaryCondition.hpp>
|
|
||||||
#include <tug/Diffusion.hpp>
|
|
||||||
#include <vector>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace tug::bc;
|
|
||||||
using namespace tug::diffusion;
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
TugInput input;
|
|
||||||
|
|
||||||
BoundaryCondition example(10);
|
|
||||||
|
|
||||||
uint8_t side = BC_SIDE_LEFT;
|
|
||||||
boundary_condition bc;
|
|
||||||
bc.type = BC_TYPE_CONSTANT;
|
|
||||||
bc.value = 1;
|
|
||||||
input.setBoundaryCondition(example);
|
|
||||||
BoundaryCondition returnedBC = input.getBoundaryCondition();
|
|
||||||
|
|
||||||
// example.setSide(side, bc);
|
|
||||||
vector<boundary_condition> result_left = example.getSide(side);
|
|
||||||
// vector<boundary_condition> result_top = example.getSide(BC_SIDE_TOP);
|
|
||||||
|
|
||||||
for (auto i : result_left) {
|
|
||||||
cout << i.value << " ";
|
|
||||||
}
|
|
||||||
cout << endl;
|
|
||||||
// for (auto i : result_top) {
|
|
||||||
// cout << i.value << " ";
|
|
||||||
// }
|
|
||||||
// cout << endl;
|
|
||||||
}
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
#include "tug/BoundaryCondition.hpp"
|
|
||||||
#include <tug/Diffusion.hpp>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace tug::diffusion;
|
|
||||||
using namespace tug::bc;
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
|
|
||||||
// define problem dimensionality
|
|
||||||
// set grid sizes for each dimension
|
|
||||||
int dim = 1;
|
|
||||||
int n = 20;
|
|
||||||
|
|
||||||
vector<double> alpha(n, 1e-1);
|
|
||||||
// double alpha = 1e-1;
|
|
||||||
vector<double> field(n, 1e-6);
|
|
||||||
for (int i = 1; i<20; i++) {
|
|
||||||
field[i] = 0;
|
|
||||||
}
|
|
||||||
// double field = 1e-6;
|
|
||||||
|
|
||||||
|
|
||||||
TugGrid grid_param; // why is grid_param defined separately?
|
|
||||||
// grid_param.grid_cells[0] = 20;
|
|
||||||
// grid_param.grid_cells[1] = 0;
|
|
||||||
// grid_param.grid_cells[2] = 0;
|
|
||||||
|
|
||||||
// grid_param.domain_size[0] = 20;
|
|
||||||
// grid_param.domain_size[1] = 0;
|
|
||||||
// grid_param.domain_size[2] = 0;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TugInput input_param;
|
|
||||||
input_param.setTimestep(1.);
|
|
||||||
//input_param.grid = grid_param;
|
|
||||||
input_param.setGridCellN(n);
|
|
||||||
input_param.setDomainSize(n); // what is domain?????
|
|
||||||
BoundaryCondition bc(n);
|
|
||||||
input_param.setBoundaryCondition(bc);
|
|
||||||
|
|
||||||
BoundaryCondition bc2 = input_param.getBoundaryCondition();
|
|
||||||
auto [bc_left, bc_right] = bc2.row_boundary(0);
|
|
||||||
cout << "left: " << unsigned(bc_left.type) << endl;
|
|
||||||
cout << "right: " << unsigned(bc_right.type) << endl;
|
|
||||||
|
|
||||||
ofstream myfile;
|
|
||||||
myfile.open("output.csv");
|
|
||||||
if (!myfile) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int t = 0; t < 10000; t++) {
|
|
||||||
double result = BTCS_1D(input_param, &field[0], &alpha[0]);
|
|
||||||
//myfile << result;
|
|
||||||
//myfile << '\n';
|
|
||||||
//myfile << "Vector contents: ";
|
|
||||||
for (int i = 0; i < field.size(); i++) {
|
|
||||||
myfile << field[i];
|
|
||||||
if (i < field.size()-1) {
|
|
||||||
myfile << ", ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
myfile << std::endl;
|
|
||||||
}
|
|
||||||
myfile.close();
|
|
||||||
}
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
#include "diffusion/BTCSBoundaryCondition.hpp"
|
|
||||||
#include <diffusion/BTCSDiffusion.hpp>
|
|
||||||
|
|
||||||
#include <iomanip>
|
|
||||||
#include <iostream> // for std
|
|
||||||
#include <vector> // for vector
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
using namespace Diffusion;
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
|
|
||||||
// dimension of grid
|
|
||||||
int dim = 1;
|
|
||||||
|
|
||||||
int n = 20;
|
|
||||||
|
|
||||||
// create input + diffusion coefficients for each grid cell
|
|
||||||
std::vector<double> alpha(n, 1e-1);
|
|
||||||
std::vector<double> field(n, 1e-6);
|
|
||||||
|
|
||||||
BTCSBoundaryCondition bc(n);
|
|
||||||
|
|
||||||
// create instance of diffusion module
|
|
||||||
BTCSDiffusion diffu(dim);
|
|
||||||
|
|
||||||
diffu.setXDimensions(1, n);
|
|
||||||
|
|
||||||
// set the boundary condition for the left ghost cell to dirichlet
|
|
||||||
bc(BC_SIDE_LEFT) = {BC_TYPE_CONSTANT, 5e-6};
|
|
||||||
// bc[0] = {Diffusion::BC_CONSTANT, 5e-6};
|
|
||||||
// diffu.setBoundaryCondition(1, 0, BTCSDiffusion::BC_CONSTANT,
|
|
||||||
// 5. * std::pow(10, -6));
|
|
||||||
|
|
||||||
// set timestep for simulation to 1 second
|
|
||||||
diffu.setTimestep(1.);
|
|
||||||
|
|
||||||
cout << setprecision(12);
|
|
||||||
|
|
||||||
// loop 100 times
|
|
||||||
// output is currently generated by the method itself
|
|
||||||
for (int i = 0; i < 100; i++) {
|
|
||||||
diffu.simulate(field.data(), alpha.data(), bc);
|
|
||||||
|
|
||||||
cout << "Iteration: " << i << "\n\n";
|
|
||||||
|
|
||||||
for (auto &cell : field) {
|
|
||||||
cout << cell << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "\n" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
#include "diffusion/BTCSBoundaryCondition.hpp"
|
|
||||||
#include <diffusion/BTCSDiffusion.hpp>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <iostream> // for std
|
|
||||||
#include <vector> // for vector
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
using namespace Diffusion;
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
|
|
||||||
// dimension of grid
|
|
||||||
int dim = 2;
|
|
||||||
|
|
||||||
int n = 5;
|
|
||||||
int m = 5;
|
|
||||||
|
|
||||||
// create input + diffusion coefficients for each grid cell
|
|
||||||
std::vector<double> alpha(n * m, 1e-6);
|
|
||||||
std::vector<double> field(n * m, 0);
|
|
||||||
BTCSBoundaryCondition bc(n, m);
|
|
||||||
|
|
||||||
// create instance of diffusion module
|
|
||||||
BTCSDiffusion diffu(dim);
|
|
||||||
|
|
||||||
diffu.setXDimensions(n, n);
|
|
||||||
diffu.setYDimensions(m, m);
|
|
||||||
|
|
||||||
// set inlet to higher concentration without setting bc
|
|
||||||
field[12] = 1;
|
|
||||||
|
|
||||||
// set timestep for simulation to 1 second
|
|
||||||
diffu.setTimestep(1);
|
|
||||||
|
|
||||||
cout << setprecision(12);
|
|
||||||
|
|
||||||
for (int t = 0; t < 1000; t++) {
|
|
||||||
diffu.simulate(field.data(), alpha.data(), bc);
|
|
||||||
|
|
||||||
cout << "Iteration: " << t << "\n\n";
|
|
||||||
|
|
||||||
double sum = 0;
|
|
||||||
|
|
||||||
// iterate through rows
|
|
||||||
for (int i = 0; i < m; i++) {
|
|
||||||
// iterate through columns
|
|
||||||
for (int j = 0; j < n; j++) {
|
|
||||||
cout << left << std::setw(20) << field[i * n + j];
|
|
||||||
sum += field[i * n + j];
|
|
||||||
}
|
|
||||||
cout << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "sum: " << sum << "\n" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
#include "diffusion/BTCSBoundaryCondition.hpp"
|
|
||||||
#include <diffusion/BTCSDiffusion.hpp>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <iostream> // for std
|
|
||||||
#include <vector> // for vector
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
using namespace Diffusion;
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
|
|
||||||
// dimension of grid
|
|
||||||
int dim = 2;
|
|
||||||
|
|
||||||
int n = 5;
|
|
||||||
int m = 5;
|
|
||||||
|
|
||||||
// create input + diffusion coefficients for each grid cell
|
|
||||||
std::vector<double> alpha(n * m, 1e-1);
|
|
||||||
std::vector<double> field(n * m, 1e-6);
|
|
||||||
BTCSBoundaryCondition bc(n, m);
|
|
||||||
|
|
||||||
// create instance of diffusion module
|
|
||||||
BTCSDiffusion diffu(dim);
|
|
||||||
|
|
||||||
diffu.setXDimensions(1, n);
|
|
||||||
diffu.setYDimensions(1, m);
|
|
||||||
|
|
||||||
boundary_condition input = {Diffusion::BC_TYPE_CONSTANT, 5e-6};
|
|
||||||
|
|
||||||
bc.setSide(BC_SIDE_LEFT, input);
|
|
||||||
|
|
||||||
// for (int i = 1; i <= n; i++) {
|
|
||||||
// bc[(n + 2) * i] = {Diffusion::BC_CONSTANT, 5e-6};
|
|
||||||
// }
|
|
||||||
// set timestep for simulation to 1 second
|
|
||||||
diffu.setTimestep(1.);
|
|
||||||
|
|
||||||
cout << setprecision(12);
|
|
||||||
|
|
||||||
for (int t = 0; t < 10; t++) {
|
|
||||||
diffu.simulate(field.data(), alpha.data(), bc);
|
|
||||||
|
|
||||||
cout << "Iteration: " << t << "\n\n";
|
|
||||||
|
|
||||||
// iterate through rows
|
|
||||||
for (int i = 0; i < m; i++) {
|
|
||||||
// iterate through columns
|
|
||||||
for (int j = 0; j < n; j++) {
|
|
||||||
cout << left << std::setw(20) << field[i * n + j];
|
|
||||||
}
|
|
||||||
cout << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "\n" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
#include "diffusion/BTCSBoundaryCondition.hpp"
|
|
||||||
#include <diffusion/BTCSDiffusion.hpp>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <iostream> // for std
|
|
||||||
#include <vector> // for vector
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
using namespace Diffusion;
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
|
|
||||||
// dimension of grid
|
|
||||||
int dim = 2;
|
|
||||||
|
|
||||||
int n = 501;
|
|
||||||
int m = 501;
|
|
||||||
|
|
||||||
// create input + diffusion coefficients for each grid cell
|
|
||||||
std::vector<double> alpha(n * m, 1e-3);
|
|
||||||
std::vector<double> field(n * m, 0.);
|
|
||||||
BTCSBoundaryCondition bc(n, m);
|
|
||||||
|
|
||||||
field[125500] = 1;
|
|
||||||
|
|
||||||
// create instance of diffusion module
|
|
||||||
BTCSDiffusion diffu(dim);
|
|
||||||
|
|
||||||
diffu.setXDimensions(1., n);
|
|
||||||
diffu.setYDimensions(1., m);
|
|
||||||
|
|
||||||
// set the boundary condition for the left ghost cell to dirichlet
|
|
||||||
// diffu.setBoundaryCondition(250, 250, BTCSDiffusion::BC_CONSTANT, 1);
|
|
||||||
// for (int d=0; d<5;d++){
|
|
||||||
// diffu.setBoundaryCondition(d, 0, BC_CONSTANT, .1);
|
|
||||||
// }
|
|
||||||
// diffu.setBoundaryCondition(1, 1, BTCSDiffusion::BC_CONSTANT, .1);
|
|
||||||
// diffu.setBoundaryCondition(1, 1, BTCSDiffusion::BC_CONSTANT, .1);
|
|
||||||
|
|
||||||
// set timestep for simulation to 1 second
|
|
||||||
diffu.setTimestep(1.);
|
|
||||||
|
|
||||||
cout << setprecision(7);
|
|
||||||
|
|
||||||
// First we output the initial state
|
|
||||||
cout << 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < m * n; i++) {
|
|
||||||
cout << "," << field[i];
|
|
||||||
}
|
|
||||||
cout << endl;
|
|
||||||
|
|
||||||
// Now we simulate and output 8 steps à 1 sec
|
|
||||||
for (int t = 1; t < 6; t++) {
|
|
||||||
double time = diffu.simulate(field.data(), alpha.data(), bc);
|
|
||||||
|
|
||||||
cerr << "time elapsed: " << time << " seconds" << endl;
|
|
||||||
|
|
||||||
cout << t;
|
|
||||||
|
|
||||||
for (int i = 0; i < m * n; i++) {
|
|
||||||
cout << "," << field[i];
|
|
||||||
}
|
|
||||||
cout << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
#include "tug/Boundary.hpp"
|
|
||||||
#include <tug/Simulation.hpp>
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
int row = 20;
|
|
||||||
int col = 30;
|
|
||||||
|
|
||||||
// grid
|
|
||||||
Grid grid = Grid(row,col);
|
|
||||||
MatrixXd concentrations = MatrixXd::Constant(row,col,0);
|
|
||||||
concentrations(10,4) = 2000;
|
|
||||||
grid.setConcentrations(concentrations);
|
|
||||||
MatrixXd alphaX = MatrixXd::Constant(row,col,1);
|
|
||||||
for (int i = 0; i < row; i++) {
|
|
||||||
alphaX(i,0) = 0.05;
|
|
||||||
}
|
|
||||||
MatrixXd alphaY = MatrixXd::Constant(row,col,1);
|
|
||||||
grid.setAlpha(alphaX, alphaY);
|
|
||||||
|
|
||||||
// boundary
|
|
||||||
Boundary bc = Boundary(grid);
|
|
||||||
bc.setBoundarySideConstant(BC_SIDE_LEFT, 0);
|
|
||||||
bc.setBoundarySideConstant(BC_SIDE_RIGHT, 0);
|
|
||||||
bc.setBoundarySideConstant(BC_SIDE_TOP, 0);
|
|
||||||
bc.setBoundarySideConstant(BC_SIDE_BOTTOM, 0);
|
|
||||||
bc.setBoundaryElementClosed(BC_SIDE_LEFT, 3);
|
|
||||||
bc.setBoundaryElementClosed(BC_SIDE_LEFT, 4);
|
|
||||||
bc.setBoundaryElementClosed(BC_SIDE_LEFT, 5);
|
|
||||||
bc.setBoundaryElementConstant(BC_SIDE_BOTTOM, 17, 100);
|
|
||||||
|
|
||||||
// simulation
|
|
||||||
Simulation sim = Simulation(grid, bc, BTCS_APPROACH);
|
|
||||||
sim.setTimestep(0.1);
|
|
||||||
sim.setIterations(100);
|
|
||||||
sim.setOutputCSV(CSV_OUTPUT_XTREME);
|
|
||||||
|
|
||||||
sim.run();
|
|
||||||
}
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
#include <tug/Simulation.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
|
|
||||||
int n[4] = {10, 20, 50, 100};
|
|
||||||
int iterations[1] = {100};
|
|
||||||
int repetition = 10;
|
|
||||||
|
|
||||||
ofstream myfile;
|
|
||||||
myfile.open("btcs_time_measurement_openmp_10.csv");
|
|
||||||
|
|
||||||
for (int i = 0; i < size(n); i++){
|
|
||||||
cout << "Grid size: " << n[i] << " x " << n[i] << endl << endl;
|
|
||||||
myfile << "Grid size: " << n[i] << " x " << n[i] << endl;
|
|
||||||
for(int j = 0; j < size(iterations); j++){
|
|
||||||
cout << "Iterations: " << iterations[j] << endl;
|
|
||||||
for (int k = 0; k < repetition; k++){
|
|
||||||
cout << "Wiederholung: " << k << endl;
|
|
||||||
Grid grid = Grid(n[i], n[i]);
|
|
||||||
grid.setDomain(n[i], n[i]);
|
|
||||||
|
|
||||||
MatrixXd concentrations = MatrixXd::Constant(n[i], n[i], 0);
|
|
||||||
concentrations(5,5) = 1;
|
|
||||||
grid.setConcentrations(concentrations);
|
|
||||||
MatrixXd alpha = MatrixXd::Constant(n[i], n[i], 0.5);
|
|
||||||
|
|
||||||
Boundary bc = Boundary(grid);
|
|
||||||
|
|
||||||
Simulation sim = Simulation(grid, bc, BTCS_APPROACH);
|
|
||||||
|
|
||||||
|
|
||||||
sim.setTimestep(0.001);
|
|
||||||
sim.setIterations(iterations[j]);
|
|
||||||
sim.setOutputCSV(CSV_OUTPUT_OFF);
|
|
||||||
|
|
||||||
auto begin = std::chrono::high_resolution_clock::now();
|
|
||||||
sim.run();
|
|
||||||
auto end = std::chrono::high_resolution_clock::now();
|
|
||||||
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
|
|
||||||
myfile << milliseconds.count() << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << endl;
|
|
||||||
myfile << endl;
|
|
||||||
|
|
||||||
}
|
|
||||||
myfile.close();
|
|
||||||
}
|
|
||||||
@ -9,7 +9,7 @@ int main(int argc, char *argv[]) {
|
|||||||
int repetition = 10;
|
int repetition = 10;
|
||||||
|
|
||||||
ofstream myfile;
|
ofstream myfile;
|
||||||
myfile.open("time_measure_experiment_openmp_thread_6.csv");
|
myfile.open("time_measure_experiment_openmp_thread_1_EigenLU.csv");
|
||||||
|
|
||||||
for (int i = 0; i < size(n); i++){
|
for (int i = 0; i < size(n); i++){
|
||||||
cout << "Grid size: " << n[i] << " x " << n[i] << endl << endl;
|
cout << "Grid size: " << n[i] << " x " << n[i] << endl << endl;
|
||||||
@ -29,7 +29,8 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
Boundary bc = Boundary(grid);
|
Boundary bc = Boundary(grid);
|
||||||
|
|
||||||
Simulation sim = Simulation(grid, bc, FTCS_APPROACH);
|
Simulation sim = Simulation(grid, bc, BTCS_APPROACH);
|
||||||
|
sim.setSolver(EIGEN_LU_SOLVER);
|
||||||
|
|
||||||
|
|
||||||
sim.setTimestep(0.001);
|
sim.setTimestep(0.001);
|
||||||
|
|||||||
@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
// create a new grid
|
|
||||||
// dimension is implicitly determined by number of arguments
|
|
||||||
// grid = new Grid(m=10, n=10)
|
|
||||||
|
|
||||||
// array_x = array[]
|
|
||||||
// array_y = array[]
|
|
||||||
// grid.setAlpha_x(&array_x)
|
|
||||||
// grid.setAlpha_y(&array_y)
|
|
||||||
|
|
||||||
// float time
|
|
||||||
// grid.setTimestep(time)
|
|
||||||
|
|
||||||
// bc = new BoundaryCondition()
|
|
||||||
// grid.setBoundaryCondition(bc)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// create new simulation run
|
|
||||||
// int iterations
|
|
||||||
// bool csv = true
|
|
||||||
// bool explicit = true
|
|
||||||
// simulation = new Simulation(grid, iterations)
|
|
||||||
// simulation.setSolver(BTCS, Thomas)
|
|
||||||
// simulation.run()
|
|
||||||
@ -1,93 +0,0 @@
|
|||||||
#include "tug/BoundaryCondition.hpp"
|
|
||||||
#include <tug/Diffusion.hpp>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace tug::diffusion;
|
|
||||||
using namespace tug::bc;
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
|
|
||||||
int dim = 2;
|
|
||||||
int n = 20;
|
|
||||||
int m = 20;
|
|
||||||
|
|
||||||
vector<double> alpha(n * m, 1);
|
|
||||||
vector<double> field(n * m, 0);
|
|
||||||
field[0] = 2000;
|
|
||||||
// field[n * 19] = 2000;
|
|
||||||
// field[n * 19 + 19] = 2000;
|
|
||||||
|
|
||||||
// for (int i = 1; i<20; i++) {
|
|
||||||
// for (int j = 0; j<20; j++ ) {
|
|
||||||
// field[i] = 0;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// print field
|
|
||||||
cout << "Initial field:" << endl;
|
|
||||||
for (int i = 0; i<n; i++) {
|
|
||||||
for (int j = 0; j<m; j++) {
|
|
||||||
cout << field[n * i + j] << " ";
|
|
||||||
}
|
|
||||||
cout << endl;
|
|
||||||
}
|
|
||||||
cout << endl;
|
|
||||||
|
|
||||||
TugInput input_param;
|
|
||||||
input_param.setTimestep(0.1);
|
|
||||||
input_param.setGridCellN(n, m);
|
|
||||||
input_param.setDomainSize(n, m);
|
|
||||||
BoundaryCondition bc(n, m);
|
|
||||||
boundary_condition bc_constant;
|
|
||||||
bc_constant.type = BC_TYPE_CONSTANT;
|
|
||||||
bc_constant.value = 0;
|
|
||||||
bc.setSide(BC_SIDE_LEFT, bc_constant);
|
|
||||||
bc.setSide(BC_SIDE_RIGHT, bc_constant);
|
|
||||||
bc.setSide(BC_SIDE_BOTTOM, bc_constant);
|
|
||||||
// bc_constant.value = 2000;
|
|
||||||
bc.setSide(BC_SIDE_TOP, bc_constant);
|
|
||||||
input_param.setBoundaryCondition(bc);
|
|
||||||
|
|
||||||
// int iterations = 1000;
|
|
||||||
// for (int t = 0; t < iterations; t++) {
|
|
||||||
// double result = ADI_2D(input_param, &field[0], &alpha[0]);
|
|
||||||
|
|
||||||
// if (t % 100 == 0) {
|
|
||||||
// cout << "Iteration " << t << ":" << endl;
|
|
||||||
// for (int i = 0; i<n; i++) {
|
|
||||||
// for (int j = 0; j<m; j++) {
|
|
||||||
// cout << field[n * i + j] << " ";
|
|
||||||
// }
|
|
||||||
// cout << endl;
|
|
||||||
// }
|
|
||||||
// cout << endl;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
ofstream myfile;
|
|
||||||
myfile.open("output.csv");
|
|
||||||
if (!myfile) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int iterations = 100;
|
|
||||||
for (int t = 0; t < iterations; t++) {
|
|
||||||
double result = ADI_2D(input_param, &field[0], &alpha[0]);
|
|
||||||
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
for (int j = 0; j < m; j++) {
|
|
||||||
myfile << field[i * m + j];
|
|
||||||
if (j < m-1) {
|
|
||||||
myfile << ", ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
myfile << "\n";
|
|
||||||
}
|
|
||||||
myfile << std::endl << std::endl;
|
|
||||||
}
|
|
||||||
myfile.close();
|
|
||||||
}
|
|
||||||
@ -1,283 +0,0 @@
|
|||||||
#ifndef BOUNDARYCONDITION_H_
|
|
||||||
#define BOUNDARYCONDITION_H_
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <map>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
typedef uint8_t bctype;
|
|
||||||
|
|
||||||
namespace tug {
|
|
||||||
namespace bc {
|
|
||||||
|
|
||||||
enum {
|
|
||||||
// flux = Neumann? Cauchy combination of Neumann and Dirichlet?
|
|
||||||
BC_TYPE_CLOSED, /**< Defines a closed boundary condition (special case of Neumann condition). */
|
|
||||||
BC_TYPE_FLUX, /**< Defines a flux/Cauchy boundary condition. */
|
|
||||||
BC_TYPE_CONSTANT, /**< Defines a constant/Dirichlet boundary condition. */
|
|
||||||
BC_UNSET /**< Indicates undefined boundary condition*/
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
BC_SIDE_LEFT, /**< Defines boundary conditions for the left side of the grid.
|
|
||||||
*/
|
|
||||||
BC_SIDE_RIGHT, /**< Defines boundary conditions for the right side of the
|
|
||||||
grid. */
|
|
||||||
BC_SIDE_TOP, /**< Defines boundary conditions for the top of the grid. */
|
|
||||||
BC_SIDE_BOTTOM, /**< Defines boundary conditions for the bottom of the grid.
|
|
||||||
*/
|
|
||||||
BC_INNER
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines the boundary condition type and according value.
|
|
||||||
* QUESTION: For what is the struct bc necessary?
|
|
||||||
*/
|
|
||||||
typedef struct boundary_condition_s {
|
|
||||||
bctype type; /**< Type of the boundary condition */
|
|
||||||
double value; /**< Value of the boundary condition. Either a concrete value of
|
|
||||||
concentration for BC_TYPE_CONSTANT or gradient when type is
|
|
||||||
BC_TYPE_FLUX. Unused if BC_TYPE_CLOSED.*/
|
|
||||||
} boundary_condition;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents both boundary conditions of a row/column.
|
|
||||||
*/
|
|
||||||
typedef std::array<boundary_condition, 2> bc_tuple;
|
|
||||||
typedef std::vector<boundary_condition> bc_vec;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to define the boundary condition of a grid.
|
|
||||||
*/
|
|
||||||
class BoundaryCondition {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Creates a new instance with two elements. Used when defining boundary
|
|
||||||
* conditions of 1D grids.
|
|
||||||
*
|
|
||||||
* \param x Number of grid cells in x-direction
|
|
||||||
*/
|
|
||||||
BoundaryCondition(int x);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance with 4 * max(x,y) elements. Used to describe the
|
|
||||||
* boundary conditions for 2D grids. NOTE: On non-squared grids there are more
|
|
||||||
* elements than needed and no exception is thrown if some index exceeding
|
|
||||||
* grid limits.
|
|
||||||
*
|
|
||||||
* QUESTION: why not use non-squared grids with the correct size?
|
|
||||||
*
|
|
||||||
* \param x Number of grid cells in x-direction
|
|
||||||
* \param y Number of grid cells in y-direction
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
BoundaryCondition(int x, int y);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the boundary condition for a specific side of the grid.
|
|
||||||
*
|
|
||||||
* \param side Side for which the given boundary condition should be set.
|
|
||||||
* \param input_bc Instance of struct boundary_condition with desired boundary
|
|
||||||
* condition.
|
|
||||||
*
|
|
||||||
* \throws std::invalid_argument Indicates wrong dimensions of the grid.
|
|
||||||
* \throws std::out_of_range Indicates a out of range value for side.
|
|
||||||
*/
|
|
||||||
void setSide(uint8_t side, boundary_condition &input_bc);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the boundary condition for a specific side of the grid.
|
|
||||||
*
|
|
||||||
* \param side Side for which the given boundary condition should be set.
|
|
||||||
* \param input_bc Vector of boundary conditions for specific side.
|
|
||||||
*
|
|
||||||
* \throws std::invalid_argument Indicates wrong dimensions of the grid.
|
|
||||||
* \throws std::out_of_range Indicates a out of range value for side or
|
|
||||||
* invalid size of input vector.
|
|
||||||
*/
|
|
||||||
void setSide(uint8_t side, std::vector<boundary_condition> &input_bc);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a vector of boundary conditions of given side. Can be used to set
|
|
||||||
* custom boundary conditions and set back via setSide() with vector input.
|
|
||||||
*
|
|
||||||
* \param side Side which boundary conditions should be returned
|
|
||||||
*
|
|
||||||
* \returns Vector of boundary conditions
|
|
||||||
*
|
|
||||||
* \throws std::invalid_argument If given dimension is less or equal to 1.
|
|
||||||
* \throws std::out_of_range Indicates a out of range value for side.
|
|
||||||
*/
|
|
||||||
auto getSide(uint8_t side) -> std::vector<boundary_condition>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get both boundary conditions of a given row (left and right).
|
|
||||||
*
|
|
||||||
* \param i Index of row
|
|
||||||
*
|
|
||||||
* \returns Left and right boundary values as an array (defined as data
|
|
||||||
* type bc_tuple).
|
|
||||||
*/
|
|
||||||
auto row_boundary(uint32_t i) const -> bc_tuple;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get both boundary conditions of a given column (top and bottom).
|
|
||||||
*
|
|
||||||
* \param i Index of column
|
|
||||||
*
|
|
||||||
* \returns Top and bottom boundary values as an array (defined as data
|
|
||||||
* type bc_tuple).
|
|
||||||
*/
|
|
||||||
auto col_boundary(uint32_t i) const -> bc_tuple;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets one cell of the inner grid to a given boundary condition.
|
|
||||||
*
|
|
||||||
* \param bc Boundary condition to be set.
|
|
||||||
* \param x Index of grid cell in x direction.
|
|
||||||
* \param y Index of grid cell in y direction.
|
|
||||||
*/
|
|
||||||
void setInnerBC(boundary_condition bc, int x, int y);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unsets a previously set inner boundary condition.
|
|
||||||
*
|
|
||||||
* \param x Index of grid cell in x direction.
|
|
||||||
* \param y Index of grid cell in y direction.
|
|
||||||
*/
|
|
||||||
void unsetInnerBC(int x, int y);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current boundary condition set for specific inner grid cell.
|
|
||||||
*
|
|
||||||
* \param x Index of grid cell in x direction.
|
|
||||||
* \param y Index of grid cell in y direction.
|
|
||||||
*/
|
|
||||||
auto getInnerBC(int x, int y) -> boundary_condition;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a row of field and its inner boundary conditions.
|
|
||||||
*
|
|
||||||
* \param i Index of the row starting at 0.
|
|
||||||
*
|
|
||||||
* \returns Row of the inner boundary conditions of the field.
|
|
||||||
*/
|
|
||||||
auto getInnerRow(uint32_t i) const -> bc_vec;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a column of field and its inner boundary conditions.
|
|
||||||
*
|
|
||||||
* \param i Index of the column starting at 0.
|
|
||||||
*
|
|
||||||
* \returns Column of the inner boundary conditions of the field.
|
|
||||||
*/
|
|
||||||
auto getInnerCol(uint32_t i) const -> bc_vec;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an instance of boundary_condition data type. Can be seen as a helper
|
|
||||||
* function.
|
|
||||||
*
|
|
||||||
* \param type Type of the boundary condition.
|
|
||||||
* \param value According value of condition.
|
|
||||||
*
|
|
||||||
* \returns Instance of boundary_condition
|
|
||||||
*/
|
|
||||||
static boundary_condition returnBoundaryCondition(bctype type, double value) {
|
|
||||||
return {type, value};
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<boundary_condition> bc_internal;
|
|
||||||
|
|
||||||
std::map<uint32_t, boundary_condition> inner_cells;
|
|
||||||
|
|
||||||
uint8_t dim;
|
|
||||||
|
|
||||||
std::array<uint32_t, 2> sizes;
|
|
||||||
uint32_t maxsize;
|
|
||||||
uint32_t maxindex;
|
|
||||||
|
|
||||||
enum { X_DIM, Y_DIM };
|
|
||||||
|
|
||||||
// TODO combine the 'public' blocks
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Returns the left/right boundary condition for 1D grid.
|
|
||||||
*
|
|
||||||
* \param side Side of the boundary condition to get.
|
|
||||||
*
|
|
||||||
* \returns Boundary condition
|
|
||||||
*/
|
|
||||||
boundary_condition operator()(uint8_t side) const {
|
|
||||||
if (dim != 1) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Only 1D grid support 1 parameter in operator");
|
|
||||||
}
|
|
||||||
if (side > 1) {
|
|
||||||
throw std::out_of_range("1D index out of range");
|
|
||||||
}
|
|
||||||
return bc_internal[side];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the boundary condition of a given side for 2D grids.
|
|
||||||
*
|
|
||||||
* \param side Side of the boundary condition to get.
|
|
||||||
* \param i Index of the boundary condition.
|
|
||||||
*
|
|
||||||
* \returns Boundary condition
|
|
||||||
*/
|
|
||||||
boundary_condition operator()(uint8_t side, uint32_t i) const {
|
|
||||||
if (dim != 2) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Only 2D grids support 2 parameters in operator");
|
|
||||||
}
|
|
||||||
if (side > 3) {
|
|
||||||
throw std::out_of_range("2D index out of range");
|
|
||||||
}
|
|
||||||
return bc_internal[side * maxsize + i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the left/right boundary condition for 1D grid.
|
|
||||||
*
|
|
||||||
* \param side Side of the boundary condition to get.
|
|
||||||
*
|
|
||||||
* \returns Boundary condition
|
|
||||||
*/
|
|
||||||
boundary_condition &operator()(uint8_t side) {
|
|
||||||
if (dim != 1) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Only 1D grid support 1 parameter in operator");
|
|
||||||
}
|
|
||||||
if (side > 1) {
|
|
||||||
throw std::out_of_range("1D index out of range");
|
|
||||||
}
|
|
||||||
return bc_internal[side];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the boundary condition of a given side for 2D grids.
|
|
||||||
*
|
|
||||||
* \param side Side of the boundary condition to get.
|
|
||||||
* \param i Index of the boundary condition.
|
|
||||||
*
|
|
||||||
* \returns Boundary condition
|
|
||||||
*/
|
|
||||||
boundary_condition &operator()(uint8_t side, uint32_t i) {
|
|
||||||
if (dim != 2) {
|
|
||||||
throw std::invalid_argument("Explicit setting of bc value with 2 "
|
|
||||||
"parameters is only supported for 2D grids");
|
|
||||||
}
|
|
||||||
if (side > 3) {
|
|
||||||
throw std::out_of_range("2D index out of range");
|
|
||||||
}
|
|
||||||
return bc_internal[side * maxsize + i];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace bc
|
|
||||||
} // namespace tug
|
|
||||||
#endif // BOUNDARYCONDITION_H_
|
|
||||||
@ -1,140 +0,0 @@
|
|||||||
#ifndef DIFFUSION_H_
|
|
||||||
#define DIFFUSION_H_
|
|
||||||
|
|
||||||
#include "BoundaryCondition.hpp"
|
|
||||||
#include "Solver.hpp"
|
|
||||||
#include <Eigen/Dense>
|
|
||||||
#include <Eigen/Sparse>
|
|
||||||
#include <array>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace tug {
|
|
||||||
namespace diffusion {
|
|
||||||
|
|
||||||
constexpr uint8_t MAX_ARR_SIZE = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines grid dimensions and boundary conditions.
|
|
||||||
* QUESTION: why is TugGrid a separate struct? For conceptual reasons?
|
|
||||||
* why not combine TugGrid and TugInput?
|
|
||||||
*/
|
|
||||||
typedef struct tug_grid_s {
|
|
||||||
std::array<uint32_t, MAX_ARR_SIZE>
|
|
||||||
grid_cells; /**< Count of grid cells in each of the 3 directions.*/
|
|
||||||
std::array<double, MAX_ARR_SIZE>
|
|
||||||
domain_size; /**< Domain sizes in each of the 3 directions.*/
|
|
||||||
bc::BoundaryCondition *bc = NULL; /**< Boundary conditions for the grid.*/
|
|
||||||
} TugGrid;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Besides containing the grid structure it holds also information about the
|
|
||||||
* desired time step to simulate and which solver to use.
|
|
||||||
*/
|
|
||||||
typedef struct tug_input_s {
|
|
||||||
double time_step; /**< Time step which should be simulated by diffusion.*/
|
|
||||||
Eigen::VectorXd (*solver)(const Eigen::SparseMatrix<double> &,
|
|
||||||
const Eigen::VectorXd &) =
|
|
||||||
tug::solver::ThomasAlgorithm; /**< Solver function to use.*/
|
|
||||||
TugGrid grid; /**< Grid specification.*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the desired time step for diffusion simulation.
|
|
||||||
*
|
|
||||||
* \param dt Time step in seconds.
|
|
||||||
*/
|
|
||||||
void setTimestep(double dt) { time_step = dt; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the count of grid cells in each dimension.
|
|
||||||
*
|
|
||||||
* \param x Count of grid cells in x direction.
|
|
||||||
* \param y Count of grid cells in y direction.
|
|
||||||
* \param z Count of grid cells in z direction.
|
|
||||||
*/
|
|
||||||
void setGridCellN(uint32_t x, uint32_t y = 0, uint32_t z = 0) {
|
|
||||||
grid.grid_cells[0] = x;
|
|
||||||
grid.grid_cells[1] = y;
|
|
||||||
grid.grid_cells[2] = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the domain size of the grid in each direction.
|
|
||||||
|
|
||||||
* \param Domain size in x direction.
|
|
||||||
* \param Domain size in y direction.
|
|
||||||
* \param Domain size in z direction.
|
|
||||||
*/
|
|
||||||
void setDomainSize(double x, double y = 0, double z = 0) {
|
|
||||||
grid.domain_size[0] = x;
|
|
||||||
grid.domain_size[1] = y;
|
|
||||||
grid.domain_size[2] = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set boundary conditions for grid instance.
|
|
||||||
*
|
|
||||||
* \param bc Boundary conditions to be set.
|
|
||||||
*/
|
|
||||||
void setBoundaryCondition(bc::BoundaryCondition &bc) { grid.bc = &bc; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the set boundary condition from grid instance.
|
|
||||||
*
|
|
||||||
* \return Boundary condition object if boundary conditions were set,
|
|
||||||
* otherwise NULL.
|
|
||||||
*/
|
|
||||||
auto getBoundaryCondition() -> bc::BoundaryCondition { return *(grid.bc); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the solver function.
|
|
||||||
*
|
|
||||||
* \param f_in Pointer to function which takes a sparse matrix and a vector as
|
|
||||||
* input and returns another vector.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
setSolverFunction(Eigen::VectorXd (*f_in)(const Eigen::SparseMatrix<double> &,
|
|
||||||
const Eigen::VectorXd &)) {
|
|
||||||
solver = f_in;
|
|
||||||
}
|
|
||||||
} TugInput;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Solving 1D diffusion problems with Backward Time Centred Space scheme.
|
|
||||||
*
|
|
||||||
* \param input_param Object with information for the simulation e.g. grid
|
|
||||||
* dimensions, time step ...
|
|
||||||
*
|
|
||||||
* \param field Pointer to continious memory holding the concentrations for each
|
|
||||||
* grid cell of the grid. It doesn't matter if stored in row (most likely) or
|
|
||||||
* column major.
|
|
||||||
*
|
|
||||||
* \param alpha Pointer to continious memory holding the alpha for each grid
|
|
||||||
* cell of the grid. (NOTE: only constant alphas are supported currently)
|
|
||||||
*
|
|
||||||
* \return Runtime in seconds
|
|
||||||
*/
|
|
||||||
auto BTCS_1D(const TugInput &input_param, double *field, const double *alpha)
|
|
||||||
-> double;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Solving 2D diffusion problems with Alternating-direction implicit method.
|
|
||||||
*
|
|
||||||
* \param input_param Object with information for the simulation e.g. grid
|
|
||||||
* dimensions, time step ...
|
|
||||||
*
|
|
||||||
* \param field Pointer to continious memory holding the concentrations for each
|
|
||||||
* grid cell of the grid. It doesn't matter if stored in row (most likely) or
|
|
||||||
* column major.
|
|
||||||
*
|
|
||||||
* \param alpha Pointer to continious memory holding the alpha for each grid
|
|
||||||
* cell of the grid. (NOTE: only constant alphas are supported currently)
|
|
||||||
*
|
|
||||||
* \return Runtime in seconds
|
|
||||||
*/
|
|
||||||
auto ADI_2D(const TugInput &input_param, double *field, const double *alpha)
|
|
||||||
-> double;
|
|
||||||
|
|
||||||
} // namespace diffusion
|
|
||||||
} // namespace tug
|
|
||||||
|
|
||||||
#endif // DIFFUSION_H_
|
|
||||||
@ -16,7 +16,16 @@ using namespace std;
|
|||||||
*/
|
*/
|
||||||
enum APPROACH {
|
enum APPROACH {
|
||||||
FTCS_APPROACH, // Forward Time-Centered Space
|
FTCS_APPROACH, // Forward Time-Centered Space
|
||||||
BTCS_APPROACH // Backward Time-Centered Space
|
BTCS_APPROACH, // Backward Time-Centered Space solved with EigenLU solver
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enum defining the Linear Equation solvers
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
enum SOLVER {
|
||||||
|
EIGEN_LU_SOLVER, // EigenLU solver
|
||||||
|
THOMAS_ALGORITHM_SOLVER // Thomas Algorithm solver; more efficient for tridiagonal matrices
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -124,6 +133,15 @@ class Simulation {
|
|||||||
*/
|
*/
|
||||||
void setIterations(int iterations);
|
void setIterations(int iterations);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the desired linear equation solver to be used for BTCS approach. Without effect
|
||||||
|
* in case of FTCS approach.
|
||||||
|
*
|
||||||
|
* @param solver Solver to be used. Default is Thomas Algorithm as it is more efficient for
|
||||||
|
* tridiagonal Matrices.
|
||||||
|
*/
|
||||||
|
void setSolver(SOLVER solver);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the currently set iterations to be calculated.
|
* @brief Return the currently set iterations to be calculated.
|
||||||
*
|
*
|
||||||
@ -174,5 +192,6 @@ class Simulation {
|
|||||||
Grid &grid;
|
Grid &grid;
|
||||||
Boundary &bc;
|
Boundary &bc;
|
||||||
APPROACH approach;
|
APPROACH approach;
|
||||||
|
SOLVER solver;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,41 +0,0 @@
|
|||||||
#ifndef SOLVER_H_
|
|
||||||
#define SOLVER_H_
|
|
||||||
|
|
||||||
#include <Eigen/Dense>
|
|
||||||
#include <Eigen/Sparse>
|
|
||||||
|
|
||||||
namespace tug {
|
|
||||||
namespace solver {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Solving linear equation system with LU-decomposition implemented in Eigen
|
|
||||||
* library.
|
|
||||||
*
|
|
||||||
* \param A_matrix The A matrix represented as a sparse matrix using Eigen
|
|
||||||
* library.
|
|
||||||
*
|
|
||||||
* \param b_vector Right hand side vector of the linear equation system.
|
|
||||||
*
|
|
||||||
* \return Solution represented as vector.
|
|
||||||
*/
|
|
||||||
auto EigenLU(const Eigen::SparseMatrix<double> &A_matrix,
|
|
||||||
const Eigen::VectorXd &b_vector) -> Eigen::VectorXd;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Solving linear equation system with brutal implementation of the Thomas
|
|
||||||
* algorithm (a.k.a. Tridiagonal matrix algorithm).
|
|
||||||
*
|
|
||||||
* \param A_matrix The A matrix represented as a sparse matrix using Eigen
|
|
||||||
* library.
|
|
||||||
*
|
|
||||||
* \param b_vector Right hand side vector of the linear equation system.
|
|
||||||
*
|
|
||||||
* \return Solution represented as vector.
|
|
||||||
*/
|
|
||||||
auto ThomasAlgorithm(const Eigen::SparseMatrix<double> &A_matrix,
|
|
||||||
const Eigen::VectorXd &b_vector) -> Eigen::VectorXd;
|
|
||||||
|
|
||||||
} // namespace solver
|
|
||||||
} // namespace tug
|
|
||||||
|
|
||||||
#endif // SOLVER_H_
|
|
||||||
@ -1,191 +0,0 @@
|
|||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2019 Luigi Pertoldi
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to
|
|
||||||
// deal in the Software without restriction, including without limitation the
|
|
||||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
// sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
||||||
// IN THE SOFTWARE.
|
|
||||||
//
|
|
||||||
// ============================================================================
|
|
||||||
// ___ ___ ___ __ ___ ____ __ __ ___ __ ___
|
|
||||||
// | |_) | |_) / / \ / /`_ | |_) | |_ ( (` ( (` | |_) / /\ | |_)
|
|
||||||
// |_| |_| \ \_\_/ \_\_/ |_| \ |_|__ _)_) _)_) |_|_) /_/--\ |_| \_
|
|
||||||
//
|
|
||||||
// Very simple progress bar for c++ loops with internal running variable
|
|
||||||
//
|
|
||||||
// Author: Luigi Pertoldi
|
|
||||||
// Created: 3 dic 2016
|
|
||||||
//
|
|
||||||
// Notes: The bar must be used when there's no other possible source of output
|
|
||||||
// inside the for loop
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef __PROGRESSBAR_HPP
|
|
||||||
#define __PROGRESSBAR_HPP
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <ostream>
|
|
||||||
#include <string>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
class progressbar {
|
|
||||||
|
|
||||||
public:
|
|
||||||
// default destructor
|
|
||||||
~progressbar() = default;
|
|
||||||
|
|
||||||
// delete everything else
|
|
||||||
progressbar (progressbar const&) = delete;
|
|
||||||
progressbar& operator=(progressbar const&) = delete;
|
|
||||||
progressbar (progressbar&&) = delete;
|
|
||||||
progressbar& operator=(progressbar&&) = delete;
|
|
||||||
|
|
||||||
// default constructor, must call set_niter later
|
|
||||||
inline progressbar();
|
|
||||||
inline progressbar(int n, bool showbar=true, std::ostream& out=std::cerr);
|
|
||||||
|
|
||||||
// reset bar to use it again
|
|
||||||
inline void reset();
|
|
||||||
// set number of loop iterations
|
|
||||||
inline void set_niter(int iter);
|
|
||||||
// chose your style
|
|
||||||
inline void set_done_char(const std::string& sym) {done_char = sym;}
|
|
||||||
inline void set_todo_char(const std::string& sym) {todo_char = sym;}
|
|
||||||
inline void set_opening_bracket_char(const std::string& sym) {opening_bracket_char = sym;}
|
|
||||||
inline void set_closing_bracket_char(const std::string& sym) {closing_bracket_char = sym;}
|
|
||||||
// to show only the percentage
|
|
||||||
inline void show_bar(bool flag = true) {do_show_bar = flag;}
|
|
||||||
// set the output stream
|
|
||||||
inline void set_output_stream(const std::ostream& stream) {output.rdbuf(stream.rdbuf());}
|
|
||||||
// main function
|
|
||||||
inline void update();
|
|
||||||
|
|
||||||
private:
|
|
||||||
int progress;
|
|
||||||
int n_cycles;
|
|
||||||
int last_perc;
|
|
||||||
bool do_show_bar;
|
|
||||||
bool update_is_called;
|
|
||||||
|
|
||||||
std::string done_char;
|
|
||||||
std::string todo_char;
|
|
||||||
std::string opening_bracket_char;
|
|
||||||
std::string closing_bracket_char;
|
|
||||||
|
|
||||||
std::ostream& output;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline progressbar::progressbar() :
|
|
||||||
progress(0),
|
|
||||||
n_cycles(0),
|
|
||||||
last_perc(0),
|
|
||||||
do_show_bar(true),
|
|
||||||
update_is_called(false),
|
|
||||||
done_char("#"),
|
|
||||||
todo_char(" "),
|
|
||||||
opening_bracket_char("["),
|
|
||||||
closing_bracket_char("]"),
|
|
||||||
output(std::cerr) {}
|
|
||||||
|
|
||||||
inline progressbar::progressbar(int n, bool showbar, std::ostream& out) :
|
|
||||||
progress(0),
|
|
||||||
n_cycles(n),
|
|
||||||
last_perc(0),
|
|
||||||
do_show_bar(showbar),
|
|
||||||
update_is_called(false),
|
|
||||||
done_char("#"),
|
|
||||||
todo_char(" "),
|
|
||||||
opening_bracket_char("["),
|
|
||||||
closing_bracket_char("]"),
|
|
||||||
output(out) {}
|
|
||||||
|
|
||||||
inline void progressbar::reset() {
|
|
||||||
progress = 0,
|
|
||||||
update_is_called = false;
|
|
||||||
last_perc = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void progressbar::set_niter(int niter) {
|
|
||||||
if (niter <= 0) throw std::invalid_argument(
|
|
||||||
"progressbar::set_niter: number of iterations null or negative");
|
|
||||||
n_cycles = niter;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void progressbar::update() {
|
|
||||||
|
|
||||||
if (n_cycles == 0) throw std::runtime_error(
|
|
||||||
"progressbar::update: number of cycles not set");
|
|
||||||
|
|
||||||
if (!update_is_called) {
|
|
||||||
if (do_show_bar == true) {
|
|
||||||
output << opening_bracket_char;
|
|
||||||
for (int _ = 0; _ < 50; _++) output << todo_char;
|
|
||||||
output << closing_bracket_char << " 0%";
|
|
||||||
}
|
|
||||||
else output << "0%";
|
|
||||||
}
|
|
||||||
update_is_called = true;
|
|
||||||
|
|
||||||
int perc = 0;
|
|
||||||
|
|
||||||
// compute percentage, if did not change, do nothing and return
|
|
||||||
perc = progress*100./(n_cycles-1);
|
|
||||||
if (perc < last_perc) return;
|
|
||||||
|
|
||||||
// update percentage each unit
|
|
||||||
if (perc == last_perc + 1) {
|
|
||||||
// erase the correct number of characters
|
|
||||||
if (perc <= 10) output << "\b\b" << perc << '%';
|
|
||||||
else if (perc > 10 and perc < 100) output << "\b\b\b" << perc << '%';
|
|
||||||
else if (perc == 100) output << "\b\b\b" << perc << '%';
|
|
||||||
}
|
|
||||||
if (do_show_bar == true) {
|
|
||||||
// update bar every ten units
|
|
||||||
if (perc % 2 == 0) {
|
|
||||||
// erase closing bracket
|
|
||||||
output << std::string(closing_bracket_char.size(), '\b');
|
|
||||||
// erase trailing percentage characters
|
|
||||||
if (perc < 10) output << "\b\b\b";
|
|
||||||
else if (perc >= 10 && perc < 100) output << "\b\b\b\b";
|
|
||||||
else if (perc == 100) output << "\b\b\b\b\b";
|
|
||||||
|
|
||||||
// erase 'todo_char'
|
|
||||||
for (int j = 0; j < 50-(perc-1)/2; ++j) {
|
|
||||||
output << std::string(todo_char.size(), '\b');
|
|
||||||
}
|
|
||||||
|
|
||||||
// add one additional 'done_char'
|
|
||||||
if (perc == 0) output << todo_char;
|
|
||||||
else output << done_char;
|
|
||||||
|
|
||||||
// refill with 'todo_char'
|
|
||||||
for (int j = 0; j < 50-(perc-1)/2-1; ++j) output << todo_char;
|
|
||||||
|
|
||||||
// readd trailing percentage characters
|
|
||||||
output << closing_bracket_char << ' ' << perc << '%';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last_perc = perc;
|
|
||||||
++progress;
|
|
||||||
output << std::flush;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
328
src/BTCS.cpp
328
src/BTCS.cpp
@ -1,328 +0,0 @@
|
|||||||
#include <array>
|
|
||||||
#include <iostream>
|
|
||||||
#include <tug/BoundaryCondition.hpp>
|
|
||||||
#include <tug/Diffusion.hpp>
|
|
||||||
#include <tug/Solver.hpp>
|
|
||||||
|
|
||||||
#include <Eigen/Dense>
|
|
||||||
#include <Eigen/Sparse>
|
|
||||||
#include <Eigen/src/Core/Matrix.h>
|
|
||||||
#include <chrono>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "TugUtils.hpp"
|
|
||||||
|
|
||||||
#ifdef _OPENMP
|
|
||||||
#include <omp.h>
|
|
||||||
#else
|
|
||||||
#define omp_get_thread_num() 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inline auto
|
|
||||||
init_delta(const std::array<double, tug::diffusion::MAX_ARR_SIZE> &domain_size,
|
|
||||||
const std::array<uint32_t, tug::diffusion::MAX_ARR_SIZE> &grid_cells,
|
|
||||||
const uint8_t dim) -> std::vector<double> {
|
|
||||||
std::vector<double> out(dim);
|
|
||||||
for (uint8_t i = 0; i < dim; i++) {
|
|
||||||
// calculate 'size' of each cell in grid
|
|
||||||
out[i] = (double)(domain_size.at(i) / grid_cells.at(i));
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
enum { GRID_1D = 1, GRID_2D, GRID_3D };
|
|
||||||
|
|
||||||
constexpr int BTCS_MAX_DEP_PER_CELL = 3;
|
|
||||||
constexpr int BTCS_2D_DT_SIZE = 2;
|
|
||||||
|
|
||||||
using DMatrixRowMajor =
|
|
||||||
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
|
|
||||||
using DVectorRowMajor =
|
|
||||||
Eigen::Matrix<double, 1, Eigen::Dynamic, Eigen::RowMajor>;
|
|
||||||
|
|
||||||
inline auto getBCFromFlux(tug::bc::boundary_condition bc, double neighbor_c,
|
|
||||||
double neighbor_alpha) -> double {
|
|
||||||
double val = 0;
|
|
||||||
|
|
||||||
if (bc.type == tug::bc::BC_TYPE_CLOSED) {
|
|
||||||
val = neighbor_c;
|
|
||||||
} else if (bc.type == tug::bc::BC_TYPE_FLUX) {
|
|
||||||
// TODO
|
|
||||||
// val = bc[index].value;
|
|
||||||
} else {
|
|
||||||
// TODO: implement error handling here. Type was set to wrong value.
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto calc_d_ortho(const DMatrixRowMajor &c, const DMatrixRowMajor &alpha,
|
|
||||||
const tug::bc::BoundaryCondition &bc, bool transposed,
|
|
||||||
double time_step, double dx) -> DMatrixRowMajor {
|
|
||||||
|
|
||||||
uint8_t upper = (transposed ? tug::bc::BC_SIDE_LEFT : tug::bc::BC_SIDE_TOP);
|
|
||||||
uint8_t lower =
|
|
||||||
(transposed ? tug::bc::BC_SIDE_RIGHT : tug::bc::BC_SIDE_BOTTOM);
|
|
||||||
|
|
||||||
int n_rows = c.rows();
|
|
||||||
int n_cols = c.cols();
|
|
||||||
|
|
||||||
DMatrixRowMajor d_ortho(n_rows, n_cols);
|
|
||||||
|
|
||||||
std::array<double, 3> y_values{};
|
|
||||||
|
|
||||||
// first, iterate over first row
|
|
||||||
for (int j = 0; j < n_cols; j++) {
|
|
||||||
tug::bc::boundary_condition tmp_bc = bc(upper, j);
|
|
||||||
double sy = (time_step * alpha(0, j)) / (dx * dx);
|
|
||||||
|
|
||||||
y_values[0] = (tmp_bc.type == tug::bc::BC_TYPE_CONSTANT
|
|
||||||
? tmp_bc.value
|
|
||||||
: getBCFromFlux(tmp_bc, c(0, j), alpha(0, j)));
|
|
||||||
y_values[1] = c(0, j);
|
|
||||||
y_values[2] = c(1, j);
|
|
||||||
|
|
||||||
d_ortho(0, j) = -sy * (2 * y_values[0] - 3 * y_values[1] + y_values[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// then iterate over inlet
|
|
||||||
for (int i = 1; i < n_rows - 1; i++) {
|
|
||||||
for (int j = 0; j < n_cols; j++) {
|
|
||||||
double sy = (time_step * alpha(i, j)) / (dx * dx);
|
|
||||||
|
|
||||||
y_values[0] = c(i - 1, j);
|
|
||||||
y_values[1] = c(i, j);
|
|
||||||
y_values[2] = c(i + 1, j);
|
|
||||||
|
|
||||||
d_ortho(i, j) = -sy * (y_values[0] - 2 * y_values[1] + y_values[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int end = n_rows - 1;
|
|
||||||
|
|
||||||
// and finally over last row
|
|
||||||
for (int j = 0; j < n_cols; j++) {
|
|
||||||
tug::bc::boundary_condition tmp_bc = bc(lower, j);
|
|
||||||
double sy = (time_step * alpha(end, j)) / (dx * dx);
|
|
||||||
|
|
||||||
y_values[0] = c(end - 1, j);
|
|
||||||
y_values[1] = c(end, j);
|
|
||||||
y_values[2] = (tmp_bc.type == tug::bc::BC_TYPE_CONSTANT
|
|
||||||
? tmp_bc.value
|
|
||||||
: getBCFromFlux(tmp_bc, c(end, j), alpha(end, j)));
|
|
||||||
|
|
||||||
d_ortho(end, j) = -sy * (y_values[0] - 3 * y_values[1] + 2 * y_values[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return d_ortho;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto fillMatrixFromRow(const DVectorRowMajor &alpha,
|
|
||||||
const tug::bc::bc_vec &bc_inner, int size, double dx,
|
|
||||||
double time_step) -> Eigen::SparseMatrix<double> {
|
|
||||||
|
|
||||||
Eigen::SparseMatrix<double> A_matrix(size + 2, size + 2);
|
|
||||||
|
|
||||||
A_matrix.reserve(Eigen::VectorXi::Constant(size + 2, BTCS_MAX_DEP_PER_CELL));
|
|
||||||
|
|
||||||
double sx = 0;
|
|
||||||
|
|
||||||
int A_size = A_matrix.cols();
|
|
||||||
|
|
||||||
A_matrix.insert(0, 0) = 1;
|
|
||||||
|
|
||||||
if (bc_inner[0].type != tug::bc::BC_UNSET) {
|
|
||||||
if (bc_inner[0].type != tug::bc::BC_TYPE_CONSTANT) {
|
|
||||||
throw_invalid_argument("Inner boundary conditions with other type than "
|
|
||||||
"BC_TYPE_CONSTANT are currently not supported.");
|
|
||||||
}
|
|
||||||
A_matrix.insert(1, 1) = 1;
|
|
||||||
} else { // if BC_UNSET
|
|
||||||
sx = (alpha[0] * time_step) / (dx * dx);
|
|
||||||
A_matrix.insert(1, 1) = -1. - 3. * sx;
|
|
||||||
A_matrix.insert(1, 0) = 2. * sx;
|
|
||||||
A_matrix.insert(1, 2) = sx;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int j = 2, k = j - 1; k < size - 1; j++, k++) {
|
|
||||||
if (bc_inner[k].type != tug::bc::BC_UNSET) {
|
|
||||||
if (bc_inner[k].type != tug::bc::BC_TYPE_CONSTANT) {
|
|
||||||
throw_invalid_argument("Inner boundary conditions with other type than "
|
|
||||||
"BC_TYPE_CONSTANT are currently not supported.");
|
|
||||||
}
|
|
||||||
A_matrix.insert(j, j) = 1;
|
|
||||||
continue;
|
|
||||||
} // if BC_UNSET
|
|
||||||
sx = (alpha[k] * time_step) / (dx * dx);
|
|
||||||
|
|
||||||
A_matrix.insert(j, j) = -1. - 2. * sx;
|
|
||||||
A_matrix.insert(j, (j - 1)) = sx;
|
|
||||||
A_matrix.insert(j, (j + 1)) = sx;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bc_inner[size - 1].type != tug::bc::BC_UNSET) {
|
|
||||||
if (bc_inner[size - 1].type != tug::bc::BC_TYPE_CONSTANT) {
|
|
||||||
throw_invalid_argument("Inner boundary conditions with other type than "
|
|
||||||
"BC_TYPE_CONSTANT are currently not supported.");
|
|
||||||
}
|
|
||||||
A_matrix.insert(A_size - 2, A_size - 2) = 1;
|
|
||||||
} else { // if BC_UNSET
|
|
||||||
sx = (alpha[size - 1] * time_step) / (dx * dx);
|
|
||||||
A_matrix.insert(A_size - 2, A_size - 2) = -1. - 3. * sx;
|
|
||||||
A_matrix.insert(A_size - 2, A_size - 3) = sx;
|
|
||||||
A_matrix.insert(A_size - 2, A_size - 1) = 2. * sx;
|
|
||||||
}
|
|
||||||
|
|
||||||
A_matrix.insert(A_size - 1, A_size - 1) = 1;
|
|
||||||
|
|
||||||
return A_matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto fillVectorFromRow(const DVectorRowMajor &c, const DVectorRowMajor &alpha,
|
|
||||||
const tug::bc::bc_tuple &bc,
|
|
||||||
const tug::bc::bc_vec &bc_inner,
|
|
||||||
const DVectorRowMajor &d_ortho, int size, double dx,
|
|
||||||
double time_step) -> Eigen::VectorXd {
|
|
||||||
|
|
||||||
Eigen::VectorXd b_vector(size + 2);
|
|
||||||
|
|
||||||
tug::bc::boundary_condition left = bc[0];
|
|
||||||
tug::bc::boundary_condition right = bc[1];
|
|
||||||
|
|
||||||
bool left_constant = (left.type == tug::bc::BC_TYPE_CONSTANT);
|
|
||||||
bool right_constant = (right.type == tug::bc::BC_TYPE_CONSTANT);
|
|
||||||
|
|
||||||
int b_size = b_vector.size();
|
|
||||||
|
|
||||||
for (int j = 0; j < size; j++) {
|
|
||||||
if (bc_inner[j].type != tug::bc::BC_UNSET) {
|
|
||||||
if (bc_inner[j].type != tug::bc::BC_TYPE_CONSTANT) {
|
|
||||||
throw_invalid_argument("Inner boundary conditions with other type than "
|
|
||||||
"BC_TYPE_CONSTANT are currently not supported.");
|
|
||||||
}
|
|
||||||
b_vector[j + 1] = bc_inner[j].value;
|
|
||||||
continue;
|
|
||||||
} // if BC_UNSET
|
|
||||||
b_vector[j + 1] = -c[j] + d_ortho[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is not correct currently.We will fix this when we are able to define
|
|
||||||
// FLUX boundary conditions
|
|
||||||
b_vector[0] =
|
|
||||||
(left_constant ? left.value : getBCFromFlux(left, c[0], alpha[0]));
|
|
||||||
|
|
||||||
b_vector[b_size - 1] =
|
|
||||||
(right_constant ? right.value
|
|
||||||
: getBCFromFlux(right, c[size - 1], alpha[size - 1]));
|
|
||||||
|
|
||||||
return b_vector;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto setupBTCSAndSolve(
|
|
||||||
DVectorRowMajor &c, const tug::bc::bc_tuple bc_ghost,
|
|
||||||
const tug::bc::bc_vec &bc_inner, const DVectorRowMajor &alpha, double dx,
|
|
||||||
double time_step, int size, const DVectorRowMajor &d_ortho,
|
|
||||||
Eigen::VectorXd (*solver)(const Eigen::SparseMatrix<double> &,
|
|
||||||
const Eigen::VectorXd &)) -> DVectorRowMajor {
|
|
||||||
|
|
||||||
const Eigen::SparseMatrix<double> A_matrix =
|
|
||||||
fillMatrixFromRow(alpha, bc_inner, size, dx, time_step);
|
|
||||||
|
|
||||||
const Eigen::VectorXd b_vector = fillVectorFromRow(
|
|
||||||
c, alpha, bc_ghost, bc_inner, d_ortho, size, dx, time_step);
|
|
||||||
|
|
||||||
// solving of the LEQ
|
|
||||||
Eigen::VectorXd x_vector = solver(A_matrix, b_vector);
|
|
||||||
|
|
||||||
DVectorRowMajor out_vector = x_vector.segment(1, size);
|
|
||||||
|
|
||||||
return out_vector;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
//
|
|
||||||
auto tug::diffusion::BTCS_1D(const tug::diffusion::TugInput &input_param,
|
|
||||||
double *field, const double *alpha) -> double {
|
|
||||||
|
|
||||||
auto start = time_marker();
|
|
||||||
|
|
||||||
uint32_t size = input_param.grid.grid_cells[0];
|
|
||||||
|
|
||||||
auto deltas = init_delta(input_param.grid.domain_size,
|
|
||||||
input_param.grid.grid_cells, GRID_1D);
|
|
||||||
double dx = deltas[0];
|
|
||||||
|
|
||||||
double time_step = input_param.time_step;
|
|
||||||
|
|
||||||
const tug::bc::BoundaryCondition bc =
|
|
||||||
(input_param.grid.bc != nullptr ? *input_param.grid.bc
|
|
||||||
: tug::bc::BoundaryCondition(size));
|
|
||||||
|
|
||||||
Eigen::Map<DVectorRowMajor> c_in(field, size);
|
|
||||||
Eigen::Map<const DVectorRowMajor> alpha_in(alpha, size);
|
|
||||||
|
|
||||||
DVectorRowMajor input_field = c_in.row(0);
|
|
||||||
|
|
||||||
DVectorRowMajor output = setupBTCSAndSolve(
|
|
||||||
input_field, bc.row_boundary(0), bc.getInnerRow(0), alpha_in, dx,
|
|
||||||
time_step, size, Eigen::VectorXd::Constant(size, 0), input_param.solver);
|
|
||||||
|
|
||||||
c_in.row(0) << output;
|
|
||||||
|
|
||||||
auto end = time_marker();
|
|
||||||
|
|
||||||
return diff_time(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tug::diffusion::ADI_2D(const tug::diffusion::TugInput &input_param,
|
|
||||||
double *field, const double *alpha) -> double {
|
|
||||||
|
|
||||||
auto start = time_marker();
|
|
||||||
|
|
||||||
uint32_t n_cols = input_param.grid.grid_cells[0];
|
|
||||||
uint32_t n_rows = input_param.grid.grid_cells[1];
|
|
||||||
|
|
||||||
auto deltas = init_delta(input_param.grid.domain_size,
|
|
||||||
input_param.grid.grid_cells, GRID_2D);
|
|
||||||
double dx = deltas[0];
|
|
||||||
double dy = deltas[1];
|
|
||||||
|
|
||||||
double local_dt = input_param.time_step / BTCS_2D_DT_SIZE;
|
|
||||||
|
|
||||||
tug::bc::BoundaryCondition bc =
|
|
||||||
(input_param.grid.bc != nullptr
|
|
||||||
? *input_param.grid.bc
|
|
||||||
: tug::bc::BoundaryCondition(n_cols, n_rows));
|
|
||||||
|
|
||||||
Eigen::Map<DMatrixRowMajor> c_in(field, n_rows, n_cols);
|
|
||||||
Eigen::Map<const DMatrixRowMajor> alpha_in(alpha, n_rows, n_cols);
|
|
||||||
|
|
||||||
DMatrixRowMajor d_ortho =
|
|
||||||
calc_d_ortho(c_in, alpha_in, bc, false, local_dt, dx);
|
|
||||||
|
|
||||||
#pragma omp parallel for schedule(dynamic)
|
|
||||||
for (int i = 0; i < n_rows; i++) {
|
|
||||||
DVectorRowMajor input_field = c_in.row(i);
|
|
||||||
DVectorRowMajor output = setupBTCSAndSolve(
|
|
||||||
input_field, bc.row_boundary(i), bc.getInnerRow(i), alpha_in.row(i), dx,
|
|
||||||
local_dt, n_cols, d_ortho.row(i), input_param.solver);
|
|
||||||
c_in.row(i) << output;
|
|
||||||
}
|
|
||||||
|
|
||||||
d_ortho = calc_d_ortho(c_in.transpose(), alpha_in.transpose(), bc, true,
|
|
||||||
local_dt, dy);
|
|
||||||
|
|
||||||
#pragma omp parallel for schedule(dynamic)
|
|
||||||
for (int i = 0; i < n_cols; i++) {
|
|
||||||
DVectorRowMajor input_field = c_in.col(i);
|
|
||||||
DVectorRowMajor output = setupBTCSAndSolve(
|
|
||||||
input_field, bc.col_boundary(i), bc.getInnerCol(i), alpha_in.col(i), dy,
|
|
||||||
local_dt, n_rows, d_ortho.row(i), input_param.solver);
|
|
||||||
c_in.col(i) << output.transpose();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto end = time_marker();
|
|
||||||
|
|
||||||
return diff_time(start, end);
|
|
||||||
}
|
|
||||||
@ -264,7 +264,8 @@ static VectorXd createSolutionVector(MatrixXd &concentrations, MatrixXd &alphaX,
|
|||||||
|
|
||||||
// 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
|
||||||
static VectorXd solve(SparseMatrix<double> &A, VectorXd &b) {
|
// use of EigenLU solver
|
||||||
|
static VectorXd EigenLUAlgorithm(SparseMatrix<double> &A, VectorXd &b) {
|
||||||
|
|
||||||
SparseLU<SparseMatrix<double>> solver;
|
SparseLU<SparseMatrix<double>> solver;
|
||||||
solver.analyzePattern(A);
|
solver.analyzePattern(A);
|
||||||
@ -273,9 +274,53 @@ static VectorXd solve(SparseMatrix<double> &A, VectorXd &b) {
|
|||||||
return solver.solve(b);
|
return solver.solve(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// solver for linear equation system; A corresponds to coefficient matrix,
|
||||||
|
// b to the solution vector
|
||||||
|
// implementation of Thomas Algorithm
|
||||||
|
static VectorXd ThomasAlgorithm(SparseMatrix<double> &A, VectorXd &b) {
|
||||||
|
uint32_t n = b.size();
|
||||||
|
|
||||||
|
Eigen::VectorXd a_diag(n);
|
||||||
|
Eigen::VectorXd b_diag(n);
|
||||||
|
Eigen::VectorXd c_diag(n);
|
||||||
|
Eigen::VectorXd x_vec = b;
|
||||||
|
|
||||||
|
// Fill diagonals vectors
|
||||||
|
b_diag[0] = A.coeff(0, 0);
|
||||||
|
c_diag[0] = A.coeff(0, 1);
|
||||||
|
|
||||||
|
for (int i = 1; i < n - 1; i++) {
|
||||||
|
a_diag[i] = A.coeff(i, i - 1);
|
||||||
|
b_diag[i] = A.coeff(i, i);
|
||||||
|
c_diag[i] = A.coeff(i, i + 1);
|
||||||
|
}
|
||||||
|
a_diag[n - 1] = A.coeff(n - 1, n - 2);
|
||||||
|
b_diag[n - 1] = A.coeff(n - 1, n - 1);
|
||||||
|
|
||||||
|
// start solving - c_diag and x_vec are overwritten
|
||||||
|
n--;
|
||||||
|
c_diag[0] /= b_diag[0];
|
||||||
|
x_vec[0] /= b_diag[0];
|
||||||
|
|
||||||
|
for (int i = 1; i < n; i++) {
|
||||||
|
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]) /
|
||||||
|
(b_diag[i] - a_diag[i] * c_diag[i - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
x_vec[n] = (x_vec[n] - a_diag[n] * x_vec[n - 1]) /
|
||||||
|
(b_diag[n] - a_diag[n] * c_diag[n - 1]);
|
||||||
|
|
||||||
|
for (int i = n; i-- > 0;) {
|
||||||
|
x_vec[i] -= c_diag[i] * x_vec[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return x_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// BTCS solution for 1D grid
|
// BTCS solution for 1D grid
|
||||||
static void BTCS_1D(Grid &grid, Boundary &bc, double ×tep) {
|
static void BTCS_1D(Grid &grid, Boundary &bc, double ×tep, VectorXd (*solverFunc) (SparseMatrix<double> &A, VectorXd &b)) {
|
||||||
int length = grid.getLength();
|
int length = grid.getLength();
|
||||||
double sx = timestep / (grid.getDelta() * grid.getDelta());
|
double sx = timestep / (grid.getDelta() * grid.getDelta());
|
||||||
|
|
||||||
@ -301,7 +346,7 @@ static void BTCS_1D(Grid &grid, Boundary &bc, double ×tep) {
|
|||||||
b(length-1) += 2 * sx * alpha(0,length-1) * bcRight[0].getValue();
|
b(length-1) += 2 * sx * alpha(0,length-1) * bcRight[0].getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
concentrations_t1 = solve(A, b);
|
concentrations_t1 = solverFunc(A, b);
|
||||||
|
|
||||||
for (int j = 0; j < length; j++) {
|
for (int j = 0; j < length; j++) {
|
||||||
concentrations(0,j) = concentrations_t1(j);
|
concentrations(0,j) = concentrations_t1(j);
|
||||||
@ -312,7 +357,7 @@ static void BTCS_1D(Grid &grid, Boundary &bc, double ×tep) {
|
|||||||
|
|
||||||
|
|
||||||
// BTCS solution for 2D grid
|
// BTCS solution for 2D grid
|
||||||
static void BTCS_2D(Grid &grid, Boundary &bc, double ×tep) {
|
static void BTCS_2D(Grid &grid, Boundary &bc, double ×tep, VectorXd (*solverFunc) (SparseMatrix<double> &A, VectorXd &b)) {
|
||||||
int rowMax = grid.getRow();
|
int rowMax = grid.getRow();
|
||||||
int colMax = grid.getCol();
|
int colMax = grid.getCol();
|
||||||
double sx = timestep / (2 * grid.getDeltaCol() * grid.getDeltaCol());
|
double sx = timestep / (2 * grid.getDeltaCol() * grid.getDeltaCol());
|
||||||
@ -342,7 +387,7 @@ static void BTCS_2D(Grid &grid, Boundary &bc, double ×tep) {
|
|||||||
|
|
||||||
SparseLU<SparseMatrix<double>> solver;
|
SparseLU<SparseMatrix<double>> solver;
|
||||||
|
|
||||||
row_t1 = solve(A, b);
|
row_t1 = solverFunc(A, b);
|
||||||
|
|
||||||
concentrations_t1.row(i) = row_t1;
|
concentrations_t1.row(i) = row_t1;
|
||||||
}
|
}
|
||||||
@ -360,7 +405,7 @@ static void BTCS_2D(Grid &grid, Boundary &bc, double ×tep) {
|
|||||||
b = createSolutionVector(concentrations_t1, alphaY, alphaX, bcTop, bcBottom,
|
b = createSolutionVector(concentrations_t1, alphaY, alphaX, bcTop, bcBottom,
|
||||||
bcLeft, bcRight, rowMax, i, sy, sx);
|
bcLeft, bcRight, rowMax, i, sy, sx);
|
||||||
|
|
||||||
row_t1 = solve(A, b);
|
row_t1 = solverFunc(A, b);
|
||||||
|
|
||||||
concentrations.row(i) = row_t1;
|
concentrations.row(i) = row_t1;
|
||||||
}
|
}
|
||||||
@ -371,12 +416,23 @@ static void BTCS_2D(Grid &grid, Boundary &bc, double ×tep) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// entry point; differentiate between 1D and 2D grid
|
// entry point for EigenLU solver; differentiate between 1D and 2D grid
|
||||||
static void BTCS(Grid &grid, Boundary &bc, double ×tep) {
|
static void BTCS_LU(Grid &grid, Boundary &bc, double ×tep) {
|
||||||
if (grid.getDim() == 1) {
|
if (grid.getDim() == 1) {
|
||||||
BTCS_1D(grid, bc, timestep);
|
BTCS_1D(grid, bc, timestep, EigenLUAlgorithm);
|
||||||
} else if (grid.getDim() == 2) {
|
} else if (grid.getDim() == 2) {
|
||||||
BTCS_2D(grid, bc, timestep);
|
BTCS_2D(grid, bc, timestep, EigenLUAlgorithm);
|
||||||
|
} else {
|
||||||
|
throw_invalid_argument("Error: Only 1- and 2-dimensional grids are defined!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// entry point for Thomas algorithm solver; differentiate 1D and 2D grid
|
||||||
|
static void BTCS_Thomas(Grid &grid, Boundary &bc, double ×tep) {
|
||||||
|
if (grid.getDim() == 1) {
|
||||||
|
BTCS_1D(grid, bc, timestep, ThomasAlgorithm);
|
||||||
|
} else if (grid.getDim() == 2) {
|
||||||
|
BTCS_2D(grid, bc, timestep, ThomasAlgorithm);
|
||||||
} 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!");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
#include "TugUtils.hpp"
|
#include "TugUtils.hpp"
|
||||||
#include "tug/BoundaryCondition.hpp"
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <omp.h>
|
#include <omp.h>
|
||||||
#include <tug/Boundary.hpp>
|
#include <tug/Boundary.hpp>
|
||||||
@ -129,7 +128,7 @@ VectorXd Boundary::getBoundarySideValues(BC_SIDE side) {
|
|||||||
VectorXd values(length);
|
VectorXd values(length);
|
||||||
|
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
if (getBoundaryElementType(side, i) == tug::bc::BC_TYPE_CLOSED) {
|
if (getBoundaryElementType(side, i) == BC_TYPE_CLOSED) {
|
||||||
values(i) = -1;
|
values(i) = -1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,209 +0,0 @@
|
|||||||
#include <algorithm>
|
|
||||||
#include <tug/BoundaryCondition.hpp>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "TugUtils.hpp"
|
|
||||||
|
|
||||||
constexpr uint8_t DIM_1D = 2;
|
|
||||||
constexpr uint8_t DIM_2D = 4;
|
|
||||||
|
|
||||||
tug::bc::BoundaryCondition::BoundaryCondition(int x) {
|
|
||||||
this->bc_internal.resize(DIM_1D, {0, 0});
|
|
||||||
this->dim = 1;
|
|
||||||
// this value is actually unused
|
|
||||||
this->maxsize = 1;
|
|
||||||
|
|
||||||
this->sizes[X_DIM] = x;
|
|
||||||
this->sizes[Y_DIM] = 1;
|
|
||||||
|
|
||||||
this->maxindex = x - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
tug::bc::BoundaryCondition::BoundaryCondition(int x, int y) {
|
|
||||||
this->maxsize = (x >= y ? x : y);
|
|
||||||
this->bc_internal.resize(DIM_2D * maxsize, {0, 0});
|
|
||||||
this->dim = 2;
|
|
||||||
|
|
||||||
this->sizes[X_DIM] = x;
|
|
||||||
this->sizes[Y_DIM] = y;
|
|
||||||
|
|
||||||
this->maxindex = (x * y) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tug::bc::BoundaryCondition::setSide(
|
|
||||||
uint8_t side, tug::bc::boundary_condition &input_bc) {
|
|
||||||
// QUESTION: why cant the BC be changed for dim = 1?
|
|
||||||
if (this->dim == 1) {
|
|
||||||
throw_invalid_argument("setSide requires at least a 2D grid");
|
|
||||||
}
|
|
||||||
if (side > 3) {
|
|
||||||
throw_out_of_range("Invalid range for 2D grid");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t size =
|
|
||||||
(side == tug::bc::BC_SIDE_LEFT || side == tug::bc::BC_SIDE_RIGHT
|
|
||||||
? this->sizes[Y_DIM]
|
|
||||||
: this->sizes[X_DIM]);
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < size; i++) {
|
|
||||||
this->bc_internal[side * maxsize + i] = input_bc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void tug::bc::BoundaryCondition::setSide(
|
|
||||||
uint8_t side, std::vector<tug::bc::boundary_condition> &input_bc) {
|
|
||||||
if (this->dim == 1) {
|
|
||||||
throw_invalid_argument("setSide requires at least a 2D grid");
|
|
||||||
}
|
|
||||||
if (side > 3) {
|
|
||||||
throw_out_of_range("Invalid range for 2D grid");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t size =
|
|
||||||
(side == tug::bc::BC_SIDE_LEFT || side == tug::bc::BC_SIDE_RIGHT
|
|
||||||
? this->sizes[Y_DIM]
|
|
||||||
: this->sizes[X_DIM]);
|
|
||||||
|
|
||||||
if (input_bc.size() > size) {
|
|
||||||
throw_out_of_range("Input vector is greater than maximum excpected value");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
bc_internal[this->maxsize * side + i] = input_bc[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tug::bc::BoundaryCondition::getSide(uint8_t side)
|
|
||||||
-> std::vector<tug::bc::boundary_condition> {
|
|
||||||
if (this->dim == 1) {
|
|
||||||
throw_invalid_argument("getSide requires at least a 2D grid");
|
|
||||||
}
|
|
||||||
if (side > 3) {
|
|
||||||
throw_out_of_range("Invalid range for 2D grid");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t size =
|
|
||||||
(side == tug::bc::BC_SIDE_LEFT || side == tug::bc::BC_SIDE_RIGHT
|
|
||||||
? this->sizes[Y_DIM]
|
|
||||||
: this->sizes[X_DIM]);
|
|
||||||
|
|
||||||
std::vector<tug::bc::boundary_condition> out(size);
|
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
out[i] = this->bc_internal[this->maxsize * side + i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tug::bc::BoundaryCondition::row_boundary(uint32_t i) const
|
|
||||||
-> tug::bc::bc_tuple {
|
|
||||||
if (i >= this->sizes[Y_DIM]) {
|
|
||||||
throw_out_of_range("Index out of range");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {this->bc_internal[BC_SIDE_LEFT * this->maxsize + i],
|
|
||||||
this->bc_internal[BC_SIDE_RIGHT * this->maxsize + i]};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tug::bc::BoundaryCondition::col_boundary(uint32_t i) const
|
|
||||||
-> tug::bc::bc_tuple {
|
|
||||||
if (this->dim == 1) {
|
|
||||||
throw_invalid_argument("Access of column requires at least 2D grid");
|
|
||||||
}
|
|
||||||
if (i >= this->sizes[X_DIM]) {
|
|
||||||
throw_out_of_range("Index out of range");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {this->bc_internal[BC_SIDE_TOP * this->maxsize + i],
|
|
||||||
this->bc_internal[BC_SIDE_BOTTOM * this->maxsize + i]};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tug::bc::BoundaryCondition::getInnerRow(uint32_t i) const -> bc_vec {
|
|
||||||
if (i >= this->sizes[Y_DIM]) {
|
|
||||||
throw_out_of_range("Index is out of range");
|
|
||||||
}
|
|
||||||
|
|
||||||
bc_vec row(this->sizes[X_DIM], {tug::bc::BC_UNSET, 0});
|
|
||||||
|
|
||||||
if (this->inner_cells.empty()) {
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t index_min = i * this->sizes[X_DIM];
|
|
||||||
uint32_t index_max = ((i + 1) * this->sizes[X_DIM]) - 1;
|
|
||||||
|
|
||||||
for (auto const &cell : this->inner_cells) {
|
|
||||||
if (cell.first < index_min) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (cell.first > index_max) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
row[cell.first - index_min] = cell.second;
|
|
||||||
}
|
|
||||||
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tug::bc::BoundaryCondition::getInnerCol(uint32_t i) const -> bc_vec {
|
|
||||||
if (this->dim != 2) {
|
|
||||||
throw_invalid_argument("getInnerCol is only applicable for 2D grids");
|
|
||||||
}
|
|
||||||
if (i >= this->sizes[X_DIM]) {
|
|
||||||
throw_out_of_range("Index is out of range");
|
|
||||||
}
|
|
||||||
|
|
||||||
bc_vec col(this->sizes[Y_DIM], {tug::bc::BC_UNSET, 0});
|
|
||||||
|
|
||||||
if (this->inner_cells.empty()) {
|
|
||||||
return col;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto const &cell : this->inner_cells) {
|
|
||||||
if (cell.first % this->sizes[X_DIM] == i) {
|
|
||||||
col[cell.first / this->sizes[X_DIM]] = cell.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return col;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tug::bc::BoundaryCondition::setInnerBC(boundary_condition bc, int x,
|
|
||||||
int y = 0) {
|
|
||||||
if (x >= this->sizes[X_DIM] || y >= this->sizes[Y_DIM]) {
|
|
||||||
throw_out_of_range("One input parameter is out of range");
|
|
||||||
}
|
|
||||||
uint32_t index = y * this->sizes[X_DIM] + x;
|
|
||||||
auto it = this->inner_cells.find(index);
|
|
||||||
|
|
||||||
if (it != this->inner_cells.end()) {
|
|
||||||
it->second = bc;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->inner_cells.insert({index, bc});
|
|
||||||
}
|
|
||||||
|
|
||||||
void tug::bc::BoundaryCondition::unsetInnerBC(int x, int y) {
|
|
||||||
uint32_t index = y * this->sizes[X_DIM] + x;
|
|
||||||
this->inner_cells.erase(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tug::bc::BoundaryCondition::getInnerBC(int x, int y = 0)
|
|
||||||
-> boundary_condition {
|
|
||||||
if (x >= this->sizes[X_DIM] || y >= this->sizes[Y_DIM]) {
|
|
||||||
throw_out_of_range("One input parameter is out of range");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t index = y * this->sizes[X_DIM] + x;
|
|
||||||
|
|
||||||
auto it = this->inner_cells.find(index);
|
|
||||||
|
|
||||||
if (it != this->inner_cells.end()) {
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {tug::bc::BC_UNSET, 0};
|
|
||||||
}
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
add_library(tug BTCS.cpp BoundaryCondition.cpp Solver.cpp Boundary.cpp Grid.cpp Simulation.cpp FTCS.cpp BTCSv2.cpp)
|
add_library(tug Boundary.cpp Grid.cpp Simulation.cpp FTCS.cpp BTCSv2.cpp)
|
||||||
|
|
||||||
target_link_libraries(tug Eigen3::Eigen)
|
target_link_libraries(tug Eigen3::Eigen)
|
||||||
|
|
||||||
|
|||||||
@ -5,15 +5,12 @@ This is the src-directory that holds the source code to the implementation of th
|
|||||||
src/
|
src/
|
||||||
├── CMakeFiles/
|
├── CMakeFiles/
|
||||||
├── Boundary.cpp
|
├── Boundary.cpp
|
||||||
├── BoundaryCondition.cpp
|
|
||||||
├── BTCS.cpp
|
|
||||||
├── BTCSv2.cpp
|
├── BTCSv2.cpp
|
||||||
├── CMakeLists.txt
|
├── CMakeLists.txt
|
||||||
├── FTCS.cpp
|
├── FTCS.cpp
|
||||||
├── Grid.cpp
|
├── Grid.cpp
|
||||||
├── README.md
|
├── README.md
|
||||||
├── Simulation.cpp
|
├── Simulation.cpp
|
||||||
├── Solver.cpp
|
|
||||||
└── TugUtils.hpp
|
└── TugUtils.hpp
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@ -23,10 +20,6 @@ src/
|
|||||||
|
|
||||||
**Boundary.cpp** Implementation of Boundary class, that holds the boundary conditions.
|
**Boundary.cpp** Implementation of Boundary class, that holds the boundary conditions.
|
||||||
|
|
||||||
**BoundaryCondition.cpp** <i>Outdated</i> implementation of boundary conditions.
|
|
||||||
|
|
||||||
**BTCS.cpp** <i>Outdated</i> implementation of BTCS solution to homogeneous diffusion.
|
|
||||||
|
|
||||||
**BTCSv2.cpp** Implementation of BTCS solution to heterogeneous diffusion in 1D and 2D.
|
**BTCSv2.cpp** Implementation of BTCS solution to heterogeneous diffusion in 1D and 2D.
|
||||||
|
|
||||||
**CMakeLists.txt** CMakeLists for this directory.
|
**CMakeLists.txt** CMakeLists for this directory.
|
||||||
@ -39,7 +32,5 @@ src/
|
|||||||
|
|
||||||
**Simulation.cpp** Implementation of Simulation class, that holds all of the information for a specific simulation run, as well as the Boundary and Grid objects.
|
**Simulation.cpp** Implementation of Simulation class, that holds all of the information for a specific simulation run, as well as the Boundary and Grid objects.
|
||||||
|
|
||||||
**Solver.cpp** <i>Outdated</i> implementation of Eigen solvers.
|
|
||||||
|
|
||||||
**TugUtils.hpp** Helper functions for other source files.
|
**TugUtils.hpp** Helper functions for other source files.
|
||||||
|
|
||||||
|
|||||||
@ -7,8 +7,10 @@
|
|||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#ifndef SIMULATION_H_
|
||||||
|
#define SIMULATION_H_
|
||||||
|
|
||||||
#include "BTCSv2.cpp"
|
#include "BTCSv2.cpp"
|
||||||
#include <tug/progressbar.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -16,6 +18,7 @@ using namespace std;
|
|||||||
Simulation::Simulation(Grid &grid, Boundary &bc, APPROACH approach) : grid(grid), bc(bc) {
|
Simulation::Simulation(Grid &grid, Boundary &bc, APPROACH approach) : grid(grid), bc(bc) {
|
||||||
|
|
||||||
this->approach = approach;
|
this->approach = approach;
|
||||||
|
this->solver = THOMAS_ALGORITHM_SOLVER;
|
||||||
this->timestep = -1; // error per default
|
this->timestep = -1; // error per default
|
||||||
this->iterations = -1;
|
this->iterations = -1;
|
||||||
this->innerIterations = 1;
|
this->innerIterations = 1;
|
||||||
@ -54,53 +57,62 @@ void Simulation::setTimestep(double timestep) {
|
|||||||
throw_invalid_argument("Timestep has to be greater than zero.");
|
throw_invalid_argument("Timestep has to be greater than zero.");
|
||||||
}
|
}
|
||||||
|
|
||||||
double deltaRowSquare;
|
if (approach == FTCS_APPROACH) {
|
||||||
double deltaColSquare = grid.getDeltaCol() * grid.getDeltaCol();
|
|
||||||
double minDeltaSquare;
|
|
||||||
double maxAlphaX, maxAlphaY, maxAlpha;
|
|
||||||
if (grid.getDim() == 2) {
|
|
||||||
|
|
||||||
deltaRowSquare = grid.getDeltaRow() * grid.getDeltaRow();
|
double deltaRowSquare;
|
||||||
|
double deltaColSquare = grid.getDeltaCol() * grid.getDeltaCol();
|
||||||
|
double minDeltaSquare;
|
||||||
|
double maxAlphaX, maxAlphaY, maxAlpha;
|
||||||
|
string dim;
|
||||||
|
if (grid.getDim() == 2) {
|
||||||
|
dim = "2D";
|
||||||
|
|
||||||
minDeltaSquare = (deltaRowSquare < deltaColSquare) ? deltaRowSquare : deltaColSquare;
|
deltaRowSquare = grid.getDeltaRow() * grid.getDeltaRow();
|
||||||
maxAlphaX = grid.getAlphaX().maxCoeff();
|
|
||||||
maxAlphaY = grid.getAlphaY().maxCoeff();
|
|
||||||
maxAlpha = (maxAlphaX > maxAlphaY) ? maxAlphaX : maxAlphaY;
|
|
||||||
|
|
||||||
} else if (grid.getDim() == 1) {
|
minDeltaSquare = (deltaRowSquare < deltaColSquare) ? deltaRowSquare : deltaColSquare;
|
||||||
minDeltaSquare = deltaColSquare;
|
maxAlphaX = grid.getAlphaX().maxCoeff();
|
||||||
maxAlpha = grid.getAlpha().maxCoeff();
|
maxAlphaY = grid.getAlphaY().maxCoeff();
|
||||||
|
maxAlpha = (maxAlphaX > maxAlphaY) ? maxAlphaX : maxAlphaY;
|
||||||
|
|
||||||
|
} else if (grid.getDim() == 1) {
|
||||||
} else {
|
dim = "1D";
|
||||||
throw_invalid_argument("Critical error: Undefined number of dimensions!");
|
minDeltaSquare = deltaColSquare;
|
||||||
}
|
maxAlpha = grid.getAlpha().maxCoeff();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw_invalid_argument("Critical error: Undefined number of dimensions!");
|
||||||
|
}
|
||||||
|
|
||||||
// TODO check formula 1D case
|
// Courant-Friedrichs-Lewy condition
|
||||||
double CFL_MDL = minDeltaSquare / (4*maxAlpha); // Formula from Marco --> seems to be unstable
|
double cfl = minDeltaSquare / (4*maxAlpha);
|
||||||
double CFL_Wiki = 1 / (4 * maxAlpha * ((1/deltaRowSquare) + (1/deltaColSquare))); // Formula from Wikipedia
|
|
||||||
|
|
||||||
cout << "FTCS_2D :: CFL condition MDL: " << CFL_MDL << endl;
|
// stability equation from Wikipedia; might be useful if applied cfl does not work in some cases
|
||||||
// cout << "FTCS_2D :: CFL condition Wiki: " << CFL_Wiki << endl;
|
// double CFL_Wiki = 1 / (4 * maxAlpha * ((1/deltaRowSquare) + (1/deltaColSquare)));
|
||||||
cout << "FTCS_2D :: required dt=" << timestep << endl;
|
|
||||||
|
|
||||||
if (timestep > CFL_MDL) {
|
cout << "FTCS_" << dim << " :: CFL condition MDL: " << cfl << endl;
|
||||||
|
cout << "FTCS_" << dim << " :: required dt=" << timestep << endl;
|
||||||
|
|
||||||
this->innerIterations = (int)ceil(timestep / CFL_MDL);
|
if (timestep > cfl) {
|
||||||
this->timestep = timestep / (double)innerIterations;
|
|
||||||
|
|
||||||
cerr << "Warning: Timestep was adjusted, because of stability "
|
this->innerIterations = (int)ceil(timestep / cfl);
|
||||||
"conditions. Time duration was approximately preserved by "
|
this->timestep = timestep / (double)innerIterations;
|
||||||
"adjusting internal number of iterations."
|
|
||||||
<< endl;
|
cerr << "Warning :: Timestep was adjusted, because of stability "
|
||||||
cout << "FTCS_2D :: Required " << this->innerIterations
|
"conditions. Time duration was approximately preserved by "
|
||||||
<< " inner iterations with dt=" << this->timestep << endl;
|
"adjusting internal number of iterations."
|
||||||
|
<< endl;
|
||||||
|
cout << "FTCS_" << dim << " :: Required " << this->innerIterations
|
||||||
|
<< " inner iterations with dt=" << this->timestep << endl;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
this->timestep = timestep;
|
||||||
|
cout << "FTCS_" << dim << " :: No inner iterations required, dt=" << timestep << endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
this->timestep = timestep;
|
this->timestep = timestep;
|
||||||
cout << "FTCS_2D :: No inner iterations required, dt=" << timestep << endl;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -116,6 +128,16 @@ void Simulation::setIterations(int iterations) {
|
|||||||
this->iterations = iterations;
|
this->iterations = iterations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Simulation::setSolver(SOLVER solver) {
|
||||||
|
if (this->approach == FTCS_APPROACH) {
|
||||||
|
cerr << "Warning: Solver was set, but FTCS approach initialized. Setting the solver "
|
||||||
|
"is thus without effect."
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->solver = solver;
|
||||||
|
}
|
||||||
|
|
||||||
int Simulation::getIterations() {
|
int Simulation::getIterations() {
|
||||||
return this->iterations;
|
return this->iterations;
|
||||||
}
|
}
|
||||||
@ -196,7 +218,7 @@ void Simulation::run() {
|
|||||||
|
|
||||||
auto begin = std::chrono::high_resolution_clock::now();
|
auto begin = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
if (approach == FTCS_APPROACH) {
|
if (approach == FTCS_APPROACH) { // FTCS case
|
||||||
for (int i = 0; i < iterations * innerIterations; i++) {
|
for (int i = 0; i < iterations * innerIterations; i++) {
|
||||||
if (console_output == CONSOLE_OUTPUT_VERBOSE && i > 0) {
|
if (console_output == CONSOLE_OUTPUT_VERBOSE && i > 0) {
|
||||||
printConcentrationsConsole();
|
printConcentrationsConsole();
|
||||||
@ -215,18 +237,32 @@ void Simulation::run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (approach == BTCS_APPROACH) {
|
} else if (approach == BTCS_APPROACH) { // BTCS case
|
||||||
|
|
||||||
for (int i = 0; i < iterations * innerIterations; i++) {
|
if (solver == EIGEN_LU_SOLVER) {
|
||||||
if (console_output == CONSOLE_OUTPUT_VERBOSE && i > 0) {
|
for (int i = 0; i < iterations; i++) {
|
||||||
printConcentrationsConsole();
|
if (console_output == CONSOLE_OUTPUT_VERBOSE && i > 0) {
|
||||||
}
|
printConcentrationsConsole();
|
||||||
if (csv_output >= CSV_OUTPUT_VERBOSE) {
|
}
|
||||||
printConcentrationsCSV(filename);
|
if (csv_output >= CSV_OUTPUT_VERBOSE) {
|
||||||
}
|
printConcentrationsCSV(filename);
|
||||||
|
}
|
||||||
|
|
||||||
BTCS(this->grid, this->bc, this->timestep);
|
BTCS_LU(this->grid, this->bc, this->timestep);
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (solver == THOMAS_ALGORITHM_SOLVER) {
|
||||||
|
for (int i = 0; i < iterations; i++) {
|
||||||
|
if (console_output == CONSOLE_OUTPUT_VERBOSE && i > 0) {
|
||||||
|
printConcentrationsConsole();
|
||||||
|
}
|
||||||
|
if (csv_output >= CSV_OUTPUT_VERBOSE) {
|
||||||
|
printConcentrationsCSV(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
BTCS_Thomas(this->grid, this->bc, this->timestep);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -247,3 +283,5 @@ void Simulation::run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -1,61 +0,0 @@
|
|||||||
#include <tug/Solver.hpp>
|
|
||||||
|
|
||||||
#include <Eigen/Dense>
|
|
||||||
#include <Eigen/Sparse>
|
|
||||||
|
|
||||||
auto tug::solver::EigenLU(const Eigen::SparseMatrix<double> &A_matrix,
|
|
||||||
const Eigen::VectorXd &b_vector) -> Eigen::VectorXd {
|
|
||||||
|
|
||||||
Eigen::SparseLU<Eigen::SparseMatrix<double>, Eigen::COLAMDOrdering<int>>
|
|
||||||
solver;
|
|
||||||
solver.analyzePattern(A_matrix);
|
|
||||||
|
|
||||||
solver.factorize(A_matrix);
|
|
||||||
|
|
||||||
Eigen::VectorXd x_vec = solver.solve(b_vector);
|
|
||||||
|
|
||||||
return solver.solve(b_vector);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tug::solver::ThomasAlgorithm(const Eigen::SparseMatrix<double> &A_matrix,
|
|
||||||
const Eigen::VectorXd &b_vector)
|
|
||||||
-> Eigen::VectorXd {
|
|
||||||
uint32_t n = b_vector.size();
|
|
||||||
|
|
||||||
Eigen::VectorXd a_diag(n);
|
|
||||||
Eigen::VectorXd b_diag(n);
|
|
||||||
Eigen::VectorXd c_diag(n);
|
|
||||||
Eigen::VectorXd x_vec = b_vector;
|
|
||||||
|
|
||||||
// Fill diagonals vectors
|
|
||||||
b_diag[0] = A_matrix.coeff(0, 0);
|
|
||||||
c_diag[0] = A_matrix.coeff(0, 1);
|
|
||||||
|
|
||||||
for (int i = 1; i < n - 1; i++) {
|
|
||||||
a_diag[i] = A_matrix.coeff(i, i - 1);
|
|
||||||
b_diag[i] = A_matrix.coeff(i, i);
|
|
||||||
c_diag[i] = A_matrix.coeff(i, i + 1);
|
|
||||||
}
|
|
||||||
a_diag[n - 1] = A_matrix.coeff(n - 1, n - 2);
|
|
||||||
b_diag[n - 1] = A_matrix.coeff(n - 1, n - 1);
|
|
||||||
|
|
||||||
// start solving - c_diag and x_vec are overwritten
|
|
||||||
n--;
|
|
||||||
c_diag[0] /= b_diag[0];
|
|
||||||
x_vec[0] /= b_diag[0];
|
|
||||||
|
|
||||||
for (int i = 1; i < n; i++) {
|
|
||||||
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]) /
|
|
||||||
(b_diag[i] - a_diag[i] * c_diag[i - 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
x_vec[n] = (x_vec[n] - a_diag[n] * x_vec[n - 1]) /
|
|
||||||
(b_diag[n] - a_diag[n] * c_diag[n - 1]);
|
|
||||||
|
|
||||||
for (int i = n; i-- > 0;) {
|
|
||||||
x_vec[i] -= c_diag[i] * x_vec[i + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return x_vec;
|
|
||||||
}
|
|
||||||
@ -11,7 +11,7 @@ if(NOT DOCTEST_LIB)
|
|||||||
FetchContent_MakeAvailable(DocTest)
|
FetchContent_MakeAvailable(DocTest)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(testTug setup.cpp testSimulation.cpp testGrid.cpp testFTCS.cpp) # testBoundaryCondition.cpp testDiffusion.cpp
|
add_executable(testTug setup.cpp testSimulation.cpp testGrid.cpp testFTCS.cpp)
|
||||||
target_link_libraries(testTug doctest tug)
|
target_link_libraries(testTug doctest tug)
|
||||||
|
|
||||||
# get relative path of the CSV file
|
# get relative path of the CSV file
|
||||||
|
|||||||
@ -1,196 +0,0 @@
|
|||||||
#include <doctest/doctest.h>
|
|
||||||
#include <tug/BoundaryCondition.hpp>
|
|
||||||
|
|
||||||
using namespace tug::bc;
|
|
||||||
|
|
||||||
#define BC_CONST_VALUE 1e-5
|
|
||||||
|
|
||||||
TEST_CASE("1D Boundary Condition") {
|
|
||||||
|
|
||||||
BoundaryCondition bc(5);
|
|
||||||
boundary_condition bc_set = {BC_TYPE_CONSTANT, BC_CONST_VALUE};
|
|
||||||
|
|
||||||
SUBCASE("valid get") { CHECK_EQ(bc(BC_SIDE_LEFT).value, 0); }
|
|
||||||
|
|
||||||
SUBCASE("invalid get") {
|
|
||||||
CHECK_THROWS(bc(BC_SIDE_TOP));
|
|
||||||
CHECK_THROWS(bc(BC_SIDE_LEFT, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("valid set") {
|
|
||||||
CHECK_NOTHROW(bc(BC_SIDE_LEFT) = bc_set);
|
|
||||||
CHECK_EQ(bc(BC_SIDE_LEFT).value, bc_set.value);
|
|
||||||
CHECK_EQ(bc(BC_SIDE_LEFT).type, bc_set.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("invalid set") {
|
|
||||||
CHECK_THROWS(bc(BC_SIDE_TOP) = bc_set);
|
|
||||||
CHECK_THROWS(bc(BC_SIDE_LEFT, 0) = bc_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("valid row getter") {
|
|
||||||
bc(BC_SIDE_LEFT) = bc_set;
|
|
||||||
bc_tuple tup = bc.row_boundary(0);
|
|
||||||
|
|
||||||
CHECK_EQ(tup[0].value, BC_CONST_VALUE);
|
|
||||||
CHECK_EQ(tup[1].value, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("invalid row and col getter") {
|
|
||||||
CHECK_THROWS(bc.row_boundary(1));
|
|
||||||
CHECK_THROWS(bc.col_boundary(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("2D Boundary Condition") {
|
|
||||||
|
|
||||||
BoundaryCondition bc(5, 5);
|
|
||||||
boundary_condition bc_set = {BC_TYPE_CONSTANT, BC_CONST_VALUE};
|
|
||||||
|
|
||||||
SUBCASE("valid get") { CHECK_EQ(bc(BC_SIDE_LEFT, 0).value, 0); }
|
|
||||||
|
|
||||||
SUBCASE("invalid get") {
|
|
||||||
CHECK_THROWS(bc(5, 0));
|
|
||||||
CHECK_THROWS(bc(BC_SIDE_LEFT));
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("valid set") {
|
|
||||||
CHECK_NOTHROW(bc(BC_SIDE_LEFT, 0) = bc_set);
|
|
||||||
CHECK_EQ(bc(BC_SIDE_LEFT, 0).value, bc_set.value);
|
|
||||||
CHECK_EQ(bc(BC_SIDE_LEFT, 0).type, bc_set.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("invalid set") {
|
|
||||||
CHECK_THROWS(bc(BC_SIDE_LEFT) = bc_set);
|
|
||||||
CHECK_THROWS(bc(5, 0) = bc_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("call of setSide") {
|
|
||||||
CHECK_NOTHROW(bc.setSide(BC_SIDE_BOTTOM, bc_set));
|
|
||||||
CHECK_EQ(bc(BC_SIDE_BOTTOM, 1).value, bc_set.value);
|
|
||||||
CHECK_EQ(bc(BC_SIDE_BOTTOM, 1).type, bc_set.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("get and set of side") {
|
|
||||||
std::vector<boundary_condition> bc_vec;
|
|
||||||
CHECK_NOTHROW(bc_vec = bc.getSide(BC_SIDE_BOTTOM));
|
|
||||||
bc_vec[3] = {BC_TYPE_CONSTANT, 1e-5};
|
|
||||||
CHECK_NOTHROW(bc.setSide(BC_SIDE_BOTTOM, bc_vec));
|
|
||||||
CHECK_EQ(bc(BC_SIDE_BOTTOM, 3).type, BC_TYPE_CONSTANT);
|
|
||||||
CHECK_EQ(bc(BC_SIDE_BOTTOM, 3).value, 1e-5);
|
|
||||||
|
|
||||||
CHECK_EQ(bc(BC_SIDE_BOTTOM, 2).value, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Boundary Condition helpers") {
|
|
||||||
boundary_condition bc_set = {BC_TYPE_CONSTANT, BC_CONST_VALUE};
|
|
||||||
|
|
||||||
SUBCASE("return boundary condition skeleton") {
|
|
||||||
boundary_condition bc_test =
|
|
||||||
BoundaryCondition::returnBoundaryCondition(bc_set.type, bc_set.value);
|
|
||||||
CHECK_EQ(bc_test.value, bc_set.value);
|
|
||||||
CHECK_EQ(bc_test.type, bc_set.type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("1D special inner grid cells") {
|
|
||||||
BoundaryCondition bc(5);
|
|
||||||
boundary_condition bc_set = {BC_TYPE_CONSTANT, BC_CONST_VALUE};
|
|
||||||
|
|
||||||
SUBCASE("valid set") { CHECK_NOTHROW(bc.setInnerBC(bc_set, 0, 0)); }
|
|
||||||
|
|
||||||
SUBCASE("valid get") {
|
|
||||||
bc.setInnerBC(bc_set, 0, 0);
|
|
||||||
CHECK_EQ(bc.getInnerBC(0, 0).type, bc_set.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("invalid get") {
|
|
||||||
CHECK_EQ(bc.getInnerBC(1, 0).type, BC_UNSET);
|
|
||||||
CHECK_THROWS(bc.getInnerBC(0, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("invalid set") { CHECK_THROWS(bc.setInnerBC(bc_set, 0, 1)); }
|
|
||||||
|
|
||||||
SUBCASE("valid row getter") {
|
|
||||||
bc.setInnerBC(bc_set, 1, 0);
|
|
||||||
|
|
||||||
bc_vec ret = bc.getInnerRow(0);
|
|
||||||
|
|
||||||
CHECK_EQ(ret[0].type, BC_UNSET);
|
|
||||||
CHECK_EQ(ret[1].type, bc_set.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("invalid row getter") { CHECK_THROWS(bc.getInnerRow(1)); }
|
|
||||||
|
|
||||||
SUBCASE("invalid col getter") { CHECK_THROWS(bc.getInnerCol(0)); }
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("2D special inner grid cells") {
|
|
||||||
BoundaryCondition bc(5, 5);
|
|
||||||
boundary_condition bc_set = {BC_TYPE_CONSTANT, BC_CONST_VALUE};
|
|
||||||
|
|
||||||
SUBCASE("valid set") { CHECK_NOTHROW(bc.setInnerBC(bc_set, 0, 0)); }
|
|
||||||
|
|
||||||
SUBCASE("valid get") {
|
|
||||||
bc.setInnerBC(bc_set, 0, 0);
|
|
||||||
CHECK_EQ(bc.getInnerBC(0, 0).type, bc_set.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("invalid get") {
|
|
||||||
CHECK_EQ(bc.getInnerBC(1, 0).type, BC_UNSET);
|
|
||||||
CHECK_THROWS(bc.getInnerBC(5, 5));
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("invalid set") { CHECK_THROWS(bc.setInnerBC(bc_set, 5, 5)); }
|
|
||||||
|
|
||||||
SUBCASE("valid row getter") {
|
|
||||||
bc.setInnerBC(bc_set, 0, 0);
|
|
||||||
bc.setInnerBC(bc_set, 1, 1);
|
|
||||||
|
|
||||||
bc_vec ret = bc.getInnerRow(0);
|
|
||||||
|
|
||||||
CHECK_EQ(ret[0].type, bc_set.type);
|
|
||||||
CHECK_EQ(ret[1].type, BC_UNSET);
|
|
||||||
|
|
||||||
ret = bc.getInnerRow(1);
|
|
||||||
|
|
||||||
CHECK_EQ(ret[0].type, BC_UNSET);
|
|
||||||
CHECK_EQ(ret[1].type, bc_set.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("valid col getter") {
|
|
||||||
bc.setInnerBC(bc_set, 0, 1);
|
|
||||||
bc.setInnerBC(bc_set, 1, 0);
|
|
||||||
|
|
||||||
bc_vec ret = bc.getInnerCol(0);
|
|
||||||
|
|
||||||
CHECK_EQ(ret[0].type, BC_UNSET);
|
|
||||||
CHECK_EQ(ret[1].type, bc_set.type);
|
|
||||||
|
|
||||||
ret = bc.getInnerCol(1);
|
|
||||||
|
|
||||||
CHECK_EQ(ret[0].type, bc_set.type);
|
|
||||||
CHECK_EQ(ret[1].type, BC_UNSET);
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("unset boundary condition") {
|
|
||||||
bc.setInnerBC(bc_set, 0, 0);
|
|
||||||
bc.setInnerBC(bc_set, 1, 1);
|
|
||||||
bc.unsetInnerBC(1, 1);
|
|
||||||
|
|
||||||
bc_vec ret = bc.getInnerRow(1);
|
|
||||||
|
|
||||||
CHECK_EQ(ret[0].type, BC_UNSET);
|
|
||||||
CHECK_EQ(ret[1].type, BC_UNSET);
|
|
||||||
|
|
||||||
ret = bc.getInnerCol(1);
|
|
||||||
|
|
||||||
CHECK_EQ(ret[0].type, BC_UNSET);
|
|
||||||
CHECK_EQ(ret[1].type, BC_UNSET);
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCASE("invalid row getter") { CHECK_THROWS(bc.getInnerRow(5)); }
|
|
||||||
|
|
||||||
SUBCASE("invalid col getter") { CHECK_THROWS(bc.getInnerCol(5)); }
|
|
||||||
}
|
|
||||||
@ -1,170 +0,0 @@
|
|||||||
#include <doctest/doctest.h>
|
|
||||||
#include <tug/BoundaryCondition.hpp>
|
|
||||||
#include <tug/Diffusion.hpp>
|
|
||||||
#include <tug/Solver.hpp>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
using namespace tug::bc;
|
|
||||||
using namespace tug::diffusion;
|
|
||||||
|
|
||||||
#define DIMENSION 2
|
|
||||||
#define N 51
|
|
||||||
#define M 51
|
|
||||||
#define MID 1300
|
|
||||||
|
|
||||||
static std::vector<double> alpha(N *M, 1e-3);
|
|
||||||
|
|
||||||
static TugInput setupDiffu() {
|
|
||||||
TugInput diffu;
|
|
||||||
|
|
||||||
diffu.setTimestep(1);
|
|
||||||
diffu.setGridCellN(N, M);
|
|
||||||
diffu.setDomainSize(N, M);
|
|
||||||
|
|
||||||
return diffu;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("closed boundaries - 1 concentration to 1 - rest 0") {
|
|
||||||
std::vector<double> field(N * M, 0);
|
|
||||||
|
|
||||||
field[MID] = 1;
|
|
||||||
|
|
||||||
BoundaryCondition bc(N, M);
|
|
||||||
|
|
||||||
TugInput diffu = setupDiffu();
|
|
||||||
|
|
||||||
uint32_t iterations = 1000;
|
|
||||||
double sum = 0;
|
|
||||||
|
|
||||||
for (int t = 0; t < iterations; t++) {
|
|
||||||
ADI_2D(diffu, field.data(), alpha.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
// iterate through rows
|
|
||||||
for (int i = 0; i < M; i++) {
|
|
||||||
// iterate through columns
|
|
||||||
for (int j = 0; j < N; j++) {
|
|
||||||
sum += field[i * N + j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CAPTURE(sum);
|
|
||||||
// epsilon of 1e-8
|
|
||||||
CHECK(sum == doctest::Approx(1).epsilon(1e-6));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("constant boundaries (0) - 1 concentration to 1 - rest 0") {
|
|
||||||
std::vector<double> field(N * M, 0);
|
|
||||||
|
|
||||||
field[MID] = 1;
|
|
||||||
|
|
||||||
BoundaryCondition bc(N, M);
|
|
||||||
|
|
||||||
boundary_condition input = {BC_TYPE_CONSTANT, 0};
|
|
||||||
|
|
||||||
bc.setSide(BC_SIDE_LEFT, input);
|
|
||||||
bc.setSide(BC_SIDE_RIGHT, input);
|
|
||||||
bc.setSide(BC_SIDE_TOP, input);
|
|
||||||
bc.setSide(BC_SIDE_BOTTOM, input);
|
|
||||||
|
|
||||||
TugInput diffu = setupDiffu();
|
|
||||||
diffu.setBoundaryCondition(bc);
|
|
||||||
|
|
||||||
uint32_t max_iterations = 20000;
|
|
||||||
bool reached = false;
|
|
||||||
|
|
||||||
int t = 0;
|
|
||||||
|
|
||||||
for (t = 0; t < max_iterations; t++) {
|
|
||||||
ADI_2D(diffu, field.data(), alpha.data());
|
|
||||||
|
|
||||||
if (field[N * M - 1] > 1e-15) {
|
|
||||||
reached = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!reached) {
|
|
||||||
CAPTURE(field[N * M - 1]);
|
|
||||||
FAIL_CHECK(
|
|
||||||
"Concentration did not reach boundaries after count of iterations: ",
|
|
||||||
t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE(
|
|
||||||
"constant top and bottom (1 and 0) - left and right closed - 0 inlet") {
|
|
||||||
std::vector<double> field(N * M, 0);
|
|
||||||
|
|
||||||
BoundaryCondition bc(N, M);
|
|
||||||
|
|
||||||
boundary_condition top =
|
|
||||||
BoundaryCondition::returnBoundaryCondition(BC_TYPE_CONSTANT, 1);
|
|
||||||
boundary_condition bottom =
|
|
||||||
BoundaryCondition::returnBoundaryCondition(BC_TYPE_CONSTANT, 0);
|
|
||||||
|
|
||||||
bc.setSide(BC_SIDE_TOP, top);
|
|
||||||
bc.setSide(BC_SIDE_BOTTOM, bottom);
|
|
||||||
|
|
||||||
TugInput diffu = setupDiffu();
|
|
||||||
diffu.setBoundaryCondition(bc);
|
|
||||||
|
|
||||||
uint32_t max_iterations = 100;
|
|
||||||
|
|
||||||
for (int t = 0; t < max_iterations; t++) {
|
|
||||||
ADI_2D(diffu, field.data(), alpha.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < N; i++) {
|
|
||||||
double above = field[i];
|
|
||||||
for (int j = 1; j < M; j++) {
|
|
||||||
double curr = field[j * N + i];
|
|
||||||
if (curr > above) {
|
|
||||||
CAPTURE(curr);
|
|
||||||
CAPTURE(above);
|
|
||||||
FAIL("Concentration below is greater than above @ cell ", j * N + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("2D closed boundaries, 1 constant cell in the middle") {
|
|
||||||
std::vector<double> field(N * M, 0);
|
|
||||||
double val = 1e-2;
|
|
||||||
|
|
||||||
BoundaryCondition bc(N, M);
|
|
||||||
|
|
||||||
field[MID] = val;
|
|
||||||
bc.setInnerBC({BC_TYPE_CONSTANT, val}, N / 2, M / 2);
|
|
||||||
|
|
||||||
TugInput diffu = setupDiffu();
|
|
||||||
diffu.setBoundaryCondition(bc);
|
|
||||||
|
|
||||||
uint32_t max_iterations = 100;
|
|
||||||
|
|
||||||
double sum = val;
|
|
||||||
|
|
||||||
for (int t = 0; t < max_iterations; t++) {
|
|
||||||
ADI_2D(diffu, field.data(), alpha.data());
|
|
||||||
|
|
||||||
CHECK_EQ(field[MID], val);
|
|
||||||
|
|
||||||
double new_sum = .0;
|
|
||||||
|
|
||||||
for (int i = 0; i < M; i++) {
|
|
||||||
// iterate through columns
|
|
||||||
for (int j = 0; j < N; j++) {
|
|
||||||
new_sum += field[i * N + j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sum > new_sum) {
|
|
||||||
CAPTURE(sum);
|
|
||||||
CAPTURE(new_sum);
|
|
||||||
FAIL("Sum of concentrations is equal or lower than to previous iteration "
|
|
||||||
"after iteration ",
|
|
||||||
t + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
sum = new_sum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user