TugJulia/julia/tug/Boundary.jl
2023-11-30 13:53:39 +01:00

131 lines
4.2 KiB
Julia

# Boundary.jl
# API of Boundary class, that holds all information for each boundary
# condition at the edges of the diffusion grid.
# Translated from C++'s Boundary.hpp.
@enum TYPE CLOSED CONSTANT
@enum SIDE LEFT = 1 RIGHT = 2 TOP = 3 BOTTOM = 4
# BoundaryElement class
struct BoundaryElement{T}
type::TYPE
value::T
# Generic constructor for closed case
BoundaryElement{T}() where {T} = new{T}(CLOSED, convert(T, -1))
# Constructor for constant case
BoundaryElement{T}(value::T) where {T} = new{T}(CONSTANT, value)
end
function getType(be::BoundaryElement{T})::TYPE where {T}
be.type
end
function getValue(be::BoundaryElement{T})::T where {T}
be.value
end
function getValue(be::Vector{BoundaryElement{T}})::Vector{T} where {T}
[b.value for b in be]
end
function setType!(be::BoundaryElement{T}, type::Symbol) where {T}
be.type = type
end
function setValue!(be::BoundaryElement{T}, value::T) where {T}
if value < 0
throw(ArgumentError("No negative concentration allowed."))
end
if be.type == BC_TYPE_CLOSED
throw(ArgumentError("No constant boundary concentrations can be set for closed boundaries. Please change type first."))
end
be.value = value
end
# Boundary class
struct Boundary{T}
dim::UInt8
cols::UInt32
rows::UInt32
boundaries::Vector{Vector{BoundaryElement{T}}}
# Constructor
function Boundary(grid::Grid{T}) where {T}
dim = grid.dim
cols = grid.cols
rows = grid.rows
boundaries = Vector{Vector{BoundaryElement{T}}}(undef, 4)
if dim == 1
boundaries[Int(LEFT)] = [BoundaryElement{T}()]
boundaries[Int(RIGHT)] = [BoundaryElement{T}()]
elseif dim == 2
boundaries[Int(LEFT)] = [BoundaryElement{T}() for _ in 1:rows]
boundaries[Int(RIGHT)] = [BoundaryElement{T}() for _ in 1:rows]
boundaries[Int(TOP)] = [BoundaryElement{T}() for _ in 1:cols]
boundaries[Int(BOTTOM)] = [BoundaryElement{T}() for _ in 1:cols]
else
throw(ArgumentError("Only 1- and 2-dimensional grids are defined!"))
end
new{T}(dim, cols, rows, boundaries)
end
end
function getBoundaryElementType(boundary::Boundary{T}, side::SIDE, index::Int)::TYPE where {T}
if boundary.dim == 1 && (side == BOTTOM || side == TOP)
throw(ArgumentError("For the one-dimensional case, only the left and right borders exist."))
end
if index < 1 || index > (side in (LEFT, RIGHT) ? boundary.rows : boundary.cols)
throw(ArgumentError("Index out of bounds!"))
end
getType(boundary.boundaries[Int(side)][index])
end
function getBoundaryElementValue(boundary::Boundary{T}, side::SIDE, index::Int)::T where {T}
if boundary.dim == 1 && (side == BOTTOM || side == TOP)
throw(ArgumentError("For the one-dimensional case, only the left and right borders exist."))
end
if index < 1 || index > (side in (LEFT, RIGHT) ? boundary.rows : boundary.cols)
throw(ArgumentError("Index out of bounds!"))
end
getValue(boundary.boundaries[Int(side)][index])
end
function getBoundarySide(boundary::Boundary{T}, side::SIDE)::Vector{BoundaryElement{T}} where {T}
if boundary.dim == 1 && (side == BOTTOM || side == TOP)
throw(ArgumentError("For the one-dimensional case, only the left and right borders exist."))
end
boundary.boundaries[Int(side)]
end
function setBoundarySideClosed!(boundary::Boundary{T}, side::SIDE) where {T}
if boundary.dim == 1 && (side == BOTTOM || side == TOP)
throw(ArgumentError("For the one-dimensional case, only the left and right borders exist."))
end
is_vertical = side in (LEFT, RIGHT)
n = is_vertical ? boundary.rows : boundary.cols
boundary.boundaries[Int(side)] = [BoundaryElement{T}() for _ in 1:n]
end
function setBoundarySideConstant!(boundary::Boundary{T}, side::SIDE, value::T) where {T}
if boundary.dim == 1 && (side == BOTTOM || side == TOP)
throw(ArgumentError("For the one-dimensional case, only the left and right borders exist."))
end
is_vertical = side in (LEFT, RIGHT)
n = is_vertical ? boundary.rows : boundary.cols
boundary.boundaries[Int(side)] = [BoundaryElement{T}(value) for _ in 1:n]
end