# 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