diff --git a/examples/app/input-file.toml b/examples/app/input-file.toml index 6cc0d1f..1a23e2d 100644 --- a/examples/app/input-file.toml +++ b/examples/app/input-file.toml @@ -12,7 +12,7 @@ expression = "1.0" variables = ["x", "y"] [mesh] -file_path = "poisson.g" +file_path = "poisson/poisson.g" file_type = "exodus" [[initial_conditions]] diff --git a/src/AppTools.jl b/src/AppTools.jl index 79c27df..a120a02 100644 --- a/src/AppTools.jl +++ b/src/AppTools.jl @@ -420,7 +420,6 @@ function parse_input_file(cli_args::CLIArgParser, log_file::LogFile, ::Type{T} = functions = _parse_function_settings(log_file, data, T) bcs = _parse_boundary_condition_settings(log_file, data, functions) ics = _parse_initial_condition_settings(log_file, data, functions) - println(log_file.io, "HERER") mesh = _parse_mesh_settings(log_file, data) # fspaces = _parse_function_space_settings(log_file, data) # vars = _parse_variable_settings(log_file, data) @@ -432,7 +431,7 @@ end # MeshIO strongly typed helpers ####################################################### function read_exodus_mesh(mesh_settings::MeshSettings) - mesh_path = mesh_settings.file_path + mesh_path = joinpath(pwd(), mesh_settings.file_path) exo = ExodusDatabase{Int32, Int32, Int32, Float64}(mesh_path, "r") fm = FileMesh{ ExodusDatabase{Int32, Int32, Int32, Float64}, @@ -634,7 +633,7 @@ function generate_app( end if "mpi" in backends - push!("deps", "PartitionedArrays" => "5a9dfac6-5c52-46f7-8278-5e2210713be9") + push!(deps, "PartitionedArrays" => "5a9dfac6-5c52-46f7-8278-5e2210713be9") end if "rocm" in backends diff --git a/src/constraints/Constraints.jl b/src/Constraints.jl similarity index 100% rename from src/constraints/Constraints.jl rename to src/Constraints.jl diff --git a/src/Fields.jl b/src/Fields.jl new file mode 100644 index 0000000..23aca49 --- /dev/null +++ b/src/Fields.jl @@ -0,0 +1,352 @@ +###################################################################################################### +# Abstract types +###################################################################################################### +""" +$(TYPEDEF) +Thin wrapper that subtypes ```AbstractArray``` and serves +as the base ```Field``` type +""" +abstract type AbstractField{T, N, D <: AbstractArray{T, 1}} <: AbstractArray{T, N} end +""" +$(TYPEDSIGNATURES) +""" +Base.fill!(field::AbstractField{T, N, D}, v::T) where {T, N, D} = fill!(field.data, v) +""" +$(TYPEDSIGNATURES) +""" +Base.unique(field::AbstractField) = unique(field.data) +""" +$(TYPEDSIGNATURES) +""" +KA.get_backend(field::AbstractField) = KA.get_backend(field.data) + +abstract type AbstractContinuousField{T, D <: AbstractArray{T, 1}, NF} <: AbstractField{T, 2, D} end + +function Adapt.adapt_structure(to, field::AbstractContinuousField{T, D, NF}) where {T, D, NF} + data = adapt(to, field.data) + type = typeof(field).name.name + return eval(type){T, typeof(data), NF}(data) +end + +# minimal abstractarray interface methods below + +function Base.axes(field::AbstractContinuousField{T, D, NF}) where {T, D, NF} + NN = length(field) ÷ NF + return (Base.OneTo(NF), Base.OneTo(NN)) +end + +function Base.getindex(field::AbstractContinuousField, n::Int) + return getindex(field.data, n) +end + +function Base.getindex(field::AbstractContinuousField, d::Int, n::Int) + @assert d > 0 && d <= num_fields(field) + @assert n > 0 && n <= num_entities(field) + getindex(field.data, (n - 1) * num_fields(field) + d) +end + +function Base.IndexStyle(::Type{<:AbstractContinuousField}) + return IndexLinear() +end + +function Base.setindex!(field::AbstractContinuousField{T, D, NF}, v::T, n::Int) where {T, D, NF} + setindex!(field.data, v, n) + return nothing +end + +function Base.setindex!(field::AbstractContinuousField{T, D, NF}, v, d::Int, n::Int) where {T, D, NF} + @assert d > 0 && d <= num_fields(field) + @assert n > 0 && n <= num_entities(field) + setindex!(field.data, v, (n - 1) * num_fields(field) + d) +end + +function Base.similar(field::AbstractContinuousField) + data = similar(field.data) + return typeof(field)(data) +end + +function Base.size(field::AbstractContinuousField{T, D, NF}) where {T, D, NF} + NN = length(field.data) ÷ NF + return (NF, NN) +end + +""" +$(TYPEDSIGNATURES) +""" +function num_entities(field::AbstractContinuousField{T, D, NF}) where {T, D, NF} + return length(field.data) ÷ NF +end +""" +$(TYPEDSIGNATURES) +""" +function num_fields(::AbstractContinuousField{T, D, NF}) where {T, D, NF} + return NF +end + +abstract type AbstractDiscontinuousField{T, D <: AbstractArray{T, 1}} <: AbstractField{T, 1, D} end + +###################################################################################################### +# Connectivity +###################################################################################################### +""" +$(TYPEDEF) +""" +struct Connectivity{ + T <: Integer, + D <: AbstractVector{T} +} + data::D + nblocks::T + nepes::Vector{T} + nelems::Vector{T} + offsets::Vector{T} +end + +function Connectivity(mats::Vector{<:AbstractArray{<:Integer, 2}}) + nblocks = length(mats) + nepes = map(x -> size(x, 1), mats) + nelems = map(x -> size(x, 2), mats) + offsets = Vector{eltype(nepes)}(undef, 0) + offset = 1 + for (nepe, nelem) in zip(nepes, nelems) + push!(offsets, offset) + offset += nepe * nelem + end + data = mapreduce(vec, vcat, mats) + return Connectivity(data, nblocks, nepes, nelems, offsets) +end + +function Adapt.adapt_structure(to, conn::Connectivity{T, D}) where {T, D} + return Connectivity( + adapt(to, conn.data), + conn.nblocks, + conn.nepes, + conn.nelems, + conn.offsets + ) +end + +# NOT GPU safe +function connectivity(conn::Connectivity, b::Int) + nepe = conn.nepes[b] + nelem = conn.nelems[b] + boffset = conn.offsets[b] + return reshape(view(conn.data, boffset:boffset + nepe * nelem - 1), nepe, nelem) +end + +# GPU safe +@inline function connectivity(ref_fe::ReferenceFE, conn_data, e::Int, boffset::Int) + NNPE = ReferenceFiniteElements.num_cell_dofs(ref_fe) + base = boffset + (e - 1) * NNPE + data = ntuple(i -> conn_data[base + i - 1], NNPE) + return SVector{NNPE, Int}(data) +end + +function num_blocks(conn::Connectivity) + return conn.nblocks +end + +function num_elements(conn::Connectivity) + return sum(conn.nelems) +end + +# NOT GPU safe +function num_elements(conn::Connectivity, b::Int) + return conn.nelems[b] +end + +# NOT GPU safe +function num_entities_per_element(conn::Connectivity, b::Int) + return conn.nepes[b] +end + +# GPU safe +@inline function surface_connectivity(ref_fe::ReferenceFE, conn_data, side::Int, e::Int, boffset::Int) + # Stride through conn_data using the VOLUME element DOF count, not the surface element's. + # The connectivity array is packed with NNPE_vol entries per element; using NNPE_surf as + # the stride reads from the wrong position for element e > 1. + NNPE_vol = ReferenceFiniteElements.num_cell_dofs(ref_fe) + face_nodes = ReferenceFiniteElements.boundary_dofs(ref_fe, side) # 1-based local indices + NNPE_surf = length(face_nodes) + base = boffset + (e - 1) * NNPE_vol + data = ntuple(i -> conn_data[base + face_nodes[i] - 1], NNPE_surf) + return SVector{NNPE_surf, Int}(data) +end + +function unsafe_connectivity(conn::Connectivity, e::Int, b::Int) + nepe = conn.nepes[b] + boffset = conn.offsets[b] + start = boffset + nepe * (e - 1) + finish = boffset + nepe * e - 1 + return view(conn.data, start:finish) +end + +###################################################################################################### +# H1Field +###################################################################################################### +""" +$(TYPEDEF) +$(TYPEDSIGNATURES) +Implementation of fields that live on nodes. +""" +struct H1Field{T, D, NF} <: AbstractContinuousField{T, D, NF} + data::D +end + +""" +$(TYPEDSIGNATURES) +""" +function H1Field(data::M) where M <: AbstractMatrix + NF = size(data, 1) + data = vec(data) + return H1Field{eltype(data), typeof(data), NF}(data) +end + +function Base.zeros(::Type{<:H1Field}, nf::Int, ne::Int) + data = zeros(nf * ne) + return H1Field{eltype(data), typeof(data), nf}(data) +end + +###################################################################################################### +# HcurlField +###################################################################################################### +""" +$(TYPEDEF) +$(TYPEDSIGNATURES) +Implementation of fields that live in Hdiv spaces. +""" +struct HcurlField{T, D, NF} <: AbstractContinuousField{T, D, NF} + data::D +end + +""" +$(TYPEDSIGNATURES) +""" +function HcurlField(data::M) where M <: AbstractMatrix + NF = size(data, 1) + data = vec(data) + return HcurlField{eltype(data), typeof(data), NF}(data) +end + +function Base.zeros(::Type{<:HcurlField}, nf::Int, ne::Int) + data = zeros(nf * ne) + return HcurlField{eltype(data), typeof(data), nf}(data) +end + +###################################################################################################### +# HdivField +###################################################################################################### +""" +$(TYPEDEF) +$(TYPEDSIGNATURES) +Implementation of fields that live in Hdiv spaces. +""" +struct HdivField{T, D, NF} <: AbstractContinuousField{T, D, NF} + data::D +end + +""" +$(TYPEDSIGNATURES) +""" +function HdivField(data::M) where M <: AbstractMatrix + NF = size(data, 1) + data = vec(data) + return HdivField{eltype(data), typeof(data), NF}(data) +end + +function Base.zeros(::Type{<:HdivField}, nf::Int, ne::Int) + data = zeros(nf * ne) + return HdivField{eltype(data), typeof(data), nf}(data) +end + +###################################################################################################### +# L2Field +###################################################################################################### +struct L2Field{ + T, # Let it be anything to allow for structs + D <: AbstractVector{T} +} <: AbstractDiscontinuousField{T, D} + data::D # flat storage (CPU or GPU) + nfields::Vector{Int} + nepes::Vector{Int} # num nodes, q points, etc. + nelems::Vector{Int} + offsets::Vector{Int} +end + +function L2Field(arrs::Vector{<:AbstractArray{T, 3}}) where T + nfields = map(x -> size(x, 1), arrs) + nepes = map(x -> size(x, 2), arrs) + nelems = map(x -> size(x, 3), arrs) + offsets = Vector{eltype(nepes)}(undef, 0) + offset = 1 + for b in 1:length(nepes) + push!(offsets, offset) + offset += nfields[b] * nepes[b] * nelems[b] + end + data = mapreduce(vec, vcat, arrs) + return L2Field(data, nfields, nepes, nelems, offsets) +end + +function L2Field(::UndefInitializer, ::Type{T}, nfields::Int, qsizes::Vector{Tuple{Int, Int}}) where T + arrs = Array{T, 3}[] + for (nq, ne) in qsizes + push!(arrs, Array{T, 3}(undef, nfields, nq, ne)) + end + return L2Field(arrs) +end + +function L2Field(::UndefInitializer, ::Type{T}, nfields::Vector{Int}, qsizes::Vector{Tuple{Int, Int}}) where T + arrs = Array{T, 3}[] + for (nf, (nq, ne)) in zip(nfields, qsizes) + push!(arrs, Array{T, 3}(undef, nf, nq, ne)) + end + return L2Field(arrs) +end + +function Adapt.adapt_structure(to, field::L2Field{T, D}) where {T, D} + data = adapt(to, field.data) + return L2Field{T, typeof(data)}( + data, + field.nfields, + field.nepes, + field.nelems, + field.offsets + ) +end + +function Base.show(io::IO, field::L2Field) + println(io, "L2Field:") + for b in 1:num_blocks(field) + nf, nepe, ne = block_size(field, b) + println(io, " Block $b:") + println(io, " Number of fields = $nf") + println(io, " Number of entities per element = $nepe") + println(io, " Number of elements = $ne") + end +end + +# just to have something to fall back to +Base.getindex(field::L2Field, i::Int) = field.data[i] +Base.IndexStyle(::Type{<:L2Field}) = IndexLinear() +Base.size(field::L2Field) = size(field.data) + +function Base.show(io::IO, ::MIME"text/plain", field::L2Field) + show(io, field) +end + +function block_size(field::L2Field, b::Int) + return (field.nfields[b], field.nepes[b], field.nelems[b]) +end + +function block_view(field::L2Field, b::Int) + nfield = field.nfields[b] + nepe = field.nepes[b] + nelem = field.nelems[b] + boffset = field.offsets[b] + bend = boffset + nfield * nepe * nelem - 1 + return reshape(view(field.data, boffset:bend), nfield, nepe, nelem) +end + +function num_blocks(field::L2Field) + return length(field.nelems) +end diff --git a/src/FiniteElementContainers.jl b/src/FiniteElementContainers.jl index f3fdd0d..59f06b6 100644 --- a/src/FiniteElementContainers.jl +++ b/src/FiniteElementContainers.jl @@ -223,8 +223,9 @@ end # TODO clean this up, make it make sense in an ordered way # include("parallel/Parallel.jl") include("Expressions.jl") +include("Fields.jl") include("PostProcessors.jl") -include("fields/Fields.jl") +# include("fields/Fields.jl") # include("Utils.jl") include("meshes/Meshes.jl") include("FunctionSpaces.jl") @@ -235,7 +236,7 @@ include("DofManagers.jl") # include("Utils.jl") include("bcs/BoundaryConditions.jl") -include("constraints/Constraints.jl") +include("Constraints.jl") include("InitialConditions.jl") include("Formulations.jl") diff --git a/src/fields/Connectivity.jl b/src/fields/Connectivity.jl deleted file mode 100644 index b1a9e8e..0000000 --- a/src/fields/Connectivity.jl +++ /dev/null @@ -1,92 +0,0 @@ -""" -$(TYPEDEF) -""" -struct Connectivity{ - T <: Integer, - D <: AbstractVector{T} -} - data::D - nblocks::T - nepes::Vector{T} - nelems::Vector{T} - offsets::Vector{T} -end - -function Connectivity(mats::Vector{<:AbstractArray{<:Integer, 2}}) - nblocks = length(mats) - nepes = map(x -> size(x, 1), mats) - nelems = map(x -> size(x, 2), mats) - offsets = Vector{eltype(nepes)}(undef, 0) - offset = 1 - for (nepe, nelem) in zip(nepes, nelems) - push!(offsets, offset) - offset += nepe * nelem - end - data = mapreduce(vec, vcat, mats) - return Connectivity(data, nblocks, nepes, nelems, offsets) -end - -function Adapt.adapt_structure(to, conn::Connectivity{T, D}) where {T, D} - return Connectivity( - adapt(to, conn.data), - conn.nblocks, - conn.nepes, - conn.nelems, - conn.offsets - ) -end - -# NOT GPU safe -function connectivity(conn::Connectivity, b::Int) - nepe = conn.nepes[b] - nelem = conn.nelems[b] - boffset = conn.offsets[b] - return reshape(view(conn.data, boffset:boffset + nepe * nelem - 1), nepe, nelem) -end - -# GPU safe -@inline function connectivity(ref_fe::ReferenceFE, conn_data, e::Int, boffset::Int) - NNPE = ReferenceFiniteElements.num_cell_dofs(ref_fe) - base = boffset + (e - 1) * NNPE - data = ntuple(i -> conn_data[base + i - 1], NNPE) - return SVector{NNPE, Int}(data) -end - -function num_blocks(conn::Connectivity) - return conn.nblocks -end - -function num_elements(conn::Connectivity) - return sum(conn.nelems) -end - -# NOT GPU safe -function num_elements(conn::Connectivity, b::Int) - return conn.nelems[b] -end - -# NOT GPU safe -function num_entities_per_element(conn::Connectivity, b::Int) - return conn.nepes[b] -end - -# GPU safe -@inline function surface_connectivity(ref_fe::ReferenceFE, conn_data, side::Int, e::Int, boffset::Int) - # Stride through conn_data using the VOLUME element DOF count, not the surface element's. - # The connectivity array is packed with NNPE_vol entries per element; using NNPE_surf as - # the stride reads from the wrong position for element e > 1. - NNPE_vol = ReferenceFiniteElements.num_cell_dofs(ref_fe) - face_nodes = ReferenceFiniteElements.boundary_dofs(ref_fe, side) # 1-based local indices - NNPE_surf = length(face_nodes) - base = boffset + (e - 1) * NNPE_vol - data = ntuple(i -> conn_data[base + face_nodes[i] - 1], NNPE_surf) - return SVector{NNPE_surf, Int}(data) -end - -function unsafe_connectivity(conn::Connectivity, e::Int, b::Int) - nepe = conn.nepes[b] - boffset = conn.offsets[b] - start = boffset + nepe * (e - 1) - finish = boffset + nepe * e - 1 - return view(conn.data, start:finish) -end diff --git a/src/fields/Fields.jl b/src/fields/Fields.jl deleted file mode 100644 index 3aaf5de..0000000 --- a/src/fields/Fields.jl +++ /dev/null @@ -1,96 +0,0 @@ -""" -$(TYPEDEF) -Thin wrapper that subtypes ```AbstractArray``` and serves -as the base ```Field``` type -""" -abstract type AbstractField{T, N, D <: AbstractArray{T, 1}} <: AbstractArray{T, N} end -""" -$(TYPEDSIGNATURES) -""" -Base.fill!(field::AbstractField{T, N, D}, v::T) where {T, N, D} = fill!(field.data, v) -""" -$(TYPEDSIGNATURES) -""" -Base.unique(field::AbstractField) = unique(field.data) -""" -$(TYPEDSIGNATURES) -""" -KA.get_backend(field::AbstractField) = KA.get_backend(field.data) - -abstract type AbstractContinuousField{T, D <: AbstractArray{T, 1}, NF} <: AbstractField{T, 2, D} end - -function Adapt.adapt_structure(to, field::AbstractContinuousField{T, D, NF}) where {T, D, NF} - data = adapt(to, field.data) - type = typeof(field).name.name - return eval(type){T, typeof(data), NF}(data) -end - -# minimal abstractarray interface methods below - -function Base.axes(field::AbstractContinuousField{T, D, NF}) where {T, D, NF} - NN = length(field) ÷ NF - return (Base.OneTo(NF), Base.OneTo(NN)) -end - -function Base.getindex(field::AbstractContinuousField, n::Int) - return getindex(field.data, n) -end - -function Base.getindex(field::AbstractContinuousField, d::Int, n::Int) - @assert d > 0 && d <= num_fields(field) - @assert n > 0 && n <= num_entities(field) - getindex(field.data, (n - 1) * num_fields(field) + d) -end - -function Base.IndexStyle(::Type{<:AbstractContinuousField}) - return IndexLinear() -end - -function Base.setindex!(field::AbstractContinuousField{T, D, NF}, v::T, n::Int) where {T, D, NF} - setindex!(field.data, v, n) - return nothing -end - -function Base.setindex!(field::AbstractContinuousField{T, D, NF}, v, d::Int, n::Int) where {T, D, NF} - @assert d > 0 && d <= num_fields(field) - @assert n > 0 && n <= num_entities(field) - setindex!(field.data, v, (n - 1) * num_fields(field) + d) -end - -function Base.similar(field::AbstractContinuousField) - data = similar(field.data) - return typeof(field)(data) -end - -function Base.size(field::AbstractContinuousField{T, D, NF}) where {T, D, NF} - NN = length(field.data) ÷ NF - return (NF, NN) -end - -# function Base.zeros(type::Type{<:AbstractContinuousField}, nf::Int, ne::Int) -# @show "Hur" -# data = zeros(nf * ne) -# return eval(type.name.name){eltype(data), typeof(data), nf}(data) -# end - -""" -$(TYPEDSIGNATURES) -""" -function num_entities(field::AbstractContinuousField{T, D, NF}) where {T, D, NF} - return length(field.data) ÷ NF -end -""" -$(TYPEDSIGNATURES) -""" -function num_fields(::AbstractContinuousField{T, D, NF}) where {T, D, NF} - return NF -end - -abstract type AbstractDiscontinuousField{T, D <: AbstractArray{T, 1}} <: AbstractField{T, 1, D} end - -# actual implementations -include("Connectivity.jl") -include("H1Field.jl") -include("HcurlField.jl") -include("HdivField.jl") -include("L2Field.jl") diff --git a/src/fields/H1Field.jl b/src/fields/H1Field.jl deleted file mode 100644 index 5cfa7c9..0000000 --- a/src/fields/H1Field.jl +++ /dev/null @@ -1,22 +0,0 @@ -""" -$(TYPEDEF) -$(TYPEDSIGNATURES) -Implementation of fields that live on nodes. -""" -struct H1Field{T, D, NF} <: AbstractContinuousField{T, D, NF} - data::D -end - -""" -$(TYPEDSIGNATURES) -""" -function H1Field(data::M) where M <: AbstractMatrix - NF = size(data, 1) - data = vec(data) - return H1Field{eltype(data), typeof(data), NF}(data) -end - -function Base.zeros(::Type{<:H1Field}, nf::Int, ne::Int) - data = zeros(nf * ne) - return H1Field{eltype(data), typeof(data), nf}(data) -end diff --git a/src/fields/HcurlField.jl b/src/fields/HcurlField.jl deleted file mode 100644 index 1b35956..0000000 --- a/src/fields/HcurlField.jl +++ /dev/null @@ -1,22 +0,0 @@ -""" -$(TYPEDEF) -$(TYPEDSIGNATURES) -Implementation of fields that live in Hdiv spaces. -""" -struct HcurlField{T, D, NF} <: AbstractContinuousField{T, D, NF} - data::D -end - -""" -$(TYPEDSIGNATURES) -""" -function HcurlField(data::M) where M <: AbstractMatrix - NF = size(data, 1) - data = vec(data) - return HcurlField{eltype(data), typeof(data), NF}(data) -end - -function Base.zeros(::Type{<:HcurlField}, nf::Int, ne::Int) - data = zeros(nf * ne) - return HcurlField{eltype(data), typeof(data), nf}(data) -end diff --git a/src/fields/HdivField.jl b/src/fields/HdivField.jl deleted file mode 100644 index 3576018..0000000 --- a/src/fields/HdivField.jl +++ /dev/null @@ -1,22 +0,0 @@ -""" -$(TYPEDEF) -$(TYPEDSIGNATURES) -Implementation of fields that live in Hdiv spaces. -""" -struct HdivField{T, D, NF} <: AbstractContinuousField{T, D, NF} - data::D -end - -""" -$(TYPEDSIGNATURES) -""" -function HdivField(data::M) where M <: AbstractMatrix - NF = size(data, 1) - data = vec(data) - return HdivField{eltype(data), typeof(data), NF}(data) -end - -function Base.zeros(::Type{<:HdivField}, nf::Int, ne::Int) - data = zeros(nf * ne) - return HdivField{eltype(data), typeof(data), nf}(data) -end diff --git a/src/fields/L2Field.jl b/src/fields/L2Field.jl deleted file mode 100644 index d6209f6..0000000 --- a/src/fields/L2Field.jl +++ /dev/null @@ -1,88 +0,0 @@ -struct L2Field{ - T, # Let it be anything to allow for structs - D <: AbstractVector{T} -} <: AbstractDiscontinuousField{T, D} - data::D # flat storage (CPU or GPU) - nfields::Vector{Int} - nepes::Vector{Int} # num nodes, q points, etc. - nelems::Vector{Int} - offsets::Vector{Int} -end - -function L2Field(arrs::Vector{<:AbstractArray{T, 3}}) where T - nfields = map(x -> size(x, 1), arrs) - nepes = map(x -> size(x, 2), arrs) - nelems = map(x -> size(x, 3), arrs) - offsets = Vector{eltype(nepes)}(undef, 0) - offset = 1 - for b in 1:length(nepes) - push!(offsets, offset) - offset += nfields[b] * nepes[b] * nelems[b] - end - data = mapreduce(vec, vcat, arrs) - return L2Field(data, nfields, nepes, nelems, offsets) -end - -function L2Field(::UndefInitializer, ::Type{T}, nfields::Int, qsizes::Vector{Tuple{Int, Int}}) where T - arrs = Array{T, 3}[] - for (nq, ne) in qsizes - push!(arrs, Array{T, 3}(undef, nfields, nq, ne)) - end - return L2Field(arrs) -end - -function L2Field(::UndefInitializer, ::Type{T}, nfields::Vector{Int}, qsizes::Vector{Tuple{Int, Int}}) where T - arrs = Array{T, 3}[] - for (nf, (nq, ne)) in zip(nfields, qsizes) - push!(arrs, Array{T, 3}(undef, nf, nq, ne)) - end - return L2Field(arrs) -end - -function Adapt.adapt_structure(to, field::L2Field{T, D}) where {T, D} - data = adapt(to, field.data) - return L2Field{T, typeof(data)}( - data, - field.nfields, - field.nepes, - field.nelems, - field.offsets - ) -end - -function Base.show(io::IO, field::L2Field) - println(io, "L2Field:") - for b in 1:num_blocks(field) - nf, nepe, ne = block_size(field, b) - println(io, " Block $b:") - println(io, " Number of fields = $nf") - println(io, " Number of entities per element = $nepe") - println(io, " Number of elements = $ne") - end -end - -# just to have something to fall back to -Base.getindex(field::L2Field, i::Int) = field.data[i] -Base.IndexStyle(::Type{<:L2Field}) = IndexLinear() -Base.size(field::L2Field) = size(field.data) - -function Base.show(io::IO, ::MIME"text/plain", field::L2Field) - show(io, field) -end - -function block_size(field::L2Field, b::Int) - return (field.nfields[b], field.nepes[b], field.nelems[b]) -end - -function block_view(field::L2Field, b::Int) - nfield = field.nfields[b] - nepe = field.nepes[b] - nelem = field.nelems[b] - boffset = field.offsets[b] - bend = boffset + nfield * nepe * nelem - 1 - return reshape(view(field.data, boffset:bend), nfield, nepe, nelem) -end - -function num_blocks(field::L2Field) - return length(field.nelems) -end diff --git a/test/TestAppTools.jl b/test/TestAppTools.jl index f1d30f7..9ffe1cf 100644 --- a/test/TestAppTools.jl +++ b/test/TestAppTools.jl @@ -107,8 +107,35 @@ end import FiniteElementContainers.AppTools as AT args = [ "--input-file", "input-file.toml", - "--log-file", "log.log" + "--log-file", "log.log", + "--backend", "cpu" ] app = AT.App("MyApp") + AT.add_cli_arg!(app, "--backend") + AT.parse!(app.cli_arg_parser, args) + arg = AT.get_cli_arg(app, "--backend") + @test arg == "cpu" + + sim = AT.setup(app, args) # sim = AT.setup(app, args) end + +@testitem "AppTools - generate app" begin + import FiniteElementContainers.AppTools as AT + AT.generate_app("MyApp") + @test isdir("MyApp") + @test isfile("MyApp/build.jl") + @test isfile("MyApp/Project.toml") + @test isdir("MyApp/src") + @test isfile("MyApp/src/MyApp.jl") + rm("MyApp"; force = true, recursive = true) + + mkdir("app_dir") + AT.generate_app("MyApp"; backends = ["cpu", "cuda", "mpi", "rocm"], directory = "app_dir", trim = true) + @test isdir("app_dir/MyApp") + @test isfile("app_dir/MyApp/build.jl") + @test isfile("app_dir/MyApp/Project.toml") + @test isdir("app_dir/MyApp/src") + @test isfile("app_dir/MyApp/src/MyApp.jl") + rm("app_dir"; force = true, recursive = true) +end diff --git a/test/input-file.toml b/test/input-file.toml new file mode 100644 index 0000000..1a23e2d --- /dev/null +++ b/test/input-file.toml @@ -0,0 +1,26 @@ +[device] +backend = "cpu" + +[functions.zero] +type = "constant" +expression = "0.0" +variables = ["x", "y"] + +[functions.one] +type = "constant" +expression = "1.0" +variables = ["x", "y"] + +[mesh] +file_path = "poisson/poisson.g" +file_type = "exodus" + +[[initial_conditions]] +function = "one" +block = "block_1" +variable = "u" + +[[boundary_conditions.dirichlet]] +function = "zero" +side_set = "sset_1" +variable = "u" diff --git a/test/poisson/TestPoisson.jl b/test/poisson/TestPoisson.jl index 5af9b1f..611ad49 100644 --- a/test/poisson/TestPoisson.jl +++ b/test/poisson/TestPoisson.jl @@ -266,6 +266,7 @@ end end @testitem "Regression test - test_poisson_dirichlet_with_nodesets_gmsh_msh_tri3" setup=[PoissonRegressionHelper] begin + using Gmsh msh_file_tri3 = dirname(Base.source_dir()) * "/gmsh/square_meshed_with_tris.msh" output_file = "poisson_test_4.e" mesh = UnstructuredMesh(msh_file_tri3)