Compare commits

...

10 Commits

Author SHA1 Message Date
nebmit
f69d58e070
test: adapt tests to change from mr !2
[skip ci]
2024-03-12 15:06:20 +01:00
nebmit
539c6f9544
fix(BTCS): create swapped b vector with correct length
[skip ci]
2024-03-12 15:05:11 +01:00
nebmit
6a98a23439
feat(Grid): add domain values as optional arguments
[skip ci]
2024-03-12 15:04:38 +01:00
nebmit
65a16cac1c
refactor: unify field ordering
[skip ci]
2024-03-12 15:03:50 +01:00
Tim Werner
deb71df259 Merge branch 'fix-alpha' into 'main'
fix(btcs): alpha intercell on explicit constant boundaries

See merge request werner10/tug!2

[skip ci]
2024-03-11 15:47:30 +01:00
Max Lübke
5c6ac062cc fix(btcs): alpha intercell on explicit constant boundaries
See MR @ https://git.gfz-potsdam.de/naaice/tug/-/merge_requests/25

[skip ci]
2024-03-11 15:47:29 +01:00
Tim Werner
8233d868b2 Merge branch 'fix-btcs' into 'main'
See merge request werner10/tug!1 

[skip ci]
2024-02-28 17:06:24 +01:00
Max Lübke
e431af68ca fix(btcs): erroneous resolution of constant boundaries
See https://git.gfz-potsdam.de/naaice/tug/-/merge_requests/23

[skip ci]
2024-02-28 17:06:24 +01:00
nebmit
bd288e00e1
docs: add TUG Julia package README.md 2024-01-10 19:04:04 +01:00
nebmit
da65b6fa14
docs: add TUG documentation and make.jl script
[skip ci]
2024-01-10 19:03:46 +01:00
10 changed files with 261 additions and 56 deletions

88
julia/TUG/README.md Normal file
View File

@ -0,0 +1,88 @@
# TUG: Transport on Uniform Grids for Julia
## Overview
The TUG Julia package is a port of the same-named C++ library.
## Prerequisites
Before installing TUG, ensure you have Julia installed on your system. Julia can be downloaded and installed from [the official Julia website](https://julialang.org/downloads/).
## Installation
To install the TUG package locally, follow these steps in the Julia REPL (Read-Eval-Print Loop):
1. **Open Julia REPL**: You can start it by executing `julia` in your command line.
2. **Enter Pkg mode**: Press `]` to enter Pkg mode, which is Julia's package manager.
3. **Develop the Package Locally**:
```julia
(v1.x) pkg> develop path/to/tug/julia/TUG # Replace with the actual path to your TUG directory
```
4. **Exit Pkg mode**: Press `backspace` to exit Pkg mode.
5. **Use the Package**:
```julia
julia> using TUG
```
## Building the Documentation
To build the documentation for TUG:
1. **Navigate to the `docs` Directory**:
```shell
cd path/to/tug/julia/TUG/docs
```
2. **Build the Documentation**:
```shell
julia make.jl
```
## Running Tests
To run the tests for TUG, follow these steps:
1. **Navigate to the TUG Package Directory**:
```shell
cd path/to/tug/julia/TUG
```
2. **Enter Pkg mode and run the tests**:
```julia
(v1.x) pkg> test TUG
```
## Getting Started
To get started with TUG:
### Creating a Simulation
```julia
# Import the TUG package
using TUG
# Create a grid
grid = TUG.Grid{Float64}(5, ones(1, 5))
# Define boundary conditions
boundary = TUG.Boundary{Float64}(grid)
# Initialize a simulation
simulation = TUG.Simulation{Float64}(grid, boundary)
```
### Running the Simulation
```julia
# Set initial concentrations
TUG.setConcentrations!(grid, [1.0, 1.0, 20.0, 1.0, 1.0])
# Run the simulation
TUG.run(simulation)
# Retrieve the concentrations
concentrations = TUG.getConcentrations(grid)
```
## More Information
For a detailed reference of all functionalities and more comprehensive examples, please refer to the documentation in this repository.

13
julia/TUG/docs/make.jl Normal file
View File

@ -0,0 +1,13 @@
using Pkg
using Documenter
pkg_path = abspath(joinpath(@__DIR__, ".."))
Pkg.develop(path = pkg_path)
using TUG
makedocs(
sitename = "TUG Documentation",
modules = [TUG],
format = Documenter.HTML(),
remotes = nothing,
)

View File

@ -0,0 +1,97 @@
# TUG Documentation
TUG is a Julia package that provides a framework for solving transport problems, notably diffusion, on uniform grids. It implements different numerical approaches, including implicit BTCS (Backward Time, Central Space) Euler and parallel 2D ADI (Alternating Direction Implicit).
```@contents
```
## Introduction
TUG, originally developed as a C++ library, is now available as a Julia package. It aims to offer a comprehensive toolkit for solving transport problems, such as diffusion and advection, on uniform grids.
## Installation
If TUG is locally cloned on your machine, you can install it by pointing to the local path. Open Julia REPL and follow these steps:
```julia
using Pkg
Pkg.develop(path="path/to/tug/julia/TUG") # Replace with the actual path to the TUG directory
using TUG
```
## Getting Started
Below are some basic examples of using TUG. For more detailed information, see the API section. For more advanced examples, see the test files in the `test` directory.
### Creating a Simulation
To create a simulation with TUG, you first need to set up a grid and boundary conditions. Here is an example of setting up a basic simulation:
```julia
using TUG
# Create a 1D grid
grid = TUG.Grid{Float64}(5, ones(1, 5))
# Define boundary conditions
boundary = TUG.Boundary{Float64}(grid)
# Initialize a simulation with default parameters
simulation = TUG.Simulation{Float64}(grid, boundary)
```
### Running a Simulation
After setting up the simulation, you can run it and analyze the results:
```julia
# Set initial concentrations
TUG.setConcentrations!(grid, [1.0, 1.0, 20.0, 1.0, 1.0])
# Run the simulation
TUG.run(simulation)
# Retrieve the concentrations after simulation
concentrations = TUG.getConcentrations(grid)
```
### Advanced Setup
You can also customize your simulation with different parameters:
```julia
# Create a simulation with custom parameters
simulation = TUG.Simulation{Float64}(
grid,
boundary;
approach = TUG.FTCS,
iterations = 2,
timestep = 0.2,
consoleOutput = TUG.CONSOLE_OUTPUT_ON,
csvOutput = TUG.CSV_OUTPUT_ON
)
```
### Dynamic Simulation
For dynamic simulations where the concentration is manipulated externally during runtime:
```julia
# Initialize a dynamic simulation
dynamicSimulation = TUG.DynamicSimulation{Float64}(grid, boundary; timestep = 0.1)
# Create and update the grid over iterations
TUG.createGrid(dynamicSimulation)
for _ = 1:20
TUG.next(dynamicSimulation)
# Update the concentration
end
```
## API Reference
For a detailed reference of all functionalities, see the API section:
```@autodocs
Modules = [TUG]
```

View File

@ -46,10 +46,7 @@ struct BoundaryElement{T}
end
function BoundaryElement{T}(value::T)::BoundaryElement{T} where {T}
if value < 0
throw(ArgumentError("No negative concentration allowed."))
end
new{T}(CONSTANT, value)
new{T}(TUG.CONSTANT, value)
end
end
@ -114,14 +111,14 @@ It includes the dimension of the grid and boundary elements for each side.
"""
struct Boundary{T}
dim::UInt8
cols::UInt32
rows::UInt32
cols::UInt32
boundaries::Vector{Vector{BoundaryElement{T}}}
function Boundary{T}(grid::Grid{T})::Boundary{T} where {T}
dim = grid.dim
cols = grid.cols
rows = grid.rows
cols = grid.cols
boundaries = Vector{Vector{BoundaryElement{T}}}(undef, 4)
if dim == 1
@ -136,7 +133,7 @@ struct Boundary{T}
throw(ArgumentError("Only 1- and 2-dimensional grids are defined!"))
end
new{T}(dim, cols, rows, boundaries)
new{T}(dim, rows, cols, boundaries)
end
end

View File

@ -68,12 +68,9 @@ function calcExplicitConcentrationsBoundaryConstant(
sy::T,
)::T where {T}
alpha_center_neighbor = calcAlphaIntercell(alpha_center, alpha_neighbor)
alpha_center_center =
alpha_center == alpha_neighbor ? alpha_center_neighbor :
calcAlphaIntercell(alpha_center, alpha_center)
return sy * alpha_center_neighbor * conc_center +
(1 - sy * (alpha_center_center + 2 * alpha_center)) * conc_center +
(1 - sy * (alpha_center_neighbor + alpha_center)) * conc_center +
sy * alpha_center * conc_bc
end
@ -269,7 +266,7 @@ function BTCS_2D(
# Swap alphas, boundary conditions and sx/sy for column-wise calculation
Threads.@threads for i = 1:cols
localB = zeros(T, cols)
localB = zeros(T, rows)
A::Tridiagonal{T} = createCoeffMatrix(
view(alphaY_t, i, :),
view(alphaY_t_left, i, :),

View File

@ -12,11 +12,11 @@ Represents a computational grid with concentration values and alpha coefficients
It can be either 1D or 2D and includes dimensions, domain sizes, delta values, and matrices for concentrations and alpha coefficients.
# Fields
- `cols::Int`: Number of columns in the grid.
- `rows::Int`: Number of rows in the grid.
- `cols::Int`: Number of columns in the grid.
- `dim::Int`: Dimension of the grid (1 for 1D, 2 for 2D).
- `domainCol::T`, `domainRow::T`: Size of the grid's domain in column and row direction.
- `deltaCol::T`, `deltaRow::T`: Delta values for columns and rows.
- `domainRow::T`, `domainCol::T`: Size of the grid's domain in column and row direction.
- `deltaRow::T`, `deltaCol::T`: Delta values for columns and rows.
- `concentrations::Ref{Matrix{T}}`: Reference to the matrix holding concentration values.
- `alphaX::Ref{Matrix{T}}`: Reference to the matrix of alpha coefficients in the X direction.
- `alphaY::Union{Ref{Matrix{T}},Nothing}`: Reference to the matrix of alpha coefficients in the Y direction (if applicable).
@ -25,23 +25,31 @@ It can be either 1D or 2D and includes dimensions, domain sizes, delta values, a
# Constructors
- `Grid(length, alphaX)` creates a 1D grid with the given length and alphaX matrix.
- `Grid(rows, cols, alphaX, alphaY)` creates a 2D grid with the given rows, columns, and alphaX and alphaY matrices.
- `Grid(rows, cols, dim, domainCol, domainRow, deltaCol, deltaRow, concentrations, alphaX, alphaY, alphaX_t, alphaY_t)` creates a grid with the given parameters.
- `Grid(rows, cols, dim, domainRow, domainCol, deltaRow, deltaCol, concentrations, alphaX, alphaY, alphaX_t, alphaY_t)` creates a grid with the given parameters.
"""
struct Grid{T}
cols::Int
rows::Int
cols::Int
dim::Int
domainCol::T
domainRow::T
deltaCol::T
domainCol::T
deltaRow::T
deltaCol::T
concentrations::Matrix{T}
alphaX::Matrix{T}
alphaY::Union{Matrix{T},Nothing}
alphaX_t::Matrix{T}
alphaY_t::Union{Matrix{T},Nothing}
function Grid{T}(length::Int, alphaX::Matrix{T})::Grid{T} where {T}
function Grid{T}(
length::Int,
alphaX::Matrix{T};
domainLength::T = T(-1),
)::Grid{T} where {T}
if domainLength < 0
domainLength = T(length)
end
if length <= 3
throw(ArgumentError("Given grid length too small. Must be greater than 3."))
end
@ -56,13 +64,13 @@ struct Grid{T}
alphaX_t = alphaX'
new{T}(
1,
length,
1,
1,
T(length),
0,
T(1),
T(domainLength),
0,
T(domainLength / length),
fill(T(0), 1, length),
alphaX,
nothing,
@ -75,8 +83,17 @@ struct Grid{T}
rows::Int,
cols::Int,
alphaX::Matrix{T},
alphaY::Matrix{T},
alphaY::Matrix{T};
domainRow::T = T(-1),
domainCol::T = T(-1),
)::Grid{T} where {T}
if domainRow < 0
domainRow = T(rows)
end
if domainCol < 0
domainCol = T(cols)
end
if rows <= 3 || cols <= 3
throw(
ArgumentError(
@ -96,13 +113,13 @@ struct Grid{T}
alphaY_t = alphaY'
new{T}(
cols,
rows,
cols,
2,
T(cols),
T(rows),
T(1),
T(1),
T(domainRow),
T(domainCol),
T(domainRow / rows),
T(domainCol / cols),
fill(T(0), rows, cols),
alphaX,
alphaY,
@ -115,10 +132,10 @@ struct Grid{T}
rows::Int,
cols::Int,
dim::Int,
domainCol::T,
domainRow::T,
deltaCol::T,
domainCol::T,
deltaRow::T,
deltaCol::T,
concentrations::Matrix{T},
alphaX::Matrix{T},
alphaY::Union{Matrix{T},Nothing},
@ -126,13 +143,13 @@ struct Grid{T}
alphaY_t::Union{Matrix{T},Nothing},
)::Grid{T} where {T}
new{T}(
cols,
rows,
cols,
dim,
domainCol,
domainRow,
deltaCol,
domainCol,
deltaRow,
deltaCol,
concentrations,
alphaX,
alphaY,
@ -160,10 +177,10 @@ function clone(grid::Grid{T})::Grid{T} where {T}
1,
grid.cols,
grid.dim,
grid.domainCol,
grid.domainRow,
grid.deltaCol,
grid.domainCol,
grid.deltaRow,
grid.deltaCol,
copy(grid.concentrations),
copy(grid.alphaX),
nothing,
@ -175,10 +192,10 @@ function clone(grid::Grid{T})::Grid{T} where {T}
grid.rows,
grid.cols,
grid.dim,
grid.domainCol,
grid.domainRow,
grid.deltaCol,
grid.domainCol,
grid.deltaRow,
grid.deltaCol,
copy(grid.concentrations),
copy(grid.alphaX),
copy(grid.alphaY),

View File

@ -9,14 +9,14 @@ export clone,
getAlphaX_t,
getAlphaY_t,
getConcentrations,
setConcentrations!,
setAlphaX!,
setAlphaY!,
getDomainCol,
getDomainRow,
getDeltaCol,
getDeltaRow,
getDim
getDim,
setAlphaX!,
setAlphaY!,
setConcentrations!
include("Boundary.jl")

View File

@ -8,8 +8,6 @@
@test TUG.getType(be) == TUG.CONSTANT
@test TUG.getValue(be) == 1.0
@test TUG.getValue([be]) == [1.0]
@test_throws ArgumentError TUG.BoundaryElement{Float64}(-1.0)
end
@testset "Boundary" begin
@ -25,7 +23,6 @@
@test TUG.getBoundaryElementType(boundary, TUG.TOP, 1) == TUG.CLOSED
@test TUG.getBoundaryElementType(boundary, TUG.BOTTOM, 1) == TUG.CLOSED
@test_throws ArgumentError TUG.getBoundaryElementType(boundary, TUG.LEFT, -1)
@test_throws ArgumentError TUG.getBoundaryElementType(boundary, TUG.RIGHT, 26)
@test TUG.getBoundaryElementValue(boundary, TUG.LEFT, 1) == -1.0
@ -33,7 +30,6 @@
@test TUG.getBoundaryElementValue(boundary, TUG.TOP, 1) == -1.0
@test TUG.getBoundaryElementValue(boundary, TUG.BOTTOM, 1) == -1.0
@test_throws ArgumentError TUG.getBoundaryElementValue(boundary, TUG.BOTTOM, -1)
@test_throws ArgumentError TUG.getBoundaryElementValue(boundary, TUG.TOP, 21)
TUG.setBoundarySideClosed!(boundary, TUG.LEFT)

View File

@ -113,11 +113,11 @@
TUG.next(simulation)
end
expected_concentrations = [
1.9866377371338924 3.67421468453773 14.255058363518529 3.5916629034159486 1.1419105589005596
1.98663773713389 3.674214684537723 14.255058363518497 3.5916629034159406 1.1419105589005576
1.9866377371338884 3.6742146845377186 14.255058363518481 3.591662903415937 1.1419105589005565
1.9866377371338895 3.674214684537725 14.255058363518502 3.5916629034159424 1.1419105589005574
1.9866377371338952 3.6742146845377377 14.255058363518547 3.591662903415955 1.141910558900562
2.116922560959072 3.6843335107065727 14.255652775906785 3.5916901126508205 1.141911092414447
2.1169225609590687 3.684333510706568 14.255652775906759 3.5916901126508134 1.1419110924144453
2.1169225609590674 3.6843335107065607 14.255652775906748 3.591690112650811 1.1419110924144442
2.1169225609590687 3.684333510706565 14.255652775906766 3.5916901126508147 1.1419110924144449
2.116922560959073 3.684333510706576 14.25565277590681 3.5916901126508267 1.141911092414448
]
@test isapprox(
TUG.getConcentrations(simulation, 1),

View File

@ -114,11 +114,11 @@
)
TUG.run(simulation)
expected_concentrations = [
1.9866377371338924 3.67421468453773 14.255058363518529 3.5916629034159486 1.1419105589005596
1.98663773713389 3.674214684537723 14.255058363518497 3.5916629034159406 1.1419105589005576
1.9866377371338884 3.6742146845377186 14.255058363518481 3.591662903415937 1.1419105589005565
1.9866377371338895 3.674214684537725 14.255058363518502 3.5916629034159424 1.1419105589005574
1.9866377371338952 3.6742146845377377 14.255058363518547 3.591662903415955 1.141910558900562
2.116922560959072 3.6843335107065727 14.255652775906785 3.5916901126508205 1.141911092414447
2.1169225609590687 3.684333510706568 14.255652775906759 3.5916901126508134 1.1419110924144453
2.1169225609590674 3.6843335107065607 14.255652775906748 3.591690112650811 1.1419110924144442
2.1169225609590687 3.684333510706565 14.255652775906766 3.5916901126508147 1.1419110924144449
2.116922560959073 3.684333510706576 14.25565277590681 3.5916901126508267 1.141911092414448
]
@test isapprox(TUG.getConcentrations(grid), expected_concentrations, atol = 1e-6)
end