mirror of
https://git.gfz-potsdam.de/naaice/tug.git
synced 2025-12-13 01:18:22 +01:00
BREAKING CHANGE: tug as header-only library
build: installation of library is now possible
This commit is contained in:
parent
0471f3d8f9
commit
8456f2212d
102
CMakeLists.txt
102
CMakeLists.txt
@ -1,49 +1,93 @@
|
||||
#debian stable (currently bullseye)
|
||||
# debian stable (currently bullseye)
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
|
||||
project(tug CXX)
|
||||
project(
|
||||
tug
|
||||
VERSION 0.4
|
||||
LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
find_package(Eigen3 REQUIRED NO_MODULE)
|
||||
find_package(OpenMP)
|
||||
# find_package(easy_profiler)
|
||||
# option(EASY_OPTION_LOG "Verbose easy_profiler" 1)
|
||||
|
||||
## SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -mfma")
|
||||
option(TUG_USE_OPENMP "Compile with OpenMP support" ON)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_GENERICOPT "-O3 -march=native" CACHE STRING
|
||||
"Flags used by the C++ compiler during opt builds."
|
||||
FORCE)
|
||||
# find_package(easy_profiler) option(EASY_OPTION_LOG "Verbose easy_profiler" 1)
|
||||
|
||||
set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING
|
||||
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel GenericOpt."
|
||||
FORCE)
|
||||
# SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -mfma")
|
||||
option(TUG_USE_OPENMP "Compile tug with OpenMP support" ON)
|
||||
|
||||
option(TUG_USE_UNSAFE_MATH_OPT
|
||||
"Use compiler options to break IEEE compliances by
|
||||
set(CMAKE_CXX_FLAGS_GENERICOPT
|
||||
"-O3 -march=native"
|
||||
CACHE STRING "Flags used by the C++ compiler during opt builds." FORCE)
|
||||
|
||||
set(CMAKE_BUILD_TYPE
|
||||
"${CMAKE_BUILD_TYPE}"
|
||||
CACHE
|
||||
STRING
|
||||
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel GenericOpt."
|
||||
FORCE)
|
||||
|
||||
option(
|
||||
TUG_USE_UNSAFE_MATH_OPT "Use compiler options to break IEEE compliances by
|
||||
oenabling reordering of instructions when adding/multiplying of floating
|
||||
points."
|
||||
OFF)
|
||||
points." OFF)
|
||||
|
||||
if(TUG_USE_UNSAFE_MATH_OPT)
|
||||
add_compile_options(-ffast-math)
|
||||
|
||||
option(TUG_ENABLE_TESTING "Run tests after succesfull compilation" OFF)
|
||||
|
||||
option(TUG_HANNESPHILIPP_EXAMPLES "Compile example applications" OFF)
|
||||
|
||||
option(TUG_NAAICE_EXAMPLE "Enables NAAICE examples with export of CSV files"
|
||||
OFF)
|
||||
|
||||
add_library(tug INTERFACE)
|
||||
target_include_directories(
|
||||
tug INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||
|
||||
target_link_libraries(tug INTERFACE Eigen3::Eigen)
|
||||
|
||||
target_compile_features(tug INTERFACE cxx_std_17)
|
||||
|
||||
if(TUG_USE_OPENMP AND OpenMP_CXX_FOUND)
|
||||
target_link_libraries(tug INTERFACE OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
|
||||
option(TUG_ENABLE_TESTING
|
||||
"Run tests after succesfull compilation"
|
||||
OFF)
|
||||
if(TUG_USE_UNSAFE_MATH_OPT)
|
||||
target_compile_options(tug INTERFACE -ffast-math)
|
||||
endif()
|
||||
|
||||
option(TUG_HANNESPHILIPP_EXAMPLES
|
||||
"Compile example applications"
|
||||
OFF)
|
||||
install(
|
||||
TARGETS tug
|
||||
EXPORT ${PROJECT_NAME}_Targets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
option(TUG_NAAICE_EXAMPLE
|
||||
"Enables NAAICE examples with export of CSV files"
|
||||
OFF)
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file(
|
||||
"tugConfigVersion.cmake"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
|
||||
add_subdirectory(src)
|
||||
configure_package_config_file(
|
||||
"${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in"
|
||||
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake)
|
||||
|
||||
install(
|
||||
EXPORT ${PROJECT_NAME}_Targets
|
||||
FILE ${PROJECT_NAME}Targets.cmake
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake)
|
||||
|
||||
install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake)
|
||||
|
||||
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/tug DESTINATION include)
|
||||
|
||||
if(TUG_ENABLE_TESTING)
|
||||
add_subdirectory(test)
|
||||
@ -53,6 +97,6 @@ if(TUG_HANNESPHILIPP_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
if (TUG_NAAICE_EXAMPLE)
|
||||
if(TUG_NAAICE_EXAMPLE)
|
||||
add_subdirectory(naaice)
|
||||
endif()
|
||||
|
||||
4
cmake/tugConfig.cmake.in
Normal file
4
cmake/tugConfig.cmake.in
Normal file
@ -0,0 +1,4 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||
check_required_components("@PROJECT_NAME@")
|
||||
@ -1,4 +1,8 @@
|
||||
Boundary
|
||||
========
|
||||
|
||||
.. doxygenclass:: Boundary
|
||||
.. doxygenenum:: tug::BC_TYPE
|
||||
.. doxygenenum:: tug::BC_SIDE
|
||||
|
||||
.. doxygenclass:: tug::Boundary
|
||||
.. doxygenclass:: tug::BoundaryElement
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
Grid
|
||||
====
|
||||
|
||||
.. doxygenclass:: Grid
|
||||
.. doxygenclass:: tug::Grid
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
Simulation
|
||||
==========
|
||||
|
||||
.. doxygenclass:: Simulation
|
||||
.. doxygenenum:: tug::APPROACH
|
||||
.. doxygenenum:: tug::SOLVER
|
||||
.. doxygenenum:: tug::CSV_OUTPUT
|
||||
.. doxygenenum:: tug::CONSOLE_OUTPUT
|
||||
.. doxygenenum:: tug::TIME_MEASURE
|
||||
|
||||
.. doxygenclass:: tug::Simulation
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
Developper API
|
||||
==============
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 41 KiB |
@ -12,4 +12,4 @@ Numerical Solver
|
||||
**Backward Time-Centered Space (BTCS) Method**
|
||||
|
||||
|
||||
**Forward Time-Centered Space (BTCS) Method**
|
||||
**Forward Time-Centered Space (FTCS) Method**
|
||||
|
||||
@ -3,7 +3,6 @@ User API
|
||||
|
||||
.. toctree::
|
||||
|
||||
:maxdepth: 2
|
||||
Grid
|
||||
Boundary
|
||||
Simulation
|
||||
Simulation
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include <tug/Simulation.hpp>
|
||||
|
||||
using namespace Eigen;
|
||||
using namespace tug;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// **************
|
||||
@ -31,8 +32,7 @@ int main(int argc, char *argv[]) {
|
||||
// ************************
|
||||
|
||||
// set up a simulation environment
|
||||
Simulation simulation =
|
||||
Simulation(grid, bc, BTCS_APPROACH); // grid,boundary,simulation-approach
|
||||
Simulation simulation = Simulation(grid, bc); // grid,boundary
|
||||
|
||||
// set the timestep of the simulation
|
||||
simulation.setTimestep(0.1); // timestep
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include <tug/Simulation.hpp>
|
||||
|
||||
using namespace Eigen;
|
||||
using namespace tug;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// EASY_PROFILER_ENABLE;
|
||||
@ -61,7 +62,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// set up a simulation environment
|
||||
Simulation simulation =
|
||||
Simulation(grid, bc, BTCS_APPROACH); // grid,boundary,simulation-approach
|
||||
Simulation(grid, bc); // grid,boundary
|
||||
|
||||
// set the timestep of the simulation
|
||||
simulation.setTimestep(0.1); // timestep
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include <tug/Simulation.hpp>
|
||||
|
||||
using namespace Eigen;
|
||||
using namespace tug;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int row = 20;
|
||||
@ -18,7 +19,8 @@ int main(int argc, char *argv[]) {
|
||||
bc.setBoundarySideClosed(BC_SIDE_TOP);
|
||||
bc.setBoundarySideClosed(BC_SIDE_BOTTOM);
|
||||
|
||||
Simulation simulation = Simulation(grid, bc, CRANK_NICOLSON_APPROACH);
|
||||
Simulation simulation =
|
||||
Simulation<double, tug::CRANK_NICOLSON_APPROACH>(grid, bc);
|
||||
simulation.setTimestep(0.1);
|
||||
simulation.setIterations(50);
|
||||
simulation.setOutputCSV(CSV_OUTPUT_XTREME);
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include <tug/Simulation.hpp>
|
||||
|
||||
using namespace Eigen;
|
||||
using namespace tug;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// **************
|
||||
@ -31,7 +32,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// set up a simulation environment
|
||||
Simulation simulation =
|
||||
Simulation(grid, bc, FTCS_APPROACH); // grid,boundary,simulation-approach
|
||||
Simulation<double, tug::FTCS_APPROACH>(grid, bc); // grid,boundary,simulation-approach
|
||||
|
||||
// (optional) set the timestep of the simulation
|
||||
simulation.setTimestep(0.1); // timestep
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#include <tug/Simulation.hpp>
|
||||
|
||||
using namespace Eigen;
|
||||
using namespace tug;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
@ -69,7 +70,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// set up a simulation environment
|
||||
Simulation simulation =
|
||||
Simulation(grid, bc, FTCS_APPROACH); // grid,boundary,simulation-approach
|
||||
Simulation<double, FTCS_APPROACH>(grid, bc); // grid,boundary,simulation-approach
|
||||
|
||||
// set the timestep of the simulation
|
||||
simulation.setTimestep(10000); // timestep
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include <tug/Simulation.hpp>
|
||||
|
||||
using namespace Eigen;
|
||||
using namespace tug;
|
||||
// #include <easy/profiler.h>
|
||||
// #define EASY_PROFILER_ENABLE ::profiler::setEnabled(true);
|
||||
|
||||
@ -67,7 +68,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// set up a simulation environment
|
||||
Simulation simulation =
|
||||
Simulation(grid, bc, FTCS_APPROACH); // grid,boundary,simulation-approach
|
||||
Simulation<double, tug::FTCS_APPROACH>(grid, bc); // grid,boundary,simulation-approach
|
||||
|
||||
// set the timestep of the simulation
|
||||
simulation.setTimestep(0.1); // timestep
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include <tug/Simulation.hpp>
|
||||
|
||||
using namespace Eigen;
|
||||
using namespace tug;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
@ -60,7 +61,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// set up a simulation environment
|
||||
Simulation simulation =
|
||||
Simulation(grid, bc, FTCS_APPROACH); // grid,boundary,simulation-approach
|
||||
Simulation<double, tug::FTCS_APPROACH>(grid, bc); // grid,boundary,simulation-approach
|
||||
|
||||
// (optional) set the timestep of the simulation
|
||||
simulation.setTimestep(1000); // timestep
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
using namespace tug;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
@ -39,8 +40,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
Boundary bc = Boundary(grid);
|
||||
|
||||
Simulation sim = Simulation(grid, bc, BTCS_APPROACH);
|
||||
sim.setSolver(THOMAS_ALGORITHM_SOLVER);
|
||||
Simulation sim = Simulation(grid, bc);
|
||||
|
||||
if (argc == 2) {
|
||||
int numThreads = atoi(argv[1]);
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
using namespace tug;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
@ -39,8 +40,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
Boundary bc = Boundary(grid);
|
||||
|
||||
Simulation sim = Simulation(grid, bc, BTCS_APPROACH);
|
||||
sim.setSolver(THOMAS_ALGORITHM_SOLVER);
|
||||
Simulation sim = Simulation(grid, bc);
|
||||
|
||||
if (argc == 2) {
|
||||
int numThreads = atoi(argv[1]);
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
using namespace tug;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int row = 50;
|
||||
@ -41,7 +42,7 @@ int main(int argc, char *argv[]) {
|
||||
Boundary bc = Boundary(grid);
|
||||
|
||||
// Simulation
|
||||
Simulation sim = Simulation(grid, bc, FTCS_APPROACH);
|
||||
Simulation sim = Simulation<double, tug::FTCS_APPROACH>(grid, bc);
|
||||
sim.setTimestep(0.001);
|
||||
sim.setIterations(10000);
|
||||
sim.setOutputCSV(CSV_OUTPUT_OFF);
|
||||
|
||||
@ -30,6 +30,8 @@ enum BC_SIDE { BC_SIDE_LEFT, BC_SIDE_RIGHT, BC_SIDE_TOP, BC_SIDE_BOTTOM };
|
||||
* This class defines the boundary conditions of individual boundary elements.
|
||||
* These can be flexibly used and combined later in other classes.
|
||||
* The class serves as an auxiliary class for structuring the Boundary class.
|
||||
*
|
||||
* @tparam T Data type of the boundary condition element
|
||||
*/
|
||||
template <class T> class BoundaryElement {
|
||||
public:
|
||||
@ -82,7 +84,7 @@ public:
|
||||
* @brief Return the type of the boundary condition, i.e. whether the
|
||||
* boundary is considered closed or constant.
|
||||
*
|
||||
* @return BC_TYPE Type of boundary condition, either BC_TYPE_CLOSED or
|
||||
* @return Type of boundary condition, either BC_TYPE_CLOSED or
|
||||
BC_TYPE_CONSTANT.
|
||||
*/
|
||||
BC_TYPE getType() const { return this->type; }
|
||||
@ -90,7 +92,7 @@ public:
|
||||
/**
|
||||
* @brief Return the concentration value for the constant boundary condition.
|
||||
*
|
||||
* @return double Value of the concentration.
|
||||
* @return Value of the concentration.
|
||||
*/
|
||||
T getValue() const { return this->value; }
|
||||
|
||||
@ -102,6 +104,8 @@ private:
|
||||
/**
|
||||
* This class implements the functionality and management of the boundary
|
||||
* conditions in the grid to be simulated.
|
||||
*
|
||||
* @tparam Data type of the boundary condition value
|
||||
*/
|
||||
template <class T> class Boundary {
|
||||
public:
|
||||
@ -227,7 +231,7 @@ public:
|
||||
*
|
||||
* @param side Boundary side from which the boundary conditions are to be
|
||||
* returned.
|
||||
* @return vector<BoundaryElement<T>> Contains the boundary conditions as
|
||||
* @return Contains the boundary conditions as
|
||||
* BoundaryElement<T> objects.
|
||||
*/
|
||||
const std::vector<BoundaryElement<T>> &getBoundarySide(BC_SIDE side) const {
|
||||
@ -246,7 +250,7 @@ public:
|
||||
specific boundary is closed.
|
||||
*
|
||||
* @param side Boundary side for which the values are to be returned.
|
||||
* @return VectorX<T> Vector with values as T.
|
||||
* @return Vector with values as T.
|
||||
*/
|
||||
Eigen::VectorX<T> getBoundarySideValues(BC_SIDE side) const {
|
||||
const std::size_t length = boundaries[side].size();
|
||||
@ -271,7 +275,7 @@ public:
|
||||
* @param index Index of the boundary element on the corresponding
|
||||
* boundary side. Must index an element of the corresponding
|
||||
* side.
|
||||
* @return BoundaryElement<T> Boundary condition as a BoundaryElement<T>
|
||||
* @return Boundary condition as a BoundaryElement<T>
|
||||
* object.
|
||||
*/
|
||||
BoundaryElement<T> getBoundaryElement(BC_SIDE side, int index) const {
|
||||
@ -290,7 +294,7 @@ public:
|
||||
* @param index Index of the boundary element on the corresponding
|
||||
* boundary side. Must index an element of the corresponding
|
||||
side.
|
||||
* @return BC_TYPE Boundary Type of the corresponding boundary condition.
|
||||
* @return Boundary Type of the corresponding boundary condition.
|
||||
*/
|
||||
BC_TYPE getBoundaryElementType(BC_SIDE side, int index) const {
|
||||
if ((boundaries[side].size() < index) || index < 0) {
|
||||
@ -309,7 +313,7 @@ public:
|
||||
* @param index Index of the boundary element on the corresponding
|
||||
* boundary side. Must index an element of the corresponding
|
||||
* side.
|
||||
* @return double Concentration of the corresponding BoundaryElement<T>
|
||||
* @return Concentration of the corresponding BoundaryElement<T>
|
||||
* object.
|
||||
*/
|
||||
T getBoundaryElementValue(BC_SIDE side, int index) const {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file BTCSv2.cpp
|
||||
* @file BTCS.hpp
|
||||
* @brief Implementation of heterogenous BTCS (backward time-centered space)
|
||||
* solution of diffusion equation in 1D and 2D space. Internally the
|
||||
* alternating-direction implicit (ADI) method is used. Version 2, because
|
||||
@ -7,10 +7,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Schemes.hpp"
|
||||
#ifndef BTCS_H_
|
||||
#define BTCS_H_
|
||||
|
||||
#include "TugUtils.hpp"
|
||||
|
||||
#include <Eigen/src/Core/util/Meta.h>
|
||||
#include <cstddef>
|
||||
#include <tug/Boundary.hpp>
|
||||
#include <tug/Grid.hpp>
|
||||
@ -428,14 +429,6 @@ void BTCS_Thomas(Grid<T> &grid, Boundary<T> &bc, T timestep, int numThreads) {
|
||||
"Error: Only 1- and 2-dimensional grids are defined!");
|
||||
}
|
||||
}
|
||||
|
||||
template void BTCS_Thomas(Grid<double> &grid, Boundary<double> &bc,
|
||||
double timestep, int numThreads);
|
||||
template void BTCS_Thomas(Grid<float> &grid, Boundary<float> &bc,
|
||||
float timestep, int numThreads);
|
||||
|
||||
template void BTCS_LU(Grid<double> &grid, Boundary<double> &bc, double timestep,
|
||||
int numThreads);
|
||||
template void BTCS_LU(Grid<float> &grid, Boundary<float> &bc, float timestep,
|
||||
int numThreads);
|
||||
} // namespace tug
|
||||
|
||||
#endif // BTCS_H_
|
||||
@ -1,11 +1,13 @@
|
||||
/**
|
||||
* @file FTCS.cpp
|
||||
* @file FTCS.hpp
|
||||
* @brief Implementation of heterogenous FTCS (forward time-centered space)
|
||||
* solution of diffusion equation in 1D and 2D space.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Schemes.hpp"
|
||||
#ifndef FTCS_H_
|
||||
#define FTCS_H_
|
||||
|
||||
#include "TugUtils.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
@ -397,9 +399,6 @@ void FTCS(Grid<T> &grid, Boundary<T> &bc, T timestep, int &numThreads) {
|
||||
"Error: Only 1- and 2-dimensional grids are defined!");
|
||||
}
|
||||
}
|
||||
|
||||
template void FTCS(Grid<double> &grid, Boundary<double> &bc, double timestep,
|
||||
int &numThreads);
|
||||
template void FTCS(Grid<float> &grid, Boundary<float> &bc, float timestep,
|
||||
int &numThreads);
|
||||
} // namespace tug
|
||||
|
||||
#endif // FTCS_H_
|
||||
@ -14,6 +14,12 @@
|
||||
|
||||
namespace tug {
|
||||
|
||||
/**
|
||||
* @brief Holds a matrix with concenctration and respective matrix/matrices of
|
||||
* alpha coefficients.
|
||||
*
|
||||
* @tparam T Type to be used for matrices, e.g. double or float
|
||||
*/
|
||||
template <class T> class Grid {
|
||||
public:
|
||||
/**
|
||||
@ -31,10 +37,11 @@ public:
|
||||
}
|
||||
|
||||
this->dim = 1;
|
||||
this->deltaCol = double(this->domainCol) / double(this->col); // -> 1
|
||||
this->deltaCol =
|
||||
static_cast<T>(this->domainCol) / static_cast<T>(this->col); // -> 1
|
||||
|
||||
this->concentrations = Eigen::MatrixXd::Constant(1, col, MAT_INIT_VAL);
|
||||
this->alphaX = Eigen::MatrixXd::Constant(1, col, MAT_INIT_VAL);
|
||||
this->concentrations = Eigen::MatrixX<T>::Constant(1, col, MAT_INIT_VAL);
|
||||
this->alphaX = Eigen::MatrixX<T>::Constant(1, col, MAT_INIT_VAL);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,8 +63,10 @@ public:
|
||||
}
|
||||
|
||||
this->dim = 2;
|
||||
this->deltaRow = double(this->domainRow) / double(this->row); // -> 1
|
||||
this->deltaCol = double(this->domainCol) / double(this->col); // -> 1
|
||||
this->deltaRow =
|
||||
static_cast<T>(this->domainRow) / static_cast<T>(this->row); // -> 1
|
||||
this->deltaCol =
|
||||
static_cast<T>(this->domainCol) / static_cast<T>(this->col); // -> 1
|
||||
|
||||
this->concentrations = Eigen::MatrixX<T>::Constant(row, col, MAT_INIT_VAL);
|
||||
this->alphaX = Eigen::MatrixX<T>::Constant(row, col, MAT_INIT_VAL);
|
||||
@ -84,7 +93,7 @@ public:
|
||||
/**
|
||||
* @brief Gets the concentrations matrix for a Grid.
|
||||
*
|
||||
* @return MatrixX<T> An Eigen3 matrix holding the concentrations and having
|
||||
* @return An Eigen3 matrix holding the concentrations and having
|
||||
* the same dimensions as the grid.
|
||||
*/
|
||||
const Eigen::MatrixX<T> &getConcentrations() { return this->concentrations; }
|
||||
@ -145,7 +154,7 @@ public:
|
||||
* @brief Gets the matrix of alpha coefficients of a 1D-Grid. Grid must be one
|
||||
* dimensional.
|
||||
*
|
||||
* @return MatrixX<T> A matrix with 1 row holding the alpha coefficients.
|
||||
* @return A matrix with 1 row holding the alpha coefficients.
|
||||
*/
|
||||
const Eigen::MatrixX<T> &getAlpha() const {
|
||||
if (dim != 1) {
|
||||
@ -161,7 +170,7 @@ public:
|
||||
* @brief Gets the matrix of alpha coefficients in x-direction of a 2D-Grid.
|
||||
* Grid must be two dimensional.
|
||||
*
|
||||
* @return MatrixX<T> A matrix holding the alpha coefficients in x-direction.
|
||||
* @return A matrix holding the alpha coefficients in x-direction.
|
||||
*/
|
||||
const Eigen::MatrixX<T> &getAlphaX() const {
|
||||
|
||||
@ -177,7 +186,7 @@ public:
|
||||
* @brief Gets the matrix of alpha coefficients in y-direction of a 2D-Grid.
|
||||
* Grid must be two dimensional.
|
||||
*
|
||||
* @return MatrixX<T> A matrix holding the alpha coefficients in y-direction.
|
||||
* @return A matrix holding the alpha coefficients in y-direction.
|
||||
*/
|
||||
const Eigen::MatrixX<T> &getAlphaY() const {
|
||||
|
||||
@ -192,14 +201,14 @@ public:
|
||||
/**
|
||||
* @brief Gets the dimensions of the grid.
|
||||
*
|
||||
* @return int Dimensions, either 1 or 2.
|
||||
* @return Dimensions, either 1 or 2.
|
||||
*/
|
||||
int getDim() const { return this->dim; }
|
||||
|
||||
/**
|
||||
* @brief Gets length of 1D grid. Must be one dimensional grid.
|
||||
*
|
||||
* @return int Length of 1D grid.
|
||||
* @return Length of 1D grid.
|
||||
*/
|
||||
int getLength() const {
|
||||
if (dim != 1) {
|
||||
@ -214,14 +223,14 @@ public:
|
||||
/**
|
||||
* @brief Gets the number of rows of the grid.
|
||||
*
|
||||
* @return int Number of rows.
|
||||
* @return Number of rows.
|
||||
*/
|
||||
int getRow() const { return this->row; }
|
||||
|
||||
/**
|
||||
* @brief Gets the number of columns of the grid.
|
||||
*
|
||||
* @return int Number of columns.
|
||||
* @return Number of columns.
|
||||
*/
|
||||
int getCol() const { return this->col; }
|
||||
|
||||
@ -271,7 +280,7 @@ public:
|
||||
/**
|
||||
* @brief Gets the delta value for 1D-Grid. Grid must be one dimensional.
|
||||
*
|
||||
* @return double Delta value.
|
||||
* @return Delta value.
|
||||
*/
|
||||
T getDelta() const {
|
||||
|
||||
@ -287,14 +296,14 @@ public:
|
||||
/**
|
||||
* @brief Gets the delta value in x-direction.
|
||||
*
|
||||
* @return double Delta value in x-direction.
|
||||
* @return Delta value in x-direction.
|
||||
*/
|
||||
T getDeltaCol() const { return this->deltaCol; }
|
||||
|
||||
/**
|
||||
* @brief Gets the delta value in y-direction. Must be two dimensional grid.
|
||||
*
|
||||
* @return double Delta value in y-direction.
|
||||
* @return Delta value in y-direction.
|
||||
*/
|
||||
T getDeltaRow() const {
|
||||
if (dim != 2) {
|
||||
@ -318,7 +327,7 @@ private:
|
||||
Eigen::MatrixX<T> alphaX; // Matrix holding alpha coefficients in x-direction
|
||||
Eigen::MatrixX<T> alphaY; // Matrix holding alpha coefficients in y-direction
|
||||
|
||||
static constexpr double MAT_INIT_VAL = 0;
|
||||
static constexpr T MAT_INIT_VAL = 0;
|
||||
};
|
||||
|
||||
using Grid64 = Grid<double>;
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
#include "Boundary.hpp"
|
||||
#include "Grid.hpp"
|
||||
#include <exception>
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
@ -19,6 +19,10 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Core/BTCS.hpp"
|
||||
#include "Core/FTCS.hpp"
|
||||
#include "Core/TugUtils.hpp"
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#else
|
||||
@ -28,13 +32,13 @@
|
||||
namespace tug {
|
||||
|
||||
/**
|
||||
* @brief Enum defining the two implemented solution approaches.
|
||||
* @brief Enum defining the implemented solution approaches.
|
||||
*
|
||||
*/
|
||||
enum APPROACH {
|
||||
FTCS_APPROACH, // Forward Time-Centered Space
|
||||
BTCS_APPROACH, // Backward Time-Centered Space solved with EigenLU solver
|
||||
CRANK_NICOLSON_APPROACH
|
||||
FTCS_APPROACH, /*!< Forward Time-Centered Space */
|
||||
BTCS_APPROACH, /*!< Backward Time-Centered Space */
|
||||
CRANK_NICOLSON_APPROACH /*!< Crank-Nicolson method */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -42,9 +46,9 @@ enum APPROACH {
|
||||
*
|
||||
*/
|
||||
enum SOLVER {
|
||||
EIGEN_LU_SOLVER, // EigenLU solver
|
||||
THOMAS_ALGORITHM_SOLVER // Thomas Algorithm solver; more efficient for
|
||||
// tridiagonal matrices
|
||||
EIGEN_LU_SOLVER, /*!< EigenLU solver */
|
||||
THOMAS_ALGORITHM_SOLVER /*!< Thomas Algorithm solver; more efficient for
|
||||
tridiagonal matrices */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -52,11 +56,11 @@ enum SOLVER {
|
||||
*
|
||||
*/
|
||||
enum CSV_OUTPUT {
|
||||
CSV_OUTPUT_OFF, // do not produce csv output
|
||||
CSV_OUTPUT_ON, // produce csv output with last concentration matrix
|
||||
CSV_OUTPUT_VERBOSE, // produce csv output with all concentration matrices
|
||||
CSV_OUTPUT_XTREME // csv output like VERBOSE but additional boundary
|
||||
// conditions at beginning
|
||||
CSV_OUTPUT_OFF, /*!< do not produce csv output */
|
||||
CSV_OUTPUT_ON, /*!< produce csv output with last concentration matrix */
|
||||
CSV_OUTPUT_VERBOSE, /*!< produce csv output with all concentration matrices */
|
||||
CSV_OUTPUT_XTREME /*!< csv output like VERBOSE but additional boundary
|
||||
conditions at beginning */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -64,9 +68,9 @@ enum CSV_OUTPUT {
|
||||
*
|
||||
*/
|
||||
enum CONSOLE_OUTPUT {
|
||||
CONSOLE_OUTPUT_OFF, // do not print any output to console
|
||||
CONSOLE_OUTPUT_ON, // print before and after concentrations to console
|
||||
CONSOLE_OUTPUT_VERBOSE // print all concentration matrices to console
|
||||
CONSOLE_OUTPUT_OFF, /*!< do not print any output to console */
|
||||
CONSOLE_OUTPUT_ON, /*!< print before and after concentrations to console */
|
||||
CONSOLE_OUTPUT_VERBOSE /*!< print all concentration matrices to console */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -74,8 +78,8 @@ enum CONSOLE_OUTPUT {
|
||||
*
|
||||
*/
|
||||
enum TIME_MEASURE {
|
||||
TIME_MEASURE_OFF, // do not print any time measures
|
||||
TIME_MEASURE_ON // print time measure after last iteration
|
||||
TIME_MEASURE_OFF, /*!< do not print any time measures */
|
||||
TIME_MEASURE_ON /*!< print time measure after last iteration */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -83,9 +87,14 @@ enum TIME_MEASURE {
|
||||
* and contains all the methods for controlling the desired parameters, such as
|
||||
* time step, number of simulations, etc.
|
||||
*
|
||||
* @tparam T the type of the internal data structures for grid, boundary
|
||||
* condition and timestep
|
||||
* @tparam approach Set the SLE scheme to be used
|
||||
* @tparam solver Set the solver to be used
|
||||
*/
|
||||
|
||||
template <class T> class Simulation {
|
||||
template <class T, APPROACH approach = BTCS_APPROACH,
|
||||
SOLVER solver = THOMAS_ALGORITHM_SOLVER>
|
||||
class Simulation {
|
||||
public:
|
||||
/**
|
||||
* @brief Set up a simulation environment. The timestep and number of
|
||||
@ -99,8 +108,7 @@ public:
|
||||
* @param bc Valid boundary condition object
|
||||
* @param approach Approach to solving the problem. Either FTCS or BTCS.
|
||||
*/
|
||||
Simulation(Grid<T> &_grid, Boundary<T> &_bc, APPROACH _approach)
|
||||
: grid(_grid), bc(_bc), approach(_approach){};
|
||||
Simulation(Grid<T> &_grid, Boundary<T> &_bc) : grid(_grid), bc(_bc){};
|
||||
|
||||
/**
|
||||
* @brief Set the option to output the results to a CSV file. Off by default.
|
||||
@ -169,7 +177,65 @@ public:
|
||||
*
|
||||
* @param timestep Valid timestep greater than zero.
|
||||
*/
|
||||
void setTimestep(T timestep);
|
||||
void setTimestep(T timestep) {
|
||||
if (timestep <= 0) {
|
||||
throw_invalid_argument("Timestep has to be greater than zero.");
|
||||
}
|
||||
|
||||
if constexpr (approach == FTCS_APPROACH ||
|
||||
approach == CRANK_NICOLSON_APPROACH) {
|
||||
T cfl;
|
||||
if (grid.getDim() == 1) {
|
||||
|
||||
const T deltaSquare = grid.getDelta();
|
||||
const T maxAlpha = grid.getAlpha().maxCoeff();
|
||||
|
||||
// Courant-Friedrichs-Lewy condition
|
||||
cfl = deltaSquare / (4 * maxAlpha);
|
||||
} else if (grid.getDim() == 2) {
|
||||
const T deltaColSquare = grid.getDeltaCol() * grid.getDeltaCol();
|
||||
// will be 0 if 1D, else ...
|
||||
const T deltaRowSquare = grid.getDeltaRow() * grid.getDeltaRow();
|
||||
const T minDeltaSquare = std::min(deltaColSquare, deltaRowSquare);
|
||||
|
||||
const T maxAlpha =
|
||||
std::min(grid.getAlphaX().maxCoeff(), grid.getAlphaY().maxCoeff());
|
||||
|
||||
cfl = minDeltaSquare / (4 * maxAlpha);
|
||||
}
|
||||
const std::string dim = std::to_string(grid.getDim()) + "D";
|
||||
|
||||
const std::string &approachPrefix = this->approach_names[approach];
|
||||
std::cout << approachPrefix << "_" << dim << " :: CFL condition: " << cfl
|
||||
<< std::endl;
|
||||
std::cout << approachPrefix << "_" << dim
|
||||
<< " :: required dt=" << timestep << std::endl;
|
||||
|
||||
if (timestep > cfl) {
|
||||
|
||||
this->innerIterations = (int)ceil(timestep / cfl);
|
||||
this->timestep = timestep / (double)innerIterations;
|
||||
|
||||
std::cerr << "Warning :: Timestep was adjusted, because of stability "
|
||||
"conditions. Time duration was approximately preserved by "
|
||||
"adjusting internal number of iterations."
|
||||
<< std::endl;
|
||||
std::cout << approachPrefix << "_" << dim << " :: Required "
|
||||
<< this->innerIterations
|
||||
<< " inner iterations with dt=" << this->timestep
|
||||
<< std::endl;
|
||||
|
||||
} else {
|
||||
|
||||
this->timestep = timestep;
|
||||
std::cout << approachPrefix << "_" << dim
|
||||
<< " :: No inner iterations required, dt=" << timestep
|
||||
<< std::endl;
|
||||
}
|
||||
} else {
|
||||
this->timestep = timestep;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Currently set time step is returned.
|
||||
@ -192,25 +258,6 @@ public:
|
||||
this->iterations = 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) {
|
||||
if (this->approach == FTCS_APPROACH) {
|
||||
std::cerr
|
||||
<< "Warning: Solver was set, but FTCS approach initialized. Setting "
|
||||
"the solver "
|
||||
"is thus without effect."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
this->solver = solver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the number of desired openMP Threads.
|
||||
*
|
||||
@ -327,7 +374,117 @@ public:
|
||||
* @brief Method starts the simulation process with the previously set
|
||||
* parameters.
|
||||
*/
|
||||
void run();
|
||||
void run() {
|
||||
if (this->timestep == -1) {
|
||||
throw_invalid_argument("Timestep is not set!");
|
||||
}
|
||||
if (this->iterations == -1) {
|
||||
throw_invalid_argument("Number of iterations are not set!");
|
||||
}
|
||||
|
||||
std::string filename;
|
||||
if (this->console_output > CONSOLE_OUTPUT_OFF) {
|
||||
printConcentrationsConsole();
|
||||
}
|
||||
if (this->csv_output > CSV_OUTPUT_OFF) {
|
||||
filename = createCSVfile();
|
||||
}
|
||||
|
||||
auto begin = std::chrono::high_resolution_clock::now();
|
||||
|
||||
if constexpr (approach == FTCS_APPROACH) { // FTCS case
|
||||
|
||||
for (int i = 0; i < iterations * innerIterations; i++) {
|
||||
if (console_output == CONSOLE_OUTPUT_VERBOSE && i > 0) {
|
||||
printConcentrationsConsole();
|
||||
}
|
||||
if (csv_output >= CSV_OUTPUT_VERBOSE) {
|
||||
printConcentrationsCSV(filename);
|
||||
}
|
||||
|
||||
FTCS(this->grid, this->bc, this->timestep, this->numThreads);
|
||||
|
||||
// if (i % (iterations * innerIterations / 100) == 0) {
|
||||
// double percentage = (double)i / ((double)iterations *
|
||||
// (double)innerIterations) * 100; if ((int)percentage % 10 == 0) {
|
||||
// cout << "Progress: " << percentage << "%" << endl;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
} else if constexpr (approach == BTCS_APPROACH) { // BTCS case
|
||||
|
||||
if constexpr (solver == EIGEN_LU_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_LU(this->grid, this->bc, this->timestep, this->numThreads);
|
||||
}
|
||||
} else if constexpr (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, this->numThreads);
|
||||
}
|
||||
}
|
||||
|
||||
} else if constexpr (approach ==
|
||||
CRANK_NICOLSON_APPROACH) { // Crank-Nicolson case
|
||||
|
||||
constexpr T beta = 0.5;
|
||||
|
||||
// TODO this implementation is very inefficient!
|
||||
// a separate implementation that sets up a specific tridiagonal matrix
|
||||
// for Crank-Nicolson would be better
|
||||
Eigen::MatrixX<T> concentrations;
|
||||
Eigen::MatrixX<T> concentrationsFTCS;
|
||||
Eigen::MatrixX<T> concentrationsResult;
|
||||
for (int i = 0; i < iterations * innerIterations; i++) {
|
||||
if (console_output == CONSOLE_OUTPUT_VERBOSE && i > 0) {
|
||||
printConcentrationsConsole();
|
||||
}
|
||||
if (csv_output >= CSV_OUTPUT_VERBOSE) {
|
||||
printConcentrationsCSV(filename);
|
||||
}
|
||||
|
||||
concentrations = grid.getConcentrations();
|
||||
FTCS(this->grid, this->bc, this->timestep, this->numThreads);
|
||||
concentrationsFTCS = grid.getConcentrations();
|
||||
grid.setConcentrations(concentrations);
|
||||
BTCS_Thomas(this->grid, this->bc, this->timestep, this->numThreads);
|
||||
concentrationsResult =
|
||||
beta * concentrationsFTCS + (1 - beta) * grid.getConcentrations();
|
||||
grid.setConcentrations(concentrationsResult);
|
||||
}
|
||||
}
|
||||
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
auto milliseconds =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
|
||||
|
||||
if (this->console_output > CONSOLE_OUTPUT_OFF) {
|
||||
printConcentrationsConsole();
|
||||
}
|
||||
if (this->csv_output > CSV_OUTPUT_OFF) {
|
||||
printConcentrationsCSV(filename);
|
||||
}
|
||||
if (this->time_measure > TIME_MEASURE_OFF) {
|
||||
const std::string &approachString = this->approach_names[approach];
|
||||
const std::string dimString = std::to_string(grid.getDim()) + "D";
|
||||
std::cout << approachString << dimString << ":: run() finished in "
|
||||
<< milliseconds.count() << "ms" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
T timestep{-1};
|
||||
@ -340,8 +497,6 @@ private:
|
||||
|
||||
Grid<T> &grid;
|
||||
Boundary<T> &bc;
|
||||
APPROACH approach;
|
||||
SOLVER solver{THOMAS_ALGORITHM_SOLVER};
|
||||
|
||||
const std::vector<std::string> approach_names = {"FTCS", "BTCS", "CRNI"};
|
||||
};
|
||||
|
||||
@ -121,7 +121,8 @@ int main(int argc, char *argv[]) {
|
||||
Eigen::MatrixXd alphax = rmVecTocmMatrix(alphax_vec, row, col);
|
||||
|
||||
constexpr double alphay_val = 5e-10;
|
||||
Eigen::MatrixXd alphay = Eigen::MatrixXd::Constant(row, col, alphay_val); // row,col,value
|
||||
Eigen::MatrixXd alphay =
|
||||
Eigen::MatrixXd::Constant(row, col, alphay_val); // row,col,value
|
||||
grid.setAlpha(alphax, alphay);
|
||||
|
||||
// // ******************
|
||||
@ -140,8 +141,7 @@ int main(int argc, char *argv[]) {
|
||||
// // ************************
|
||||
|
||||
// set up a simulation environment
|
||||
Simulation simulation =
|
||||
Simulation(grid, bc, BTCS_APPROACH); // grid,boundary,simulation-approach
|
||||
Simulation simulation = Simulation(grid, bc); // grid,boundary
|
||||
|
||||
// set the timestep of the simulation
|
||||
simulation.setTimestep(360); // timestep
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
add_library(tug Simulation.cpp FTCS.cpp BTCS.cpp)
|
||||
|
||||
IF(TUG_NAAICE_EXAMPLE)
|
||||
target_compile_definitions(tug PRIVATE WRITE_THOMAS_CSV)
|
||||
endif()
|
||||
|
||||
target_link_libraries(tug Eigen3::Eigen)
|
||||
|
||||
if(TUG_USE_OPENMP AND OpenMP_CXX_FOUND)
|
||||
target_link_libraries(tug OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
|
||||
target_include_directories(tug PUBLIC ${PROJECT_SOURCE_DIR}/include)
|
||||
@ -1,36 +0,0 @@
|
||||
<h1>src-Directory</h1>
|
||||
This is the src-directory that holds the source code to the implementation of the TUG framework.
|
||||
|
||||
<pre>
|
||||
src/
|
||||
├── CMakeFiles/
|
||||
├── Boundary.cpp
|
||||
├── BTCSv2.cpp
|
||||
├── CMakeLists.txt
|
||||
├── FTCS.cpp
|
||||
├── Grid.cpp
|
||||
├── README.md
|
||||
├── Simulation.cpp
|
||||
└── TugUtils.hpp
|
||||
</pre>
|
||||
|
||||
**src/** Directory with the source code.
|
||||
|
||||
**CMakeFiles/** Automatically generated directory by CMake.
|
||||
|
||||
**Boundary.cpp** Implementation of Boundary class, that holds the boundary conditions.
|
||||
|
||||
**BTCSv2.cpp** Implementation of BTCS solution to heterogeneous diffusion in 1D and 2D.
|
||||
|
||||
**CMakeLists.txt** CMakeLists for this directory.
|
||||
|
||||
**FTCS.cpp** Implementation of FTCS solution to heterogeneous diffusion in 1D and 2D.
|
||||
|
||||
**Grid.cpp** Implementation of Grid class, that holds all of the concentrations alpha coefficient in x- and y-direction.
|
||||
|
||||
**README.md** <i>This</i> file.
|
||||
|
||||
**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.
|
||||
|
||||
**TugUtils.hpp** Helper functions for other source files.
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
/**
|
||||
* @file BTCSv2.cpp
|
||||
* @brief Implementation of heterogenous BTCS (backward time-centered space)
|
||||
* solution of diffusion equation in 1D and 2D space. Internally the
|
||||
* alternating-direction implicit (ADI) method is used. Version 2, because
|
||||
* Version 1 was an implementation for the homogeneous BTCS solution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCHEMES_H_
|
||||
#define SCHEMES_H_
|
||||
|
||||
#include "TugUtils.hpp"
|
||||
|
||||
#include <tug/Boundary.hpp>
|
||||
#include <tug/Grid.hpp>
|
||||
|
||||
namespace tug {
|
||||
|
||||
// entry point; differentiate between 1D and 2D grid
|
||||
template <class T>
|
||||
extern void FTCS(tug::Grid<T> &grid, tug::Boundary<T> &bc, T timestep,
|
||||
int &numThreads);
|
||||
|
||||
// entry point for EigenLU solver; differentiate between 1D and 2D grid
|
||||
template <class T>
|
||||
extern void BTCS_LU(tug::Grid<T> &grid, tug::Boundary<T> &bc, T timestep,
|
||||
int numThreads);
|
||||
|
||||
// entry point for Thomas algorithm solver; differentiate 1D and 2D grid
|
||||
template <class T>
|
||||
extern void BTCS_Thomas(tug::Grid<T> &grid, tug::Boundary<T> &bc, T timestep,
|
||||
int numThreads);
|
||||
} // namespace tug
|
||||
|
||||
#endif // SCHEMES_H_
|
||||
@ -1,205 +0,0 @@
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <tug/Simulation.hpp>
|
||||
|
||||
#include "Schemes.hpp"
|
||||
#include "TugUtils.hpp"
|
||||
|
||||
namespace tug {
|
||||
|
||||
template <class T> void Simulation<T>::setTimestep(T timestep) {
|
||||
if (timestep <= 0) {
|
||||
throw_invalid_argument("Timestep has to be greater than zero.");
|
||||
}
|
||||
|
||||
if (approach == FTCS_APPROACH || approach == CRANK_NICOLSON_APPROACH) {
|
||||
|
||||
const T deltaColSquare = grid.getDeltaCol() * grid.getDeltaCol();
|
||||
// will be 0 if 1D, else ...
|
||||
const T deltaRowSquare = grid.getDim() != 1
|
||||
? grid.getDeltaRow() * grid.getDeltaRow()
|
||||
: deltaColSquare;
|
||||
const T minDeltaSquare =
|
||||
(deltaRowSquare < deltaColSquare) ? deltaRowSquare : deltaColSquare;
|
||||
|
||||
T maxAlpha = std::numeric_limits<T>::quiet_NaN();
|
||||
|
||||
// determine maximum alpha
|
||||
if (grid.getDim() == 2) {
|
||||
|
||||
const T maxAlphaX = grid.getAlphaX().maxCoeff();
|
||||
const T maxAlphaY = grid.getAlphaY().maxCoeff();
|
||||
maxAlpha = (maxAlphaX > maxAlphaY) ? maxAlphaX : maxAlphaY;
|
||||
|
||||
} else if (grid.getDim() == 1) {
|
||||
maxAlpha = grid.getAlpha().maxCoeff();
|
||||
|
||||
} else {
|
||||
throw_invalid_argument("Critical error: Undefined number of dimensions!");
|
||||
}
|
||||
|
||||
const std::string dim = std::to_string(grid.getDim()) + "D";
|
||||
|
||||
// Courant-Friedrichs-Lewy condition
|
||||
T cfl = minDeltaSquare / (4 * maxAlpha);
|
||||
|
||||
// stability equation from Wikipedia; might be useful if applied cfl does
|
||||
// not work in some cases double CFL_Wiki = 1 / (4 * maxAlpha *
|
||||
// ((1/deltaRowSquare) + (1/deltaColSquare)));
|
||||
|
||||
const std::string &approachPrefix = this->approach_names[approach];
|
||||
std::cout << approachPrefix << "_" << dim << " :: CFL condition: " << cfl
|
||||
<< std::endl;
|
||||
std::cout << approachPrefix << "_" << dim << " :: required dt=" << timestep
|
||||
<< std::endl;
|
||||
|
||||
if (timestep > cfl) {
|
||||
|
||||
this->innerIterations = (int)ceil(timestep / cfl);
|
||||
this->timestep = timestep / (double)innerIterations;
|
||||
|
||||
std::cerr << "Warning :: Timestep was adjusted, because of stability "
|
||||
"conditions. Time duration was approximately preserved by "
|
||||
"adjusting internal number of iterations."
|
||||
<< std::endl;
|
||||
std::cout << approachPrefix << "_" << dim << " :: Required "
|
||||
<< this->innerIterations
|
||||
<< " inner iterations with dt=" << this->timestep << std::endl;
|
||||
|
||||
} else {
|
||||
|
||||
this->timestep = timestep;
|
||||
std::cout << approachPrefix << "_" << dim
|
||||
<< " :: No inner iterations required, dt=" << timestep
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
} else {
|
||||
this->timestep = timestep;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T> void Simulation<T>::run() {
|
||||
if (this->timestep == -1) {
|
||||
throw_invalid_argument("Timestep is not set!");
|
||||
}
|
||||
if (this->iterations == -1) {
|
||||
throw_invalid_argument("Number of iterations are not set!");
|
||||
}
|
||||
|
||||
std::string filename;
|
||||
if (this->console_output > CONSOLE_OUTPUT_OFF) {
|
||||
printConcentrationsConsole();
|
||||
}
|
||||
if (this->csv_output > CSV_OUTPUT_OFF) {
|
||||
filename = createCSVfile();
|
||||
}
|
||||
|
||||
auto begin = std::chrono::high_resolution_clock::now();
|
||||
|
||||
if (approach == FTCS_APPROACH) { // FTCS case
|
||||
|
||||
for (int i = 0; i < iterations * innerIterations; i++) {
|
||||
if (console_output == CONSOLE_OUTPUT_VERBOSE && i > 0) {
|
||||
printConcentrationsConsole();
|
||||
}
|
||||
if (csv_output >= CSV_OUTPUT_VERBOSE) {
|
||||
printConcentrationsCSV(filename);
|
||||
}
|
||||
|
||||
FTCS(this->grid, this->bc, this->timestep, this->numThreads);
|
||||
|
||||
// if (i % (iterations * innerIterations / 100) == 0) {
|
||||
// double percentage = (double)i / ((double)iterations *
|
||||
// (double)innerIterations) * 100; if ((int)percentage % 10 == 0) {
|
||||
// cout << "Progress: " << percentage << "%" << endl;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
} else if (approach == BTCS_APPROACH) { // BTCS case
|
||||
|
||||
if (solver == EIGEN_LU_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_LU(this->grid, this->bc, this->timestep, this->numThreads);
|
||||
}
|
||||
} 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, this->numThreads);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (approach == CRANK_NICOLSON_APPROACH) { // Crank-Nicolson case
|
||||
|
||||
constexpr T beta = 0.5;
|
||||
|
||||
// TODO this implementation is very inefficient!
|
||||
// a separate implementation that sets up a specific tridiagonal matrix for
|
||||
// Crank-Nicolson would be better
|
||||
Eigen::MatrixX<T> concentrations;
|
||||
Eigen::MatrixX<T> concentrationsFTCS;
|
||||
Eigen::MatrixX<T> concentrationsResult;
|
||||
for (int i = 0; i < iterations * innerIterations; i++) {
|
||||
if (console_output == CONSOLE_OUTPUT_VERBOSE && i > 0) {
|
||||
printConcentrationsConsole();
|
||||
}
|
||||
if (csv_output >= CSV_OUTPUT_VERBOSE) {
|
||||
printConcentrationsCSV(filename);
|
||||
}
|
||||
|
||||
concentrations = grid.getConcentrations();
|
||||
FTCS(this->grid, this->bc, this->timestep, this->numThreads);
|
||||
concentrationsFTCS = grid.getConcentrations();
|
||||
grid.setConcentrations(concentrations);
|
||||
BTCS_Thomas(this->grid, this->bc, this->timestep, this->numThreads);
|
||||
concentrationsResult =
|
||||
beta * concentrationsFTCS + (1 - beta) * grid.getConcentrations();
|
||||
grid.setConcentrations(concentrationsResult);
|
||||
}
|
||||
}
|
||||
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
auto milliseconds =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
|
||||
|
||||
if (this->console_output > CONSOLE_OUTPUT_OFF) {
|
||||
printConcentrationsConsole();
|
||||
}
|
||||
if (this->csv_output > CSV_OUTPUT_OFF) {
|
||||
printConcentrationsCSV(filename);
|
||||
}
|
||||
if (this->time_measure > TIME_MEASURE_OFF) {
|
||||
const std::string &approachString = this->approach_names[approach];
|
||||
const std::string dimString = std::to_string(grid.getDim()) + "D";
|
||||
std::cout << approachString << dimString << ":: run() finished in "
|
||||
<< milliseconds.count() << "ms" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
template void Simulation<double>::setTimestep(double timestep);
|
||||
template void Simulation<float>::setTimestep(float timestep);
|
||||
|
||||
template void Simulation<double>::run();
|
||||
template void Simulation<float>::run();
|
||||
} // namespace tug
|
||||
@ -1,4 +1,4 @@
|
||||
#include <TugUtils.hpp>
|
||||
#include <tug/Core/TugUtils.hpp>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
#include <limits>
|
||||
|
||||
@ -12,8 +12,7 @@ using namespace Eigen;
|
||||
using namespace std;
|
||||
using namespace tug;
|
||||
|
||||
static Grid64 setupSimulation(APPROACH approach, double timestep,
|
||||
int iterations) {
|
||||
Grid64 setupSimulation(double timestep, int iterations) {
|
||||
int row = 11;
|
||||
int col = 11;
|
||||
int domain_row = 10;
|
||||
@ -45,26 +44,29 @@ static Grid64 setupSimulation(APPROACH approach, double timestep,
|
||||
}
|
||||
grid.setAlpha(alpha, alpha);
|
||||
|
||||
// Boundary
|
||||
Boundary bc = Boundary(grid);
|
||||
|
||||
// Simulation
|
||||
Simulation sim = Simulation(grid, bc, approach);
|
||||
// sim.setOutputConsole(CONSOLE_OUTPUT_ON);
|
||||
sim.setTimestep(timestep);
|
||||
sim.setIterations(iterations);
|
||||
sim.run();
|
||||
|
||||
// RUN
|
||||
return grid;
|
||||
}
|
||||
|
||||
constexpr double timestep = 0.001;
|
||||
constexpr double iterations = 7000;
|
||||
|
||||
TEST_CASE("equality to reference matrix with FTCS") {
|
||||
// set string from the header file
|
||||
string test_path = testSimulationCSVDir;
|
||||
MatrixXd reference = CSV2Eigen(test_path);
|
||||
cout << "FTCS Test: " << endl;
|
||||
Grid grid = setupSimulation(FTCS_APPROACH, 0.001, 7000);
|
||||
|
||||
Grid grid = setupSimulation(timestep, iterations); // Boundary
|
||||
Boundary bc = Boundary(grid);
|
||||
|
||||
// Simulation
|
||||
|
||||
Simulation sim = Simulation<double, tug::FTCS_APPROACH>(grid, bc);
|
||||
// sim.setOutputConsole(CONSOLE_OUTPUT_ON);
|
||||
sim.setTimestep(timestep);
|
||||
sim.setIterations(iterations);
|
||||
sim.run();
|
||||
|
||||
cout << endl;
|
||||
CHECK(checkSimilarity(reference, grid.getConcentrations(), 0.1) == true);
|
||||
}
|
||||
@ -74,7 +76,17 @@ TEST_CASE("equality to reference matrix with BTCS") {
|
||||
string test_path = testSimulationCSVDir;
|
||||
MatrixXd reference = CSV2Eigen(test_path);
|
||||
cout << "BTCS Test: " << endl;
|
||||
Grid grid = setupSimulation(BTCS_APPROACH, 1, 7);
|
||||
|
||||
Grid grid = setupSimulation(timestep, iterations); // Boundary
|
||||
Boundary bc = Boundary(grid);
|
||||
|
||||
// Simulation
|
||||
Simulation sim = Simulation<double, tug::FTCS_APPROACH>(grid, bc);
|
||||
// sim.setOutputConsole(CONSOLE_OUTPUT_ON);
|
||||
sim.setTimestep(timestep);
|
||||
sim.setIterations(iterations);
|
||||
sim.run();
|
||||
|
||||
cout << endl;
|
||||
CHECK(checkSimilarityV2(reference, grid.getConcentrations(), 0.01) == true);
|
||||
}
|
||||
@ -84,14 +96,14 @@ TEST_CASE("Initialize environment") {
|
||||
Grid64 grid(rc, rc);
|
||||
Boundary boundary(grid);
|
||||
|
||||
CHECK_NOTHROW(Simulation sim(grid, boundary, BTCS_APPROACH));
|
||||
CHECK_NOTHROW(Simulation sim(grid, boundary));
|
||||
}
|
||||
|
||||
TEST_CASE("Simulation environment") {
|
||||
int rc = 12;
|
||||
Grid64 grid(rc, rc);
|
||||
Boundary boundary(grid);
|
||||
Simulation sim(grid, boundary, FTCS_APPROACH);
|
||||
Simulation<double, tug::FTCS_APPROACH> sim(grid, boundary);
|
||||
|
||||
SUBCASE("default paremeters") { CHECK_EQ(sim.getIterations(), -1); }
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user