diff --git a/.travis.yml b/.travis.yml index d962ec16f..1d3429e33 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,8 @@ language: julia os: - linux julia: - - 1.0 - - 1.4 + - 1.3 + - 1.5 notifications: email: on_success: never diff --git a/NEWS.md b/NEWS.md index 2cf9eb612..f44de332f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.14.0] - Unreleased + +### Changed + - Table struct has been generalized such that data and ptrs arrays can be of an arbitrary type extending AbstractArray. Since PR [#310](https://github.com/gridap/Gridap.jl/pull/310/) + - `interpolate, interpolate!, interpolate_dirichlet...` switched argument order to function first style. For instance `interpolate(u, V)` instead of `interpolate(V, u)` ## [0.13.4] - 2020-08-23 @@ -69,6 +74,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Possibility to have 0 order in `DISC` directions of a `CDLagrangianRefFE`. Since PR [#308](https://github.com/gridap/Gridap.jl/pull/308). - Added setindex! method for Reindexed. Since PR [#309](https://github.com/gridap/Gridap.jl/pull/309). + ### Changed - Changed the interfaces of `ReferenceFE` and `NodalReferenceFE` in relation of DOF ownership. Now function `get_face_own_dofs` and related ones are parametrized by a `Conformity` object. Since PR [#311](https://github.com/gridap/Gridap.jl/pull/311). @@ -76,6 +82,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Renamed `PDiscRefFE` -> `DiscRefFE` struct keeping the name for constructor. Since PR [#293](https://github.com/gridap/Gridap.jl/pull/293). - One of the `GradConformingFESpace` methods now more general `ConformingFESpace`. Since PR [#293](https://github.com/gridap/Gridap.jl/pull/293). - `DivConformingFESpace` and `CurlConformingFESpace` constructors eliminated. Since PR [#293](https://github.com/gridap/Gridap.jl/pull/293). + - Extend table to support arbitrary vector types. Since PR [#310](https://github.com/gridap/Gridap.jl/pull/310). ### Fixed diff --git a/Project.toml b/Project.toml index 24ce5ff83..b659e2a1f 100644 --- a/Project.toml +++ b/Project.toml @@ -1,11 +1,12 @@ name = "Gridap" uuid = "56d4f2e9-7ea1-5844-9cf6-b9c51ca7ce8e" authors = ["Santiago Badia ", "Francesc Verdugo "] -version = "0.13.4" +version = "0.14.0" [deps] AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" BSON = "fbb218c0-5317-5bc6-957e-2ee96dd4b1f0" +BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" FastGaussQuadrature = "442a2c76-b920-505d-bb47-c5924d526838" @@ -26,6 +27,7 @@ WriteVTK = "64499a7a-5c06-52f2-abe2-ccb03c286192" [compat] AbstractTrees = "0.3.3" BSON = "0.2.5" +BlockArrays = "0.12.12" Combinatorics = "1.0.0" DocStringExtensions = "0.8.1" FastGaussQuadrature = "0.4.2" @@ -39,7 +41,7 @@ NLsolve = "4.3.0" QuadGK = "2.3.1" StaticArrays = "0.12.1" WriteVTK = "1.7" -julia = "1.0" +julia = "1.3" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/bench/FieldsBenchs/FieldApplyBenchs.jl b/bench/FieldsBenchs/FieldApplyBenchs.jl index a37e44d56..fee52be25 100644 --- a/bench/FieldsBenchs/FieldApplyBenchs.jl +++ b/bench/FieldsBenchs/FieldApplyBenchs.jl @@ -18,13 +18,13 @@ function bench1(n) v = 3.0 d = 2 f = MockField{d}(v) - g = apply_kernel_to_field(bcast(+),f,v) + g = operate_fields(+,f,v) cg = field_cache(g,x) @time repeat(n,evaluate!,cg,g,x) ∇g = gradient(g) ∇cg = field_cache(∇g,x) @time repeat(n,evaluate!,∇cg,∇g,x) - h = apply_kernel_to_field(bcast(+),f,f) + h = operate_fields(+,f,f) ch = field_cache(h,x) @time repeat(n,evaluate!,ch,h,x) end diff --git a/bench/FieldsBenchs/FieldArraysBenchs.jl b/bench/FieldsBenchs/FieldArraysBenchs.jl index 60f5ee60e..e7adbc19c 100644 --- a/bench/FieldsBenchs/FieldArraysBenchs.jl +++ b/bench/FieldsBenchs/FieldArraysBenchs.jl @@ -33,7 +33,7 @@ function bench1(n) afx = evaluate(af,ax) cafx = array_cache(afx) @time loop(afx,cafx) - ag = apply_to_field_array(bcast(+),af,af) + ag = operate_arrays_of_fields(+,af,af) cag = array_cache(ag) @time loop(ag,cag) agx = evaluate(ag,ax) @@ -58,7 +58,7 @@ function bench2(n) afx = evaluate(af,ax) cafx = array_cache(afx) @time loop(afx,cafx) - _ag = apply_to_field_array(bcast(+),af,af) + _ag = operate_arrays_of_fields(+,af,af) ag = gradient(_ag) cag = array_cache(ag) @time loop(ag,cag) @@ -85,7 +85,7 @@ function bench2a(n) afx = evaluate(af,ax) cafx = array_cache(afx) @time loop(afx,cafx) - _ag = apply_to_field_array(bcast(+),af,av) + _ag = operate_arrays_of_fields(+,af,av) ag = gradient(_ag) cag = array_cache(ag) @time loop(ag,cag) @@ -115,7 +115,7 @@ function bench3(n) afx = evaluate(af,ax) cafx = array_cache(afx) @time loop(afx,cafx) - ag = apply_to_field_array(bcast(+),af,aw) + ag = operate_arrays_of_fields(+,af,aw) cag = array_cache(ag) @time loop(ag,cag) agx = evaluate(ag,ax) diff --git a/bench/FieldsBenchs/FieldOperationsBenchs.jl b/bench/FieldsBenchs/FieldOperationsBenchs.jl index 272d25460..8b5ba383a 100644 --- a/bench/FieldsBenchs/FieldOperationsBenchs.jl +++ b/bench/FieldsBenchs/FieldOperationsBenchs.jl @@ -37,20 +37,20 @@ function bench1(n) aba = Fill(ba,l) abb = Fill(bb,l) - ag_ff = field_array_operation(inner,afa,afb) + ag_ff = operate_arrays_of_fields(inner,afa,afb) agx_ff = evaluate(ag_ff,ax) cagx_ff = array_cache(agx_ff) @time loop(agx_ff,cagx_ff) - ag_bf = field_array_operation(inner,aba,afb) + ag_bf = operate_arrays_of_fields(inner,aba,afb) agx_bf = evaluate(ag_bf,ax) cagx_bf = array_cache(agx_bf) @time loop(agx_bf,cagx_bf) - ag_bb = field_array_operation(inner,aba,abb) - agx_bb = evaluate(ag_bb,ax) - cagx_bb = array_cache(agx_bb) - @time loop(agx_bb,cagx_bb) + #ag_bb = operate_arrays_of_fields(inner,aba,abb) + #agx_bb = evaluate(ag_bb,ax) + #cagx_bb = array_cache(agx_bb) + #@time loop(agx_bb,cagx_bb) end diff --git a/bench/FieldsBenchs/IntegrateBenchs.jl b/bench/FieldsBenchs/IntegrateBenchs.jl index a792e15d6..6cd47c3a3 100644 --- a/bench/FieldsBenchs/IntegrateBenchs.jl +++ b/bench/FieldsBenchs/IntegrateBenchs.jl @@ -79,13 +79,13 @@ function bench3(n) ar = Fill(r,l) ab = attachmap(ar,aϕ) - fmass = field_array_operation(inner,ab,ab) + fmass = operate_arrays_of_fields(inner,ab,ab) mmass = integrate(fmass,ax,aw,aj) cmmass = array_cache(mmass) @time loop(mmass,cmmass) - fstif = field_array_operation(inner,∇(ab),∇(ab)) + fstif = operate_arrays_of_fields(inner,∇(ab),∇(ab)) mstif = integrate(fstif,ax,aw,aj) cmstif = array_cache(mstif) diff --git a/docs/src/Geometry.md b/docs/src/Geometry.md index b7d3312cb..2d52bd1cc 100644 --- a/docs/src/Geometry.md +++ b/docs/src/Geometry.md @@ -340,19 +340,6 @@ RestrictedDiscreteModel ## CellFields -### CellFieldLike interface -```@docs -CellFieldLike -get_array(cf::CellFieldLike) -get_cell_map(cf::CellFieldLike) -similar_object(cf::CellFieldLike,array::AbstractArray) -similar_object(cf1::CellFieldLike,cf2::CellFieldLike,array::AbstractArray) -gradient(cf::CellFieldLike) -grad2curl(cf::CellFieldLike) -test_cell_field_like -evaluate(cf::CellFieldLike,x) -length(cf::CellFieldLike) -``` ### CellField interface ```@docs diff --git a/src/Algebra/LinearSolvers.jl b/src/Algebra/LinearSolvers.jl index 0af0b0efa..484d549a0 100644 --- a/src/Algebra/LinearSolvers.jl +++ b/src/Algebra/LinearSolvers.jl @@ -11,10 +11,18 @@ struct AffineOperator{A<:AbstractMatrix,B<:AbstractVector} <: NonlinearOperator end """ + get_matrix(operator) + +Return the matrix corresponding to the assembled left hand side of the operator. +This matrix incorporates all boundary conditions and constraints. """ get_matrix(op::AffineOperator) = op.matrix """ + get_vector(operator) + +Return the vector corresponding to the assembled right hand side of the operator. +This vector includes all boundary conditions and constraints. """ get_vector(op::AffineOperator) = op.vector diff --git a/src/Arrays/Arrays.jl b/src/Arrays/Arrays.jl index cada75191..75fa2f5ed 100644 --- a/src/Arrays/Arrays.jl +++ b/src/Arrays/Arrays.jl @@ -12,6 +12,7 @@ module Arrays using Gridap.Helpers using Gridap.Inference +using Gridap.Algebra using DocStringExtensions using Test @@ -19,6 +20,20 @@ using FillArrays using Base: @propagate_inbounds using LinearAlgebra using ForwardDiff +using BlockArrays + +export BlockArrayCoo +export BlockVectorCoo +export BlockMatrixCoo +export is_zero_block +export is_nonzero_block +export enumerateblocks +export eachblockindex +export VectorOfBlockArrayCoo +export VectorOfBlockVectorCoo +export VectorOfBlockMatrixCoo +export zeros_like +export TwoLevelBlockedUnitRange export array_cache export getindex! @@ -37,6 +52,7 @@ export CachedArray export CachedMatrix export CachedVector export setsize! +export setaxes! export CompressedArray export LocalToGlobalArray @@ -52,6 +68,8 @@ export test_kernel export bcast export elem export contract +export MulKernel +export MulAddKernel export kernel_return_type export kernel_return_types export kernel_testitem @@ -103,8 +121,12 @@ import Base: IndexStyle import Gridap.Io: to_dict import Gridap.Io: from_dict +import Gridap.Algebra: scale_entries! + include("Interface.jl") +include("BlockArraysCoo.jl") + include("CachedArrays.jl") include("Kernels.jl") @@ -131,6 +153,8 @@ include("ArrayPairs.jl") include("AppendedArrays.jl") +include("VectorsOfBlockArrayCoo.jl") + include("Autodiff.jl") end # module diff --git a/src/Arrays/BlockArraysCoo.jl b/src/Arrays/BlockArraysCoo.jl new file mode 100644 index 000000000..fa3e5c87e --- /dev/null +++ b/src/Arrays/BlockArraysCoo.jl @@ -0,0 +1,490 @@ + +struct BlockArrayCoo{T,N,A,X} <: AbstractBlockArray{T,N} + blocks::Vector{A} + blockids::Vector{NTuple{N,Int}} + axes::X + ptrs::Array{Int,N} + zero_blocks::Vector{A} + function BlockArrayCoo( + blocks::Vector{A}, + blockids::Vector{NTuple{N,Int}}, + axes::NTuple{N}, + ptrs::Array{Int,N}=_compute_ptrs(blockids,axes), + zero_blocks::Vector{A}=_compute_zero_blocks(A,ptrs,axes)) where {T,N,A<:AbstractArray{T,N}} + + X = typeof(axes) + new{T,N,A,X}(blocks,blockids,axes,ptrs,zero_blocks) + end +end + +function BlockArrayCoo( + blocks::Vector{A},ax::NTuple{N},ptrs::Array{Int,N},zero_blocks::Vector{A}) where {A,N} + cis = CartesianIndices(ptrs) + blockids = NTuple{N,Int}[] + for ci in cis + p = ptrs[ci] + if p>0 + push!(blockids,Tuple(ci)) + end + end + BlockArrayCoo(blocks,blockids,ax,ptrs,zero_blocks) +end + +function BlockArrayCoo(allblocks::AbstractArray{A,N},ax::NTuple{N},mask::AbstractArray{Bool,N}=fill(true,size(allblocks))) where {A,N} + blocks = A[] + zero_blocks = A[] + ptrs = zeros(Int,size(allblocks)) + pp = 1 + pn = 1 + cis = CartesianIndices(allblocks) + for ci in cis + if mask[ci] + push!(blocks,allblocks[ci]) + ptrs[ci] = pp + pp += 1 + else + push!(zero_blocks,allblocks[ci]) + ptrs[ci] = -pn + pn += 1 + end + end + BlockArrayCoo(blocks,ax,ptrs,zero_blocks) +end + +# axs = _compute_axes_from_allblocks(allblocks) +# +#function _compute_axes_from_allblocks(allblocks) +# N = ndims(allblocks) +# s = size(allblocks) +# axtmp = [ zeros(Int,s[n]) for n in 1:N] +# cis = CartesianIndices(allblocks) +# for ci in cis +# block = allblocks[ci] +# sb = size(block) +# for (n,cin) in enumerate(Tuple(ci)) +# axtmp[n][cin] = sb[n] +# end +# end +# axs = map(blockedrange,Tuple(axtmp)) +# axs +#end + +const BlockMatrixCoo = BlockArrayCoo{T,2} where T +const BlockVectorCoo = BlockArrayCoo{T,1} where T + +zeros_like(a::AbstractArray) = zeros_like(a,axes(a)) + +function zeros_like(a::BlockArrayCoo,axs::Tuple) + blocks = eltype(a.blocks)[] + blockids = eltype(a.blockids)[] + BlockArrayCoo(blocks,blockids,axs) +end + +function zeros_like(a::AbstractArray,axs::Tuple) + T = eltype(a) + b = similar(a,T,axs) + fill!(b,zero(T)) + b +end + +function zeros_like(::Type{<:BlockArrayCoo{T,N,A}},axs::Tuple) where {T,N,A} + blocks = A[] + blockids = NTuple{N,Int}[] + BlockArrayCoo(blocks,blockids,axs) +end + +function zeros_like(::Type{A},axs::Tuple) where A <: AbstractArray + a = similar(A,axs) + fill!(a,zero(eltype(a))) + a +end + +Base.similar(a::BlockArrayCoo) = similar(a,eltype(a),axes(a)) + +Base.similar(a::BlockArrayCoo,axs::Tuple) = similar(a,eltype(a),axs) + +function Base.similar(a::BlockArrayCoo{S,N} where S,::Type{T}, axs::NTuple{N,<:BlockedUnitRange}) where {T,N} + _similar_block_array_coo(a,T,axs) +end + +function _similar_block_array_coo(a,::Type{T},axs) where T + S = eltype(a) + @notimplementedif S != T + A = eltype(a.blocks) + blocks = A[] + for p in 1:length(a.blocks) + I = a.blockids[p] + laxs = map( local_range, axs, I) + block = similar(a.blocks[p],T,laxs) + push!(blocks,block) + end + BlockArrayCoo(blocks,a.blockids,axs,a.ptrs) +end + +function local_range(a::BlockedUnitRange,k::Integer) + n = length(a[Block(k)]) + Base.OneTo(n) +end + +function _compute_ptrs(blockids,axes) + s = map(i->first(blocksize(i)),axes) + ptrs = zeros(Int,s) + for (i,c) in enumerate(blockids) + ptrs[c...] = i + end + m = 1 + for (k,p) in enumerate(ptrs) + if p ==0 + ptrs[k] = -m + m += 1 + end + end + ptrs +end + +function _compute_zero_blocks(::Type{A},ptrs,axs) where A + cis = CartesianIndices(ptrs) + zero_blocks = A[] + for ci in cis + p = ptrs[ci] + if p<0 + I = Tuple(ci) + laxs = map( local_range, axs, I) + block = zeros_like(A,laxs) + push!(zero_blocks,block) + end + end + zero_blocks +end + +function BlockArrays.getblock(a::BlockArrayCoo,i::Integer...) + p = a.ptrs[i...] + if p>0 + a.blocks[p] + else + a.zero_blocks[-p] + end +end + +@inline is_nonzero_block(a,b...) = ! is_zero_block(a,b...) + +function is_zero_block(a,b::Block) + i = convert(Tuple,b) + is_zero_block(a,i...) +end + +function is_zero_block(a,b::Block...) + i = map(Int,b) + is_zero_block(a,i...) +end + +function is_zero_block(a,b::CartesianIndex) + i = Tuple(b) + is_zero_block(a,i...) +end + +function is_zero_block(a::BlockArrayCoo,i::Integer...) + p = a.ptrs[i...] + @assert p != 0 + p < 0 +end + +function BlockArrays.getblock!(block,a::BlockArrayCoo,i::Integer...) + p = a.ptrs[i...] + if p>0 + block .= a.blocks[p] + else + block .= a.zero_blocks[-p] + end +end + +function BlockArrays.eachblock(a::BlockArrayCoo) + cis = CartesianIndices(blocksize(a)) + blocks = map(ci->Block(Tuple(ci)),cis) + ( a[block] for block in blocks ) +end + +function enumerateblocks(a) + blocks = eachblockindex(a) + zip(blocks,eachblock(a)) +end + +function eachblockindex(a) + cis = CartesianIndices(blocksize(a)) + map(ci->Block(Tuple(ci)),cis) +end + +Base.size(a::BlockArrayCoo) = map(length,Base.axes(a)) + +Base.axes(a::BlockArrayCoo) = a.axes + +function Base.getindex(a::BlockArrayCoo{T,N} where T,i::Vararg{Integer,N}) where N + s = map(findblockindex,a.axes,i) + ai = a[s...] + ai +end + +function Base.getindex(a::BlockVectorCoo,i::Integer,j::Integer...) + @assert all( j .== 1) + s = map(findblockindex,a.axes,(i,)) + ai = a[s...] + ai +end + +function Base.:+(a::BlockArrayCoo{Ta,N},b::BlockArrayCoo{Tb,N}) where {Ta,Tb,N} + @assert axes(a) == axes(b) + @assert blockaxes(a) == blockaxes(b) + I1 = first(eachblockindex(a)) + A = typeof(a[I1]+b[I1]) + blocks = A[] + blockids = NTuple{N,Int}[] + for (I,aI) in enumerateblocks(a) + bI = b[I] + if is_nonzero_block(a,I) || is_nonzero_block(b,I) + block = aI + bI + push!(blocks,block) + push!(blockids,I.n) + end + end + BlockArrayCoo(blocks,blockids,a.axes) +end + +function Base.:-(a::BlockArrayCoo{Ta,N},b::BlockArrayCoo{Tb,N}) where {Ta,Tb,N} + @assert axes(a) == axes(b) + @assert blockaxes(a) == blockaxes(b) + I1 = first(eachblockindex(a)) + A = typeof(a[I1]-b[I1]) + blocks = A[] + blockids = NTuple{N,Int}[] + for (I,aI) in enumerateblocks(a) + bI = b[I] + if is_nonzero_block(a,I) || is_nonzero_block(b,I) + block = aI - bI + push!(blocks,block) + push!(blockids,I.n) + end + end + BlockArrayCoo(blocks,blockids,a.axes) +end + +function Base.:*(a::BlockArrayCoo,b::Number) + *(b,a) +end + +function Base.:*(a::Number,b::BlockArrayCoo) + f(block)= a*block + blocks = f.(b.blocks) + BlockArrayCoo(blocks,b.blockids,b.axes,b.ptrs,b.zero_blocks) +end + +function Base.:*(a::BlockMatrixCoo,b::BlockVectorCoo) + @assert blocksize(a,2) == blocksize(b,1) + A = typeof(a[Block(1,1)]*b[Block(1)]) + blocks = A[] + blockids = Tuple{Int}[] + for i in 1:blocksize(a,1) + block = zeros_like(a[Block(i,1)]*b[Block(1)]) + for j in 1:blocksize(a,2) + if is_nonzero_block(a,Block(i,j)) && is_nonzero_block(b,Block(j)) + block += a[Block(i,j)]*b[Block(j)] + end + end + push!(blocks,block) + push!(blockids,(i,)) + end + axs = (axes(a)[1],) + BlockArrayCoo(blocks,blockids,axs) +end + +function Base.:*(a::BlockMatrixCoo,b::BlockMatrixCoo) + @assert blocksize(a,2) == blocksize(b,1) + A = typeof(a[Block(1,1)]*b[Block(1,1)]) + blocks = A[] + blockids = Tuple{Int,Int}[] + for i in 1:blocksize(a,1) + for j in 1:blocksize(b,2) + block = zeros_like(a[Block(i,1)]*b[Block(1,j)]) + for k in 1:blocksize(a,2) + if is_nonzero_block(a,Block(i,k)) && is_nonzero_block(b,Block(k,j)) + block += a[Block(i,k)]*b[Block(k,j)] + end + end + push!(blocks,block) + push!(blockids,(i,j)) + end + end + axs = (axes(a)[1],axes(b)[2]) + BlockArrayCoo(blocks,blockids,axs) +end + +function LinearAlgebra.mul!(c::BlockVectorCoo,a::BlockMatrixCoo,b::BlockVectorCoo) + fill!(c,zero(eltype(c))) + mul!(c,a,b,1,0) +end + +function LinearAlgebra.mul!(c::BlockMatrixCoo,a::BlockMatrixCoo,b::BlockMatrixCoo) + fill!(c,zero(eltype(c))) + mul!(c,a,b,1,0) +end + +function scale_entries!(c::BlockArrayCoo,β) + for block in c.blocks + scale_entries!(block,β) + end + c +end + +function LinearAlgebra.mul!(c::BlockVectorCoo,a::BlockMatrixCoo,b::BlockVectorCoo,α::Number,β::Number) + for I in 1:blocksize(a,1) + cI = c[Block(I)] + if is_nonzero_block(c,Block(I)) + scale_entries!(cI,β) + end + for J in 1:blocksize(a,2) + if is_nonzero_block(a,Block(I,J)) && is_nonzero_block(b,Block(J)) + @assert is_nonzero_block(c,Block(I)) + aIJ = a[Block(I,J)] + bJ = b[Block(J)] + mul!(cI,aIJ,bJ,α,1) + end + end + end + c +end + +function LinearAlgebra.mul!(c::BlockMatrixCoo,a::BlockMatrixCoo,b::BlockMatrixCoo,α::Number,β::Number) + for I in 1:blocksize(a,1) + for J in 1:blocksize(b,2) + cIJ = c[Block(I,J)] + if is_nonzero_block(c,Block(I,J)) + scale_entries!(cIJ,β) + end + for K in 1:blocksize(a,2) + if is_nonzero_block(a,Block(I,K)) && is_nonzero_block(b,Block(K,J)) + @assert is_nonzero_block(c,Block(I,J)) + cIJ = c[Block(I,J)] + aIK = a[Block(I,K)] + bKJ = b[Block(K,J)] + mymul!(cIJ,aIK,bKJ,α) # Hack to avoid allocations + #mul!(cIJ,aIK,bKJ,α,1) # Why this leads to memory allocations?? Specially with Ints + end + end + end + end + c +end + +# Hack to avoid allocations +@inline function mymul!(cIJ,aIK,bKJ,α) + @boundscheck begin + @assert size(cIJ,1) == size(aIK,1) + @assert size(cIJ,2) == size(bKJ,2) + @assert size(aIK,2) == size(bKJ,1) + end + for i in 1:size(cIJ,1) + for j in 1:size(bKJ,2) + for k in 1:size(bKJ,1) + @inbounds cIJ[i,j] += α*aIK[i,k]*bKJ[k,j] + end + end + end +end + +# Hack to avoid allocations +@inline function mymul!(cIJ::BlockMatrixCoo,aIK::BlockMatrixCoo,bKJ::BlockMatrixCoo,α) + mul!(cIJ,aIK,bKJ,α,1) +end + +function Base.fill!(a::BlockArrayCoo,v) + @notimplementedif v != zero(v) + for b in a.blocks + fill!(b,v) + end + a +end + +function LinearAlgebra.transpose(a::BlockMatrixCoo) + blocks = transpose.(a.blocks) + zero_blocks = transpose.(a.zero_blocks) + blockids = [ (j,i) for (i,j) in a.blockids ] + ax,ay = axes(a) + axs = (ay,ax) + ptrs = collect(transpose(a.ptrs)) + BlockArrayCoo(blocks,blockids,axs,ptrs,zero_blocks) +end + +function Base.copy(a::BlockArrayCoo) + blocks = copy.(a.blocks) + blockids = copy(a.blockids) + axes = copy.(a.axes) + ptrs = copy(a.ptrs) + zero_blocks = copy.(a.zero_blocks) + BlockArrayCoo(blocks,blockids,axes,ptrs,zero_blocks) +end + +function Base.copy!(a::BlockArrayCoo,b::BlockArrayCoo) + copyto!(a,b) +end + +function Base.copyto!(a::BlockArrayCoo,b::BlockArrayCoo) + if a.ptrs === b.ptrs || a.ptrs == b.ptrs + for p in 1:length(a.blocks) + copyto!(a.blocks[p],b.blocks[p]) + end + else + for I in eachblockindex(a) + if is_nonzero_block(a,I) + copyto!(a[I],b[I]) + end + end + end + a +end + +# For blocks of blocks + +struct TwoLevelBlockedUnitRange{CS} <: AbstractUnitRange{Int} + global_range::BlockedUnitRange{CS} + local_ranges::Vector{BlockedUnitRange{CS}} +end + +function TwoLevelBlockedUnitRange(local_ranges::Vector{<:BlockedUnitRange}) + global_range = blockedrange(length.(local_ranges)) + TwoLevelBlockedUnitRange(global_range,local_ranges) +end + +function BlockArrays.blockedrange(local_ranges::Vector{<:BlockedUnitRange}) + TwoLevelBlockedUnitRange(local_ranges) +end + +function Base.similar(a::BlockArrayCoo{S,N} where S,::Type{T}, axs::NTuple{N,<:TwoLevelBlockedUnitRange}) where {T,N} + _similar_block_array_coo(a,T,axs) +end + +function Base.similar(::Type{T},axs::NTuple{N,<:TwoLevelBlockedUnitRange}) where {N,T<:Array} + similar(T,map(length,axs)) +end + +local_range(a::TwoLevelBlockedUnitRange,k::Integer) = a.local_ranges[k] + +Base.first(a::TwoLevelBlockedUnitRange) = first(a.global_range) +Base.last(a::TwoLevelBlockedUnitRange) = last(a.global_range) +BlockArrays.blockaxes(a::TwoLevelBlockedUnitRange) = blockaxes(a.global_range) +BlockArrays.blocklasts(a::TwoLevelBlockedUnitRange) = blocklasts(a.global_range) +BlockArrays.findblock(a::TwoLevelBlockedUnitRange,k::Integer) = findblock(a.global_range,k) +Base.getindex(a::TwoLevelBlockedUnitRange,i::Integer) = a.global_range[i] +Base.getindex(a::TwoLevelBlockedUnitRange,i::Block{1}) = a.global_range[i] +Base.axes(a::TwoLevelBlockedUnitRange) = axes(a.global_range) +Base.Broadcast.axistype(a::T, b::T) where T<:TwoLevelBlockedUnitRange = Base.Broadcast.axistype(a.global_range,b.global_range) +Base.Broadcast.axistype(a::TwoLevelBlockedUnitRange, b::TwoLevelBlockedUnitRange) = Base.Broadcast.axistype(a.global_range,b.global_range) +Base.Broadcast.axistype(a::TwoLevelBlockedUnitRange, b) = Base.Broadcast.axistype(a.global_range,b) +Base.Broadcast.axistype(a, b::TwoLevelBlockedUnitRange) =Base.Broadcast.axistype(a,b.global_range) +Base.print_matrix_row( + io::IO, + X::TwoLevelBlockedUnitRange, + A::Vector, + i::Integer, + cols::AbstractVector, + sep::AbstractString) = print_matrix_row(io,X.global_range,A,i,cols,sep) +Base.show(io::IO, mimetype::MIME"text/plain", a::TwoLevelBlockedUnitRange) = show(io,mimetype,a.global_range) + diff --git a/src/Arrays/CachedArrays.jl b/src/Arrays/CachedArrays.jl index da851b7ff..b32442e52 100644 --- a/src/Arrays/CachedArrays.jl +++ b/src/Arrays/CachedArrays.jl @@ -131,3 +131,58 @@ function similar(::Type{CachedArray{T,N,A}},s::Tuple{Vararg{Int}}) where {T,N,A} CachedArray(a) end +function setaxes!(a::CachedArray,ax) + if ! _same_axes(axes(a.array),ax) + s = map(length,ax) + if haskey(a.buffer,s) + a.array = a.buffer[s] + if ! _same_axes(axes(a.array),ax) + a.array = similar(a.array,ax) + a.buffer[s] = a.array + end + else + a.array = similar(a.array,ax) + a.buffer[s] = a.array + end + end + nothing +end + +function _same_axes(a,b) + a === b || a == b +end + +function _same_axes(a::NTuple{N,BlockedUnitRange},b::NTuple{N,BlockedUnitRange}) where N + if a === b + true + else + all(map(_same_axes_1d,a,b)) + end +end + +_same_axes_1d(a::BlockedUnitRange,b::BlockedUnitRange) = blocklasts(a) == blocklasts(b) + +function _same_axes(a::NTuple{N,TwoLevelBlockedUnitRange},b::NTuple{N,TwoLevelBlockedUnitRange}) where N + if a === b + true + else + all(map(_same_axes_1d,a,b)) + end +end + +function _same_axes_1d(a::TwoLevelBlockedUnitRange,b::TwoLevelBlockedUnitRange) + r = _same_axes_1d(a.global_range,b.global_range) + la = length(a.local_ranges) + lb = length(b.local_ranges) + if la!=lb + return false + else + for i in 1:la + @inbounds ra = a.local_ranges[i] + @inbounds rb = b.local_ranges[i] + r = r && _same_axes_1d(ra,rb) + end + return r + end +end + diff --git a/src/Arrays/IdentityVectors.jl b/src/Arrays/IdentityVectors.jl index 766fd326c..10163ca88 100644 --- a/src/Arrays/IdentityVectors.jl +++ b/src/Arrays/IdentityVectors.jl @@ -27,9 +27,21 @@ function reindex(values::AbstractArray, indices::IdentityVector) end function reindex(a::AppliedArray,b::IdentityVector) + @assert length(a) == length(b) a end function reindex(a::Fill,b::IdentityVector) + @assert length(a) == length(b) + a +end + +function reindex(a::CompressedArray,b::IdentityVector) + @assert length(a) == length(b) + a +end + +function reindex(a::Reindexed,b::IdentityVector) + @assert length(a) == length(b) a end diff --git a/src/Arrays/Interface.jl b/src/Arrays/Interface.jl index 923438532..bf2a66ca0 100644 --- a/src/Arrays/Interface.jl +++ b/src/Arrays/Interface.jl @@ -257,6 +257,8 @@ function array_caches(hash::Dict,a::AbstractArray) (ca,) end +array_caches() = () + """ getitems!(c::Tuple,a::Tuple,i...) -> Tuple @@ -294,6 +296,8 @@ end _getitems!(cf,i,a...) end +getitems!(::Tuple{},::Tuple{},i) = () + @inline function _getitems!(c,i,a,b...) ca,cb = _split(c...) ai = getindex!(ca,a,i...) @@ -307,6 +311,66 @@ end (ai,) end +# Hack to fix type-instability (use generated function?) +@inline function _getitems!(c,i,a1,a2) + ca1,ca2 = c + a1i = getindex!(ca1,a1,i...) + a2i = getindex!(ca2,a2,i...) + (a1i,a2i) +end + +# Hack to fix type-instability (use generated function?) +@inline function _getitems!(c,i,a1,a2,a3) + ca1,ca2,ca3 = c + a1i = getindex!(ca1,a1,i...) + a2i = getindex!(ca2,a2,i...) + a3i = getindex!(ca3,a3,i...) + (a1i,a2i,a3i) +end + +# Hack to fix type-instability +@inline function _getitems!(c,i,a1,a2,a3,a4) + ca1,ca2,ca3,ca4 = c + a1i = getindex!(ca1,a1,i...) + a2i = getindex!(ca2,a2,i...) + a3i = getindex!(ca3,a3,i...) + a4i = getindex!(ca4,a4,i...) + (a1i,a2i,a3i,a4i) +end + +@inline function _getitems!(c,i,a1,a2,a3,a4,a5) + ca1,ca2,ca3,ca4,ca5 = c + a1i = getindex!(ca1,a1,i...) + a2i = getindex!(ca2,a2,i...) + a3i = getindex!(ca3,a3,i...) + a4i = getindex!(ca4,a4,i...) + a5i = getindex!(ca5,a5,i...) + (a1i,a2i,a3i,a4i,a5i) +end + +@inline function _getitems!(c,i,a1,a2,a3,a4,a5,a6) + ca1,ca2,ca3,ca4,ca5,ca6 = c + a1i = getindex!(ca1,a1,i...) + a2i = getindex!(ca2,a2,i...) + a3i = getindex!(ca3,a3,i...) + a4i = getindex!(ca4,a4,i...) + a5i = getindex!(ca5,a5,i...) + a6i = getindex!(ca6,a6,i...) + (a1i,a2i,a3i,a4i,a5i,a6i) +end + +@inline function _getitems!(c,i,a1,a2,a3,a4,a5,a6,a7) + ca1,ca2,ca3,ca4,ca5,ca6,ca7 = c + a1i = getindex!(ca1,a1,i...) + a2i = getindex!(ca2,a2,i...) + a3i = getindex!(ca3,a3,i...) + a4i = getindex!(ca4,a4,i...) + a5i = getindex!(ca5,a5,i...) + a6i = getindex!(ca6,a6,i...) + a7i = getindex!(ca7,a7,i...) + (a1i,a2i,a3i,a4i,a5i,a6i,a7i) +end + """ """ @inline function getitems(a::Tuple{Vararg{<:AbstractArray}},i...) diff --git a/src/Arrays/Kernels.jl b/src/Arrays/Kernels.jl index 929ad2b54..c11465e2e 100644 --- a/src/Arrays/Kernels.jl +++ b/src/Arrays/Kernels.jl @@ -81,7 +81,7 @@ function test_kernel(f,x::Tuple,y,cmp=(==)) z = apply_kernel!(cache,f,x...) @test cmp(z,y) z = kernel_testitem!(cache,f,x...) - @test cmp(typeof(z),typeof(y)) + #@test cmp(typeof(z),typeof(y)) end @@ -464,3 +464,46 @@ end end c end + +struct MulKernel <: Kernel end + +function kernel_cache(k::MulKernel,a,b) + c = a*b + CachedArray(c) +end + +@inline function apply_kernel!(cache,k::MulKernel,a::AbstractMatrix,b::AbstractVector) + m = axes(a,1) + setaxes!(cache,(m,)) + c = cache.array + mul!(c,a,b) + c +end + +@inline function apply_kernel!(cache,k::MulKernel,a::AbstractMatrix,b::AbstractMatrix) + m = axes(a,1) + n = axes(b,2) + setaxes!(cache,(m,n)) + c = cache.array + mul!(c,a,b) + c +end + +struct MulAddKernel{T} <: Kernel + α::T + β::T +end + +function kernel_cache(k::MulAddKernel,a,b,c) + d = a*b+c + CachedArray(d) +end + +@inline function apply_kernel!(cache,k::MulAddKernel,a,b,c) + setaxes!(cache,axes(c)) + d = cache.array + copyto!(d,c) + mul!(d,a,b,k.α,k.β) + d +end + diff --git a/src/Arrays/Tables.jl b/src/Arrays/Tables.jl index cb9b2d3c6..6500cab6e 100644 --- a/src/Arrays/Tables.jl +++ b/src/Arrays/Tables.jl @@ -1,30 +1,20 @@ """ - struct Table{T,P} <: AbstractVector{Vector{T}} - data::Vector{T} - ptrs::Vector{P} - end + struct Table{T,Vd<:AbstractVector{T},Vp<:AbstractVector} <: AbstractVector{Vector{T}} + data::Vd + ptrs::Vp + end Type representing a list of lists (i.e., a table) in compressed format. """ -struct Table{T,P} <: AbstractVector{Vector{T}} - data::Vector{T} - ptrs::Vector{P} - function Table(data::Vector{T},ptrs::Vector{P}) where {T,P} - new{T,P}(data,ptrs) - end -end - -@doc """ - Table(data::AbstractVector{T},ptrs::AbstractVector{P}) where {T,P} - -Build a table from the given data and pointers. If the arguments are not of -type `Vector`, they will be converted. -""" -function Table(data::AbstractVector{T},ptrs::AbstractVector{P}) where {T,P} - Table(Vector{T}(data),Vector{P}(ptrs)) +struct Table{T,Vd<:AbstractVector{T},Vp<:AbstractVector} <: AbstractVector{Vector{T}} + data::Vd + ptrs::Vp + function Table(data::AbstractVector,ptrs::AbstractVector) + new{eltype(data),typeof(data),typeof(ptrs)}(data,ptrs) + end end """ @@ -42,13 +32,13 @@ function Table(a::Table) a end -function Base.convert(::Type{Table{T,P}},table::Table{Ta,Pa}) where {T,P,Ta,Pa} - data = convert(Vector{T},table.data) - ptrs = convert(Vector{P},table.ptrs) +function Base.convert(::Type{Table{T,Vd,Vp}},table::Table{Ta,Vda,Vpa}) where {T,Vd,Vp,Ta,Vda,Vpa} + data = convert(Vd,table.data) + ptrs = convert(Vp,table.ptrs) Table(data,ptrs) end -function Base.convert(::Type{Table{T,P}},table::Table{T,P}) where {T,P} +function Base.convert(::Type{Table{T,Vd,Vp}},table::Table{T,Vd,Vp}) where {T,Vd,Vp} table end @@ -103,7 +93,7 @@ function getindex!(c,a::Table,i::Integer) r end -function getindex(a::Table,i::Integer) +function Base.getindex(a::Table,i::Integer) cache = array_cache(a) getindex!(cache,a,i) end @@ -243,7 +233,7 @@ end """ """ -function append_tables_globally(tables::Table{T,P}...) where {T,P} +function append_tables_globally(tables::Table{T,Vd,Vp}...) where {T,Vd,Vp} first_table, = tables data = copy(first_table.data) ptrs = copy(first_table.ptrs) @@ -262,13 +252,13 @@ end """ """ -get_ptrs_eltype(::Table{T,P}) where {T,P} = P -get_ptrs_eltype(::Type{Table{T,P}}) where {T,P} = P +get_ptrs_eltype(::Table{T,Vd,Vp}) where {T,Vd,Vp} = eltype(Vp) +get_ptrs_eltype(::Type{Table{T,Vd,Vp}}) where {T,Vd,Vp} = eltype(Vp) """ """ -get_data_eltype(::Table{T,P}) where {T,P} = T -get_data_eltype(::Type{Table{T,P}}) where {T,P} = T +get_data_eltype(::Table{T,Vd,Vp}) where {T,Vd,Vp} = T +get_data_eltype(::Type{Table{T,Vd,Vp}}) where {T,Vd,Vp} = T """ append_tables_locally(tables::Table...) @@ -360,8 +350,8 @@ function get_local_item(a_to_lb_to_b::Table, lb::AbstractArray{<:Integer}) a_to_b end -struct LocalItemFromTable{T,P,A} <: AbstractVector{T} - a_to_lb_to_b::Table{T,P} +struct LocalItemFromTable{T,Vd,Vp,A} <: AbstractVector{T} + a_to_lb_to_b::Table{T,Vd,Vp} lb::A end @@ -386,9 +376,9 @@ function find_local_index(a_to_b, b_to_la_to_a::Table) a_to_la end -struct LocalIndexFromTable{T,P,V<:AbstractVector} <: AbstractVector{T} +struct LocalIndexFromTable{T,Vd,Vp,V<:AbstractVector} <: AbstractVector{T} a_to_b::V - b_to_la_to_a::Table{T,P} + b_to_la_to_a::Table{T,Vd,Vp} end Base.size(m::LocalIndexFromTable) = size(m.a_to_b) @@ -437,9 +427,9 @@ function to_dict(table::Table) dict end -function from_dict(::Type{Table{T,P}}, dict::Dict{Symbol,Any}) where {T,P} - data::Vector{T} = dict[:data] - ptrs::Vector{P} = dict[:ptrs] +function from_dict(::Type{Table{T,Vd,Vp}}, dict::Dict{Symbol,Any}) where {T,Vd,Vp} + data::Vd = dict[:data] + ptrs::Vp = dict[:ptrs] Table(data,ptrs) end diff --git a/src/Arrays/VectorsOfBlockArrayCoo.jl b/src/Arrays/VectorsOfBlockArrayCoo.jl new file mode 100644 index 000000000..7514189ca --- /dev/null +++ b/src/Arrays/VectorsOfBlockArrayCoo.jl @@ -0,0 +1,197 @@ + +struct VectorOfBlockArrayCoo{T,N,B,X,Z} <: AbstractVector{T} + blocks::B + blockids::Vector{NTuple{N,Int}} + axes::X + ptrs::Array{Int,N} + zero_blocks::Z + function VectorOfBlockArrayCoo( + blocks::Tuple, + blockids::Vector{NTuple{N,Int}}, + axes::AbstractArray{<:NTuple{N}}, + ptrs::Array{Int,N} = _compute_ptrs(blockids,testitem(axes)), + zero_blocks::Tuple=_compute_zero_blocks_array(blocks,ptrs,axes)) where N + + msg = "Trying to build a VectorOfBlockArrayCoo with repeated blocks" + @assert _no_has_repeaded_blocks(blockids,ptrs) msg + + if length(blocks) != 0 + @assert all(map(length,blocks) .== length(first(blocks)) ) + blocks_i = collect(map(testitem,blocks)) + zero_blocks_i = collect(eltype(blocks_i),map(testitem,zero_blocks)) + else + @assert length(zero_blocks) !=0 + zero_blocks_i = collect(map(testitem,zero_blocks)) + blocks_i = collect(eltype(zero_blocks_i),map(testitem,blocks)) + end + + B = typeof(blocks) + X = typeof(axes) + axes_i = testitem(axes) + t = BlockArrayCoo(blocks_i,blockids,axes_i,ptrs,zero_blocks_i) + T = typeof(t) + Z = typeof(zero_blocks) + new{T,N,B,X,Z}(blocks,blockids,axes,ptrs,zero_blocks) + end +end + +function VectorOfBlockArrayCoo( + blocks::Tuple, + blockids::Vector{NTuple{N,Int}}, + axes::AbstractArray{<:NTuple{N}}, + zero_blocks::Tuple) where N + + ptrs = _compute_ptrs(blockids,testitem(axes)) + VectorOfBlockArrayCoo(blocks,blockids,axes,ptrs,zero_blocks) +end + +const VectorOfBlockVectorCoo = VectorOfBlockArrayCoo{T,1} where T +const VectorOfBlockMatrixCoo = VectorOfBlockArrayCoo{T,2} where T + +function _no_has_repeaded_blocks(blockids::Vector{NTuple{N,Int}},ptrs) where N + maxblocks = size(ptrs) + touched = zeros(Int,maxblocks) + for c in blockids + touched[c...] += 1 + end + all( touched .<= 1 ) +end + +function _compute_zero_blocks_array(blocks,ptrs,axs) + A = eltype(first(blocks)) + cis = CartesianIndices(ptrs) + zero_blocks = [] + for ci in cis + p = ptrs[ci] + if p<0 + block = _zeros_like(A,Tuple(ci),axs) + push!(zero_blocks,block) + end + end + Tuple(zero_blocks) +end + +function zeros_like(a::VectorOfBlockArrayCoo{T,N} where T) where N + ptrs = copy(a.ptrs) + for k in 1:length(ptrs) + ptrs[k] = -k + end + zero_blocks = _compute_zero_blocks_array(a.blocks,ptrs,a.axes) + blocks = () + blockids = NTuple{N,Int}[] + VectorOfBlockArrayCoo(blocks,blockids,a.axes,ptrs,zero_blocks) +end + +function _zeros_like(::Type{A},I,axs) where A + block = apply(axs) do a + laxs = map( local_range, a, I) + zeros_like(A,laxs) + end + block +end + +function _zeros_like(::Type{<:BlockArrayCoo{T,N,A} where T},I,axs) where {N,A} + axsI = apply(axs) do a + map(local_range, a, I) + end + blocks = () + blockids = NTuple{N,Int}[] + ptrs = zeros(Int,map(x->blocksize(x,1),testitem(axsI))) + for k in 1:length(ptrs) + ptrs[k] = -k + end + zero_blocks = [] + cis = CartesianIndices(ptrs) + for ci in cis + block = _zeros_like(A,Tuple(ci),axsI) + push!(zero_blocks,block) + end + VectorOfBlockArrayCoo(blocks,blockids,axsI,ptrs,Tuple(zero_blocks)) +end + +BlockArrays.blocksize(a::VectorOfBlockArrayCoo) = blocksize(testitem(a)) + +BlockArrays.blocksize(a::VectorOfBlockArrayCoo,i::Integer) = blocksize(testitem(a),i) + +function BlockArrays.eachblock(a::VectorOfBlockArrayCoo) + cis = CartesianIndices(blocksize(a)) + blocks = map(ci->Block(Tuple(ci)),cis) + ( a[block] for block in blocks ) +end + +Base.IndexStyle(::Type{<:VectorOfBlockArrayCoo}) = IndexLinear() + +function Base.size(a::VectorOfBlockArrayCoo) + if length(a.blocks) != 0 + (length(first(a.blocks)),) + else + (length(first(a.zero_blocks)),) + end +end + +function array_cache(a::VectorOfBlockArrayCoo) + + if length(a.blocks) != 0 + blocks_i = collect(map(testitem,a.blocks)) + zero_blocks_i = collect(eltype(blocks_i),map(testitem,a.zero_blocks)) + else + zero_blocks_i = collect(map(testitem,a.zero_blocks)) + blocks_i = collect(eltype(zero_blocks_i),map(testitem,a.blocks)) + end + + ca = array_cache(a.axes) + cb = array_caches(a.blocks...) + cz = array_caches(a.zero_blocks...) + (blocks_i,zero_blocks_i,ca,cb,cz) +end + +@inline function getindex!(cache,a::VectorOfBlockArrayCoo,i::Integer) + blocks_i, zero_blocks_i, ca, cb, cz = cache + axes_i = getindex!(ca,a.axes,i) + blocks_i .= getitems!(cb,a.blocks,i) + zero_blocks_i .= getitems!(cz,a.zero_blocks,i) + BlockArrayCoo(blocks_i,a.blockids,axes_i,a.ptrs,zero_blocks_i) +end + +function Base.getindex(a::VectorOfBlockArrayCoo,i::Integer) + cache = array_cache(a) + getindex!(cache,a,i) +end + +function Base.getindex(a::VectorOfBlockArrayCoo,b::Block) + _get_block_index(a,b) +end + +function Base.getindex(a::VectorOfBlockVectorCoo,b::Block{1}) + _get_block_index(a,b) +end + +function _get_block_index(a,b) + i = convert(Tuple,b) + p = a.ptrs[i...] + if p>0 + a.blocks[p] + else + a.zero_blocks[-p] + end +end + +function Base.getindex(a::VectorOfBlockArrayCoo,b::Block{1}...) + a[Block(map(Int,b)...)] +end + +function is_zero_block(a::VectorOfBlockArrayCoo,i::Integer...) + p = a.ptrs[i...] + @assert p != 0 + p < 0 +end + +function apply(::typeof(transpose),a::VectorOfBlockMatrixCoo) + blocks = [ apply(transpose,block) for block in a.blocks ] + zero_blocks = [ apply(transpose,block) for block in a.zero_blocks ] + blockids = [ (j,i) for (i,j) in a.blockids ] + axs = apply( ax->(ax[2],ax[1]), a.axes) + ptrs = collect(Transpose(a.ptrs)) + VectorOfBlockArrayCoo(Tuple(blocks),blockids,axs,ptrs,Tuple(zero_blocks)) +end + diff --git a/src/CellData/AttachConstraints.jl b/src/CellData/AttachConstraints.jl new file mode 100644 index 000000000..32851bca5 --- /dev/null +++ b/src/CellData/AttachConstraints.jl @@ -0,0 +1,104 @@ + +function attach_constraints_rows(cellvec,cellconstr,cellmask=Fill(true,length(cellconstr))) + apply(ConstrainRowsKernel(),cellvec,cellconstr,cellmask) +end + +function attach_constraints_cols(cellmat,cellconstr,cellmask=Fill(true,length(cellconstr))) + cellconstr_t = apply(transpose,cellconstr) + apply(ConstrainColsKernel(),cellmat,cellconstr_t,cellmask) +end + +struct ConstrainRowsKernel <: Kernel end + +function Arrays.kernel_cache(k::ConstrainRowsKernel,array::AbstractArray,constr,mask) + kernel_cache(MulKernel(),constr,array) +end + +@inline function Arrays.apply_kernel!(cache,k::ConstrainRowsKernel,array::AbstractArray,constr,mask) + if mask + apply_kernel!(cache,MulKernel(),constr,array) + else + array + end +end + +function Arrays.kernel_cache(k::ConstrainRowsKernel,matvec::Tuple,constr,mask) + mat, vec = matvec + cmat = kernel_cache(k,mat,constr,mask) + cvec = kernel_cache(k,vec,constr,mask) + (cmat,cvec) +end + +@inline function Arrays.apply_kernel!(cache,k::ConstrainRowsKernel,matvec::Tuple,constr,mask) + if mask + cmat, cvec = cache + mat, vec = matvec + _mat = apply_kernel!(cmat,k,mat,constr,mask) + _vec = apply_kernel!(cvec,k,vec,constr,mask) + (_mat,_vec) + else + matvec + end +end + +struct ConstrainColsKernel <: Kernel end + +function Arrays.kernel_cache(k::ConstrainColsKernel,array::AbstractArray,constr_t,mask) + kernel_cache(MulKernel(),array,constr_t) +end + +@inline function Arrays.apply_kernel!(cache,k::ConstrainColsKernel,array::AbstractArray,constr_t,mask) + if mask + apply_kernel!(cache,MulKernel(),array,constr_t) + else + array + end +end + +function Arrays.kernel_cache(k::ConstrainColsKernel,matvec::Tuple,constr_t,mask) + mat, vec = matvec + kernel_cache(k,mat,constr_t,mask) +end + +@inline function Arrays.apply_kernel!(cache,k::ConstrainColsKernel,matvec::Tuple,constr_t,mask) + if mask + mat, vec = matvec + _mat = apply_kernel!(cache,k,mat,constr_t,mask) + (_mat,vec) + else + matvec + end +end + +function merge_cell_constraints_at_skeleton(cL,cR,axesL_rows,axesR_rows,axesL_cols,axesR_cols) + blocks = (cL,cR) + blockids = [(1,1),(2,2)] + axs_rows = create_array_of_blocked_axes(axesL_rows,axesR_rows) + axs_cols = create_array_of_blocked_axes(axesL_cols,axesR_cols) + axs = apply((r,c) -> (r[1],c[1]),axs_rows,axs_cols) + VectorOfBlockArrayCoo(blocks,blockids,axs) +end + +function identity_constraints(cell_axes) + apply(IdentityConstraintKernel(),cell_axes) +end + +struct IdentityConstraintKernel <: Kernel end + +function Arrays.kernel_cache(k::IdentityConstraintKernel,axs) + n = length(axs[1]) + a = zeros(n,n) + CachedArray(a) +end + +function Arrays.apply_kernel!(cache,k::IdentityConstraintKernel,axs) + n = length(axs[1]) + setsize!(cache,(n,n)) + a = cache.array + fill!(a,zero(eltype(a))) + o = one(eltype(a)) + @inbounds for i in 1:size(a,1) + a[i,i] = o + end + a +end diff --git a/src/CellData/AttachDirichlet.jl b/src/CellData/AttachDirichlet.jl new file mode 100644 index 000000000..ca41b2e60 --- /dev/null +++ b/src/CellData/AttachDirichlet.jl @@ -0,0 +1,48 @@ + +function attach_dirichlet(cellmatvec,cellvals,cellmask=Fill(true,length(cellvals))) + k = AttachDirichletKernel() + apply(k,cellmatvec,cellvals,cellmask) +end + +struct AttachDirichletKernel <: Kernel + muladd::MulAddKernel{Int} + AttachDirichletKernel() = new(MulAddKernel(-1,1)) +end + +function Arrays.kernel_cache(k::AttachDirichletKernel,matvec::Tuple,vals,mask) + mat, vec = matvec + kernel_cache(k.muladd,mat,vals,vec) +end + +@inline function Arrays.apply_kernel!(cache,k::AttachDirichletKernel,matvec::Tuple,vals,mask) + if mask + mat, vec = matvec + vec_with_bcs = apply_kernel!(cache,k.muladd,mat,vals,vec) + (mat, vec_with_bcs) + else + matvec + end +end + +function Arrays.kernel_cache(k::AttachDirichletKernel,mat::AbstractMatrix,vals,mask) + cm = kernel_cache(MulKernel(),mat,vals) + cv = CachedArray(mat*vals) + fill!(cv.array,zero(eltype(cv))) + (cm,cv) +end + +@inline function Arrays.apply_kernel!(cache,k::AttachDirichletKernel,mat::AbstractMatrix,vals,mask) + cm, cv = cache + if mask + vec_with_bcs = apply_kernel!(cm,MulKernel(),mat,vals) + scale_entries!(vec_with_bcs,-1) + (mat, vec_with_bcs) + else + if size(mat,1) != size(cv,1) + m = axes(mat,1) + setaxes!(cv,(m,)) + fill!(cv.array,zero(eltype(cv))) + end + (mat, cv.array) + end +end diff --git a/src/CellData/CellData.jl b/src/CellData/CellData.jl new file mode 100644 index 000000000..aec87772b --- /dev/null +++ b/src/CellData/CellData.jl @@ -0,0 +1,101 @@ +""" + +The exported names are +$(EXPORTS) +""" +module CellData + +using Test +using DocStringExtensions +using FillArrays + +using Gridap.Helpers +using Gridap.Arrays +using Gridap.TensorValues +using Gridap.Fields +using Gridap.Polynomials +using Gridap.Integration +using Gridap.ReferenceFEs +using Gridap.Algebra + +import Gridap.Arrays: get_array +import Gridap.Arrays: lazy_append +import Gridap.Fields: evaluate +import Gridap.Fields: gradient +import Gridap.Fields: integrate +import Gridap.Helpers: operate +import Gridap.Integration: get_coordinates +import Gridap.Integration: get_weights +import Gridap.Fields: field_cache +import Gridap.Fields: evaluate_field! +import Gridap.Fields: evaluate_field_array +import Gridap.Arrays: array_cache +import Gridap.Arrays: getindex! +import Gridap.Arrays: reindex + +export CellField +export get_cell_map +export get_cell_axes +export get_memo +export RefStyle +export is_in_ref_space +export is_in_physical_space +export MetaSizeStyle +export get_metasize +export is_basis +export is_test +export is_trial +export test_cell_field +export GenericCellField +export similar_object +export change_ref_style +export to_ref_space +export to_physical_space +export trialize_cell_basis +export convert_to_cell_field +export SkeletonCellField +export get_inward +export get_outward +export jump +export mean +export merge_cell_dofs_at_skeleton +export merge_cell_fields_at_skeleton + +export CellQuadrature +export get_coordinates +export get_weights + +export QPointCellField +export update_state_variables! + +export CellDofBasis +export test_cell_dof_basis +export GenericCellDofBasis + +export attach_dirichlet + +export attach_constraints_rows +export attach_constraints_cols +export merge_cell_constraints_at_skeleton +export identity_constraints + +export @law +export operate +export GridapType + +include("CellFields.jl") + +include("CellQuadratures.jl") + +include("QPointCellFields.jl") + +include("CellDofBases.jl") + +include("AttachDirichlet.jl") + +include("AttachConstraints.jl") + +include("Law.jl") + +end # module + diff --git a/src/FESpaces/CellDofBases.jl b/src/CellData/CellDofBases.jl similarity index 82% rename from src/FESpaces/CellDofBases.jl rename to src/CellData/CellDofBases.jl index 7273726d7..89fbe0600 100644 --- a/src/FESpaces/CellDofBases.jl +++ b/src/CellData/CellDofBases.jl @@ -10,7 +10,7 @@ abstract type CellDofBasis end RefStyle(::Type{<:CellDofBasis}) = @abstractmethod get_array(::CellDofBasis) = @abstractmethod -function test_cell_dof_basis(cf::CellDofBasis,f::CellFieldLike) +function test_cell_dof_basis(cf::CellDofBasis,f::CellField) ar = get_array(cf) @test isa(ar,AbstractArray) a = evaluate(cf,f) @@ -31,16 +31,16 @@ The result is numerically equivalent to but it is described with a more memory-friendly lazy type. """ -function evaluate(cell_dofs::CellDofBasis,cell_field::CellFieldLike) +function evaluate(cell_dofs::CellDofBasis,cell_field::CellField) _evaluate_cell_dofs(cell_dofs,cell_field,RefStyle(cell_dofs)) end function _evaluate_cell_dofs(cell_dofs,cell_field,ref_trait::Val{true}) - evaluate_dof_array(get_array(cell_dofs),get_array(to_ref_space(cell_field))) + ReferenceFEs.evaluate_dof_array(get_array(cell_dofs),get_array(to_ref_space(cell_field))) end function _evaluate_cell_dofs(cell_dofs,cell_field,ref_trait::Val{false}) - evaluate_dof_array(get_array(cell_dofs),get_array(to_physical_space(cell_field))) + ReferenceFEs.evaluate_dof_array(get_array(cell_dofs),get_array(to_physical_space(cell_field))) end """ diff --git a/src/CellData/CellFields.jl b/src/CellData/CellFields.jl new file mode 100644 index 000000000..b1a4eab54 --- /dev/null +++ b/src/CellData/CellFields.jl @@ -0,0 +1,497 @@ + +""" + abstract type CellField <: GridapType end + +This is a plain array of fields plus some metadata. +It is interpreted as a `Field` object on each cell of a computational +mesh. +""" +abstract type CellField <: GridapType end + +""" + get_array(cf::CellField) +""" +function get_array(cf::CellField) + @abstractmethod +end + +""" + get_cell_map(cf::CellField) +""" +function get_cell_map(cf::CellField) + @abstractmethod +end + +""" + get_cell_axes(cf::CellField) +""" +function get_cell_axes(cf::CellField) + @abstractmethod +end + +function get_memo(cf::CellField) + @abstractmethod +end + +""" +This trait returns `Val{true}()` when the `CellField` is defined in a +reference finite element space, and `Val{false}()` when it is defined in the +physical space +""" +RefStyle(::Type{<:CellField}) = @notimplemented + +# We use duck typing here for all types marked with the RefStyle +RefStyle(::Type) = @notimplemented +RefStyle(a) = RefStyle(typeof(a)) +is_in_ref_space(::Type{T}) where T = get_val_parameter(RefStyle(T)) +is_in_ref_space(::T) where T = is_in_ref_space(T) +is_in_physical_space(::Type{T}) where T = !is_in_ref_space(T) +is_in_physical_space(a::T) where T = !is_in_ref_space(T) + +""" +This trait provides information about the field size at a single +evaluation point. + +For physical fields `MetaSizeStyle(T) == Val( () )` +For test bases `MetaSizeStyle(T) == Val( (:,) )` +For trial bases `MetaSizeStyle(T) = Val( (1,:) )` +For fields representing elemental matrices `MetaSizeStyle(T) = Val( (:,:) )` +""" +MetaSizeStyle(::Type{<:CellField}) = @notimplemented + +# We use duck typing here for all types marked with the MetaSizeStyle trait +MetaSizeStyle(::Type) = @notimplemented +MetaSizeStyle(::T) where T = MetaSizeStyle(T) +get_metasize(::Type{T}) where T = get_val_parameter(MetaSizeStyle(T)) +get_metasize(::T) where T = get_val_parameter(MetaSizeStyle(T)) +is_test(::Type{T}) where T = get_metasize(T) == (:,) +is_test(::T) where T = is_test(T) +is_trial(::Type{T}) where T = get_metasize(T) == (1,:) +is_trial(::T) where T = is_trial(T) +is_basis(::Type{T}) where T = is_test(T) || is_trial(T) +is_basis(::T) where T = is_basis(T) + +# Tester + +""" + test_cell_field( + cf::CellField, + x::AbstractArray, + b::AbstractArray, + pred=(==); + grad=nothing) +""" +function test_cell_field(cf::CellField,x::AbstractArray,b::AbstractArray,pred=(==);grad=nothing) + cell_map = get_cell_map(cf) + @test isa(cell_map,AbstractArray) + a = evaluate(cf,x) + test_array(a,b,pred) + if grad != nothing + g = evaluate(gradient(cf),x) + test_array(g,grad,pred) + end + rs = RefStyle(cf) + @test isa(get_val_parameter(rs),Bool) + _cf = change_ref_style(cf) + @test get_array(_cf) === get_array(cf) + @test is_in_ref_space(cf) == !is_in_ref_space(_cf) + @test is_in_physical_space(cf) == !is_in_physical_space(_cf) + @test get_metasize(_cf) == get_metasize(cf) + @test get_cell_axes(_cf) == get_cell_axes(cf) + @test isa(get_cell_axes(cf),AbstractArray{<:Tuple}) + @test isa(get_metasize(cf),Tuple) + @test isa(MetaSizeStyle(cf),Val) + @test isa(get_memo(cf),Dict) +end + +# Concrete implementation + +""" +struct GenericCellField{R,S} <: CellField + # Private fields +end + +""" +struct GenericCellField{R,S} <: CellField + array::AbstractArray + cell_map::AbstractArray + ref_trait::Val{R} + cell_axes::AbstractArray + metasize::Val{S} + memo::Dict + function GenericCellField( + array::AbstractArray, + cell_map::AbstractArray, + ref_trait::Val{R}, + cell_axes::AbstractArray, + metasize::Val{S}) where {R,S} + memo = Dict() + new{R,S}(array,cell_map,ref_trait,cell_axes,metasize,memo) + end +end + +function GenericCellField(array::AbstractArray,cell_map::AbstractArray) + GenericCellField(array,cell_map,Val{true}(),Fill((),length(cell_map))) +end + +function GenericCellField(array::AbstractArray,cell_map::AbstractArray,ref_trait::Val) + GenericCellField(array,cell_map,ref_trait,Fill((),length(cell_map))) +end + +function GenericCellField( + array::AbstractArray,cell_map::AbstractArray,ref_trait::Val,cell_axes::AbstractArray) + GenericCellField(array,cell_map,ref_trait,cell_axes,Val(())) +end + +function get_array(cf::GenericCellField) + cf.array +end + +function get_cell_map(cf::GenericCellField) + cf.cell_map +end + +function get_memo(cf::GenericCellField) + cf.memo +end + +function get_cell_axes(cf::GenericCellField) + cf.cell_axes +end + +function RefStyle(::Type{<:GenericCellField{R}}) where {R} + Val{R}() +end + +function MetaSizeStyle(::Type{<:GenericCellField{R,S}}) where {R,S} + Val{S}() +end + +# The rest of the file is some default API using the CellField interface + +# Preserving and manipulating the metadata + +""" + similar_object(cf::CellField,array::AbstractArray,cell_axes::AbstractArray,msize_style::Val) +""" +function similar_object(cf::CellField,array::AbstractArray,cell_axes::AbstractArray,msize_style::Val) + cm = get_cell_map(cf) + GenericCellField(array,cm,RefStyle(cf),cell_axes,msize_style) +end + +""" + change_ref_style(cf::CellField) + +Return an object with the same array and metadata as in `cf`, except for `RefStyle` which is changed. +""" +function change_ref_style(cf::CellField) + ref_sty = RefStyle(cf) + bool = !get_val_parameter(ref_sty) + new_sty = Val{bool}() + ar = get_array(cf) + cm = get_cell_map(cf) + GenericCellField(ar,cm,new_sty,get_cell_axes(cf),MetaSizeStyle(cf)) +end + +# Move between ref and phys spaces by using the underling cell_map + +to_ref_space(a::CellField) = _to_ref_space(a,RefStyle(a)) +_to_ref_space(a,::Val{true}) = a +function _to_ref_space(a,::Val{false}) + cell_map = get_cell_map(a) + array = compose( get_array(a), cell_map ) + no = similar_object(a,array,get_cell_axes(a),MetaSizeStyle(a)) + change_ref_style(no) +end + +to_physical_space(a::CellField) = _to_physical_space(a,RefStyle(a)) +_to_physical_space(a,::Val{true}) = @notimplemented # and probably not doable in some cases +_to_physical_space(a,::Val{false}) = a + +# Assumption : x ALWAIS defined in the reference space +# In the future we can also add the RefStyle to x by defining CellPoints +""" + evaluate(cf::CellField,x) +""" +function evaluate(cf::CellField,x::AbstractArray) + key = (:evaluate,objectid(x)) + memo = get_memo(cf) + if !haskey(memo,key) + memo[key] = _evaluate(cf,x,RefStyle(cf)) + end + memo[key] +end + +function _evaluate(cf::CellField,x::AbstractArray,::Val{true}) + evaluate_field_array(get_array(cf),x) +end + +function _evaluate(cf::CellField,x::AbstractArray,::Val{false}) + cm = get_cell_map(cf) + _x = evaluate(cm,x) + evaluate_field_array(get_array(cf),_x) +end + +""" + length(cf::CellField) +""" +function Base.length(cf::CellField) + a = get_array(cf) + length(a) +end + +function Arrays.reindex(cf::CellField,a::AbstractVector) + array = reindex(get_array(cf),a) + cell_axes = reindex(get_cell_axes(cf),a) + similar_object(cf,array,cell_axes,MetaSizeStyle(cf)) +end + +# Bases-related + +function trialize_cell_basis(test::CellField) + @assert is_test(test) + array = trialize_array_of_bases(get_array(test)) + axs = apply(Fields._add_singleton_block,get_cell_axes(test)) + similar_object(test,array,axs,Val((1,:))) +end + +function Fields.lincomb(a::CellField,b::AbstractArray) + @notimplementedif !is_test(a) + array = lincomb(get_array(a),b) + axs = Fill((),length(b)) + similar_object(a,array,axs,Val(())) +end + +# Diff ops + +""" + gradient(cf::CellField) +""" +function gradient(cf::CellField) + key = :gradient + memo = get_memo(cf) + if !haskey(memo,key) + a = get_array(cf) + ag = field_array_gradient(a) + memo[key] = similar_object(cf,ag,get_cell_axes(cf),MetaSizeStyle(cf)) + end + memo[key] +end + +# Operations + +function operate(op,cf::CellField) + key = objectid(op) + memo = get_memo(cf) + if !haskey(memo,key) + a = get_array(cf) + b = operate_arrays_of_fields(Fields._UnimplementedField,op,a) + memo[key] = similar_object(cf,b,get_cell_axes(cf),MetaSizeStyle(cf)) + end + memo[key] +end + +function operate(op,cf1::CellField,cf2::CellField) + @assert length(cf1) == length(cf2) + @assert RefStyle(cf1) == RefStyle(cf2) + a1 = get_array(cf1) + a2 = get_array(cf2) + b = operate_arrays_of_fields(Fields._UnimplementedField,op,a1,a2) + axs = apply(field_operation_axes,get_cell_axes(cf1),get_cell_axes(cf2)) + metasize = field_operation_metasize(get_metasize(cf1),get_metasize(cf2)) + similar_object(cf1,b,axs,Val(metasize)) +end + +function operate(op,cf1::CellField,object) + cm = get_cell_map(cf1) + cf2 = convert_to_cell_field(object,cm,RefStyle(cf1)) + operate(op,cf1,cf2) +end + +function operate(op,object,cf2::CellField) + cm = get_cell_map(cf2) + cf1 = convert_to_cell_field(object,cm,RefStyle(cf2)) + operate(op,cf1,cf2) +end + +function operate(op,args::CellField...) + a1 = first(args) + @assert all( map( a->length(a) == length(a1), args) ) + @assert all( map( a->RefStyle(a)==RefStyle(a1), args) ) + arrs = map(get_array,args) + m = operate_arrays_of_fields(Fields._UnimplementedField,op,arrs...) + axs = apply(field_operation_axes,map(get_cell_axes,args)...) + metasize = field_operation_metasize(map(get_metasize,args)...) + similar_object(a1,m,axs,Val(metasize)) +end + +function operate(op,a1::CellField,args...) + cm = get_cell_map(a1) + rs = RefStyle(cm) + cfs = map(obj->convert_to_cell_field(obj,cm,rs),args) + operate(op,a1,cfs...) +end + +# Conversions + +""" + convert_to_cell_field(object,cell_map,ref_style) +""" +function convert_to_cell_field(object,cell_map,ref_style::Val) + @abstractmethod +end + +function convert_to_cell_field(object,cell_map) + ref_style = Val{true}() + convert_to_cell_field(object,cell_map,ref_style) +end + +function convert_to_cell_field(object::CellField,cell_map) + @assert length(object) == length(cell_map) + object +end + +# pre-defined conversions + +function convert_to_cell_field(object::CellField,cell_map,ref_style::Val) + @assert RefStyle(object) == ref_style + object +end + +function convert_to_cell_field(object::AbstractArray,cell_map,ref_style::Val) + @assert length(object) == length(cell_map) + GenericCellField(object,cell_map,ref_style) +end + +function convert_to_cell_field(object::Function,cell_map,ref_style::Val{true}) + b = compose(object,cell_map) + GenericCellField(b,cell_map,Val{true}()) +end + +function convert_to_cell_field(fun::Function,cell_map,ref_style::Val{false}) + field = function_field(fun) + cell_field = Fill(field,length(cell_map)) + GenericCellField(cell_field,cell_map,Val{false}()) +end + +function convert_to_cell_field(object::Number,cell_map,ref_style::Val) + a = Fill(object,length(cell_map)) + GenericCellField(a,cell_map,ref_style) +end + +# Skeleton related + +""" + struct SkeletonCellField <: GridapType + left::CellField + right::CellField + end + +Supports the same differential and algebraic operations than [`CellField`](@ref) +""" +struct SkeletonCellField <: GridapType + left::CellField + right::CellField +end + +get_inward(a::SkeletonCellField) = a.left + +get_outward(a::SkeletonCellField) = a.right + +function Base.getproperty(x::SkeletonCellField, sym::Symbol) + if sym in (:inward,:⁺) + get_inward(x) + elseif sym in (:outward,:⁻) + get_outward(x) + else + getfield(x, sym) + end +end + +""" + get_cell_map(a::SkeletonCellField) +""" +function get_cell_map(a::SkeletonCellField) + get_cell_map(a.left) +end + +""" + jump(sf::SkeletonCellField) +""" +function jump(sf::SkeletonCellField) + sf.⁺ - sf.⁻ +end + +""" + mean(sf::SkeletonCellField) +""" +function mean(sf::SkeletonCellField) + operate(_mean,sf.⁺,sf.⁻) +end + +_mean(x,y) = 0.5*x + 0.5*y + +function gradient(cf::SkeletonCellField) + left = gradient(cf.left) + right = gradient(cf.right) + SkeletonCellField(left,right) +end + +function operate(op,cf::SkeletonCellField) + left = operate(op,cf.left) + right = operate(op,cf.right) + SkeletonCellField(left,right) +end + +function operate(op,cf1::SkeletonCellField,cf2::SkeletonCellField) + left = operate(op,cf1.left,cf2.left) + right = operate(op,cf1.right,cf2.right) + SkeletonCellField(left,right) +end + +function operate(op,cf1::SkeletonCellField,cf2::CellField) + left = operate(op,cf1.left,cf2) + right = operate(op,cf1.right,cf2) + SkeletonCellField(left,right) +end + +function operate(op,cf1::CellField,cf2::SkeletonCellField) + left = operate(op,cf1,cf2.left) + right = operate(op,cf1,cf2.right) + SkeletonCellField(left,right) +end + +function operate(op,cf1::SkeletonCellField,object) + cm = get_cell_map(cf1) + cf2 = convert_to_cell_field(object,cm,RefStyle(cf1.left)) + operate(op,cf1,cf2) +end + +function operate(op,object,cf2::SkeletonCellField) + cm = get_cell_map(cf2) + cf1 = convert_to_cell_field(object,cm,RefStyle(cf2.left)) + operate(op,cf1,cf2) +end + +function merge_cell_dofs_at_skeleton(idsL,idsR,axesL,axesR) + blocks = (idsL,idsR) + blockids = [(1,),(2,)] + axs = create_array_of_blocked_axes(axesL,axesR) + VectorOfBlockArrayCoo(blocks,blockids,axs) +end + +function merge_cell_fields_at_skeleton(cfL,cfR) + @assert is_basis(cfL) == is_basis(cfR) + if !is_basis(cfL) + SkeletonCellField(cfL,cfR) + else + ax1 = get_cell_axes(cfL) + ax2 = get_cell_axes(cfR) + arrL = insert_array_of_bases_in_block(1,get_array(cfL),ax1,ax2) + cfSL = similar_object(cfL,arrL,arrL.axes,MetaSizeStyle(cfL)) + arrR = insert_array_of_bases_in_block(2,get_array(cfR),ax1,ax2) + cfSR = similar_object(cfR,arrR,arrR.axes,MetaSizeStyle(cfR)) + SkeletonCellField(cfSL,cfSR) + end +end + diff --git a/src/Geometry/CellQuadratures.jl b/src/CellData/CellQuadratures.jl similarity index 80% rename from src/Geometry/CellQuadratures.jl rename to src/CellData/CellQuadratures.jl index 770d8f176..31ecf452a 100644 --- a/src/Geometry/CellQuadratures.jl +++ b/src/CellData/CellQuadratures.jl @@ -18,16 +18,7 @@ struct CellQuadrature <: GridapType end """ - CellQuadrature(trian::Triangulation, degree::Integer) -""" -function CellQuadrature(trian::Triangulation, degree::Integer) - polytopes = map(get_polytope,get_reffes(trian)) - cell_type = get_cell_type(trian) - CellQuadrature(degree,polytopes,cell_type) -end - -""" - CellQuadrature(polytopes::Vector{<:Polytope}, cell_types::AbstractVector) + CellQuadrature(degree,polytopes::Vector{<:Polytope}, cell_types::AbstractVector) """ function CellQuadrature(degree,polytopes::Vector{<:Polytope}, cell_types::AbstractVector) f = (p) -> Quadrature(p,degree) @@ -104,16 +95,13 @@ function _get_weights(q::AppendedArray) end """ - integrate(cell_field,trian::Triangulation,quad::CellQuadrature) - -The `cell_field` is aligned with the cells in `trian` + integrate(cell_field,cell_map::AbstractArray{<:Field},quad::CellQuadrature) """ -function integrate(cell_field,trian::Triangulation,quad::CellQuadrature) - cell_map = get_cell_map(trian) +function integrate(cell_field,cell_map::AbstractArray{<:Field},quad::CellQuadrature) q = get_coordinates(quad) w = get_weights(quad) j = gradient(cell_map) - _f = CellField(cell_field,trian) + _f = convert_to_cell_field(cell_field,cell_map) f = to_ref_space(_f) @assert length(f) == length(cell_map) "Are you using the right triangulation to integrate?" @assert length(f) == length(w) "Are you using the right quadrature to integrate?" diff --git a/src/FESpaces/Law.jl b/src/CellData/Law.jl similarity index 100% rename from src/FESpaces/Law.jl rename to src/CellData/Law.jl diff --git a/src/CellData/QPointCellFields.jl b/src/CellData/QPointCellFields.jl new file mode 100644 index 000000000..744f0b87d --- /dev/null +++ b/src/CellData/QPointCellFields.jl @@ -0,0 +1,129 @@ + +""" +""" +function QPointCellField(value::Number,cell_map::AbstractArray{<:Field},quad::CellQuadrature) + q = get_coordinates(quad) + v_q = [ fill(value,size(qi)) for qi in q ] + array = ArrayOfEvaluatedFields(v_q,q) + GenericCellField(array, cell_map) +end + +""" +""" +function CellField(value::Number,cell_map::AbstractArray{<:Field},quad::CellQuadrature) + QPointCellField(value,cell_map,quad) +end + +struct EvaluatedField{A<:AbstractArray,P<:AbstractArray} <:Field + array::A + points::P +end + +function field_cache(f::EvaluatedField,x) + nothing +end + +function evaluate_field!(cache,f::EvaluatedField,x) + @assert length(x) == length(f.array) + @assert x === f.points || x == f.points + f.array +end + +struct ArrayOfEvaluatedFields{T,N,A,B} <: AbstractArray{EvaluatedField{T},N} + array::A + points::B + function ArrayOfEvaluatedFields(array::AbstractArray{T,N},points::AbstractArray) where {T<:AbstractArray,N} + A = typeof(array) + B = typeof(points) + new{T,N,A,B}(array,points) + end +end + +Base.size(a::ArrayOfEvaluatedFields) = size(a.array) + +Base.IndexStyle(::Type{<:ArrayOfEvaluatedFields{T,N,A}}) where {T,N,A} = IndexStyle(A) + +@inline function Base.getindex(a::ArrayOfEvaluatedFields,i::Integer) + EvaluatedField(a.array[i],a.points[i]) +end + +@inline function Base.getindex(a::ArrayOfEvaluatedFields{T,N},i::Vararg{Int,N}) where {T,N} + EvaluatedField(a.array[i...],a.points[i...]) +end + +function array_cache(a::ArrayOfEvaluatedFields) + ca = array_cache(a.array) + cp = array_cache(a.points) + (ca,cp) +end + +@inline function getindex!(cache,a::ArrayOfEvaluatedFields,i...) + ca, cp = cache + array = getindex!(ca,a.array,i...) + points = getindex!(ca,a.points,i...) + EvaluatedField(array,points) +end + +function evaluate_field_array(a::ArrayOfEvaluatedFields,x::AbstractArray) + @assert a.points === x || a.points == x + @assert length(a) == length(x) + a.array +end + +function update_state_variables!(updater::Function,quad::CellQuadrature,f::CellField...) + x = get_coordinates(quad) + update_state_variables!(updater,x,f...) +end + +function update_state_variables!(updater::Function,x::AbstractArray,f::CellField...) + fx = map(i->evaluate(i,x),f) + caches = array_caches(fx...) + cache_x = array_cache(x) + _update_state_variables!(updater,caches,fx,cache_x,x) +end + +function update_state_variables!(quad::CellQuadrature,updater::Function,f::CellField...) + msg = + """ + The method + update_state_variables!(quad::CellQuadrature,updater::Function,f::CellField...) + has been removed. Use + update_state_variables!(updater::Function,quad::CellQuadrature,f::CellField...) + instead + """ + error(msg) +end + +@noinline function _update_state_variables!(updater,caches,fx,cache_x,x) + ncells = length(x) + for cell in 1:ncells + fxi = getitems!(caches,fx,cell) + xi = getindex!(cache_x,x,cell) + for q in 1:length(xi) + fxiq = getitems(fxi,q) + r = updater(fxiq...) + need_to_update, states = Arrays._split(r...) + if need_to_update + _update_states!(fxi,q,states,Val{length(states)}()) + end + end + end +end + +@inline function _update_states!(b,q,states,::Val{i}) where i + _update_state!(b,q,states,Val{i}()) + _update_states!(b,q,states,Val{i-1}()) + nothing +end + +@inline function _update_states!(b,q,states,::Val{0}) + nothing +end + +@inline function _update_state!(b,q,states,::Val{i}) where i + m = length(b) + n = length(states) + o = m-n + b[i+o][q] = states[i] + nothing +end diff --git a/src/Exports.jl b/src/Exports.jl index 7f6def031..5a1bc7d85 100644 --- a/src/Exports.jl +++ b/src/Exports.jl @@ -108,12 +108,13 @@ using Gridap.TensorValues: ⊗; export ⊗ @publish Geometry jump @publish Geometry mean @publish Geometry SkeletonTriangulation -@publish Geometry CellQuadrature -@publish Geometry QPointCellField -@publish Geometry CellField @publish Geometry RestrictedTriangulation @publish Geometry InterfaceTriangulation +@publish CellData CellQuadrature +@publish CellData QPointCellField +@publish CellData CellField + @publish FESpaces FESpace @publish FESpaces TrialFESpace @publish FESpaces TestFESpace @@ -135,11 +136,9 @@ using Gridap.TensorValues: ⊗; export ⊗ @publish FESpaces interpolate_dirichlet @publish FESpaces FEOperator @publish FESpaces FESolver -@publish FESpaces apply_statelaw @publish FESpaces update_state_variables! using Gridap.FESpaces: @law; export @law -using Gridap.FESpaces: @statelaw; export @statelaw @publish MultiField MultiFieldFESpace diff --git a/src/FESpaces/AffineFEOperators.jl b/src/FESpaces/AffineFEOperators.jl index 1a2163484..177748448 100644 --- a/src/FESpaces/AffineFEOperators.jl +++ b/src/FESpaces/AffineFEOperators.jl @@ -1,5 +1,9 @@ """ + AffineFEOperator + +Reprepresent a fully assembled affine (linear) finite element problem. +See also [FEOperator](@ref) """ struct AffineFEOperator <: FEOperator trial::FESpace diff --git a/src/FESpaces/Assemblers.jl b/src/FESpaces/Assemblers.jl index 010414917..b424bebc1 100644 --- a/src/FESpaces/Assemblers.jl +++ b/src/FESpaces/Assemblers.jl @@ -166,141 +166,3 @@ function test_assembler(a::Assembler,matdata,vecdata,data) @test num_free_dofs(test_fesp) == length(b) end -# This is an extended interface that only makes sense for assemblers that build (sequential) sparse matrices -# (e.g. not for matrix free assemblers or for distributed assemblers) - -""" -""" -abstract type SparseMatrixAssembler <: Assembler end - -""" -""" -function get_matrix_type(a::SparseMatrixAssembler) - @abstractmethod -end - -""" -""" -function get_vector_type(a::SparseMatrixAssembler) - @abstractmethod -end - -function allocate_vector(a::SparseMatrixAssembler,vecdata) - n = num_free_dofs(get_test(a)) - allocate_vector(get_vector_type(a),n) -end - -function assemble_vector!(b,a::SparseMatrixAssembler,vecdata) - fill_entries!(b,zero(eltype(b))) - assemble_vector_add!(b,a,vecdata) -end - -""" -""" -function count_matrix_nnz_coo(a::SparseMatrixAssembler,vecdata) - @abstractmethod -end - -""" -""" -function count_matrix_and_vector_nnz_coo(a::SparseMatrixAssembler,data) - @abstractmethod -end - -""" -""" -function fill_matrix_coo_symbolic!(I,J,a::SparseMatrixAssembler,matdata,n=0) - @abstractmethod -end - -function fill_matrix_and_vector_coo_symbolic!(I,J,a::SparseMatrixAssembler,data,n=0) - @abstractmethod -end - -function allocate_matrix(a::SparseMatrixAssembler,matdata) - n = count_matrix_nnz_coo(a,matdata) - I,J,V = allocate_coo_vectors(get_matrix_type(a),n) - fill_matrix_coo_symbolic!(I,J,a,matdata) - m = num_free_dofs(get_test(a)) - n = num_free_dofs(get_trial(a)) - finalize_coo!(get_matrix_type(a),I,J,V,m,n) - sparse_from_coo(get_matrix_type(a),I,J,V,m,n) -end - -function assemble_matrix!(mat,a::SparseMatrixAssembler,matdata) - z = zero(eltype(mat)) - fill_entries!(mat,z) - assemble_matrix_add!(mat,a,matdata) -end - -""" -""" -function fill_matrix_coo_numeric!(I,J,V,a::SparseMatrixAssembler,matdata,n=0) - @abstractmethod -end - -function assemble_matrix(a::SparseMatrixAssembler,matdata) - - n = count_matrix_nnz_coo(a,matdata) - I,J,V = allocate_coo_vectors(get_matrix_type(a),n) - - fill_matrix_coo_numeric!(I,J,V,a,matdata) - - m = num_free_dofs(get_test(a)) - n = num_free_dofs(get_trial(a)) - finalize_coo!(get_matrix_type(a),I,J,V,m,n) - sparse_from_coo(get_matrix_type(a),I,J,V,m,n) -end - - -function allocate_matrix_and_vector(a::SparseMatrixAssembler,data) - - n = count_matrix_and_vector_nnz_coo(a,data) - - I,J,V = allocate_coo_vectors(get_matrix_type(a),n) - fill_matrix_and_vector_coo_symbolic!(I,J,a,data) - m = num_free_dofs(get_test(a)) - n = num_free_dofs(get_trial(a)) - finalize_coo!(get_matrix_type(a),I,J,V,m,n) - A = sparse_from_coo(get_matrix_type(a),I,J,V,m,n) - - b = allocate_vector(get_vector_type(a),m) - - A,b -end - -function assemble_matrix_and_vector!(A,b,a::SparseMatrixAssembler, data) - fill_entries!(A,zero(eltype(A))) - fill_entries!(b,zero(eltype(b))) - assemble_matrix_and_vector_add!(A,b,a,data) - A, b -end - -""" -""" -function fill_matrix_and_vector_coo_numeric!(I,J,V,b,a::SparseMatrixAssembler,data,n=0) - @abstractmethod -end - -function assemble_matrix_and_vector(a::SparseMatrixAssembler, data) - - n = count_matrix_and_vector_nnz_coo(a,data) - I,J,V = allocate_coo_vectors(get_matrix_type(a),n) - n = num_free_dofs(get_test(a)) - b = allocate_vector(get_vector_type(a),n) - - fill_matrix_and_vector_coo_numeric!(I,J,V,b,a,data) - - m = num_free_dofs(get_test(a)) - n = num_free_dofs(get_trial(a)) - finalize_coo!(get_matrix_type(a),I,J,V,m,n) - A = sparse_from_coo(get_matrix_type(a),I,J,V,m,n) - - A, b -end - -function test_sparse_matrix_assembler(a::SparseMatrixAssembler,matdata,vecdata,data) - test_assembler(a,matdata,vecdata,data) - _ = get_matrix_type(a) - _ = get_vector_type(a) -end diff --git a/src/FESpaces/CLagrangianFESpaces.jl b/src/FESpaces/CLagrangianFESpaces.jl index 7c8cad698..eb43fbff8 100644 --- a/src/FESpaces/CLagrangianFESpaces.jl +++ b/src/FESpaces/CLagrangianFESpaces.jl @@ -120,7 +120,6 @@ function _generate_clagrangian_fespace(T,grid) cell_dofs, cell_shapefuns, cell_dof_basis, - cell_map, dirichlet_dof_tag, dirichlet_cells, ntags) diff --git a/src/FESpaces/CellBases.jl b/src/FESpaces/CellBases.jl deleted file mode 100644 index c9e61bcc3..000000000 --- a/src/FESpaces/CellBases.jl +++ /dev/null @@ -1,673 +0,0 @@ -# CellBasis - -""" -""" -abstract type CellBasis <: CellFieldLike end - -""" -""" -FECellBasisStyle(::Type{<:CellBasis}) = Val{true}() - -""" -""" -function TrialStyle(::Type{<:CellBasis}) - Val{false}() -end - -TrialStyle(cb) = TrialStyle(typeof(cb)) - -""" -""" -is_trial(cb) = is_trial(typeof(cb)) - -""" -""" -is_test(cb) = ! is_trial(cb) - -function is_trial(::Type{T}) where T - get_val_parameter(TrialStyle(T)) -end - -function is_test(::Type{T}) where T - ! is_trial(T) -end - -""" -""" -function test_cell_basis(cf::CellBasis,args...;kwargs...) - @test is_a_fe_cell_basis(cf) - test_cell_field_like(cf,args...;kwargs...) -end - -# Define how the metadata is preserved - -function change_ref_style(cf::CellBasis) - ref_sty = RefStyle(cf) - bool = !get_val_parameter(ref_sty) - new_sty = Val{bool}() - trial_style = TrialStyle(cf) - ar = get_array(cf) - cm = get_cell_map(cf) - GenericCellBasis(trial_style,ar,cm,new_sty) -end - -function similar_object(cf::CellBasis,array::AbstractArray) - cm = get_cell_map(cf) - trial_style = TrialStyle(cf) - GenericCellBasis(trial_style,array,cm,RefStyle(cf)) -end - -function similar_object(a::CellBasis,b::CellField,v::AbstractArray) - similar_object(a,v) -end - -function similar_object(a::CellField,b::CellBasis,v::AbstractArray) - similar_object(b,v) -end - -function similar_object(a::CellBasis,b::CellBasis,v::AbstractArray) - _similar_cell_basis(v,a,b,TrialStyle(a),TrialStyle(b)) -end - -function _similar_cell_basis(v,a,b,a_trial::Val{T},b_trial::Val{T}) where T - similar_object(a,v) -end - -function _similar_cell_basis(v,a,b,a_trial::Val{false},b_trial::Val{true}) - _similar_cell_basis_test_trial(v,a,b) -end - -function _similar_cell_basis(v,a,b,a_trial::Val{true},b_trial::Val{false}) - _similar_cell_basis_test_trial(v,b,a) -end - -function _similar_cell_basis_test_trial(v,a,b) - cm = get_cell_map(a) - @assert is_in_ref_space(a) == is_in_ref_space(b) - GenericCellMatrixField(v,cm,RefStyle(a)) -end - -# Operations - -function gradient(cf::CellBasis) - a = get_array(cf) - g = field_array_gradient(a) - similar_object(cf,g) -end - -function grad2curl(cf::CellBasis) - a = get_array(cf) - g = grad2curl(UnimplementedField,a) - similar_object(cf,g) -end - -function operate(op,cf::CellBasis) - a = get_array(cf) - b = field_array_operation(UnimplementedField,op,a) - similar_object(cf,b) -end - -function operate(op,cf1::CellBasis,cf2::CellField) - @assert length(cf1) == length(cf2) - a1 = get_array(cf1) - a2 = get_array(cf2) - b = field_array_operation(UnimplementedField,op,a1,a2) - similar_object(cf1,cf2,b) -end - -function operate(op,cf1::CellField,cf2::CellBasis) - @assert length(cf1) == length(cf2) - a1 = get_array(cf1) - a2 = get_array(cf2) - b = field_array_operation(UnimplementedField,op,a1,a2) - similar_object(cf1,cf2,b) -end - -function operate(op,cf1::CellBasis,object) - cm = get_cell_map(cf1) - cf2 = convert_to_cell_field(object,cm,RefStyle(cf1)) - operate(op,cf1,cf2) -end - -function operate(op,object,cf2::CellBasis) - cm = get_cell_map(cf2) - cf1 = convert_to_cell_field(object,cm,RefStyle(cf2)) - operate(op,cf1,cf2) -end - -function operate(op,a::CellBasis,b::CellBasis) - _operate_cell_basis(op,a,b,TrialStyle(a),TrialStyle(b)) -end - -function _operate_cell_basis(op,a,b,atrial::Val{T},btrial::Val{T}) where T - aa = get_array(a) - ab = get_array(b) - k = bcast(op) - c = apply_to_field_array(UnimplementedField,k,aa,ab) - similar_object(a,b,c) -end - -function _operate_cell_basis(op,a,b,atrial::Val{false},btrial::Val{true}) - _operate_cell_basis_test_trial(op,a,b) -end - -function _operate_cell_basis(op,a,b,atrial::Val{true},btrial::Val{false}) - _operate_cell_basis_test_trial(op,b,a) -end - -function _operate_cell_basis_test_trial(op,cf1,cf2) - @assert length(cf1) == length(cf2) - a1 = get_array(cf1) - a2 = get_array(cf2) - b = field_array_operation(UnimplementedField,op,a1,a2) - similar_object(cf1,cf2,b) -end - -# Operations with extra arguments - -function operate(op,a::CellField,b,objects...) - arrays = map(get_array,(a,b,objects...)) - v = apply_to_field_array(UnimplementedField,bcast(op),arrays...) - similar_object(a,v) -end - -function operate(op,a::CellBasis,b::CellField,objects...) - arrays = map(get_array,(a,b,objects...)) - v = apply_to_field_array(UnimplementedField,bcast(op),arrays...) - similar_object(a,v) -end - -function operate(op,a::CellField,b::CellBasis,objects...) - arrays = map(get_array,(a,b,objects...)) - v = apply_to_field_array(UnimplementedField,bcast(op),arrays...) - similar_object(b,v) -end - -function operate(op,a::CellBasis,b::CellBasis,objects...) - arrays = map(get_array,(a,b,objects...)) - v = apply_to_field_array(UnimplementedField,bcast(op),arrays...) - r = similar_object(a,b,v) - function fun(x) - if isa(x,CellBasis) && is_trial(x) - return true - else - return false - end - end - @notimplementedif isa(r,CellMatrixField) && any( map(fun,objects) ) - r -end - -# Concrete CellBases - -""" -""" -struct GenericCellBasis{T,R} <: CellBasis - trial_style::Val{T} - array - cell_map - ref_trait::Val{R} -end - -function GenericCellBasis(trial_style::Val{T},array::AbstractArray,cell_map::AbstractArray) where T - ref_trait = Val{true}() - GenericCellBasis(trial_style,array,cell_map,ref_trait) -end - -get_array(a::GenericCellBasis) = a.array - -get_cell_map(a::GenericCellBasis) = a.cell_map - -function TrialStyle(::Type{<:GenericCellBasis{T}}) where T - Val{T}() -end - -function RefStyle(::Type{<:GenericCellBasis{T,R}}) where {T,R} - Val{R}() -end - -""" -""" -abstract type CellMatrixField <: CellFieldLike end - -""" -""" -function test_cell_matrix_field(cb::CellMatrixField,args...; kwargs...) - test_cell_field_like(cb,args...;kwargs...) -end - -# Define how the metadata is preserved - -function change_ref_style(cf::CellMatrixField) - ref_sty = RefStyle(cf) - bool = !get_val_parameter(ref_sty) - new_sty = Val{bool}() - ar = get_array(cf) - cm = get_cell_map(cf) - GenericCellMatrixField(ar,cm,new_sty) -end - -function similar_object(cf::CellMatrixField,a::AbstractArray) - cm = get_cell_map(cf) - GenericCellMatrixField(a,cm,RefStyle(cf)) -end - -function similar_object(a::CellMatrixField,b::CellField,v::AbstractArray) - similar_object(a,v) -end - -function similar_object(a::CellField,b::CellMatrixField,v::AbstractArray) - similar_object(b,v) -end - -function similar_object(a::CellMatrixField,b::CellMatrixField,v::AbstractArray) - similar_object(a,v) -end - -# Define operations - -function operate(op,a::CellMatrixField) - aa = get_array(a) - k = bcast(op) - c = apply_to_field_array(UnimplementedField,k,aa) - similar_object(a,c) -end - -function operate(op,a::CellMatrixField,b::CellMatrixField) - _operate_cell_matrix_field(op,a,b) -end - -function operate(op,a::CellMatrixField,b::CellField) - _operate_cell_matrix_field(op,a,b) -end - -function operate(op,a::CellField,b::CellMatrixField) - _operate_cell_matrix_field(op,a,b) -end - -function _operate_cell_matrix_field(op,a,b) - aa = get_array(a) - ab = get_array(b) - k = bcast(op) - c = apply_to_field_array(UnimplementedField,k,aa,ab) - similar_object(a,b,c) -end - -function operate(op,a::CellMatrixField,b) - cm = get_cell_map(a) - _b = convert_to_cell_field(b,cm,RefStyle(a)) - operate(op,a,_b) -end - -function operate(op,a,b::CellMatrixField) - cm = get_cell_map(b) - _a = convert_to_cell_field(a,cm,RefStyle(b)) - operate(op,_a,b) -end - - -# Concrete CellMatrixField - -""" -""" -struct GenericCellMatrixField{A,B,R} <: CellMatrixField - array::A - cell_map::B - ref_style::Val{R} -end - -RefStyle(::Type{GenericCellMatrixField{A,B,R}}) where {A,B,R} = Val{R}() - -get_array(a::GenericCellMatrixField) = a.array - -get_cell_map(a::GenericCellMatrixField) = a.cell_map - -# Restrictions - -function restrict(cf::CellBasis,trian::Triangulation) - _cf = to_ref_space(cf) - a = get_array(_cf) - r = restrict(a,trian) - trial_style = TrialStyle(cf) - _restrict_cell_basis(trial_style,r,trian) -end - -function _restrict_cell_basis(trial_style,r::SkeletonPair,trian) - cm = get_cell_map(trian) - la = r.left - ra = r.right - l = GenericCellBasis(trial_style,la,cm) - r = GenericCellBasis(trial_style,ra,cm) - SkeletonCellBasis(trial_style,l,r) -end - -function _restrict_cell_basis(trial_style,r::AbstractArray,trian) - cm = get_cell_map(trian) - GenericCellBasis(trial_style,r,cm) -end - -# Integration of CellBasis and CellMatrixField - -function integrate(cell_basis::CellBasis,trian::Triangulation,quad::CellQuadrature) - cell_map = get_cell_map(trian) - q = get_coordinates(quad) - w = get_weights(quad) - j = gradient(cell_map) - @assert length(cell_basis) == length(cell_map) "Are you using the right triangulation to integrate?" - @assert length(cell_basis) == length(w) "Are you using the right quadrature to integrate?" - integrate(get_array(cell_basis),q,w,j) -end - -function integrate(cell_basis::CellMatrixField,trian::Triangulation,quad::CellQuadrature) - cell_map = get_cell_map(trian) - q = get_coordinates(quad) - w = get_weights(quad) - j = gradient(cell_map) - @assert length(cell_basis) == length(cell_map) "Are you using the right triangulation to integrate?" - @assert length(cell_basis) == length(w) "Are you using the right quadrature to integrate?" - integrate(get_array(cell_basis),q,w,j) -end - -# Skeleton-related stuff - -struct SkeletonCellBasis{T} <: GridapType - trial_style::Val{T} - left::CellBasis - right::CellBasis -end - -function Base.getproperty(a::SkeletonCellBasis, sym::Symbol) - if sym == :inward - ReducedSkeletonCellBasis(a.trial_style,1*a.left,0*a.right) - elseif sym == :outward - ReducedSkeletonCellBasis(a.trial_style,0*a.left,1*a.right) - else - getfield(a, sym) - end -end - -TrialStyle(::Type{<:SkeletonCellBasis{T}}) where T = Val{T}() - -function get_cell_map(a::SkeletonCellBasis) - get_cell_map(a.left) -end - -function gradient(cf::SkeletonCellBasis) - left = gradient(cf.left) - right = gradient(cf.right) - SkeletonCellBasis(cf.trial_style,left,right) -end - -function grad2curl(cf::SkeletonCellBasis) - left = grad2curl(cf.left) - right = grad2curl(cf.right) - SkeletonCellBasis(cf.trial_style,left,right) -end - -function operate(op,cf::SkeletonCellBasis) - left = operate(op,cf.left) - right = operate(op,cf.right) - SkeletonCellBasis(cf.trial_style,left,right) -end - -function operate(op,cf1::SkeletonCellBasis,cf2::CellField) - left = operate(op,cf1.left,cf2) - right = operate(op,cf1.right,cf2) - SkeletonCellBasis(cf1.trial_style,left,right) -end - -function operate(op,cf1::CellField,cf2::SkeletonCellBasis) - left = operate(op,cf1,cf2.left) - right = operate(op,cf1,cf2.right) - SkeletonCellBasis(cf2.trial_style,left,right) -end - -function operate(op,cf1::SkeletonCellBasis,object) - cm = get_cell_map(cf1) - cf2 = convert_to_cell_field(object,cm,RefStyle(cf1.left)) - operate(op,cf1,cf2) -end - -function operate(op,object,cf2::SkeletonCellBasis) - cm = get_cell_map(cf2) - cf1 = convert_to_cell_field(object,cm,RefStyle(cf2.left)) - operate(op,cf1,cf2) -end - -function jump(a::SkeletonCellBasis) - ReducedSkeletonCellBasis(a.trial_style,a.left,-a.right) -end - -function mean(a::SkeletonCellBasis) - ReducedSkeletonCellBasis(a.trial_style,0.5*a.left,0.5*a.right) -end - -# Result of reducing a SkeletonCellBasis - -struct ReducedSkeletonCellBasis{T} <: GridapType - trial_style::Val{T} - left - right -end - -TrialStyle(::Type{<:ReducedSkeletonCellBasis{T}}) where T = Val{T}() - -function get_cell_map(a::ReducedSkeletonCellBasis) - get_cell_map(a.left) -end - -function operate(op,cf::ReducedSkeletonCellBasis) - left = operate(op,cf.left) - right = operate(op,cf.right) - ReducedSkeletonCellBasis(cf.trial_style,left,right) -end - -function operate(op,cf1::ReducedSkeletonCellBasis,cf2::CellField) - left = operate(op,cf1.left,cf2) - right = operate(op,cf1.right,cf2) - ReducedSkeletonCellBasis(cf1.trial_style,left,right) -end - -function operate(op,cf1::CellField,cf2::ReducedSkeletonCellBasis) - left = operate(op,cf1,cf2.left) - right = operate(op,cf1,cf2.right) - ReducedSkeletonCellBasis(cf2.trial_style,left,right) -end - -function operate(op,cf1::ReducedSkeletonCellBasis,object) - cm = get_cell_map(cf1) - cf2 = convert_to_cell_field(object,cm,RefStyle(cf1.left)) - operate(op,cf1,cf2) -end - -function operate(op,object,cf2::ReducedSkeletonCellBasis) - cm = get_cell_map(cf2) - cf1 = convert_to_cell_field(object,cm,RefStyle(cf2.left)) - operate(op,cf1,cf2) -end - -function operate(op,a::ReducedSkeletonCellBasis,b::ReducedSkeletonCellBasis) - _operate_reduced_skeleton_cell_basis(op,a,b,a.trial_style,b.trial_style) -end - -function _operate_reduced_skeleton_cell_basis( - op,a,b,a_trial::Val{T},b_trial::Val{T}) where T - left = operate(op,a.left,b.left) - right = operate(op,a.right,b.right) - trial_style = Val{T}() - ReducedSkeletonCellBasis(trial_style,left,right) -end - -function _operate_reduced_skeleton_cell_basis( - op,a,b,a_trial::Val{false},b_trial::Val{true}) - _operate_skeleton_test_trial(op,a,b) -end - -function _operate_reduced_skeleton_cell_basis( - op,a,b,a_trial::Val{true},b_trial::Val{false}) - _operate_skeleton_test_trial(op,b,a) -end - -function _operate_skeleton_test_trial(op,a,b) - ll = operate(op,a.left,b.left) - lr = operate(op,a.left,b.right) - rl = operate(op,a.right,b.left) - rr = operate(op,a.right,b.right) - SkeletonCellMatrixField(ll,lr,rl,rr) -end - -struct SkeletonCellMatrixField <: GridapType - ll - lr - rl - rr -end - -get_cell_map(a::SkeletonCellMatrixField) = get_cell_map(a.ll) - -function operate(op,cf::SkeletonCellMatrixField) - ll = operate(op,cf.ll) - lr = operate(op,cf.lr) - rl = operate(op,cf.rl) - rr = operate(op,cf.rr) - SkeletonCellMatrixField(ll,lr,rl,rr) -end - -function operate(op,a::SkeletonCellMatrixField,b::SkeletonCellMatrixField) - ll = operate(op,a.ll,b.ll) - lr = operate(op,a.lr,b.lr) - rl = operate(op,a.rl,b.rl) - rr = operate(op,a.rr,b.rr) - SkeletonCellMatrixField(ll,lr,rl,rr) -end - -function operate(op,a::SkeletonCellMatrixField,b::CellField) - ll = operate(op,a.ll,b) - lr = operate(op,a.lr,b) - rl = operate(op,a.rl,b) - rr = operate(op,a.rr,b) - SkeletonCellMatrixField(ll,lr,rl,rr) -end - -function operate(op,a::CellField,b::SkeletonCellMatrixField) - ll = operate(op,a,b.ll) - lr = operate(op,a,b.lr) - rl = operate(op,a,b.rl) - rr = operate(op,a,b.rr) - SkeletonCellMatrixField(ll,lr,rl,rr) -end - -function operate(op,object,cf2::SkeletonCellMatrixField) - cm = get_cell_map(cf2) - cf1 = convert_to_cell_field(object,cm,RefStyle(cf2.ll)) - operate(op,cf1,cf2) -end - -function operate(op,cf1::SkeletonCellMatrixField,object) - cm = get_cell_map(cf1) - cf2 = convert_to_cell_field(object,cm,RefStyle(cf1.ll)) - operate(op,cf1,cf2) -end - -# Integration of Skeleton quantities - -struct SkeletonMatrix{A} <: GridapType - ll::A - lr::A - rl::A - rr::A -end - -struct SkeletonVector{A} <: GridapType - left::A - right::A -end - -struct SkeletonCellMatrix <: GridapType - ll - lr - rl - rr -end - -struct SkeletonCellVector <: GridapType - left - right -end - -function integrate( - a::SkeletonCellMatrixField,trian::Triangulation,quad::CellQuadrature) - ll = integrate(a.ll,trian,quad) - lr = integrate(a.lr,trian,quad) - rl = integrate(a.rl,trian,quad) - rr = integrate(a.rr,trian,quad) - SkeletonCellMatrix(ll,lr,rl,rr) -end - -function integrate( - a::ReducedSkeletonCellBasis,trian::Triangulation,quad::CellQuadrature) - left = integrate(a.left,trian,quad) - right = integrate(a.right,trian,quad) - SkeletonCellVector(left,right) -end - -# Dirichlet related - -function compute_dirichlet_cell_vector(cellmat,cellvals) - k = DirichletVecKernel() - apply(k,cellmat,cellvals) -end - -""" -""" -function attach_dirichlet_bcs(cellmatvec,cellvals) - k = DirichletMatVecKernel() - apply(k,cellmatvec,cellvals) -end - -struct DirichletVecKernel <: Kernel end - -function kernel_cache(k::DirichletVecKernel,mat::AbstractMatrix,vals) - vec = mat*vals - CachedArray(vec) -end - -@inline function apply_kernel!(cache,k::DirichletVecKernel,mat::AbstractMatrix,vals) - n = size(mat,1) - setsize!(cache,(n,)) - vec = cache.array - mul!(vec,mat,vals) - @inbounds for i in eachindex(vec) - vec[i] = -vec[i] - end - vec -end - -struct DirichletMatVecKernel <: Kernel - k::DirichletVecKernel - function DirichletMatVecKernel() - k = DirichletVecKernel() - new(k) - end -end - -function kernel_cache(k::DirichletMatVecKernel,mat,vals) - kernel_cache(k.k,mat,vals) -end - -function kernel_cache(k::DirichletMatVecKernel,matvec::Tuple,vals) - mat, = matvec - kernel_cache(k.k,mat,vals) -end - -@inline function apply_kernel!(cache,k::DirichletMatVecKernel,mat,vals) - vec = apply_kernel!(cache,k.k,mat,vals) - (mat,vec) -end - -@inline function apply_kernel!(cache,k::DirichletMatVecKernel,matvec::Tuple,vals) - mat, vec = matvec - vecd = apply_kernel!(cache,k.k,mat,vals) - add_to_array!(vecd,vec) - (mat, vecd) -end diff --git a/src/FESpaces/CellKernels.jl b/src/FESpaces/CellKernels.jl deleted file mode 100644 index da5988d1c..000000000 --- a/src/FESpaces/CellKernels.jl +++ /dev/null @@ -1,105 +0,0 @@ -""" -""" -function apply_cellmatvec(op::Function,a,b,c...) - k = CellMatVecKernel(op) - apply(k,a,b,c...) -end - -""" -""" -function apply_cellmatrix(op::Function,a,b,c...) - k = CellMatKernel(op) - apply(k,a,b,c...) -end - -""" -""" -function apply_cellvector(op::Function,a,c...) - k = CellVecKernel(op) - apply(k,a,c...) -end - -# Helpers - -struct CellMatVecKernel{F<:Function} <: Kernel - op::F -end - -function kernel_cache(k::CellMatVecKernel,a::AbstractMatrix,b::AbstractMatrix,c...) - @assert ndims(a) == 2 - @assert ndims(b) == 2 - Ta = eltype(a) - Tb = eltype(b) - T = return_type(inner,Ta,Tb) - m = size(a,2) - n = size(b,2) - mat = CachedArray(zeros(T,m,n)) - vec = CachedArray(zeros(T,m)) - (mat, vec) -end - -@inline function apply_kernel!(cache,k::CellMatVecKernel,a::AbstractArray,b::AbstractArray,c...) - cmat, cvec = cache - m = size(a,2) - n = size(b,2) - setsize!(cmat,(m,n)) - setsize!(cvec,(m,)) - mat = cmat.array - vec = cvec.array - z = zero(eltype(mat)) - fill!(mat,z) - fill!(vec,z) - k.op(mat,vec,a,b,c...) - (mat,vec) -end - -struct CellMatKernel{F<:Function} <: Kernel - op::F -end - -function kernel_cache(k::CellMatKernel,a::AbstractMatrix,b::AbstractMatrix,c...) - @assert ndims(a) == 2 - @assert ndims(b) == 2 - Ta = eltype(a) - Tb = eltype(b) - T = return_type(inner,Ta,Tb) - m = size(a,2) - n = size(b,2) - mat = CachedArray(zeros(T,m,n)) - mat -end - -@inline function apply_kernel!(cmat,k::CellMatKernel,a::AbstractArray,b::AbstractArray,c...) - m = size(a,2) - n = size(b,2) - setsize!(cmat,(m,n)) - mat = cmat.array - z = zero(eltype(mat)) - fill!(mat,z) - k.op(mat,a,b,c...) - mat -end - -struct CellVecKernel{F<:Function} <: Kernel - op::F -end - -function kernel_cache(k::CellVecKernel,a::AbstractMatrix,c...) - @assert ndims(a) == 2 - Ta = eltype(a) - T = return_type(inner,Ta,Ta) - m = size(a,2) - vec = CachedArray(zeros(T,m)) - vec -end - -@inline function apply_kernel!(cvec,k::CellVecKernel,a::AbstractArray,c...) - m = size(a,2) - setsize!(cvec,(m,)) - vec = cvec.array - z = zero(eltype(vec)) - fill!(vec,z) - k.op(vec,a,c...) - vec -end - diff --git a/src/FESpaces/ConformingFESpaces.jl b/src/FESpaces/ConformingFESpaces.jl index 3c10bc729..cfb169330 100644 --- a/src/FESpaces/ConformingFESpaces.jl +++ b/src/FESpaces/ConformingFESpaces.jl @@ -30,7 +30,6 @@ function ConformingFESpace( cell_dofs, cell_shapefuns, cell_dof_basis, - cell_map, dirichlet_dof_tag, dirichlet_cells, ntags) @@ -124,7 +123,10 @@ function compute_cell_space(reffes, cell_to_ctype, cell_map) shapefuns = map(get_shapefuns,reffes) refshapefuns = CompressedArray(shapefuns,cell_to_ctype) cell_shapefuns = attachmap(refshapefuns,cell_map) - cell_shapefuns = GenericCellBasis(Val{false}(),cell_shapefuns,cell_map,Val{true}()) + + reffe_to_axs = map(reffe->(Base.OneTo(num_dofs(reffe)),),reffes) + cell_axs = CompressedArray(reffe_to_axs,cell_to_ctype) + cell_shapefuns = GenericCellField(cell_shapefuns,cell_map,Val{true}(),cell_axs,Val((:,))) (cell_shapefuns, cell_dof_basis) end @@ -147,7 +149,9 @@ function compute_cell_space_physical(reffes, cell_to_ctype, cell_map) prebasis = map(get_prebasis,reffes) cell_prebasis = CompressedArray(prebasis,cell_to_ctype) - cell_prebasis = GenericCellBasis(Val{false}(),cell_prebasis,cell_map,Val{false}()) + reffe_to_axs = map(reffe->(Base.OneTo(num_dofs(reffe)),),reffes) + cell_axs = CompressedArray(reffe_to_axs,cell_to_ctype) + cell_prebasis = GenericCellField(cell_prebasis,cell_map,Val{false}(),cell_axs,Val((:,))) cell_shapefuns = _cell_shape_functions_physical_space(cell_prebasis,cell_dof_basis,cell_map) (cell_shapefuns, cell_dof_basis) @@ -190,9 +194,10 @@ function _cell_shape_functions_physical_space(cell_prebasis,cell_dof_basis,cell_ cell_matrix = evaluate(cell_dof_basis,cell_prebasis) cell_matrix_inv = apply(inv,cell_matrix) cell_shapefuns_phys = apply(change_basis,get_array(cell_prebasis),cell_matrix_inv) - ref_style = Val{false}() - trial_style = Val{false}() - GenericCellBasis(trial_style,cell_shapefuns_phys,cell_map,ref_style) + cell_axs = get_cell_axes(cell_prebasis) + metasize_style = MetaSizeStyle(cell_prebasis) + ref_style = RefStyle(cell_prebasis) + GenericCellField(cell_shapefuns_phys,cell_map,ref_style,cell_axs,metasize_style) # @santiagobadia : better implementation in the future... end @@ -279,11 +284,12 @@ end function _generate_face_to_own_dofs( n_faces, cell_to_ctype, - d_to_cell_to_dfaces::Vector{Table{T,P}}, - d_to_dface_to_cells::Vector{Table{T,P}}, + d_to_cell_to_dfaces::Vector{Table{T,Vd,Vp}}, + d_to_dface_to_cells::Vector{Table{T,Vd,Vp}}, d_to_offset, - d_to_ctype_to_ldface_to_own_ldofs) where {T,P} + d_to_ctype_to_ldface_to_own_ldofs) where {T,Vd,Vp} + P=eltype(Vp) face_to_own_dofs_ptrs = zeros(P,n_faces+1) D = length(d_to_offset)-1 @@ -539,12 +545,12 @@ function _convert_dirichlet_components(dirichlet_tags::String,dirichlet_componen end struct CellDofsNonOriented <:AbstractVector{Vector{Int}} - cell_to_faces::Table{Int,Int32} - cell_to_lface_to_pindex::Table{Int8,Int32} + cell_to_faces::Table{Int,Vector{Int},Vector{Int32}} + cell_to_lface_to_pindex::Table{Int8,Vector{Int8},Vector{Int32}} cell_to_ctype::Vector{Int8} ctype_to_lface_to_own_ldofs::Vector{Vector{Vector{Int}}} ctype_to_num_dofs::Vector{Int} - face_to_own_dofs::Table{Int,Int32} + face_to_own_dofs::Table{Int,Vector{Int},Vector{Int32}} ctype_to_lface_to_pindex_to_pdofs::Vector{Vector{Vector{Vector{Int}}}} end diff --git a/src/FESpaces/DirichletFESpaces.jl b/src/FESpaces/DirichletFESpaces.jl index 8b336d8b6..bfdc85ad4 100644 --- a/src/FESpaces/DirichletFESpaces.jl +++ b/src/FESpaces/DirichletFESpaces.jl @@ -16,17 +16,15 @@ end constraint_style(::Type{DirichletFESpace{B}}) where B = Val{B}() -function get_constraint_kernel_matrix_cols(f::DirichletFESpace) - get_constraint_kernel_matrix_cols(f.space) -end +get_cell_axes(t::DirichletFESpace)= get_cell_axes(t.space) -function get_constraint_kernel_matrix_rows(f::DirichletFESpace) - get_constraint_kernel_matrix_rows(f.space) -end +get_cell_axes_with_constraints(t::DirichletFESpace)= get_cell_axes_with_constraints(t.space) -function get_constraint_kernel_vector(f::DirichletFESpace) - get_constraint_kernel_vector(f.space) -end +CellData.CellField(t::DirichletFESpace,cell_vals) = CellField(t.space,cell_vals) + +get_cell_isconstrained(f::DirichletFESpace) = get_cell_isconstrained(f.space) + +get_cell_constraints(f::DirichletFESpace) = get_cell_constraints(f.space) function num_free_dofs(f::DirichletFESpace) num_dirichlet_dofs(f.space) diff --git a/src/FESpaces/DiscontinuousFESpaces.jl b/src/FESpaces/DiscontinuousFESpaces.jl index 9ecf61b74..3de59dfbe 100644 --- a/src/FESpaces/DiscontinuousFESpaces.jl +++ b/src/FESpaces/DiscontinuousFESpaces.jl @@ -22,7 +22,6 @@ function DiscontinuousFESpace(reffes::Vector{<:ReferenceFE}, trian::Triangulatio cell_dofs, cell_shapefuns, cell_dof_basis, - cell_map, dirichlet_dof_tag, dirichlet_cells, ntags) diff --git a/src/FESpaces/ExtendedFESpaces.jl b/src/FESpaces/ExtendedFESpaces.jl index 6f62a77e5..ec61d1f25 100644 --- a/src/FESpaces/ExtendedFESpaces.jl +++ b/src/FESpaces/ExtendedFESpaces.jl @@ -220,8 +220,47 @@ function get_cell_dofs(f::ExtendedFESpace) end +function get_cell_axes(f::ExtendedFESpace) + _extend_cell_axes(f,get_cell_axes(f.space)) +end + +function get_cell_axes_with_constraints(f::ExtendedFESpace) + _extend_cell_axes(f,get_cell_axes_with_constraints(f.space)) +end + +function _extend_cell_axes(f,cell_axes) + cell_axes_void = Fill(_empty_axes(testitem(cell_axes)...),length(f.trian.void_to_oldcell)) + array = ExtendedVector( + cell_axes_void, + cell_axes, + f.trian.oldcell_to_cell, + f.trian.void_to_oldcell, + f.trian.cell_to_oldcell) +end + +#TODO this is a little hacky +function _empty_axes(::Base.OneTo) + (Base.OneTo(0),) +end + +function _empty_axes(::Base.OneTo,::Base.OneTo) + (Base.OneTo(1),Base.OneTo(0)) +end + +function _empty_axes(::BlockedUnitRange) + (blockedrange([0]),) +end + +function _empty_axes(::BlockedUnitRange,::BlockedUnitRange) + (blockedrange([1]),blockedrange([0])) +end + function get_cell_basis(f::ExtendedFESpace) cell_basis = get_cell_basis(f.space) + _extend_cell_basis(f,cell_basis) +end + +function _extend_cell_basis(f,cell_basis) cell_to_val = get_array(cell_basis) xi = testitem(get_cell_coordinates(f.trian)) @@ -229,7 +268,9 @@ function get_cell_basis(f::ExtendedFESpace) Tv = field_return_type(vi,xi) T = eltype(Tv) D = num_components(eltype(xi)) - void_to_val = Fill(VoidBasis{T,D}(),length(f.trian.void_to_oldcell)) + + _void_to_val = Fill(VoidBasis{T,D}(),length(f.trian.void_to_oldcell)) + void_to_val = _trialize_if_needed(_void_to_val,MetaSizeStyle(cell_basis)) array = ExtendedVector( void_to_val, @@ -239,8 +280,31 @@ function get_cell_basis(f::ExtendedFESpace) f.trian.cell_to_oldcell) cm = get_cell_map(f.trian.oldtrian) - trial_style = TrialStyle(cell_basis) - GenericCellBasis(trial_style,array,cm,RefStyle(cell_basis)) + ca = _extend_cell_axes(f,get_cell_axes(cell_basis)) + GenericCellField(array,cm,RefStyle(cell_basis),ca,MetaSizeStyle(cell_basis)) +end + +function _trialize_if_needed(_void_to_val,::Val{(:,)}) + _void_to_val +end + +function _trialize_if_needed(_void_to_val,::Val{(1,:)}) + trialize_array_of_bases(_void_to_val) +end + +function CellData.CellField(f::ExtendedFESpace,cell_vals) + _cell_field_for_ext_fe_space(f,cell_vals,f.space) +end + +function _cell_field_for_ext_fe_space(f,cell_vals,ft::Any) + _default_cell_field(f,cell_vals) +end + +# TODO, this is a bit hacky, lincomb should also work for trial bases +function _cell_field_for_ext_fe_space(f,cell_vals,ft::TrialFESpace) + cell_basis = _extend_cell_basis(f,get_cell_basis(ft.space)) + cell_field = lincomb(cell_basis,cell_vals) + cell_field end function get_cell_dof_basis(f::ExtendedFESpace) diff --git a/src/FESpaces/FEAutodiff.jl b/src/FESpaces/FEAutodiff.jl index 806ee278c..6978d06da 100644 --- a/src/FESpaces/FEAutodiff.jl +++ b/src/FESpaces/FEAutodiff.jl @@ -39,11 +39,7 @@ end function _change_argument_to_cell_u(uh_to_cell_energy,U) function f(cell_u) - cell_shapefuns = get_cell_shapefuns(U) - cell_map = get_cell_map(U) - ref_style = RefStyle(get_cell_dof_basis(U)) - array = lincomb(cell_shapefuns,cell_u) - uh = GenericCellField(array,cell_map,ref_style) + uh = CellField(U,cell_u) cell_e = uh_to_cell_energy(uh) cell_e end diff --git a/src/FESpaces/FECellBases.jl b/src/FESpaces/FECellBases.jl new file mode 100644 index 000000000..d2843b047 --- /dev/null +++ b/src/FESpaces/FECellBases.jl @@ -0,0 +1,17 @@ + +FECellBasisStyle(::Type{T}) where T = Val{false}() + +FECellBasisStyle(cell_basis) = FECellBasisStyle(typeof(cell_basis)) + +FECellBasisStyle(::Type{T}) where T<:CellField = Val(is_basis(T)) + +""" +""" +function is_a_fe_cell_basis(cell_basis) + v = FECellBasisStyle(cell_basis) + get_val_parameter(v) +end + +function is_a_fe_cell_basis(::Type) + @unreachable "is_a_fe_cell_basis cannot be called on types" +end diff --git a/src/FESpaces/FEFunctions.jl b/src/FESpaces/FEFunctions.jl index 21fc8cf01..795efc9fc 100644 --- a/src/FESpaces/FEFunctions.jl +++ b/src/FESpaces/FEFunctions.jl @@ -33,6 +33,17 @@ function get_cell_values(object) @abstractmethod end +function get_cell_values(object,cellids::AbstractArray) + reindex(get_cell_values(object),cellids) +end + +function get_cell_values(object,cellids::SkeletonPair) + vals = reindex(get_cell_values(object),cellids) + f = get_fe_space(object) + axs = reindex(get_cell_axes(f),cellids) + merge_cell_dofs_at_skeleton(vals.left,vals.right,axs.left,axs.right) +end + """ """ function get_fe_space(object) diff --git a/src/FESpaces/FEOperators.jl b/src/FESpaces/FEOperators.jl index 68d2c847c..4189a9c18 100644 --- a/src/FESpaces/FEOperators.jl +++ b/src/FESpaces/FEOperators.jl @@ -1,5 +1,10 @@ """ + abstract type FEOperator <: GridapType + +A `FEOperator` contains finite element problem, +that is assembled as far as possible and ready to be solved. +See also [FETerm](@ref) """ abstract type FEOperator <: GridapType end diff --git a/src/FESpaces/FESpaces.jl b/src/FESpaces/FESpaces.jl index bbb4eb290..db847a3f0 100644 --- a/src/FESpaces/FESpaces.jl +++ b/src/FESpaces/FESpaces.jl @@ -10,6 +10,7 @@ using Test using FillArrays using SparseArrays using LinearAlgebra +using BlockArrays using Gridap.Inference using Gridap.Helpers @@ -21,13 +22,10 @@ using Gridap.Integration using Gridap.Algebra using Gridap.Polynomials using Gridap.TensorValues +using Gridap.CellData using Gridap.ReferenceFEs: evaluate_dof_array -using Gridap.Geometry: CellFieldLike -using Gridap.Geometry: UnimplementedField -using Gridap.Geometry: test_cell_field_like - using Gridap.Arrays: _split using Gridap.Arrays: Reindexed using Gridap.Arrays: IdentityVector @@ -41,16 +39,14 @@ import Gridap.Arrays: kernel_return_type import Gridap.Arrays: kernel_testitem! import Gridap.Arrays: reindex import Gridap.Arrays: apply -import Gridap.Geometry: get_cell_map -import Gridap.Geometry: get_cell_shapefuns +import Gridap.CellData: get_cell_map import Gridap.Geometry: get_reffes import Gridap.Geometry: get_cell_type -import Gridap.Geometry: RefStyle -import Gridap.Geometry: change_ref_style +import Gridap.CellData: RefStyle +import Gridap.CellData: get_cell_axes +import Gridap.CellData: change_ref_style import Gridap.Helpers: operate import Gridap.Geometry: similar_object -import Gridap.Geometry: jump -import Gridap.Geometry: mean import Gridap.Geometry: restrict import Gridap.Geometry: get_cell_id import Gridap.Fields: integrate @@ -89,21 +85,17 @@ export test_fe_function export FESpace export FEFunction +export EvaluationFunction export num_free_dofs export get_cell_basis +export get_cell_dofs export zero_free_values export constraint_style export has_constraints export get_cell_isconstrained export get_cell_constraints -export get_constraint_kernel_matrix_cols -export get_constraint_kernel_matrix_rows -export get_constraint_kernel_vector -export apply_constraints_matrix_cols -export apply_constraints_matrix_rows -export apply_constraints_vector -export apply_constraints_matrix_and_vector_cols -export apply_constraints_matrix_and_vector_rows +export get_cell_axes +export get_cell_axes_with_constraints export test_fe_space export Assembler @@ -140,7 +132,6 @@ export test_sparse_matrix_assembler export SingleFieldFESpace export num_dirichlet_dofs -export get_cell_dofs export zero_dirichlet_values export gather_free_and_dirichlet_values export gather_free_and_dirichlet_values! @@ -159,10 +150,12 @@ export compute_dirichlet_values_for_tags export compute_dirichlet_values_for_tags! export test_single_field_fe_space export interpolate +export interpolate! export interpolate_everywhere +export interpolate_everywhere! export interpolate_dirichlet +export interpolate_dirichlet! export get_cell_dof_basis -export get_cell_shapefuns export SingleFieldFEFunction @@ -170,21 +163,6 @@ export UnconstrainedFESpace export GradConformingFESpace export DiscontinuousFESpace -export CellBasis -export test_cell_basis -export CellMatrixField -export test_cell_matrix_field -export GenericCellBasis -export GenericCellMatrixField -export TrialStyle -export is_trial -export is_test -export attach_dirichlet_bcs - -export CellDofBasis -export GenericCellDofBasis -export test_cell_dof_basis - export FECellBasisStyle export is_a_fe_cell_basis @@ -195,6 +173,7 @@ export HomogeneousTrialFESpace! export TestFESpace export compute_conforming_cell_dofs export SparseMatrixAssembler +export GenericSparseMatrixAssembler export FEOperator export test_fe_operator @@ -233,56 +212,39 @@ export DirichletFESpace export FESpaceWithLinearConstraints export ExtendedFESpace -export @law -export operate -export GridapType - -export apply_cellmatvec -export apply_cellmatrix -export apply_cellvector - -export @statelaw -export apply_statelaw -export CellField -export update_state_variables! - export autodiff_cell_residual_from_energy export autodiff_cell_jacobian_from_energy export autodiff_cell_jacobian_from_residual export FEEnergy -include("CellBases.jl") - -include("CellDofBases.jl") - -include("Law.jl") - include("FEFunctions.jl") -include("FESpacesInterfaces.jl") +include("FECellBases.jl") -include("Assemblers.jl") - -include("FEOperators.jl") +include("FESpacesInterfaces.jl") include("SingleFieldFESpaces.jl") include("SingleFieldFEFunctions.jl") -include("TrialFESpaces.jl") - -include("SparseMatrixAssemblers.jl") +include("FESpaceFactories.jl") include("UnconstrainedFESpaces.jl") include("ConformingFESpaces.jl") +include("TrialFESpaces.jl") + include("DiscontinuousFESpaces.jl") +include("Assemblers.jl") + +include("SparseMatrixAssemblers.jl") + include("FETerms.jl") -include("CellKernels.jl") +include("FEOperators.jl") include("AffineFEOperators.jl") @@ -302,10 +264,6 @@ include("ExtendedFESpaces.jl") include("FESpacesWithLinearConstraints.jl") -include("FESpaceFactories.jl") - -include("StateLaws.jl") - include("FEAutodiff.jl") include("FETermsWithAutodiff.jl") diff --git a/src/FESpaces/FESpacesInterfaces.jl b/src/FESpaces/FESpacesInterfaces.jl index 38881690c..89608cddc 100644 --- a/src/FESpaces/FESpacesInterfaces.jl +++ b/src/FESpaces/FESpacesInterfaces.jl @@ -1,21 +1,4 @@ -# The object returned by get_cell_basis has to implement the following trait - -FECellBasisStyle(::Type{T}) where T = Val{false}() - -FECellBasisStyle(cell_basis) = FECellBasisStyle(typeof(cell_basis)) - -""" -""" -function is_a_fe_cell_basis(cell_basis) - v = FECellBasisStyle(cell_basis) - get_val_parameter(v) -end - -function is_a_fe_cell_basis(::Type) - @unreachable "is_a_fe_cell_basis cannot be called on types" -end - """ """ abstract type FESpace <: GridapType end @@ -34,6 +17,10 @@ function FEFunction(fe::FESpace, free_values) @abstractmethod end +function CellData.CellField(fe::FESpace,cell_vals) + @abstractmethod +end + function EvaluationFunction(fe::FESpace, free_values) FEFunction(fe,free_values) end @@ -53,12 +40,6 @@ end # Extended FEInterface used by FEOperatorFromTerms and Assemblers -""" -""" -function get_cell_basis(f::FESpace) - @abstractmethod -end - """ """ function constraint_style(::Type{<:FESpace}) @@ -67,231 +48,178 @@ end constraint_style(f::T) where T<:FESpace = constraint_style(T) -function get_cell_isconstrained(f::FESpace) - @abstractmethod -end - -function get_cell_constraints(f::FESpace) - @abstractmethod -end - """ """ -function get_constraint_kernel_matrix_cols(f::FESpace) - _default_constraint_kernel(f,constraint_style(f)) +function has_constraints(::Type{T}) where T <:FESpace + v = constraint_style(T) + get_val_parameter(v) end -""" -""" -function get_constraint_kernel_matrix_rows(f::FESpace) - _default_constraint_kernel(f,constraint_style(f)) -end +has_constraints(f::T) where T<:FESpace = has_constraints(T) """ """ -function get_constraint_kernel_vector(f::FESpace) - _default_constraint_kernel(f,constraint_style(f)) +function get_cell_dofs(f::FESpace) + @abstractmethod end -function _default_constraint_kernel(f,::Val{false}) - function default_kernel(m,isconstr,constr) - m - end +function get_cell_dofs(f::FESpace,cellids::AbstractArray) + reindex(get_cell_dofs(f),cellids) end -function _default_constraint_kernel(f,::Val{true}) - @abstractmethod +function get_cell_dofs(f::FESpace,cellids::SkeletonPair) + ids = reindex(get_cell_dofs(f),cellids) + axs = reindex(get_cell_axes_with_constraints(f),cellids) + merge_cell_dofs_at_skeleton(ids.left,ids.right,axs.left,axs.right) end """ """ -function test_fe_space(f::FESpace) - free_values = zero_free_values(f) - fe_function = FEFunction(f,free_values) - test_fe_function(fe_function) - fe_basis = get_cell_basis(f) - @test isa(has_constraints(f),Bool) - @test isa(has_constraints(typeof(f)),Bool) -end - -function test_fe_space(f::FESpace,matvecdata,matdata,vecdata) - test_fe_space(f) - - cellmat, cellidsrows, cellidscols = matdata - cm = apply_constraints_matrix_cols(f,cellmat,cellidscols) - if ! has_constraints(f) - @test cm === cellmat - end - cm = apply_constraints_matrix_rows(f,cellmat,cellidsrows) - if ! has_constraints(f) - @test cm === cellmat - end - - cellvec, cellidsrows = vecdata - cv = apply_constraints_vector(f,cellvec,cellidsrows) - if ! has_constraints(f) - @test cv === cellvec - end - - cellmatvec, cellidsrows, cellidscols = matvecdata - cmv = apply_constraints_matrix_and_vector_cols(f,cellmatvec,cellidscols) - if ! has_constraints(f) - @test cmv === cellmatvec - end - cmv = apply_constraints_matrix_and_vector_rows(f,cellmatvec,cellidsrows) - if ! has_constraints(f) - @test cmv === cellmatvec - end - +function get_cell_basis(f::FESpace) + @abstractmethod end -# API - """ """ -function has_constraints(::Type{T}) where T <:FESpace - v = constraint_style(T) - get_val_parameter(v) +function CellData.get_cell_axes(f::FESpace) + @abstractmethod end -has_constraints(f::T) where T<:FESpace = has_constraints(T) - """ """ -function apply_constraints_matrix_cols(f::FESpace,cellmat,cellids) - _apply_constraints_matrix_cols(constraint_style(f),f,cellmat,cellids) +function get_cell_axes_with_constraints(f::FESpace) + _get_cell_axes_with_constraints(f,constraint_style(f)) end -function _apply_constraints_matrix_cols(::Val{false},f,cellmat,cellids) - cellmat +function _get_cell_axes_with_constraints(f,::Val{false}) + get_cell_axes(f) end -function _apply_constraints_matrix_cols(::Val{true},f,cellmat,cellids) - cell_to_isconstr = reindex(get_cell_isconstrained(f),cellids) - cell_to_constr = reindex(get_cell_constraints(f),cellids) - k = get_constraint_kernel_matrix_cols(f) - apply(k,cellmat,cell_to_isconstr,cell_to_constr) +function _get_cell_axes_with_constraints(f,::Val{true}) + @abstractmethod end -""" -""" -function apply_constraints_matrix_rows(f::FESpace,cellmat,cellids) - _apply_constraints_matrix_rows(constraint_style(f),f,cellmat,cellids) +function get_cell_constraints(f::FESpace) + _get_cell_constraints(f,constraint_style(f)) end -function _apply_constraints_matrix_rows(::Val{false},f,cellmat,cellids) - cellmat +function _get_cell_constraints(f,::Val{false}) + identity_constraints(get_cell_axes(f)) end -function _apply_constraints_matrix_rows(::Val{true},f,cellmat,cellids) - cell_to_isconstr = reindex(get_cell_isconstrained(f),cellids) - cell_to_constr = reindex(get_cell_constraints(f),cellids) - k = get_constraint_kernel_matrix_rows(f) - apply(k,cellmat,cell_to_isconstr,cell_to_constr) +function _get_cell_constraints(f,::Val{true}) + @abstractmethod end -""" -""" -function apply_constraints_vector(f::FESpace,cellvec,cellids) - _apply_constraints_vector(constraint_style(f),f,cellvec,cellids) +function get_cell_constraints(f::FESpace,cellids::AbstractArray) + reindex(get_cell_constraints(f),cellids) end -function _apply_constraints_vector(::Val{false},f,cellvec,cellids) - cellvec +function get_cell_constraints(f::FESpace,cellids::SkeletonPair) + constr = reindex(get_cell_constraints(f),cellids) + axsrows = reindex(get_cell_axes_with_constraints(f),cellids) + axscols = reindex(get_cell_axes(f),cellids) + merge_cell_constraints_at_skeleton( + constr.left,constr.right, + axsrows.left,axsrows.right, + axscols.left,axscols.right) end -function _apply_constraints_vector(::Val{true},f,cellvec,cellids) - cell_to_isconstr = reindex(get_cell_isconstrained(f),cellids) - cell_to_constr = reindex(get_cell_constraints(f),cellids) - k = get_constraint_kernel_vector(f) - apply(k,cellvec,cell_to_isconstr,cell_to_constr) +function get_cell_isconstrained(f::FESpace) + _get_cell_isconstrained(f,constraint_style(f)) end -""" -""" -function apply_constraints_matrix_and_vector_cols(f::FESpace,cellmatvec,cellids) - _apply_constraints_matrix_and_vector_cols(constraint_style(f),f,cellmatvec,cellids) +function _get_cell_isconstrained(f,::Val{false}) + Fill(false,length(get_cell_dofs(f))) end -function _apply_constraints_matrix_and_vector_cols(::Val{false},f,cellmatvec,cellids) - cellmatvec +function _get_cell_isconstrained(f,::Val{true}) + @abstractmethod end -function _apply_constraints_matrix_and_vector_cols(::Val{true},f,cellmatvec,cellids) - cell_to_isconstr = reindex(get_cell_isconstrained(f),cellids) - cell_to_constr = reindex(get_cell_constraints(f),cellids) - kmat = get_constraint_kernel_matrix_cols(f) - k = MatKernel(kmat) - apply(k,cellmatvec,cell_to_isconstr,cell_to_constr) +function get_cell_isconstrained(f::FESpace,cellids::AbstractArray) + reindex(get_cell_isconstrained(f),cellids) end -""" -""" -function apply_constraints_matrix_and_vector_rows(f::FESpace,cellmatvec,cellids) - _apply_constraints_matrix_and_vector_rows(constraint_style(f),f,cellmatvec,cellids) +function get_cell_isconstrained(f::FESpace,cellids::SkeletonPair) + isconstr = reindex(get_cell_isconstrained(f),cellids) + apply((l,r)-> l||r,isconstr.left,isconstr.right) end -function _apply_constraints_matrix_and_vector_rows(::Val{false},f,cellmatvec,cellids) - cellmatvec +function CellData.attach_constraints_rows(f::FESpace,cellarr,cellids) + _attach_constraints_rows(f,cellarr,cellids,constraint_style(f)) end -function _apply_constraints_matrix_and_vector_rows(::Val{true},f,cellmatvec,cellids) - cell_to_isconstr = reindex(get_cell_isconstrained(f),cellids) - cell_to_constr = reindex(get_cell_constraints(f),cellids) - kmat = get_constraint_kernel_matrix_rows(f) - kvec = get_constraint_kernel_vector(f) - k = MatVecKernel(kmat,kvec) - apply(k,cellmatvec,cell_to_isconstr,cell_to_constr) +function _attach_constraints_rows(f::FESpace,cellarr,cellids,::Val{false}) + cellarr end -# Helpers - -struct MatVecKernel{A<:Kernel,B<:Kernel} <: Kernel - kmat::A - kvec::B +function _attach_constraints_rows(f::FESpace,cellarr,cellids,::Val{true}) + cellconstr = get_cell_constraints(f,cellids) + cellmask = get_cell_isconstrained(f,cellids) + attach_constraints_rows(cellarr,cellconstr,cellmask) end -function kernel_cache(k::MatVecKernel,matvec,isconstr,constr) - mat, vec = matvec - cmat = kernel_cache(k.kmat,mat,isconstr,constr) - cvec = kernel_cache(k.kvec,vec,isconstr,constr) - (cmat, cvec) +function CellData.attach_constraints_cols(f::FESpace,cellarr,cellids) + _attach_constraints_cols(f,cellarr,cellids,constraint_style(f)) end -function kernel_return_type(k::MatVecKernel,matvec,isconstr,constr) - mat, vec = matvec - A = kernel_return_type(k.kmat,mat,isconstr,constr) - B = kernel_return_type(k.kvec,vec,isconstr,constr) - Tuple{A,B} +function _attach_constraints_cols(f::FESpace,cellarr,cellids,::Val{false}) + cellarr end -@inline function apply_kernel!(cache,k::MatVecKernel,matvec,isconstr,constr) - cmat, cvec = cache - mat, vec = matvec - a = apply_kernel!(cmat,k.kmat,mat,isconstr,constr) - b = apply_kernel!(cvec,k.kvec,vec,isconstr,constr) - (a,b) +function _attach_constraints_cols(f::FESpace,cellarr,cellids,::Val{true}) + cellconstr = get_cell_constraints(f,cellids) + cellmask = get_cell_isconstrained(f,cellids) + attach_constraints_cols(cellarr,cellconstr,cellmask) end -struct MatKernel{A<:Kernel} <: Kernel - kmat::A +""" +""" +function test_fe_space(f::FESpace) + free_values = zero_free_values(f) + @test length(free_values) == num_free_dofs(f) + fe_function = FEFunction(f,free_values) + test_fe_function(fe_function) + fe_basis = get_cell_basis(f) + @test isa(has_constraints(f),Bool) + @test isa(has_constraints(typeof(f)),Bool) + @test length(get_cell_dofs(f)) == length(fe_basis) + @test length(get_cell_axes(f)) == length(fe_basis) + @test length(get_cell_axes_with_constraints(f)) == length(fe_basis) + @test length(get_cell_constraints(f)) == length(fe_basis) + @test length(get_cell_isconstrained(f)) == length(fe_basis) + @test CellField(f,get_cell_dofs(f)) != nothing end -function kernel_cache(k::MatKernel,matvec,isconstr,constr) - mat, vec = matvec - cmat = kernel_cache(k.kmat,mat,isconstr,constr) - cmat -end +function test_fe_space(f::FESpace,matvecdata,matdata,vecdata) + test_fe_space(f) -function kernel_return_type(k::MatKernel,matvec,isconstr,constr) - mat, vec = matvec - A = kernel_return_type(k.kmat,mat,isconstr,constr) - B = typeof(vec) - Tuple{A,B} -end + cellmat, cellidsrows, cellidscols = matdata + cm = attach_constraints_cols(f,cellmat,cellidscols) + if ! has_constraints(f) + @test cm === cellmat + end + cm = attach_constraints_rows(f,cellmat,cellidsrows) + if ! has_constraints(f) + @test cm === cellmat + end + + cellvec, cellidsrows = vecdata + cv = attach_constraints_rows(f,cellvec,cellidsrows) + if ! has_constraints(f) + @test cv === cellvec + end + + cellmatvec, cellidsrows, cellidscols = matvecdata + cmv = attach_constraints_cols(f,cellmatvec,cellidscols) + if ! has_constraints(f) + @test cmv === cellmatvec + end + cmv = attach_constraints_rows(f,cellmatvec,cellidsrows) + if ! has_constraints(f) + @test cmv === cellmatvec + end -@inline function apply_kernel!(cmat,k::MatKernel,matvec,isconstr,constr) - mat, vec = matvec - a = apply_kernel!(cmat,k.kmat,mat,isconstr,constr) - (a,vec) end + diff --git a/src/FESpaces/FESpacesWithLastDofRemoved.jl b/src/FESpaces/FESpacesWithLastDofRemoved.jl index 970b902c3..7be8a42b3 100644 --- a/src/FESpaces/FESpacesWithLastDofRemoved.jl +++ b/src/FESpaces/FESpacesWithLastDofRemoved.jl @@ -89,19 +89,13 @@ function get_cell_dof_basis(f::FESpaceWithLastDofRemoved) get_cell_dof_basis(f.space) end -constraint_style(::Type{FESpaceWithLastDofRemoved{B}}) where B = Val{B}() +get_cell_axes(t::FESpaceWithLastDofRemoved)= get_cell_axes(t.space) -function get_constraint_kernel_matrix_cols(f::FESpaceWithLastDofRemoved) - get_constraint_kernel_matrix_cols(f.space) -end +get_cell_axes_with_constraints(t::FESpaceWithLastDofRemoved)= get_cell_axes_with_constraints(t.space) -function get_constraint_kernel_matrix_rows(f::FESpaceWithLastDofRemoved) - get_constraint_kernel_matrix_rows(f.space) -end +CellData.CellField(t::FESpaceWithLastDofRemoved,cell_vals) = CellField(t.space,cell_vals) -function get_constraint_kernel_vector(f::FESpaceWithLastDofRemoved) - get_constraint_kernel_vector(f.space) -end +constraint_style(::Type{FESpaceWithLastDofRemoved{B}}) where B = Val{B}() # Helpers diff --git a/src/FESpaces/FESpacesWithLinearConstraints.jl b/src/FESpaces/FESpacesWithLinearConstraints.jl index 39102ed10..5fe09aafa 100644 --- a/src/FESpaces/FESpacesWithLinearConstraints.jl +++ b/src/FESpaces/FESpacesWithLinearConstraints.jl @@ -471,6 +471,21 @@ function get_cell_basis(f::FESpaceWithLinearConstraints) get_cell_basis(f.space) end +function CellData.CellField(f::FESpaceWithLinearConstraints,cellvals) + CellField(f.space,cellvals) +end + +function get_cell_axes(f::FESpaceWithLinearConstraints) + get_cell_axes(f.space) +end + +function get_cell_axes_with_constraints(f::FESpaceWithLinearConstraints) + # In some situations this can be compressed + ptrs = f.cell_to_lmdof_to_mdof.ptrs + ncells = length(get_cell_basis(f)) + apply(i->(Base.OneTo(ptrs[i+1]-ptrs[i]),),IdentityVector(ncells)) +end + function zero_free_values(f::FESpaceWithLinearConstraints) where T zeros(num_free_dofs(f)) end diff --git a/src/FESpaces/FETerms.jl b/src/FESpaces/FETerms.jl index 4a203f512..d92724baa 100644 --- a/src/FESpaces/FETerms.jl +++ b/src/FESpaces/FETerms.jl @@ -1,5 +1,9 @@ """ + abstract type FETerm <: GridapType end + +A `FETerm` is a lazy representation of a summand of a finite element problem. It is not assembled. +See also [FEOperator](@ref). """ abstract type FETerm <: GridapType end @@ -42,11 +46,6 @@ function _setup_jac_and_res(celljac,cellres) (celljacres, nothing, nothing) end -function _setup_jac_and_res(celljac::SkeletonCellMatrix,cellres::SkeletonCellVector) - #TODO for the moment do not pair on the skeleton - (nothing, celljac, cellres) -end - function _setup_jac_and_res(celljac::Nothing,cellres) (nothing, nothing, cellres) end @@ -60,6 +59,7 @@ function _setup_jac_and_res(celljac::Nothing,cellres::Nothing) end """ +See also [FETerm](@ref). """ abstract type AffineFETerm <: FETerm end @@ -74,20 +74,19 @@ end """ Returns an object (e.g. a CellVector) representing the contribution to the -system rhs of the given term. Returns nothing if the term has not +system rhs of the given term (with Dirichlet bcs included). Returns nothing if the term has not contribution (typically for linear terms) """ function get_cell_vector(t::AffineFETerm,uhd,v) @abstractmethod end -function get_cell_vector(t::AffineFETerm,v) - @abstractmethod -end - """ +Returns an object (e.g. a CellVector) representing the contribution to the +system rhs of the given term (without Dirichlet bcs). Returns nothing if the term has not +contribution (typically for linear terms) """ -function get_cell_values(t::FETerm,uhd) +function get_cell_vector(t::AffineFETerm,v) @abstractmethod end @@ -105,34 +104,19 @@ function get_cell_matrix_and_vector(t::AffineFETerm,uhd,u,v) @assert is_a_fe_cell_basis(v) @assert is_a_fe_cell_basis(u) cellmat = get_cell_matrix(t,u,v) - cellvec = _get_cell_vector_tmp_hack(cellmat,t,v,uhd) #TODO - cellvals = get_cell_values(t,uhd) - _setup_cell_matrix_and_vector(cellmat,cellvec,cellvals) -end - -function _get_cell_vector_tmp_hack(cellmat,t,v,uhd) #TODO cellvec = get_cell_vector(t,v) - cellvec -end - -function _get_cell_vector_tmp_hack(cellmat::SkeletonCellMatrix,t,v,uhd) #TODO - cellvec = get_cell_vector(t,uhd,v) - cellvec + cellvals = get_cell_values(uhd,get_cell_id(t)) + _setup_cell_matrix_and_vector(cellmat,cellvec,cellvals) end function _setup_cell_matrix_and_vector(cellmat,cellvec,cellvals) cellmatvec = pair_arrays(cellmat,cellvec) - cellmatvec_with_diri = attach_dirichlet_bcs(cellmatvec,cellvals) + cellmatvec_with_diri = attach_dirichlet(cellmatvec,cellvals) (cellmatvec_with_diri, nothing, nothing) end -function _setup_cell_matrix_and_vector(cellmat::SkeletonCellMatrix,cellvec::SkeletonCellVector,cellvals) - # TODO for the moment do not pair quantities on the skeleton and assume that cellvec has dirichlet bcs - (nothing, cellmat, cellvec) -end - function _setup_cell_matrix_and_vector(cellmat,cellvec::Nothing,cellvals) - cellmatvec_with_diri = attach_dirichlet_bcs(cellmat,cellvals) + cellmatvec_with_diri = attach_dirichlet(cellmat,cellvals) (cellmatvec_with_diri, nothing, nothing) end @@ -145,6 +129,7 @@ function _setup_cell_matrix_and_vector(cellmat::Nothing,cellvec::Nothing,cellval end """ +See also [FETerm](@ref). """ abstract type LinearFETerm <: AffineFETerm end @@ -276,18 +261,6 @@ function _push_matrix_contribution!(w,r,c,cellvals::Nothing,cellids) nothing end -function _push_matrix_contribution!(w,r,c,cellvals::SkeletonCellMatrix,cellids::SkeletonPair) - push!(w,cellvals.ll) - push!(w,cellvals.lr) - push!(w,cellvals.rl) - push!(w,cellvals.rr) - push!(r,cellids.left); push!(c,cellids.left) - push!(r,cellids.left); push!(c,cellids.right) - push!(r,cellids.right); push!(c,cellids.left) - push!(r,cellids.right); push!(c,cellids.right) - nothing -end - function _push_vector_contribution!(v,r,cellvals,cellids) push!(v,cellvals) push!(r,cellids) @@ -298,14 +271,6 @@ function _push_vector_contribution!(v,r,cellvals::Nothing,cellids) nothing end -function _push_vector_contribution!(v,r,cellvals::SkeletonCellVector,cellids::SkeletonPair) - push!(v,cellvals.left) - push!(v,cellvals.right) - push!(r,cellids.left) - push!(r,cellids.right) - nothing -end - # Concrete implementations struct AffineFETermFromIntegration <: AffineFETerm @@ -356,12 +321,6 @@ function get_cell_id(t::AffineFETermFromIntegration) get_cell_id(t.trian) end -function get_cell_values(t::AffineFETermFromIntegration,uhd) - @assert is_a_fe_function(uhd) - cellvals = get_cell_values(uhd) - reindex(cellvals,t.trian) -end - struct FESourceFromIntegration <: FESource liform::Function trian::Triangulation @@ -405,12 +364,6 @@ function get_cell_id(t::FESourceFromIntegration) get_cell_id(t.trian) end -function get_cell_values(t::FESourceFromIntegration,uhd) - @assert is_a_fe_function(uhd) - cellvals = get_cell_values(uhd) - reindex(cellvals,t.trian) -end - struct LinearFETermFromIntegration <: LinearFETerm biform::Function trian::Triangulation @@ -457,12 +410,6 @@ function get_cell_id(t::LinearFETermFromIntegration) get_cell_id(t.trian) end -function get_cell_values(t::LinearFETermFromIntegration,uhd) - @assert is_a_fe_function(uhd) - cellvals = get_cell_values(uhd) - reindex(cellvals,t.trian) -end - struct NonlinearFETerm <: FETerm res::Function jac::Function @@ -523,9 +470,9 @@ function get_cell_vector(t::AffineFETermFromCellMatVec,uhd,v) u = get_cell_basis(trial) _v = restrict(v,t.trian) _u = restrict(u,t.trian) - _cellvals = get_cell_values(t,uhd) + _cellvals = get_cell_values(uhd,get_cell_id(t.trian)) cellmatvec = t.matvecfun(_u,_v) - cellmatvec_with_diri = attach_dirichlet_bcs(cellmatvec,_cellvals) + cellmatvec_with_diri = attach_dirichlet(cellmatvec,_cellvals) _, cellvec_with_diri = unpair_arrays(cellmatvec_with_diri) cellvec_with_diri end @@ -539,21 +486,15 @@ function get_cell_id(t::AffineFETermFromCellMatVec) get_cell_id(t.trian) end -function get_cell_values(t::AffineFETermFromCellMatVec,uhd) - @assert is_a_fe_function(uhd) - cellvals = get_cell_values(uhd) - reindex(cellvals,t.trian) -end - function get_cell_matrix_and_vector(t::AffineFETermFromCellMatVec,uhd,u,v) @assert is_a_fe_function(uhd) @assert is_a_fe_cell_basis(v) @assert is_a_fe_cell_basis(u) _v = restrict(v,t.trian) _u = restrict(u,t.trian) - _cellvals = get_cell_values(t,uhd) + _cellvals = get_cell_values(uhd,get_cell_id(t.trian)) cellmatvec = t.matvecfun(_u,_v) - cellmatvec_with_diri = attach_dirichlet_bcs(cellmatvec,_cellvals) + cellmatvec_with_diri = attach_dirichlet(cellmatvec,_cellvals) (cellmatvec_with_diri, nothing, nothing) end diff --git a/src/FESpaces/SingleFieldFEFunctions.jl b/src/FESpaces/SingleFieldFEFunctions.jl index 669e5ee1f..0da82f5b8 100644 --- a/src/FESpaces/SingleFieldFEFunctions.jl +++ b/src/FESpaces/SingleFieldFEFunctions.jl @@ -1,31 +1,29 @@ """ """ -struct SingleFieldFEFunction{R} <: CellField - array +struct SingleFieldFEFunction{T<:CellField} <: CellField + cell_field::T cell_vals free_values dirichlet_values fe_space - ref_style::Val{R} @doc """ """ function SingleFieldFEFunction( - array::AbstractArray{<:Field}, + cell_field::CellField, cell_vals::AbstractArray{<:AbstractArray}, free_values::AbstractVector, dirichlet_values::AbstractVector, fe_space::SingleFieldFESpace) - ref_style = RefStyle(get_cell_dof_basis(fe_space)) - R = get_val_parameter(ref_style) - new{R}(array,cell_vals,free_values,dirichlet_values,fe_space,ref_style) + T = typeof(cell_field) + new{T}(cell_field,cell_vals,free_values,dirichlet_values,fe_space) end end FEFunctionStyle(::Type{<:SingleFieldFEFunction}) = Val{true}() -get_array(f::SingleFieldFEFunction) = f.array +get_array(f::SingleFieldFEFunction) = get_array(f.cell_field) get_free_values(f::SingleFieldFEFunction) = f.free_values @@ -33,8 +31,14 @@ get_dirichlet_values(f::SingleFieldFEFunction) = f.dirichlet_values get_fe_space(f::SingleFieldFEFunction) = f.fe_space -get_cell_map(f::SingleFieldFEFunction) = get_cell_map(f.fe_space) +get_cell_map(f::SingleFieldFEFunction) = get_cell_map(f.cell_field) get_cell_values(f::SingleFieldFEFunction) = f.cell_vals -RefStyle(::Type{SingleFieldFEFunction{R}}) where R = Val{R}() +RefStyle(::Type{SingleFieldFEFunction{T}}) where T = RefStyle(T) + +CellData.MetaSizeStyle(::Type{SingleFieldFEFunction{T}}) where T = MetaSizeStyle(T) + +CellData.get_cell_axes(a::SingleFieldFEFunction) = get_cell_axes(a.cell_field) + +CellData.get_memo(a::SingleFieldFEFunction) = get_memo(a.cell_field) diff --git a/src/FESpaces/SingleFieldFESpaces.jl b/src/FESpaces/SingleFieldFESpaces.jl index 67f526649..bead17052 100644 --- a/src/FESpaces/SingleFieldFESpaces.jl +++ b/src/FESpaces/SingleFieldFESpaces.jl @@ -3,12 +3,6 @@ """ abstract type SingleFieldFESpace <: FESpace end -""" -""" -function get_cell_dofs(f::SingleFieldFESpace) - @abstractmethod -end - """ """ function get_cell_dof_basis(f::SingleFieldFESpace) @@ -55,7 +49,8 @@ end """ function test_single_field_fe_space(f::SingleFieldFESpace,pred=(==)) fe_basis = get_cell_basis(f) - @test isa(fe_basis,CellBasis) + @test isa(fe_basis,CellField) + @test is_basis(fe_basis) test_fe_space(f) cell_dofs = get_cell_dofs(f) dirichlet_values = zero_dirichlet_values(f) @@ -80,6 +75,7 @@ function test_single_field_fe_space(f::SingleFieldFESpace,pred=(==)) @test maximum(get_dirichlet_dof_tag(f)) <= num_dirichlet_tags(f) end cell_dof_basis = get_cell_dof_basis(f) + @test isa(CellField(f,get_cell_dofs(f)),CellField) end function test_single_field_fe_space(f,matvecdata,matdata,vecdata,pred=(==)) @@ -87,133 +83,15 @@ function test_single_field_fe_space(f,matvecdata,matdata,vecdata,pred=(==)) test_fe_space(f,matvecdata,matdata,vecdata) end -function get_cell_isconstrained(f::SingleFieldFESpace) - _get_cell_isconstrained(f,constraint_style(f)) -end - -function _get_cell_isconstrained(f,::Val{false}) - n = length(get_cell_dofs(f)) - Fill(false,n) -end - -function _get_cell_isconstrained(f,::Val{true}) - @abstractmethod -end - -function get_cell_constraints(f::SingleFieldFESpace) - _get_cell_constraints(f,constraint_style(f)) -end - -function _get_cell_constraints(f,::Val{false}) - k = IdentityConstraintKernel() - cell_to_dofs = get_cell_dofs(f) - apply(k,cell_to_dofs) -end - -function _get_cell_constraints(f,::Val{true}) - @abstractmethod -end - -struct IdentityConstraintKernel <: Kernel end - -function kernel_cache(k::IdentityConstraintKernel,dofs) - n = length(dofs) - a = zeros(n,n) - CachedArray(a) -end - -function apply_kernel!(cache,k::IdentityConstraintKernel,dofs) - n = length(dofs) - setsize!(cache,(n,n)) - a = cache.array - fill!(a,zero(eltype(a))) - o = one(eltype(a)) - @inbounds for i in 1:size(a,1) - a[i,i] = o - end - a -end - -function get_constraint_kernel_vector(f::SingleFieldFESpace) - VectorConstraintKernel() -end - -struct VectorConstraintKernel <: Kernel end - -function kernel_cache(k::VectorConstraintKernel,vec,isconstr,constr) - CachedArray(copy(vec)) -end - -function apply_kernel!(cache,k::VectorConstraintKernel,vec,isconstr,constr) - if isconstr - n = size(constr,1) - setsize!(cache,(n,)) - v = cache.array - mul!(v,constr,vec) - return v - else - return vec - end -end - -function get_constraint_kernel_matrix_rows(f::SingleFieldFESpace) - MatrixRowsConstraintKernel() -end - -struct MatrixRowsConstraintKernel <: Kernel end - -function kernel_cache(k::MatrixRowsConstraintKernel,mat,isconstr,constr) - CachedArray(copy(mat)) -end - -function apply_kernel!(cache,k::MatrixRowsConstraintKernel,mat,isconstr,constr) - if isconstr - n = size(constr,1) - m = size(mat,2) - setsize!(cache,(n,m)) - v = cache.array - mul!(v,constr,mat) - return v - else - return mat - end -end - -function get_constraint_kernel_matrix_cols(f::SingleFieldFESpace) - MatrixColsConstraintKernel() -end - -struct MatrixColsConstraintKernel <: Kernel end - -function kernel_cache(k::MatrixColsConstraintKernel,mat,isconstr,constr) - CachedArray(copy(mat)) -end - -function apply_kernel!(cache,k::MatrixColsConstraintKernel,mat,isconstr,constr) - if isconstr - m = size(mat,1) - n = size(constr,1) - setsize!(cache,(m,n)) - v = cache.array - mul!(v,mat,Transpose(constr)) - return v - else - return mat - end -end - """ """ -function get_cell_map(fs::SingleFieldFESpace) +function CellData.get_cell_map(fs::SingleFieldFESpace) fe_basis = get_cell_basis(fs) get_cell_map(fe_basis) end -""" -""" -function get_cell_shapefuns(fs::SingleFieldFESpace) - fe_basis = get_cell_basis(fs) - get_array(fe_basis) +function CellData.get_cell_axes(f::SingleFieldFESpace) + get_cell_axes(get_cell_basis(f)) end """ @@ -226,11 +104,20 @@ are the ones provided by `get_dirichlet_values(fs)` function FEFunction( fs::SingleFieldFESpace, free_values::AbstractVector, dirichlet_values::AbstractVector) cell_vals = scatter_free_and_dirichlet_values(fs,free_values,dirichlet_values) - cell_shapefuns = get_cell_shapefuns(fs) - cell_field = lincomb(cell_shapefuns,cell_vals) + cell_field = CellField(fs,cell_vals) SingleFieldFEFunction(cell_field,cell_vals,free_values,dirichlet_values,fs) end +function CellData.CellField(fs::SingleFieldFESpace,cell_vals) + _default_cell_field(fs,cell_vals) +end + +function _default_cell_field(fs,cell_vals) + cell_basis = get_cell_basis(fs) + cell_field = lincomb(cell_basis,cell_vals) + cell_field +end + function FEFunction(fe::SingleFieldFESpace, free_values) diri_values = get_dirichlet_values(fe) FEFunction(fe,free_values,diri_values) @@ -282,18 +169,48 @@ function gather_free_values!(free_values,f::SingleFieldFESpace,cell_vals) free_values end +@deprecate( + interpolate(fs::SingleFieldFESpace, object), + interpolate(object, fs::SingleFieldFESpace) +) + +@deprecate( + interpolate!(free_values,fs::SingleFieldFESpace, object), + interpolate!(object, free_values,fs::SingleFieldFESpace) +) + +@deprecate( + interpolate_everywhere(fs::SingleFieldFESpace, object), + interpolate_everywhere(object, fs::SingleFieldFESpace) +) + +@deprecate( + interpolate_everywhere!(free_values,dirichlet_values,fs::SingleFieldFESpace, object), + interpolate_everywhere!(object, free_values,dirichlet_values,fs::SingleFieldFESpace) +) + +@deprecate( + interpolate_dirichlet(fs::SingleFieldFESpace, object), + interpolate_dirichlet(object, fs::SingleFieldFESpace) +) + +@deprecate( + interpolate_dirichlet!(free_values,dirichlet_values,fs::SingleFieldFESpace, object), + interpolate_dirichlet!(object, free_values,dirichlet_values,fs::SingleFieldFESpace) +) + """ The resulting FE function is in the space (in particular it fulfills Dirichlet BCs even in the case that the given cell field does not fulfill them) """ -function interpolate(fs::SingleFieldFESpace,object) +function interpolate(object, fs::SingleFieldFESpace) free_values = zero_free_values(fs) - interpolate!(free_values,fs,object) + interpolate!(object, free_values,fs) end """ """ -function interpolate!(free_values,fs::SingleFieldFESpace,object) +function interpolate!(object, free_values,fs::SingleFieldFESpace) cell_vals = _cell_vals(fs,object) gather_free_values!(free_values,fs,cell_vals) FEFunction(fs,free_values) @@ -310,15 +227,15 @@ end like interpolate, but also compute new degrees of freedom for the dirichlet component. The resulting FEFunction does not necessary belongs to the underlying space """ -function interpolate_everywhere(fs::SingleFieldFESpace,object) +function interpolate_everywhere(object, fs::SingleFieldFESpace) free_values = zero_free_values(fs) dirichlet_values = zero_dirichlet_values(fs) - interpolate_everywhere!(free_values,dirichlet_values,fs,object) + interpolate_everywhere!(object, free_values,dirichlet_values,fs) end """ """ -function interpolate_everywhere!(free_values,dirichlet_values,fs::SingleFieldFESpace,object) +function interpolate_everywhere!(object, free_values,dirichlet_values,fs::SingleFieldFESpace) cell_vals = _cell_vals(fs,object) gather_free_and_dirichlet_values!(free_values,dirichlet_values,fs,cell_vals) FEFunction(fs,free_values,dirichlet_values) @@ -326,15 +243,15 @@ end """ """ -function interpolate_dirichlet(fs::SingleFieldFESpace,object) +function interpolate_dirichlet(object, fs::SingleFieldFESpace) free_values = zero_free_values(fs) dirichlet_values = zero_dirichlet_values(fs) - interpolate_dirichlet!(free_values,dirichlet_values,fs,object) + interpolate_dirichlet!(object, free_values,dirichlet_values,fs) end """ """ -function interpolate_dirichlet!(free_values,dirichlet_values,fs::SingleFieldFESpace,object) +function interpolate_dirichlet!(object, free_values,dirichlet_values,fs::SingleFieldFESpace) cell_vals = _cell_vals(fs,object) gather_dirichlet_values!(dirichlet_values,fs,cell_vals) fill!(free_values,zero(eltype(free_values))) diff --git a/src/FESpaces/SparseMatrixAssemblers.jl b/src/FESpaces/SparseMatrixAssemblers.jl index 1c2f3c09e..52da8bda2 100644 --- a/src/FESpaces/SparseMatrixAssemblers.jl +++ b/src/FESpaces/SparseMatrixAssemblers.jl @@ -1,51 +1,188 @@ +# This is an extended interface that only makes sense for assemblers that build (sequential) sparse matrices +# (e.g. not for matrix free assemblers or for distributed assemblers) -struct SingleFieldSparseMatrixAssembler{M,V} <: SparseMatrixAssembler +""" +""" +abstract type SparseMatrixAssembler <: Assembler end + +""" +""" +function get_matrix_type(a::SparseMatrixAssembler) + @abstractmethod +end + +""" +""" +function get_vector_type(a::SparseMatrixAssembler) + @abstractmethod +end + +function allocate_vector(a::SparseMatrixAssembler,vecdata) + n = num_free_dofs(get_test(a)) + allocate_vector(get_vector_type(a),n) +end + +function assemble_vector!(b,a::SparseMatrixAssembler,vecdata) + fill_entries!(b,zero(eltype(b))) + assemble_vector_add!(b,a,vecdata) +end + +""" +""" +function count_matrix_nnz_coo(a::SparseMatrixAssembler,matdata) + @abstractmethod +end + +""" +""" +function count_matrix_and_vector_nnz_coo(a::SparseMatrixAssembler,data) + @abstractmethod +end + +""" +""" +function fill_matrix_coo_symbolic!(I,J,a::SparseMatrixAssembler,matdata,n=0) + @abstractmethod +end + +function fill_matrix_and_vector_coo_symbolic!(I,J,a::SparseMatrixAssembler,data,n=0) + @abstractmethod +end + +function allocate_matrix(a::SparseMatrixAssembler,matdata) + n = count_matrix_nnz_coo(a,matdata) + I,J,V = allocate_coo_vectors(get_matrix_type(a),n) + fill_matrix_coo_symbolic!(I,J,a,matdata) + m = num_free_dofs(get_test(a)) + n = num_free_dofs(get_trial(a)) + finalize_coo!(get_matrix_type(a),I,J,V,m,n) + sparse_from_coo(get_matrix_type(a),I,J,V,m,n) +end + +function assemble_matrix!(mat,a::SparseMatrixAssembler,matdata) + z = zero(eltype(mat)) + fill_entries!(mat,z) + assemble_matrix_add!(mat,a,matdata) +end + +""" +""" +function fill_matrix_coo_numeric!(I,J,V,a::SparseMatrixAssembler,matdata,n=0) + @abstractmethod +end + +function assemble_matrix(a::SparseMatrixAssembler,matdata) + + n = count_matrix_nnz_coo(a,matdata) + I,J,V = allocate_coo_vectors(get_matrix_type(a),n) + + fill_matrix_coo_numeric!(I,J,V,a,matdata) + + m = num_free_dofs(get_test(a)) + n = num_free_dofs(get_trial(a)) + finalize_coo!(get_matrix_type(a),I,J,V,m,n) + sparse_from_coo(get_matrix_type(a),I,J,V,m,n) +end + + +function allocate_matrix_and_vector(a::SparseMatrixAssembler,data) + + n = count_matrix_and_vector_nnz_coo(a,data) + + I,J,V = allocate_coo_vectors(get_matrix_type(a),n) + fill_matrix_and_vector_coo_symbolic!(I,J,a,data) + m = num_free_dofs(get_test(a)) + n = num_free_dofs(get_trial(a)) + finalize_coo!(get_matrix_type(a),I,J,V,m,n) + A = sparse_from_coo(get_matrix_type(a),I,J,V,m,n) + + b = allocate_vector(get_vector_type(a),m) + + A,b +end + +function assemble_matrix_and_vector!(A,b,a::SparseMatrixAssembler, data) + fill_entries!(A,zero(eltype(A))) + fill_entries!(b,zero(eltype(b))) + assemble_matrix_and_vector_add!(A,b,a,data) + A, b +end + +""" +""" +function fill_matrix_and_vector_coo_numeric!(I,J,V,b,a::SparseMatrixAssembler,data,n=0) + @abstractmethod +end + +function assemble_matrix_and_vector(a::SparseMatrixAssembler, data) + + n = count_matrix_and_vector_nnz_coo(a,data) + I,J,V = allocate_coo_vectors(get_matrix_type(a),n) + n = num_free_dofs(get_test(a)) + b = allocate_vector(get_vector_type(a),n) + + fill_matrix_and_vector_coo_numeric!(I,J,V,b,a,data) + + m = num_free_dofs(get_test(a)) + n = num_free_dofs(get_trial(a)) + finalize_coo!(get_matrix_type(a),I,J,V,m,n) + A = sparse_from_coo(get_matrix_type(a),I,J,V,m,n) + + A, b +end + +function test_sparse_matrix_assembler(a::SparseMatrixAssembler,matdata,vecdata,data) + test_assembler(a,matdata,vecdata,data) + _ = get_matrix_type(a) + _ = get_vector_type(a) +end + +struct GenericSparseMatrixAssembler{M,V} <: SparseMatrixAssembler matrix_type::Type{M} vector_type::Type{V} - trial::SingleFieldFESpace - test::SingleFieldFESpace + trial::FESpace + test::FESpace strategy::AssemblyStrategy end function SparseMatrixAssembler( - mat::Type,vec::Type,trial::SingleFieldFESpace,test::SingleFieldFESpace,strategy::AssemblyStrategy) - SingleFieldSparseMatrixAssembler(mat,vec,trial,test,strategy) + mat::Type,vec::Type,trial::FESpace,test::FESpace,strategy::AssemblyStrategy) + GenericSparseMatrixAssembler(mat,vec,trial,test,strategy) end -function SparseMatrixAssembler(mat::Type,vec::Type,trial::SingleFieldFESpace,test::SingleFieldFESpace) +function SparseMatrixAssembler(mat::Type,vec::Type,trial::FESpace,test::FESpace) strategy = DefaultAssemblyStrategy() - SingleFieldSparseMatrixAssembler(mat,vec,trial,test,strategy) + GenericSparseMatrixAssembler(mat,vec,trial,test,strategy) end -function SparseMatrixAssembler(mat::Type,trial::SingleFieldFESpace,test::SingleFieldFESpace) +function SparseMatrixAssembler(mat::Type,trial::FESpace,test::FESpace) strategy = DefaultAssemblyStrategy() - SingleFieldSparseMatrixAssembler(mat,Vector{Float64},trial,test,strategy) + GenericSparseMatrixAssembler(mat,Vector{Float64},trial,test,strategy) end """ """ -function SparseMatrixAssembler(trial::SingleFieldFESpace,test::SingleFieldFESpace) +function SparseMatrixAssembler(trial::FESpace,test::FESpace) matrix_type = SparseMatrixCSC{Float64,Int} vector_type = Vector{Float64} strategy = DefaultAssemblyStrategy() - SingleFieldSparseMatrixAssembler(matrix_type,vector_type,trial,test,strategy) + GenericSparseMatrixAssembler(matrix_type,vector_type,trial,test,strategy) end -get_test(a::SingleFieldSparseMatrixAssembler) = a.test +get_test(a::GenericSparseMatrixAssembler) = a.test -get_trial(a::SingleFieldSparseMatrixAssembler) = a.trial +get_trial(a::GenericSparseMatrixAssembler) = a.trial -get_matrix_type(a::SingleFieldSparseMatrixAssembler) = a.matrix_type +get_matrix_type(a::GenericSparseMatrixAssembler) = a.matrix_type -get_vector_type(a::SingleFieldSparseMatrixAssembler) = a.vector_type +get_vector_type(a::GenericSparseMatrixAssembler) = a.vector_type -get_assembly_strategy(a::SingleFieldSparseMatrixAssembler) = a.strategy +get_assembly_strategy(a::GenericSparseMatrixAssembler) = a.strategy -function assemble_vector_add!(b,a::SingleFieldSparseMatrixAssembler,vecdata) - celldofs = get_cell_dofs(a.test) +function assemble_vector_add!(b,a::GenericSparseMatrixAssembler,vecdata) for (cellvec, cellids) in zip(vecdata...) - rows = reindex(celldofs,cellids) - vals = apply_constraints_vector(a.test,cellvec,cellids) + rows = get_cell_dofs(a.test,cellids) + vals = attach_constraints_rows(a.test,cellvec,cellids) rows_cache = array_cache(rows) vals_cache = array_cache(vals) _assemble_vector!(b,vals_cache,rows_cache,vals,rows,a.strategy) @@ -53,51 +190,83 @@ function assemble_vector_add!(b,a::SingleFieldSparseMatrixAssembler,vecdata) b end -function _assemble_vector!(vec,vals_cache,rows_cache,cell_vals,cell_rows,strategy) +@noinline function _assemble_vector!(vec,vals_cache,rows_cache,cell_vals,cell_rows,strategy) @assert length(cell_vals) == length(cell_rows) for cell in 1:length(cell_rows) rows = getindex!(rows_cache,cell_rows,cell) vals = getindex!(vals_cache,cell_vals,cell) - for (i,gid) in enumerate(rows) - if gid > 0 && row_mask(strategy,gid) - _gid = row_map(strategy,gid) - add_entry!(vec,vals[i],_gid) - end + _assemble_vector_at_cell!(vec,rows,vals,strategy) + end +end + +@inline function _assemble_vector_at_cell!(vec,rows,vals,strategy) + for (i,gid) in enumerate(rows) + if gid > 0 && row_mask(strategy,gid) + _gid = row_map(strategy,gid) + add_entry!(vec,vals[i],_gid) end end end -function count_matrix_nnz_coo(a::SingleFieldSparseMatrixAssembler,matdata) - _,term_to_cellidsrows, term_to_cellidscols = matdata - celldofs_rows = get_cell_dofs(a.test) - celldofs_cols = get_cell_dofs(a.trial) +@inline function _assemble_vector_at_cell!(vec,rows::BlockArrayCoo,vals::BlockArrayCoo,strategy) + for I in eachblockindex(vals) + if is_nonzero_block(vals,I) + _assemble_vector_at_cell!(vec,rows[I],vals[I],strategy) + end + end +end + +function count_matrix_nnz_coo(a::GenericSparseMatrixAssembler,matdata) n = 0 - for (cellidsrows,cellidscols) in zip(term_to_cellidsrows,term_to_cellidscols) - cell_rows = reindex(celldofs_rows,cellidsrows) - cell_cols = reindex(celldofs_cols,cellidscols) + for (cellmat_rc,cellidsrows,cellidscols) in zip(matdata...) + cell_rows = get_cell_dofs(a.test,cellidsrows) + cell_cols = get_cell_dofs(a.trial,cellidscols) rows_cache = array_cache(cell_rows) cols_cache = array_cache(cell_cols) + cellmat_r = attach_constraints_cols(a.trial,cellmat_rc,cellidscols) + cellmat = attach_constraints_rows(a.test,cellmat_r,cellidsrows) @assert length(cell_cols) == length(cell_rows) - n += _count_matrix_entries(a.matrix_type,rows_cache,cols_cache,cell_rows,cell_cols,a.strategy) + if length(cell_cols) > 0 + mat = first(cellmat) + Is = _get_block_layout(mat) + n += _count_matrix_entries(a.matrix_type,rows_cache,cols_cache,cell_rows,cell_cols,a.strategy,Is) + end end - n end -@noinline function _count_matrix_entries(::Type{M},rows_cache,cols_cache,cell_rows,cell_cols,strategy) where M +function _get_block_layout(a::Tuple) + _get_block_layout(a[1]) +end + +function _get_block_layout(a::AbstractMatrix) + nothing +end + +function _get_block_layout(a::BlockArrayCoo) + [(I,_get_block_layout(a[I])) for I in eachblockindex(a) if is_nonzero_block(a,I) ] +end + +@noinline function _count_matrix_entries(::Type{M},rows_cache,cols_cache,cell_rows,cell_cols,strategy,Is) where M n = 0 for cell in 1:length(cell_cols) rows = getindex!(rows_cache,cell_rows,cell) cols = getindex!(cols_cache,cell_cols,cell) - for gidcol in cols - if gidcol > 0 && col_mask(strategy,gidcol) - _gidcol = col_map(strategy,gidcol) - for gidrow in rows - if gidrow > 0 && row_mask(strategy,gidrow) - _gidrow = row_map(strategy,gidrow) - if is_entry_stored(M,_gidrow,_gidcol) - n += 1 - end + n += _count_matrix_entries_at_cell(M,rows,cols,strategy,Is) + end + n +end + +@inline function _count_matrix_entries_at_cell(::Type{M},rows,cols,strategy,Is) where M + n = 0 + for gidcol in cols + if gidcol > 0 && col_mask(strategy,gidcol) + _gidcol = col_map(strategy,gidcol) + for gidrow in rows + if gidrow > 0 && row_mask(strategy,gidrow) + _gidrow = row_map(strategy,gidrow) + if is_entry_stored(M,_gidrow,_gidcol) + n += 1 end end end @@ -106,44 +275,65 @@ end n end -function count_matrix_and_vector_nnz_coo(a::SingleFieldSparseMatrixAssembler,data) +@inline function _count_matrix_entries_at_cell( + ::Type{M},rows::BlockArrayCoo,cols::BlockArrayCoo,strategy,Is) where M + n = 0 + for (I,Is_next) in Is + i,j = I.n + n += _count_matrix_entries_at_cell(M,rows[Block(i)],cols[Block(j)],strategy,Is_next) + end + n +end + +function count_matrix_and_vector_nnz_coo(a::GenericSparseMatrixAssembler,data) matvecdata, matdata, vecdata = data n = count_matrix_nnz_coo(a,matvecdata) n += count_matrix_nnz_coo(a,matdata) n end -function fill_matrix_coo_symbolic!(I,J,a::SingleFieldSparseMatrixAssembler,matdata,n=0) - _,term_to_cellidsrows, term_to_cellidscols = matdata - celldofs_rows = get_cell_dofs(a.test) - celldofs_cols = get_cell_dofs(a.trial) +function fill_matrix_coo_symbolic!(I,J,a::GenericSparseMatrixAssembler,matdata,n=0) + term_to_cellmat,term_to_cellidsrows, term_to_cellidscols = matdata nini = n - for (cellidsrows,cellidscols) in zip(term_to_cellidsrows,term_to_cellidscols) - cell_rows = reindex(celldofs_rows,cellidsrows) - cell_cols = reindex(celldofs_cols,cellidscols) + for (cellmat_rc,cellidsrows,cellidscols) in zip(term_to_cellmat,term_to_cellidsrows,term_to_cellidscols) + cell_rows = get_cell_dofs(a.test,cellidsrows) + cell_cols = get_cell_dofs(a.trial,cellidscols) rows_cache = array_cache(cell_rows) cols_cache = array_cache(cell_cols) - nini = _allocate_matrix!(a.matrix_type,nini,I,J,rows_cache,cols_cache,cell_rows,cell_cols,a.strategy) + cellmat_r = attach_constraints_cols(a.trial,cellmat_rc,cellidscols) + cellmat = attach_constraints_rows(a.test,cellmat_r,cellidsrows) + @assert length(cell_cols) == length(cell_rows) + if length(cell_cols) > 0 + mat = first(cellmat) + Is = _get_block_layout(mat) + nini = _allocate_matrix!(a.matrix_type,nini,I,J,rows_cache,cols_cache,cell_rows,cell_cols,a.strategy,Is) + end end nini end -@noinline function _allocate_matrix!(a::Type{M},nini,I,J,rows_cache,cols_cache,cell_rows,cell_cols,strategy) where M +@noinline function _allocate_matrix!(a::Type{M},nini,I,J,rows_cache,cols_cache,cell_rows,cell_cols,strategy,Is) where M n = nini for cell in 1:length(cell_cols) rows = getindex!(rows_cache,cell_rows,cell) cols = getindex!(cols_cache,cell_cols,cell) - for gidcol in cols - if gidcol > 0 && col_mask(strategy,gidcol) - _gidcol = col_map(strategy,gidcol) - for gidrow in rows - if gidrow > 0 && row_mask(strategy,gidrow) - _gidrow = row_map(strategy,gidrow) - if is_entry_stored(M,_gidrow,_gidcol) - n += 1 - @inbounds I[n] = _gidrow - @inbounds J[n] = _gidcol - end + n = _allocate_matrix_at_cell!(M,n,I,J,rows,cols,strategy,Is) + end + n +end + +@inline function _allocate_matrix_at_cell!(::Type{M},nini,I,J,rows,cols,strategy,Is) where M + n = nini + for gidcol in cols + if gidcol > 0 && col_mask(strategy,gidcol) + _gidcol = col_map(strategy,gidcol) + for gidrow in rows + if gidrow > 0 && row_mask(strategy,gidrow) + _gidrow = row_map(strategy,gidrow) + if is_entry_stored(M,_gidrow,_gidcol) + n += 1 + @inbounds I[n] = _gidrow + @inbounds J[n] = _gidcol end end end @@ -152,62 +342,80 @@ end n end -function fill_matrix_and_vector_coo_symbolic!(I,J,a::SingleFieldSparseMatrixAssembler,data,n=0) +@inline function _allocate_matrix_at_cell!( + ::Type{M},nini,I,J,rows::BlockArrayCoo,cols::BlockArrayCoo,strategy,Is) where M + n = nini + for (B,Is_next) in Is + i,j = B.n + n = _allocate_matrix_at_cell!(M,n,I,J,rows[Block(i)],cols[Block(j)],strategy,Is_next) + end + n +end + +function fill_matrix_and_vector_coo_symbolic!(I,J,a::GenericSparseMatrixAssembler,data,n=0) matvecdata, matdata, vecdata = data nini = fill_matrix_coo_symbolic!(I,J,a,matvecdata,n) nini = fill_matrix_coo_symbolic!(I,J,a,matdata,nini) nini end -function assemble_matrix_add!(mat,a::SingleFieldSparseMatrixAssembler,matdata) +function assemble_matrix_add!(mat,a::GenericSparseMatrixAssembler,matdata) - celldofs_rows = get_cell_dofs(a.test) - celldofs_cols = get_cell_dofs(a.trial) for (cellmat_rc,cellidsrows,cellidscols) in zip(matdata...) - cell_rows = reindex(celldofs_rows,cellidsrows) - cell_cols = reindex(celldofs_cols,cellidscols) - cellmat_r = apply_constraints_matrix_cols(a.trial,cellmat_rc,cellidscols) - cellmat = apply_constraints_matrix_rows(a.test,cellmat_r,cellidsrows) + cell_rows = get_cell_dofs(a.test,cellidsrows) + cell_cols = get_cell_dofs(a.trial,cellidscols) + cellmat_r = attach_constraints_cols(a.trial,cellmat_rc,cellidscols) + cell_vals = attach_constraints_rows(a.test,cellmat_r,cellidsrows) rows_cache = array_cache(cell_rows) cols_cache = array_cache(cell_cols) - vals_cache = array_cache(cellmat) - _assemble_matrix!(mat,vals_cache,rows_cache,cols_cache,cellmat,cell_rows,cell_cols,a.strategy) + vals_cache = array_cache(cell_vals) + @assert length(cell_cols) == length(cell_rows) + @assert length(cell_vals) == length(cell_rows) + _assemble_matrix!(mat,vals_cache,rows_cache,cols_cache,cell_vals,cell_rows,cell_cols,a.strategy) end mat end -function _assemble_matrix!(mat,vals_cache,rows_cache,cols_cache,cell_vals,cell_rows,cell_cols,strategy) - @assert length(cell_cols) == length(cell_rows) - @assert length(cell_vals) == length(cell_rows) +@noinline function _assemble_matrix!(mat,vals_cache,rows_cache,cols_cache,cell_vals,cell_rows,cell_cols,strategy) for cell in 1:length(cell_cols) rows = getindex!(rows_cache,cell_rows,cell) cols = getindex!(cols_cache,cell_cols,cell) vals = getindex!(vals_cache,cell_vals,cell) - for (j,gidcol) in enumerate(cols) - if gidcol > 0 && col_mask(strategy,gidcol) - _gidcol = col_map(strategy,gidcol) - for (i,gidrow) in enumerate(rows) - if gidrow > 0 && row_mask(strategy,gidrow) - _gidrow = row_map(strategy,gidrow) - v = vals[i,j] - add_entry!(mat,v,_gidrow,_gidcol) - end + _assemble_matrix_at_cell!(mat,rows,cols,vals,strategy) + end +end + +@inline function _assemble_matrix_at_cell!(mat,rows,cols,vals,strategy) + for (j,gidcol) in enumerate(cols) + if gidcol > 0 && col_mask(strategy,gidcol) + _gidcol = col_map(strategy,gidcol) + for (i,gidrow) in enumerate(rows) + if gidrow > 0 && row_mask(strategy,gidrow) + _gidrow = row_map(strategy,gidrow) + v = vals[i,j] + add_entry!(mat,v,_gidrow,_gidcol) end end end end end -function fill_matrix_coo_numeric!(I,J,V,a::SingleFieldSparseMatrixAssembler,matdata,n=0) +@inline function _assemble_matrix_at_cell!(mat,rows::BlockArrayCoo,cols::BlockArrayCoo,vals::BlockArrayCoo,strategy) + for I in eachblockindex(vals) + if is_nonzero_block(vals,I) + i,j = I.n + _assemble_matrix_at_cell!(mat,rows[Block(i)],cols[Block(j)],vals[I],strategy) + end + end +end +function fill_matrix_coo_numeric!(I,J,V,a::GenericSparseMatrixAssembler,matdata,n=0) nini = n - celldofs_rows = get_cell_dofs(a.test) - celldofs_cols = get_cell_dofs(a.trial) for (cellmat_rc,cellidsrows,cellidscols) in zip(matdata...) - cell_rows = reindex(celldofs_rows,cellidsrows) - cell_cols = reindex(celldofs_cols,cellidscols) - cellmat_r = apply_constraints_matrix_cols(a.trial,cellmat_rc,cellidscols) - cell_vals = apply_constraints_matrix_rows(a.test,cellmat_r,cellidsrows) + cell_rows = get_cell_dofs(a.test,cellidsrows) + cell_cols = get_cell_dofs(a.trial,cellidscols) + cellmat_r = attach_constraints_cols(a.trial,cellmat_rc,cellidscols) + cell_vals = attach_constraints_rows(a.test,cellmat_r,cellidsrows) rows_cache = array_cache(cell_rows) cols_cache = array_cache(cell_cols) vals_cache = array_cache(cell_vals) @@ -226,18 +434,24 @@ end rows = getindex!(rows_cache,cell_rows,cell) cols = getindex!(cols_cache,cell_cols,cell) vals = getindex!(vals_cache,cell_vals,cell) - for (j,gidcol) in enumerate(cols) - if gidcol > 0 && col_mask(strategy,gidcol) - _gidcol = col_map(strategy,gidcol) - for (i,gidrow) in enumerate(rows) - if gidrow > 0 && row_mask(strategy,gidrow) - _gidrow = row_map(strategy,gidrow) - if is_entry_stored(M,_gidrow,_gidcol) - n += 1 - @inbounds I[n] = _gidrow - @inbounds J[n] = _gidcol - @inbounds V[n] = vals[i,j] - end + n = _fill_matrix_at_cell!(M,n,I,J,V,rows,cols,vals,strategy) + end + n +end + +@inline function _fill_matrix_at_cell!(::Type{M},nini,I,J,V,rows,cols,vals,strategy) where M + n = nini + for (j,gidcol) in enumerate(cols) + if gidcol > 0 && col_mask(strategy,gidcol) + _gidcol = col_map(strategy,gidcol) + for (i,gidrow) in enumerate(rows) + if gidrow > 0 && row_mask(strategy,gidrow) + _gidrow = row_map(strategy,gidrow) + if is_entry_stored(M,_gidrow,_gidcol) + n += 1 + @inbounds I[n] = _gidrow + @inbounds J[n] = _gidcol + @inbounds V[n] = vals[i,j] end end end @@ -246,17 +460,27 @@ end n end -function assemble_matrix_and_vector_add!(A,b,a::SingleFieldSparseMatrixAssembler, data) +@inline function _fill_matrix_at_cell!( + ::Type{M},nini,I,J,V,rows::BlockArrayCoo,cols::BlockArrayCoo,vals::BlockArrayCoo,strategy) where M + n = nini + for B in eachblockindex(vals) + if is_nonzero_block(vals,B) + i,j = B.n + n = _fill_matrix_at_cell!(M,n,I,J,V,rows[Block(i)],cols[Block(j)],vals[B],strategy) + end + end + n +end + +function assemble_matrix_and_vector_add!(A,b,a::GenericSparseMatrixAssembler, data) matvecdata, matdata, vecdata = data - celldofs_rows = get_cell_dofs(a.test) - celldofs_cols = get_cell_dofs(a.trial) for (cellmatvec_rc,cellidsrows,cellidscols) in zip(matvecdata...) - cell_rows = reindex(celldofs_rows,cellidsrows) - cell_cols = reindex(celldofs_cols,cellidscols) - cellmatvec_r = apply_constraints_matrix_and_vector_cols(a.trial,cellmatvec_rc,cellidscols) - cellmatvec = apply_constraints_matrix_and_vector_rows(a.test,cellmatvec_r,cellidsrows) + cell_rows = get_cell_dofs(a.test,cellidsrows) + cell_cols = get_cell_dofs(a.trial,cellidscols) + cellmatvec_r = attach_constraints_cols(a.trial,cellmatvec_rc,cellidscols) + cellmatvec = attach_constraints_rows(a.test,cellmatvec_r,cellidsrows) rows_cache = array_cache(cell_rows) cols_cache = array_cache(cell_cols) vals_cache = array_cache(cellmatvec) @@ -267,7 +491,7 @@ function assemble_matrix_and_vector_add!(A,b,a::SingleFieldSparseMatrixAssembler A, b end -function _assemble_matrix_and_vector!(A,b,vals_cache,rows_cache,cols_cache,cell_vals,cell_rows,cell_cols,strategy) +@noinline function _assemble_matrix_and_vector!(A,b,vals_cache,rows_cache,cols_cache,cell_vals,cell_rows,cell_cols,strategy) @assert length(cell_cols) == length(cell_rows) @assert length(cell_vals) == length(cell_rows) for cell in 1:length(cell_cols) @@ -275,41 +499,21 @@ function _assemble_matrix_and_vector!(A,b,vals_cache,rows_cache,cols_cache,cell_ cols = getindex!(cols_cache,cell_cols,cell) vals = getindex!(vals_cache,cell_vals,cell) matvals, vecvals = vals - for (j,gidcol) in enumerate(cols) - if gidcol > 0 && col_mask(strategy,gidcol) - _gidcol = col_map(strategy,gidcol) - for (i,gidrow) in enumerate(rows) - if gidrow > 0 && row_mask(strategy,gidrow) - _gidrow = row_map(strategy,gidrow) - v = matvals[i,j] - add_entry!(A,v,_gidrow,_gidcol) - end - end - end - end - for (i,gidrow) in enumerate(rows) - if gidrow > 0 && row_mask(strategy,gidrow) - _gidrow = row_map(strategy,gidrow) - bi = vecvals[i] - add_entry!(b,bi,_gidrow) - end - end + _assemble_matrix_at_cell!(A,rows,cols,matvals,strategy) + _assemble_vector_at_cell!(b,rows,vecvals,strategy) end end -function fill_matrix_and_vector_coo_numeric!(I,J,V,b,a::SingleFieldSparseMatrixAssembler,data,n=0) +function fill_matrix_and_vector_coo_numeric!(I,J,V,b,a::GenericSparseMatrixAssembler,data,n=0) matvecdata, matdata, vecdata = data nini = n - celldofs_rows = get_cell_dofs(a.test) - celldofs_cols = get_cell_dofs(a.trial) - for (cellmatvec_rc,cellidsrows,cellidscols) in zip(matvecdata...) - cell_rows = reindex(celldofs_rows,cellidsrows) - cell_cols = reindex(celldofs_cols,cellidscols) - cellmatvec_r = apply_constraints_matrix_and_vector_cols(a.trial,cellmatvec_rc,cellidscols) - cellmatvec = apply_constraints_matrix_and_vector_rows(a.test,cellmatvec_r,cellidsrows) + cell_rows = get_cell_dofs(a.test,cellidsrows) + cell_cols = get_cell_dofs(a.trial,cellidscols) + cellmatvec_r = attach_constraints_cols(a.trial,cellmatvec_rc,cellidscols) + cellmatvec = attach_constraints_rows(a.test,cellmatvec_r,cellidsrows) rows_cache = array_cache(cell_rows) cols_cache = array_cache(cell_cols) vals_cache = array_cache(cellmatvec) @@ -333,30 +537,8 @@ end cols = getindex!(cols_cache,cell_cols,cell) vals = getindex!(vals_cache,cell_vals,cell) matvals, vecvals = vals - for (j,gidcol) in enumerate(cols) - if gidcol > 0 && col_mask(strategy,gidcol) - _gidcol = col_map(strategy,gidcol) - for (i,gidrow) in enumerate(rows) - if gidrow > 0 && row_mask(strategy,gidrow) - _gidrow = row_map(strategy,gidrow) - if is_entry_stored(M,gidrow,gidcol) - n += 1 - @inbounds v = matvals[i,j] - @inbounds I[n] = _gidrow - @inbounds J[n] = _gidcol - @inbounds V[n] = v - end - end - end - end - end - for (i,gidrow) in enumerate(rows) - if gidrow > 0 && row_mask(strategy,gidrow) - _gidrow = row_map(strategy,gidrow) - bi = vecvals[i] - add_entry!(b,bi,_gidrow) - end - end + n = _fill_matrix_at_cell!(M,n,I,J,V,rows,cols,matvals,strategy) + _assemble_vector_at_cell!(b,rows,vecvals,strategy) end n end diff --git a/src/FESpaces/StateLaws.jl b/src/FESpaces/StateLaws.jl deleted file mode 100644 index 38dab5673..000000000 --- a/src/FESpaces/StateLaws.jl +++ /dev/null @@ -1,114 +0,0 @@ - -""" -""" -function apply_statelaw(op::Function,a::CellField,b...) - T = UnimplementedField - k = StateLawKernel(op) - r = apply_to_field_array(T,k,get_array(a),get_arrays(b...)...) - similar_object(a,r) -end - -""" -""" -macro statelaw(fundef) - s = "The @statelaw macro is only allowed in function definitions" - @assert isa(fundef,Expr) s - @assert fundef.head in (:(=), :function) s - funname = fundef.args[1].args[1] - nargs = length(fundef.args[1].args)-1 - @assert nargs >= 2 "The @statelaw macro is only allowed in functions with at leats two arguments" - - y = fundef.args[1].args[2] - x = fundef.args[1].args[3:end] - a = fundef.args[1].args[2:end] - q = quote - function $(funname)($(y)::CellField,$(x...)) - apply_statelaw($(funname),$(a...)) - end - $(fundef) - end - :($(esc(q))) -end - -struct StateLawKernel{F<:Function} <: Kernel - op::F -end - -function kernel_cache(k::StateLawKernel,a::AbstractVector,b::AbstractVector...) - Ta = eltype(a) - Tb = map(eltype,b) - args = testargs(k.op,Ta,Tb...) - vi, = k.op(args...) - v = zeros(typeof(vi),size(a)) - CachedArray(v) -end - -function kernel_return_type(k::StateLawKernel,a::AbstractVector,b::AbstractVector...) - v = zeros(eltype(a),size(a)) - typeof(v) -end - -function apply_kernel!(cache,k::StateLawKernel,a::AbstractVector,b::AbstractVector...) - Q = length(a) - setsize!(cache,size(a)) - v = cache.array - for q in 1:Q - aq = a[q] - bq = getitems(b,q) - r = k.op(aq,bq...) - vq, states = _split(r...) - _update_states!(b,q,states,Val{length(states)}()) - v[q] = vq - end - v -end - -function kernel_testitem!(cache,k::StateLawKernel,a::AbstractVector,b::AbstractVector...) - Q = length(a) - setsize!(cache,size(a)) - v = cache.array - for q in 1:Q - aq = a[q] - bq = getitems(b,q) - r = k.op(aq,bq...) - vq, states = _split(r...) - v[q] = vq - end - v -end - -@inline function _update_states!(b,q,states,::Val{i}) where i - _update_state!(b,q,states,Val{i}()) - _update_states!(b,q,states,Val{i-1}()) - nothing -end - -@inline function _update_states!(b,q,states,::Val{0}) - nothing -end - -@inline function _update_state!(b,q,states,::Val{i}) where i - m = length(b) - n = length(states) - o = m-n - b[i+o][q] = states[i] - nothing -end - -""" -""" -function update_state_variables!(quad::CellQuadrature, statelaw::Function, a...) - b = apply_statelaw(statelaw,a...) - q = get_coordinates(quad) - b_q = evaluate(b,q) - c = array_cache(b_q) - _update_state_variables!(c,b_q) -end - -function _update_state_variables!(c,b) - for i in 1:length(b) - bi = getindex!(c,b,i) - end -end - - diff --git a/src/FESpaces/TrialFESpaces.jl b/src/FESpaces/TrialFESpaces.jl index db4588531..88b835008 100644 --- a/src/FESpaces/TrialFESpaces.jl +++ b/src/FESpaces/TrialFESpaces.jl @@ -2,11 +2,11 @@ struct TrialFESpace{B} <: SingleFieldFESpace space::SingleFieldFESpace dirichlet_values::AbstractVector - cell_basis::CellBasis + cell_basis::CellField constraint_style::Val{B} function TrialFESpace(dirichlet_values::AbstractVector,space::SingleFieldFESpace) - cell_basis = _prepare_trial_cell_basis(space) + cell_basis = trialize_cell_basis(get_cell_basis(space)) cs = constraint_style(space) B = get_val_parameter(cs) new{B}(space,dirichlet_values,cell_basis,cs) @@ -56,14 +56,6 @@ function HomogeneousTrialFESpace!(dirichlet_values::AbstractVector,U::FESpace) TrialFESpace(dirichlet_values,U) end -function _prepare_trial_cell_basis(space) - cb = get_cell_basis(space) - a = get_array(cb) - cm = get_cell_map(cb) - trial_style = Val{true}() - cell_basis = GenericCellBasis(trial_style,a,cm,RefStyle(cb)) -end - # Genuine functions get_dirichlet_values(f::TrialFESpace) = f.dirichlet_values @@ -72,6 +64,12 @@ get_cell_basis(f::TrialFESpace) = f.cell_basis # Delegated functions +get_cell_axes(t::TrialFESpace)= get_cell_axes(t.space) + +get_cell_axes_with_constraints(t::TrialFESpace)= get_cell_axes_with_constraints(t.space) + +CellData.CellField(t::TrialFESpace,cell_vals) = CellField(t.space,cell_vals) + constraint_style(::Type{<:TrialFESpace{B}}) where B = Val{B}() get_cell_dof_basis(f::TrialFESpace) = get_cell_dof_basis(f.space) @@ -104,23 +102,7 @@ gather_free_values(f::TrialFESpace,cv) = gather_free_values(f.space,cv) gather_free_values!(fv,f::TrialFESpace,cv) = gather_free_values!(fv,f.space,cv) -function get_constraint_kernel_matrix_cols(f::TrialFESpace) - get_constraint_kernel_matrix_cols(f.space) -end +get_cell_isconstrained(f::TrialFESpace) = get_cell_isconstrained(f.space) -function get_constraint_kernel_matrix_rows(f::TrialFESpace) - get_constraint_kernel_matrix_rows(f.space) -end - -function get_constraint_kernel_vector(f::TrialFESpace) - get_constraint_kernel_vector(f.space) -end - -function get_cell_isconstrained(f::TrialFESpace) - get_cell_isconstrained(f.space) -end - -function get_cell_constraints(f::TrialFESpace) - get_cell_constraints(f.space) -end +get_cell_constraints(f::TrialFESpace) = get_cell_constraints(f.space) diff --git a/src/FESpaces/UnconstrainedFESpaces.jl b/src/FESpaces/UnconstrainedFESpaces.jl index 97fba05da..f9365fe49 100644 --- a/src/FESpaces/UnconstrainedFESpaces.jl +++ b/src/FESpaces/UnconstrainedFESpaces.jl @@ -3,43 +3,15 @@ Generic implementation of an unconstrained single-field FE space Private fields and type parameters """ -struct UnconstrainedFESpace{A,B,C} <: SingleFieldFESpace +struct UnconstrainedFESpace <: SingleFieldFESpace nfree::Int ndirichlet::Int - cell_dofs::A - cell_basis::B - cell_dof_basis::C + cell_dofs::AbstractArray + cell_basis::CellField + cell_dof_basis::CellDofBasis dirichlet_dof_tag::Vector{Int8} dirichlet_cells::Vector{Int} ntags::Int - - @doc """ - """ - function UnconstrainedFESpace( - nfree::Int, - ndirichlet::Int, - cell_dofs::AbstractArray, - cell_basis::CellBasis, - cell_dof_basis::CellDofBasis, - cell_map::AbstractArray, - dirichlet_dof_tag::Vector{Int8}, - dirichlet_cells::Vector{Int}, - ntags) where T - - A = typeof(cell_dofs) - B = typeof(cell_basis) - C = typeof(cell_dof_basis) - - new{A,B,C}( - nfree, - ndirichlet, - cell_dofs, - cell_basis, - cell_dof_basis, - dirichlet_dof_tag, - dirichlet_cells, - ntags) - end end # FESpace interface diff --git a/src/FESpaces/ZeroMeanFESpaces.jl b/src/FESpaces/ZeroMeanFESpaces.jl index 5b86c2ebc..3b977f573 100644 --- a/src/FESpaces/ZeroMeanFESpaces.jl +++ b/src/FESpaces/ZeroMeanFESpaces.jl @@ -76,17 +76,15 @@ end constraint_style(::Type{ZeroMeanFESpace{B}}) where B = Val{B}() -function get_constraint_kernel_matrix_cols(f::ZeroMeanFESpace) - get_constraint_kernel_matrix_cols(f.space) -end +get_cell_axes(t::ZeroMeanFESpace)= get_cell_axes(t.space) -function get_constraint_kernel_matrix_rows(f::ZeroMeanFESpace) - get_constraint_kernel_matrix_rows(f.space) -end +get_cell_axes_with_constraints(t::ZeroMeanFESpace)= get_cell_axes_with_constraints(t.space) -function get_constraint_kernel_vector(f::ZeroMeanFESpace) - get_constraint_kernel_vector(f.space) -end +CellData.CellField(t::ZeroMeanFESpace,cell_vals) = CellField(t.space,cell_vals) + +get_cell_isconstrained(f::ZeroMeanFESpace) = get_cell_isconstrained(f.space) + +get_cell_constraints(f::ZeroMeanFESpace) = get_cell_constraints(f.space) get_dirichlet_values(f::ZeroMeanFESpace) = get_dirichlet_values(f.space) diff --git a/src/Fields/DiffOperators.jl b/src/Fields/DiffOperators.jl index d34884da3..8717391b6 100644 --- a/src/Fields/DiffOperators.jl +++ b/src/Fields/DiffOperators.jl @@ -4,6 +4,11 @@ """ divergence(f) = tr(gradient(f)) +function divergence(a::AbstractArray{<:Field}) + ag = gradient(a) + operate_arrays_of_fields(tr,ag) +end + function symmetric_gradient end """ @@ -11,6 +16,11 @@ function symmetric_gradient end """ symmetric_gradient(f) = symmetric_part(gradient(f)) +function symmetric_gradient(a::AbstractArray{<:Field}) + ag = gradient(a) + operate_arrays_of_fields(symmetric_part,ag) +end + """ const ε = symmetric_gradient @@ -23,6 +33,11 @@ const ε = symmetric_gradient """ curl(f) = grad2curl(gradient(f)) +function curl(a::AbstractArray{<:Field}) + ag = gradient(a) + operate_arrays_of_fields(grad2curl,ag) +end + """ grad2curl(∇f) """ @@ -30,6 +45,21 @@ function grad2curl(f) @abstractmethod end +grad2curl(a::GridapType) = operate(grad2curl,a) + +grad2curl(f::Field) = operate_fields(grad2curl,f) + +@inline function grad2curl(∇u::TensorValue{2}) + ∇u[1,2] - ∇u[2,1] +end + +@inline function grad2curl(∇u::TensorValue{3}) + c1 = ∇u[2,3] - ∇u[3,2] + c2 = ∇u[3,1] - ∇u[1,3] + c3 = ∇u[1,2] - ∇u[2,1] + VectorValue(c1,c2,c3) +end + function laplacian end """ @@ -44,8 +74,7 @@ const Δ = laplacian """ function laplacian(f) g = gradient(f) - h = gradient(g) - tr(h) + divergence(g) end """ @@ -98,27 +127,6 @@ Equivalent to cross(::typeof(∇),f) = curl(f) cross(::typeof(∇),f::GridapType) = curl(f) -# Helpers - -grad2curl(f::Field) = apply_kernel_to_field(bcast(_curl_kernel),f) - -grad2curl(f::AbstractArray{<:Field}) = apply_to_field_array(bcast(_curl_kernel),f) - -grad2curl(::Type{T}, f::AbstractArray{<:Field}) where T = apply_to_field_array(T,bcast(_curl_kernel),f) - -grad2curl(∇u::MultiValue) = _curl_kernel(∇u) - -function _curl_kernel(∇u::TensorValue{2}) - ∇u[1,2] - ∇u[2,1] -end - -function _curl_kernel(∇u::TensorValue{3}) - c1 = ∇u[2,3] - ∇u[3,2] - c2 = ∇u[3,1] - ∇u[1,3] - c3 = ∇u[1,2] - ∇u[2,1] - VectorValue(c1,c2,c3) -end - # Automatic differentiation of functions function gradient(f::Function) diff --git a/src/Fields/FieldApply.jl b/src/Fields/FieldApply.jl index db76002f5..7208f4b77 100644 --- a/src/Fields/FieldApply.jl +++ b/src/Fields/FieldApply.jl @@ -32,12 +32,6 @@ function apply_kernel_gradient(k,f...) @abstractmethod end -@inline apply_kernel_gradient(k::BCasted{typeof(+)},a) = field_gradient(a) - -@inline apply_kernel_gradient(k::BCasted{typeof(-)},a...) = apply_kernel_to_field(k,field_gradients(a...)...) - -@inline apply_kernel_gradient(k::BCasted{typeof(+)},a...) = apply_kernel_to_field(k,field_gradients(a...)...) - # Result of applying a kernel to the value of some fields struct AppliedField{K,F} <: Field diff --git a/src/Fields/FieldArrays.jl b/src/Fields/FieldArrays.jl index a519988cb..bd7b09b63 100644 --- a/src/Fields/FieldArrays.jl +++ b/src/Fields/FieldArrays.jl @@ -275,15 +275,6 @@ function kernel_evaluate(k::Valued,x,f...) a = apply(k.k,fx...) end -for op in (:+,:-) - @eval begin - function apply_gradient(k::Valued{BCasted{typeof($op)}},f...) - g = field_array_gradients(f...) - apply(k,g...) - end - end -end - # More optimizations function evaluate_field_array(a::AppendedArray,b::AppendedArray) diff --git a/src/Fields/FieldOperations.jl b/src/Fields/FieldOperations.jl index 728f10463..a522635ad 100644 --- a/src/Fields/FieldOperations.jl +++ b/src/Fields/FieldOperations.jl @@ -1,301 +1,466 @@ + +# Operate fields at local level + """ - field_operation(op::Function,a) - field_operation(op::Function,a,b) """ -function field_operation(op::Function,a,b) - k = FieldBinOp(op) - apply_kernel_to_field(k,a,b) -end - -function field_operation(op::Function,a) - k = bcast(op) - apply_kernel_to_field(k,a) +function operate_fields(op::Function,args...) + k = FieldOpKernel(op) + apply_kernel_to_field(k,args...) end """ - field_array_operation(op::Function,a) - field_array_operation(op::Function,a,b) - field_array_operation(::Type{T},op::Function,a) where T - field_array_operation(::Type{T},op::Function,a,b) where T + field_operation_axes(axs::Tuple...) + +Returns the axes after applying a FieldOpKernel to some arrays with axes `axs...` """ -function field_array_operation(op::Function,a,b) - k = FieldBinOp(op) - apply_to_field_array(k,a,b) +function field_operation_axes(axs::Tuple...) + n = maximum( map(length,axs) ) + rs = [] + for i in 1:n + r = 1:0 + for ax in axs + if length(ax) >= i + if length(r) > 1 + @assert length(ax[i]) == 1 || length(ax[i]) == length(r) + end + if length(ax[i]) > length(r) + r = ax[i] + end + end + end + push!(rs,r) + end + Tuple(rs) +end + +function field_operation_metasize(axs::Tuple...) + n = maximum( map(length,axs) ) + rs = [] + for i in 1:n + r = 1 + for ax in axs + if length(ax) >= i + if ax[i] == (:) + r = ax[i] + end + end + end + push!(rs,r) + end + Tuple(rs) end -function field_array_operation(op::Function,a) - k = bcast(op) - apply_to_field_array(k,a) -end +# Operate fields at global level -function field_array_operation(::Type{T},op::Function,a) where T - k = bcast(op) - apply_to_field_array(T,k,a) +""" +""" +function operate_arrays_of_fields(op::Function,args...) + k = FieldOpKernel(op) + apply_to_field_array(k,args...) end -function field_array_operation(::Type{T},op::Function,a,b) where T - k = FieldBinOp(op) - apply_to_field_array(T,k,a,b) +function operate_arrays_of_fields(::Type{T},op::Function,args...) where T + k = FieldOpKernel(op) + apply_to_field_array(T,k,args...) end -# Unary operations on fields and arrays of fields +# Pre-define some operations +# some of them only make sense for fields, not for arrays of fields. for op in (:+,:-,:tr, :transpose, :adjoint, :symmetric_part) @eval begin function ($op)(f::Field) - field_operation($op,f) + operate_fields($op,f) end - function ($op)(f::AbstractArray{<:Field}) - field_array_operation($op,f) - end + #function ($op)(f::AbstractArray{<:Field}) + # operate_arrays_of_fields($op,f) + #end end - end -# Binary operations on fields and arrays of fields - -for op in (:+,:-,:*,:inner,:outer) +for op in (:+,:-,:*,:inner,:outer,:dot) @eval begin - function ($op)(f::Field, g::Field) - field_operation($op,f,g) + function ($op)(f::Field,g::Field) + operate_fields($op,f,g) end - function ($op)(f::AbstractArray{<:Field},g::AbstractArray{<:Field}) - field_array_operation($op,f,g) - end + #function ($op)(f::AbstractArray{<:Field},g::AbstractArray{<:Field}) + # operate_arrays_of_fields($op,f,g) + #end end - end -# Helpers +# Operations between field values -struct FieldBinOp{F<:Function} <: Kernel - op::F +struct FieldOpKernel{T} <: Kernel + op::T end -# Vector vs Vector +# FieldOpKernel does broadcast by default. It will work always assuming that the trial bases have shape (np,1,ndof) +# but perhaps inefficient for blocked matrices. +# In any case, optimizations for block matrices will be done at the global level (for all cells) +# instead of at the cell level in this kernel. +# In other words, we can assume that this kernel receives standard non-blocked arrays in practice. -function kernel_cache( - k::FieldBinOp,a::AbstractVector,b::AbstractVector) - na = length(a) - Ta = eltype(a) - Tb = eltype(b) - T = return_type(k.op,Ta,Tb) - r = zeros(T,na) - CachedArray(r) +function kernel_cache(k::FieldOpKernel,args...) + bk = bcast(k.op) + kernel_cache(bk,args...) end -function kernel_testitem!( - c,k::FieldBinOp,a::AbstractVector,b::AbstractVector) - if _valid_checks_vecvec(a,b) - apply_kernel!(c,k,a,b) - else - c.array - end +@inline function apply_kernel!(cache,k::FieldOpKernel,args...) + bk = bcast(k.op) + apply_kernel!(cache,bk,args...) end -@inline function apply_kernel!( - c,k::FieldBinOp,a::AbstractVector,b::AbstractVector) - _field_bin_op_checks_vecvec(a,b) - na = length(a) - setsize!(c,(na,)) - r = c.array - for p in eachindex(a) - @inbounds r[p] = k.op(a[p],b[p]) - end - r -end +# Define gradients at local and global level -function _field_bin_op_checks_vecvec(a,b) - @assert _valid_checks_vecvec(a,b) "Binary operation between fields: vector vs vector size mismatch." +function apply_kernel_gradient(k::FieldOpKernel,args...) + @notimplemented "The gradient of the result of operation $(k.op) is not yet implemented." end -function _valid_checks_vecvec(a,b) - na = length(a) - nb = length(b) - na == nb +function apply_gradient(k::Valued{<:FieldOpKernel},args...) + @notimplemented "The gradient of the result of operation $(k.op) is not yet implemented." end -# Matrix vs Vector +for op in (:+,:-) + @eval begin -function kernel_cache( - k::FieldBinOp,a::AbstractMatrix,b::AbstractVector) - Ta = eltype(a) - Tb = eltype(b) - T = return_type(k.op,Ta,Tb) - r = zeros(T,size(a)) - CachedArray(r) -end + # Local level + + function apply_kernel_gradient(k::FieldOpKernel{typeof($op)},a,b) + ga = field_gradient(a) + gb = field_gradient(b) + apply_kernel_to_field(k,ga,gb) + end + + function apply_kernel_gradient(k::FieldOpKernel{typeof($op)},a) + ga = field_gradient(a) + apply_kernel_to_field(k,ga) + end + + function apply_kernel_gradient(k::FieldOpKernel{typeof($op)},a::Number,b) + gb = field_gradient(b) + apply_kernel_to_field(k,gb) + end + + function apply_kernel_gradient(k::FieldOpKernel{typeof($op)},b,a::Number) + gb = field_gradient(b) + gb + end + + # Global level + + function apply_gradient(k::Valued{FieldOpKernel{typeof($op)}},a,b) + ga = field_array_gradient(a) + gb = field_array_gradient(b) + apply(k,ga,gb) + end + + function apply_gradient(k::Valued{FieldOpKernel{typeof($op)}},a) + ga = field_array_gradient(a) + apply(k,ga) + end + + function apply_gradient(k::Valued{FieldOpKernel{typeof($op)}},a::Number,b) + gb = field_array_gradient(b) + apply(k,gb) + end + + function apply_gradient(k::Valued{FieldOpKernel{typeof($op)}},b,a::Number) + gb = field_array_gradient(b) + gb + end -function kernel_testitem!( - c,k::FieldBinOp,a::AbstractMatrix,b::AbstractVector) - if _valid_checks_matvec(a,b) - apply_kernel!(c,k,a,b) - else - c.array end end -@inline function apply_kernel!( - c,k::FieldBinOp,a::AbstractMatrix,b::AbstractVector) - _field_bin_op_checks_matvec(a,b) - s = size(a) - setsize!(c,s) - np, ni = s - r = c.array - for i in 1:ni - for p in 1:np - @inbounds r[p,i] = k.op(a[p,i],b[p]) +for op in (:*,⋅) + @eval begin + + # Local level + + function apply_kernel_gradient(k::FieldOpKernel{typeof($op)},a::Number,b) + gb = field_gradient(b) + apply_kernel_to_field(k,a,gb) + end + + function apply_kernel_gradient(k::FieldOpKernel{typeof($op)},b,a::Number) + gb = field_gradient(b) + apply_kernel_to_field(k,gb,a) + end + + function apply_kernel_gradient(k::FieldOpKernel{typeof($op)},a,b) + ga = field_gradient(a) + gb = field_gradient(b) + f1 = apply_kernel_to_field(k,ga,b) + f2 = apply_kernel_to_field(k,a,gb) + operate_fields(+,f1,f2) + end + + # Global level + + function apply_gradient(k::Valued{FieldOpKernel{typeof($op)}},a::Number,b) + gb = field_array_gradient(b) + apply(k,a,gb) + end + + function apply_gradient(k::Valued{FieldOpKernel{typeof($op)}},b,a::Number) + gb = field_array_gradient(b) + apply(k,gb,a) end + + function apply_gradient(k::Valued{FieldOpKernel{typeof($op)}},a,b) + ga = field_array_gradient(a) + gb = field_array_gradient(b) + f1 = apply(k,ga,b) + f2 = apply(k,a,gb) + operate_arrays_of_fields(+,f1,f2) + end + end - r end -function _field_bin_op_checks_matvec(a,b) - @assert _valid_checks_matvec(a,b) "Binary operation between fields: matrix vs vector size mismatch." -end +# Local level -function _valid_checks_matvec(a,b) - na, _ = size(a) - nb = length(b) - na == nb +function apply_kernel_gradient(k::FieldOpKernel{typeof(/)},b,a::Number) + gb = field_gradient(b) + apply_kernel_to_field(k,gb,a) end -# Vector vs Matrix +# Global level -function kernel_cache( - k::FieldBinOp,a::AbstractVector,b::AbstractMatrix) - Ta = eltype(a) - Tb = eltype(b) - T = return_type(k.op,Ta,Tb) - r = zeros(T,size(b)) - CachedArray(r) +function apply_gradient(k::Valued{FieldOpKernel{typeof(/)}},b,a::Number) + gb = field_array_gradient(b) + apply(k,gb,a) end -function kernel_testitem!( - c,k::FieldBinOp,a::AbstractVector,b::AbstractMatrix) - if _valid_checks_vecmat(a,b) - apply_kernel!(c,k,a,b) - else - c.array - end -end +# Move the value of a test basis into "trial" state -@inline function apply_kernel!( - c,k::FieldBinOp,a::AbstractVector,b::AbstractMatrix) - _field_bin_op_checks_vecmat(a,b) - s = size(b) - setsize!(c,s) - np, ni = s - r = c.array - for i in 1:ni - for p in 1:np - @inbounds r[p,i] = k.op(a[p],b[p,i]) - end - end - r +""" +""" +function trialize_basis(f) + apply_kernel_to_field(trialize_basis_value,f) end -function _field_bin_op_checks_vecmat(a,b) - @assert _valid_checks_vecmat(a,b) "Binary operation between fields: vector vs matrix size mismatch." +""" +""" +function trialize_array_of_bases(af) + apply_to_field_array(trialize_basis_value,af) end -function _valid_checks_vecmat(a,b) - nb, _ = size(b) - na = length(a) - na == nb +@inline function trialize_basis_value(a::AbstractMatrix) + TrializedMatrix(a) end -# Matrix vs matrix - -function kernel_cache( - k::FieldBinOp,a::AbstractMatrix,b::AbstractMatrix) - Ta = eltype(a) - Tb = eltype(b) - T = return_type(k.op,Ta,Tb) - np, ni = size(a) - _, nj = size(b) - r = zeros(T,(np,ni,nj)) - CachedArray(r) +function apply_kernel_gradient(::typeof(trialize_basis_value),a) + g = field_gradient(a) + trialize_basis(g) end -function kernel_testitem!( - c,k::FieldBinOp,a::AbstractMatrix,b::AbstractMatrix) - if _valid_checks_matmat(a,b) - apply_kernel!(c,k,a,b) - else - c.array +struct TrializedMatrix{T,A} <: AbstractArray{T,3} + matrix::A + @inline function TrializedMatrix(matrix::AbstractMatrix{T}) where T + A = typeof(matrix) + new{T,A}(matrix) end end -@inline function apply_kernel!( - c,k::FieldBinOp,a::AbstractMatrix,b::AbstractMatrix) - _field_bin_op_checks_matmat(a,b) - np, ni = size(a) - _, nj = size(b) - setsize!(c,(np,ni,nj)) - r = c.array - for j in 1:nj - for i in 1:ni - for p in 1:np - @inbounds r[p,i,j] = k.op(a[p,i],b[p,j]) - end - end - end - r +TrializedMatrix{T,A}(u::UndefInitializer,s::Tuple) where {T,A} = TrializedMatrix(A(u,(s[1],s[3]))) + +Base.size(a::TrializedMatrix) = (size(a.matrix,1),1,size(a.matrix,2)) + +Base.IndexStyle(::Type{<:TrializedMatrix{T,A}}) where {T,A} = IndexStyle(A) + +@inline Base.getindex(a::TrializedMatrix,i::Integer,j::Integer,k::Integer) = a.matrix[i,k] + +@inline Base.getindex(a::TrializedMatrix,i::Integer) = a.matrix[i] + +@inline Base.setindex!(a::TrializedMatrix,v,i::Integer,j::Integer,k::Integer) = (a.matrix[i,k] = v) + +@inline Base.setindex!(a::TrializedMatrix,v,i::Integer) = (a.matrix[i] = v) + +# Optimizations for block matrices at global level (for all cells) + +function apply(f::typeof(trialize_basis_value),a::VectorOfBlockMatrixCoo) + blocks = map(b->apply(f,b),a.blocks) + blockids = broadcast(ij->(ij[1],1,ij[2]),a.blockids) + axs = apply( ax -> (ax[1],blockedrange([1]),ax[2]), a.axes) + VectorOfBlockArrayCoo(blocks,blockids,axs) end -function _field_bin_op_checks_matmat(a,b) - @assert _valid_checks_matmat(a,b) "Binary operation between fields: matrix vs matrix size mismatch." +# Unary operations +# Assumption: op is linear wrt a +function apply(k::FieldOpKernel,a::VectorOfBlockArrayCoo) + blocks = map(b->apply(k,b), a.blocks) + VectorOfBlockArrayCoo(blocks,a.blockids,a.axes,a.ptrs) end -function _valid_checks_matmat(a,b) - na, ni = size(a) - nb, nj = size(b) - na == nb +# Binary test/field or trial/field +# Assumption: op is linear wrt a +function apply(k::FieldOpKernel,a::VectorOfBlockArrayCoo,f::AbstractArray{<:AbstractVector}) + blocks = map(b->apply(k,b,f), a.blocks) + VectorOfBlockArrayCoo(blocks,a.blockids,a.axes,a.ptrs) end -# Define gradients +function apply(k::FieldOpKernel,a::VectorOfBlockArrayCoo,f::AbstractArray{<:Number}) + blocks = map(b->apply(k,b,f), a.blocks) + VectorOfBlockArrayCoo(blocks,a.blockids,a.axes,a.ptrs) +end -function apply_kernel_gradient(k::FieldBinOp,a,b) - @notimplemented "The gradient of the result of operation $(k.op) is not yet implemented." +# Binary field/test or field/trial +# Assumption: op is linear wrt a +function apply(k::FieldOpKernel,f::AbstractArray{<:AbstractVector},a::VectorOfBlockArrayCoo) + blocks = map(b->apply(k,f,b), a.blocks) + VectorOfBlockArrayCoo(blocks,a.blockids,a.axes,a.ptrs) end -for op in (:+,:-) - @eval begin +function apply(k::FieldOpKernel,f::AbstractArray{<:Number},a::VectorOfBlockArrayCoo) + blocks = map(b->apply(k,f,b), a.blocks) + VectorOfBlockArrayCoo(blocks,a.blockids,a.axes,a.ptrs) +end - function apply_kernel_gradient(k::FieldBinOp{typeof($op)},a,b) - ga = field_gradient(a) - gb = field_gradient(b) - apply_kernel_to_field(k,ga,gb) +# Binary test/test or trial/trial +# Assumption: op is a linear combination of a and b +function apply( + k::FieldOpKernel,a::VectorOfBlockArrayCoo{Ta,N} where Ta,b::VectorOfBlockArrayCoo{Tb,N} where Tb) where N + @assert size(a.ptrs) == size(b.ptrs) + blocks = [] + blockids = NTuple{N,Int}[] + for (I,aI) in enumerateblocks(a) + bI = b[I] + if is_nonzero_block(a,I) || is_nonzero_block(b,I) + block = apply(k,aI,bI) + push!(blocks,block) + push!(blockids,I.n) end - - function apply_gradient(k::Valued{FieldBinOp{typeof($op)}},a,b) - ga = field_array_gradient(a) - gb = field_array_gradient(b) - apply(k,ga,gb) + end + VectorOfBlockArrayCoo(Tuple(blocks),blockids,a.axes) +end + +# Binary + test/test or trial/trial +function apply( + k::FieldOpKernel{typeof(+)}, + a::VectorOfBlockArrayCoo{Ta,N} where Ta, + b::VectorOfBlockArrayCoo{Tb,N} where Tb) where N + + @assert size(a.ptrs) == size(b.ptrs) + blocks = [] + blockids = NTuple{N,Int}[] + for (I,aI) in enumerateblocks(a) + bI = b[I] + if is_nonzero_block(a,I) && is_nonzero_block(b,I) + block = apply(k,aI,bI) + push!(blocks,block) + push!(blockids,I.n) + elseif is_nonzero_block(a,I) + block = aI + push!(blocks,block) + push!(blockids,I.n) + elseif is_nonzero_block(b,I) + block = bI + push!(blocks,block) + push!(blockids,I.n) + end + end + VectorOfBlockArrayCoo(Tuple(blocks),blockids,a.axes) +end + +# Binary - test/test or trial/trial +function apply( + k::FieldOpKernel{typeof(-)}, + a::VectorOfBlockArrayCoo{Ta,N} where Ta, + b::VectorOfBlockArrayCoo{Tb,N} where Tb) where N + + @assert size(a.ptrs) == size(b.ptrs) + blocks = [] + blockids = NTuple{N,Int}[] + for (I,aI) in enumerateblocks(a) + bI = b[I] + if is_nonzero_block(a,I) && is_nonzero_block(b,I) + block = apply(k,aI,bI) + push!(blocks,block) + push!(blockids,I.n) + elseif is_nonzero_block(a,I) + block = aI + push!(blocks,block) + push!(blockids,I.n) + elseif is_nonzero_block(b,I) + block = apply(k,bI) + push!(blocks,block) + push!(blockids,I.n) end - end + VectorOfBlockArrayCoo(Tuple(blocks),blockids,a.axes) +end + +# Binary test/trial +# Assumption: op is a product of a and b +function apply( + k::FieldOpKernel,a::VectorOfBlockMatrixCoo,b::VectorOfBlockArrayCoo{Tb,3} where Tb) + axs = apply( (a1,a2) -> (a1[1],a1[2],a2[3]) ,a.axes,b.axes) + blocks = [] + blockids = NTuple{3,Int}[] + nfield1 = size(a.ptrs,2) + nfield2 = size(b.ptrs,3) + for f1 in 1:nfield1 + I1 = Block(1,f1) + for f2 in 1:nfield2 + I2 = Block(1,1,f2) + if is_nonzero_block(a,I1) && is_nonzero_block(b,I2) + block = apply(k,a[I1],b[I2]) + push!(blocks,block) + push!(blockids,(1,f1,f2)) + end + end + end + VectorOfBlockArrayCoo(Tuple(blocks),blockids,axs) +end + +# Binary trial/test +# Assumption: op is a product of a and b +function apply( + k::FieldOpKernel,a::VectorOfBlockArrayCoo{Tb,3} where Tb,b::VectorOfBlockMatrixCoo) + axs = apply( (a1,a2) -> (a1[1],a2[2],a1[3]) ,a.axes,b.axes) + blocks = [] + blockids = NTuple{3,Int}[] + nfield1 = size(b.ptrs,2) + nfield2 = size(a.ptrs,3) + for f1 in 1:nfield1 + I1 = Block(1,f1) + for f2 in 1:nfield2 + I2 = Block(1,1,f2) + if is_nonzero_block(b,I1) && is_nonzero_block(a,I2) + block = apply(k,b[I1],a[I2]) + push!(blocks,block) + push!(blockids,(1,f1,f2)) + end + end + end + VectorOfBlockArrayCoo(Tuple(blocks),blockids,axs) end -for op in (:*,:/) - @eval begin +# General operation +# TODO - function apply_kernel_gradient(k::FieldBinOp{typeof($op)},a::Number,b) - gb = field_gradient(b) - apply_kernel_to_field(k,a,gb) - end - function apply_gradient(k::Valued{FieldBinOp{typeof($op)}},a::Number,b) - gb = field_array_gradient(b) - apply(k,a,gb) - end +# Integration of elem vectors +function apply(k::IntKernel,f::VectorOfBlockArrayCoo{T,2} where T,w::AbstractArray,j::AbstractArray) + ax = apply(a->(a[2],),f.axes) + blocks = map(block->apply(k,block,w,j),f.blocks) + blockids = [ (ids[2],) for ids in f.blockids ] + VectorOfBlockArrayCoo(blocks,blockids,ax) +end - end +# Integration of elem matrices +function apply(k::IntKernel,f::VectorOfBlockArrayCoo{T,3} where T,w::AbstractArray,j::AbstractArray) + ax = apply(a->(a[2],a[3]),f.axes) + blocks = map(block->apply(k,block,w,j),f.blocks) + blockids = [ (ids[2], ids[3]) for ids in f.blockids ] + VectorOfBlockArrayCoo(blocks,blockids,ax) end + diff --git a/src/Fields/Fields.jl b/src/Fields/Fields.jl index a4a9ca37e..c7bd7621c 100644 --- a/src/Fields/Fields.jl +++ b/src/Fields/Fields.jl @@ -20,6 +20,7 @@ using Gridap.Arrays: NumberOrArray using Gridap.Arrays: AppliedArray using Gridap.Arrays: Contracted using LinearAlgebra: ⋅ +using BlockArrays using Test using DocStringExtensions @@ -55,6 +56,7 @@ export evaluate_fields! export field_gradients export field_array_cache export evaluate_field_array +export evaluate_field_arrays export field_array_gradient export gradient_type export curl @@ -68,8 +70,16 @@ export symmetric_gradient export Homothecy export AffineMap -export field_operation -export field_array_operation +export VectorOfBlockBasisCoo +export insert_array_of_bases_in_block +export create_array_of_blocked_axes + +export operate_fields +export operate_arrays_of_fields +export trialize_basis +export trialize_array_of_bases +export field_operation_axes +export field_operation_metasize export function_field @@ -77,6 +87,8 @@ import Gridap.Arrays: kernel_cache import Gridap.Arrays: apply_kernel! import Gridap.Arrays: kernel_return_type import Gridap.Arrays: kernel_testitem! +import Gridap.Arrays: apply +import Gridap.Arrays: reindex import Gridap.TensorValues: outer import Gridap.TensorValues: inner import Gridap.TensorValues: symmetric_part @@ -113,6 +125,10 @@ include("Integrate.jl") include("FieldOperations.jl") +include("VectorsOfBlockBasisCoo.jl") + include("DiffOperators.jl") +include("UnimplementedFields.jl") + end # module diff --git a/src/Fields/UnimplementedFields.jl b/src/Fields/UnimplementedFields.jl new file mode 100644 index 000000000..88fb6f1f4 --- /dev/null +++ b/src/Fields/UnimplementedFields.jl @@ -0,0 +1,3 @@ + +struct _UnimplementedField <: Field end + diff --git a/src/Fields/VectorsOfBlockBasisCoo.jl b/src/Fields/VectorsOfBlockBasisCoo.jl new file mode 100644 index 000000000..40d6ae0df --- /dev/null +++ b/src/Fields/VectorsOfBlockBasisCoo.jl @@ -0,0 +1,117 @@ + +struct BlockBasisCoo <: Field end + +function evaluate_field!(cache,b::BlockBasisCoo,x) + msg = + """ + Not implemented! We not support iteration of vectors of block bases before + evaluation. This is unlikely to be be needed in the future. + """ + @notimplemented msg +end + +struct VectorOfBlockBasisCoo <: AbstractVector{BlockBasisCoo} + blocks::Tuple + blockids + axes +end + +Base.size(v::VectorOfBlockBasisCoo) = (length(first(v.blocks)) ,) +Base.getindex(v::VectorOfBlockBasisCoo,i::Integer) = BlockBasisCoo() + +function evaluate_field_array(v::VectorOfBlockBasisCoo,x::AbstractArray) + blocks = evaluate_field_arrays(v.blocks,x) + axs = apply(_new_axes,x,v.axes) + blockids = map(i->(1,i...),v.blockids) + VectorOfBlockArrayCoo(blocks,blockids,axs) +end + +function field_array_gradient(v::VectorOfBlockBasisCoo) + blocks = map(field_array_gradient,v.blocks) + VectorOfBlockBasisCoo(blocks,v.blockids,v.axes) +end + +function reindex(v::VectorOfBlockBasisCoo,j_to_i::AbstractArray) + blocks = map(b->reindex(b,j_to_i),v.blocks) + axs = reindex(v.axes,j_to_i) + VectorOfBlockBasisCoo(blocks,v.blockids,axs) +end + +function compose_field_arrays(v::VectorOfBlockBasisCoo,f) + blocks = map(b->compose_field_arrays(b,f),v.blocks) + VectorOfBlockBasisCoo(blocks,v.blockids,v.axes) +end + +function insert_array_of_bases_in_block(i::Integer,a,ax1,ax2...) + blocks = (a,) + blockids = _compute_blockids(eltype(ax1),i) + axs = create_array_of_blocked_axes(ax1,ax2...) + VectorOfBlockBasisCoo(blocks,blockids,axs) +end + +#TODO perhaps this should go into Arrays/BlockArraysCoo.jl +function create_array_of_blocked_axes(axs...) + axs = apply(_cat_axes,axs...) +end + +function _compute_blockids(::Type{<:NTuple{1}},i) + [(i,)] +end + +function _compute_blockids(::Type{<:NTuple{2}},i) + [(1,i)] +end + +function _cat_axes(a::NTuple{1},b::NTuple{1}) + (_blockedrange([a[1],b[1]]),) +end + +function _cat_axes(a::NTuple{1}...) + (_blockedrange([map(i->i[1],a)...]),) +end + +function _cat_axes(a::NTuple{2},b::NTuple{2}) + @assert length(a[1]) == 1 + @assert length(b[1]) == 1 + ran = (_blockedrange([a[2],b[2]]),) + _add_singleton_block(ran) +end + +function _cat_axes(a::NTuple{2}...) + ran = (_blockedrange([map(i->i[2],a)...]),) + _add_singleton_block(ran) +end + +function _new_axes(x,ran::NTuple{N,<:BlockedUnitRange} where N) + np = length(x) + (blockedrange([np]),ran...) +end + +function _new_axes(x,ran::NTuple{N,<:TwoLevelBlockedUnitRange} where N) + np = length(x) + r = blockedrange([np]) + (blockedrange([r]),ran...) +end + +function _add_singleton_block(ran::NTuple{N,<:Base.OneTo} where N) + (Base.OneTo(1),ran...) +end + +function _add_singleton_block(ran::NTuple{N,<:BlockedUnitRange} where N) + (blockedrange([1]),ran...) +end + +function _add_singleton_block(ran::NTuple{N,<:TwoLevelBlockedUnitRange} where N) + r = blockedrange([1]) + (blockedrange([r]),ran...) +end + +function _blockedrange(a::Vector{<:Base.OneTo}) + blockedrange(map(length,a)) +end + +function _blockedrange(a::Vector{<:BlockedUnitRange}) + blockedrange(a) +end + + diff --git a/src/Geometry/CartesianDiscreteModels.jl b/src/Geometry/CartesianDiscreteModels.jl index cc0cda601..89f33168a 100644 --- a/src/Geometry/CartesianDiscreteModels.jl +++ b/src/Geometry/CartesianDiscreteModels.jl @@ -88,7 +88,7 @@ get_face_labeling(model::CartesianDiscreteModel) = model.face_labeling # These needed to be type stable function get_face_nodes(model::CartesianDiscreteModel,d::Integer) - face_nodes::Table{Int,Int32} = compute_face_nodes(model,d) + face_nodes::Table{Int,Vector{Int},Vector{Int32}} = compute_face_nodes(model,d) face_nodes end diff --git a/src/Geometry/CellFields.jl b/src/Geometry/CellFields.jl deleted file mode 100644 index b702d5aad..000000000 --- a/src/Geometry/CellFields.jl +++ /dev/null @@ -1,386 +0,0 @@ - -""" - abstract type CellFieldLike <: GridapType end -""" -abstract type CellFieldLike <: GridapType end - -""" - get_array(cf::CellFieldLike) -""" -function get_array(cf::CellFieldLike) - @abstractmethod -end - -""" - get_cell_map(cf::CellFieldLike) -""" -function get_cell_map(cf::CellFieldLike) - @abstractmethod -end - -""" -This trait returns `Val{true}()` when the `CellFieldLike` is defined in a -reference finite element space, and `Val{false}()` when it is defined in the -physical space -""" -RefStyle(::Type{<:CellFieldLike}) = @notimplemented - -# We use duck typing here for all types marked with the RefStyle -RefStyle(::Type) = @notimplemented -RefStyle(a) = RefStyle(typeof(a)) -is_in_ref_space(::Type{T}) where T = get_val_parameter(RefStyle(T)) -is_in_ref_space(::T) where T = is_in_ref_space(T) -is_in_physical_space(::Type{T}) where T = !is_in_ref_space(T) -is_in_physical_space(a::T) where T = !is_in_ref_space(T) - -to_ref_space(a::CellFieldLike) = _to_ref_space(a,RefStyle(a)) -_to_ref_space(a,::Val{true}) = a -function _to_ref_space(a,::Val{false}) - cell_map = get_cell_map(a) - array = compose( get_array(a), cell_map ) - no = similar_object(a,array) - change_ref_style(no) -end - -to_physical_space(a::CellFieldLike) = _to_physical_space(a,RefStyle(a)) -_to_physical_space(a,::Val{true}) = @notimplemented # and probably not doable in some cases -_to_physical_space(a,::Val{false}) = a - -# Assumption : x ALWAIS defined in the reference space -# In the future we can also add the RefStyle to x -""" - evaluate(cf::CellFieldLike,x) -""" -function evaluate(cf::CellFieldLike,x::AbstractArray) - _evaluate(cf,x,RefStyle(cf)) -end - -function _evaluate(cf::CellFieldLike,x::AbstractArray,::Val{true}) - evaluate_field_array(get_array(cf),x) -end - -function _evaluate(cf::CellFieldLike,x::AbstractArray,::Val{false}) - cm = get_cell_map(cf) - _x = evaluate(cm,x) - evaluate_field_array(get_array(cf),_x) -end - -""" - similar_object(cf::CellFieldLike,array::AbstractArray) -""" -function similar_object(cf::CellFieldLike,array::AbstractArray) - @abstractmethod -end - -""" - similar_object(cf1::CellFieldLike,cf2::CellFieldLike,array::AbstractArray) -""" -function similar_object(cf1::CellFieldLike,cf2::CellFieldLike,array::AbstractArray) - @abstractmethod -end - -""" - change_ref_style(cf::CellFieldLike) - -Return an object with the same array and metadata as in `cf`, except for `RefStyle` which is changed. -""" -function change_ref_style(cf::CellFieldLike) - @abstractmethod -end - -""" - gradient(cf::CellFieldLike) -""" -function gradient(cf::CellFieldLike) - @abstractmethod -end - -""" - grad2curl(cf::CellFieldLike) -""" -function grad2curl(cf::CellFieldLike) - @abstractmethod -end - -""" - test_cell_field_like( - cf::CellFieldLike, - x::AbstractArray, - b::AbstractArray, - pred=(==); - grad=nothing) -""" -function test_cell_field_like(cf::CellFieldLike,x::AbstractArray,b::AbstractArray,pred=(==);grad=nothing) - cell_map = get_cell_map(cf) - @test isa(cell_map,AbstractArray) - a = evaluate(cf,x) - test_array(a,b,pred) - if grad != nothing - g = evaluate(gradient(cf),x) - test_array(g,grad,pred) - end - rs = RefStyle(cf) - @test isa(get_val_parameter(rs),Bool) - _cf = change_ref_style(cf) - @test get_array(_cf) === get_array(cf) - @test is_in_ref_space(cf) == !is_in_ref_space(_cf) - @test is_in_physical_space(cf) == !is_in_physical_space(_cf) -end - -""" - length(cf::CellFieldLike) -""" -function Base.length(cf::CellFieldLike) - a = get_array(cf) - length(a) -end - -function reindex(cf::CellFieldLike,a::AbstractVector) - similar_object(cf,reindex(get_array(cf),a)) -end - -""" - abstract type CellField <: CellFieldLike end -""" -abstract type CellField <: CellFieldLike end - -""" - test_cell_field(cf::CellField,args...;kwargs...) - -Same arguments as [`test_cell_field_like`](@ref) -""" -function test_cell_field(cf::CellField,args...;kwargs...) - test_cell_field_like(cf,args...;kwargs...) -end - -function similar_object(cf::CellField,array::AbstractArray) - cm = get_cell_map(cf) - GenericCellField(array,cm,RefStyle(cf)) -end - -function similar_object(cf1::CellField,cf2::CellField,array::AbstractArray) - cm = get_cell_map(cf1) - @assert is_in_ref_space(cf1) == is_in_ref_space(cf2) - GenericCellField(array,cm,RefStyle(cf1)) -end - -function change_ref_style(cf::CellField) - ref_sty = RefStyle(cf) - bool = !get_val_parameter(ref_sty) - new_sty = Val{bool}() - ar = get_array(cf) - cm = get_cell_map(cf) - GenericCellField(ar,cm,new_sty) -end - -# Diff operations - -struct UnimplementedField <: Field end - -function gradient(cf::CellField) - a = get_array(cf) - g = field_array_gradient(a) - similar_object(cf,g) -end - -function grad2curl(cf::CellField) - a = get_array(cf) - g = grad2curl(UnimplementedField,a) - similar_object(cf,g) -end - -# Operations - -function operate(op,cf::CellField) - a = get_array(cf) - b = field_array_operation(UnimplementedField,op,a) - similar_object(cf,b) -end - -function operate(op,cf1::CellField,cf2::CellField) - @assert length(cf1) == length(cf2) - a1 = get_array(cf1) - a2 = get_array(cf2) - b = field_array_operation(UnimplementedField,op,a1,a2) - similar_object(cf1,cf2,b) -end - -function operate(op,cf1::CellField,object) - cm = get_cell_map(cf1) - cf2 = convert_to_cell_field(object,cm,RefStyle(cf1)) - operate(op,cf1,cf2) -end - -function operate(op,object,cf2::CellField) - cm = get_cell_map(cf2) - cf1 = convert_to_cell_field(object,cm,RefStyle(cf2)) - operate(op,cf1,cf2) -end - -# Conversions - -function convert_to_cell_field(object,cell_map) - ref_style = Val{true}() - convert_to_cell_field(object,cell_map,ref_style) -end - -""" - convert_to_cell_field(object,cell_map,ref_style) -""" -function convert_to_cell_field(object::CellField,cell_map,ref_style::Val) - @assert RefStyle(object) == ref_style - object -end - -function convert_to_cell_field(object::CellField,cell_map) - ref_style = RefStyle(object) - convert_to_cell_field(object,cell_map,ref_style) -end - -function convert_to_cell_field(object::AbstractArray,cell_map,ref_style::Val) - @assert length(object) == length(cell_map) - GenericCellField(object,cell_map,ref_style) -end - -function convert_to_cell_field(object::Function,cell_map,ref_style::Val{true}) - b = compose(object,cell_map) - GenericCellField(b,cell_map,Val{true}()) -end - -function convert_to_cell_field(fun::Function,cell_map,ref_style::Val{false}) - field = function_field(fun) - cell_field = Fill(field,length(cell_map)) - GenericCellField(cell_field,cell_map,Val{false}()) -end - -function convert_to_cell_field(object::Number,cell_map,ref_style::Val) - a = Fill(object,length(cell_map)) - GenericCellField(a,cell_map,ref_style) -end - -# Concrete implementation - -""" -struct GenericCellField{R} <: CellField - array::AbstractArray - cell_map::AbstractArray - ref_trait::Val{R} - end -""" -struct GenericCellField{R} <: CellField - array::AbstractArray - cell_map::AbstractArray - ref_trait::Val{R} -end - -function GenericCellField(array::AbstractArray,cell_map::AbstractArray) - GenericCellField(array,cell_map,Val{true}()) -end - -function get_array(cf::GenericCellField) - cf.array -end - -function get_cell_map(cf::GenericCellField) - cf.cell_map -end - -function RefStyle(::Type{<:GenericCellField{R}}) where {R} - Val{R}() -end - -# Skeleton related - -""" - struct SkeletonCellField <: GridapType - left::CellField - right::CellField - end - -Supports the same differential and algebraic operations than [`CellField`](@ref) -""" -struct SkeletonCellField <: GridapType - left::CellField - right::CellField -end - -function Base.getproperty(x::SkeletonCellField, sym::Symbol) - if sym == :inward - x.left - elseif sym == :outward - x.right - else - getfield(x, sym) - end -end - -""" - get_cell_map(a::SkeletonCellField) -""" -function get_cell_map(a::SkeletonCellField) - get_cell_map(a.left) -end - -""" - jump(sf::SkeletonCellField) -""" -function jump(sf::SkeletonCellField) - sf.left - sf.right -end - -""" - mean(sf::SkeletonCellField) -""" -function mean(sf::SkeletonCellField) - operate(_mean,sf.left,sf.right) -end - -_mean(x,y) = 0.5*x + 0.5*y - -function gradient(cf::SkeletonCellField) - left = gradient(cf.left) - right = gradient(cf.right) - SkeletonCellField(left,right) -end - -function grad2curl(cf::SkeletonCellField) - left = grad2curl(cf.left) - right = grad2curl(cf.right) - SkeletonCellField(left,right) -end - -function operate(op,cf::SkeletonCellField) - left = operate(op,cf.left) - right = operate(op,cf.right) - SkeletonCellField(left,right) -end - -function operate(op,cf1::SkeletonCellField,cf2::SkeletonCellField) - left = operate(op,cf1.left,cf2.left) - right = operate(op,cf1.right,cf2.right) - SkeletonCellField(left,right) -end - -function operate(op,cf1::SkeletonCellField,cf2::CellField) - left = operate(op,cf1.left,cf2) - right = operate(op,cf1.right,cf2) - SkeletonCellField(left,right) -end - -function operate(op,cf1::CellField,cf2::SkeletonCellField) - left = operate(op,cf1,cf2.left) - right = operate(op,cf1,cf2.right) - SkeletonCellField(left,right) -end - -function operate(op,cf1::SkeletonCellField,object) - cm = get_cell_map(cf1) - cf2 = convert_to_cell_field(object,cm,RefStyle(cf1.left)) - operate(op,cf1,cf2) -end - -function operate(op,object,cf2::SkeletonCellField) - cm = get_cell_map(cf2) - cf1 = convert_to_cell_field(object,cm,RefStyle(cf2.left)) - operate(op,cf1,cf2) -end diff --git a/src/Geometry/GenericBoundaryTriangulations.jl b/src/Geometry/GenericBoundaryTriangulations.jl index effe94a6c..a121a173c 100644 --- a/src/Geometry/GenericBoundaryTriangulations.jl +++ b/src/Geometry/GenericBoundaryTriangulations.jl @@ -4,7 +4,7 @@ struct FaceToCellGlue{O} <: GridapType face_to_cell::Vector{Int} face_to_lface::Vector{Int8} cell_to_ctype::Vector{Int8} - cell_to_lface_to_pindex::Table{Int8,Int32} + cell_to_lface_to_pindex::Table{Int8,Vector{Int8},Vector{Int32}} ctype_to_lface_to_ftype::Vector{Vector{Int8}} end diff --git a/src/Geometry/Geometry.jl b/src/Geometry/Geometry.jl index b9e4d5489..538784c11 100644 --- a/src/Geometry/Geometry.jl +++ b/src/Geometry/Geometry.jl @@ -18,6 +18,7 @@ using Gridap.ReferenceFEs using Gridap.TensorValues using Gridap.Io using Gridap.Integration +using Gridap.CellData using Gridap.ReferenceFEs: _num_faces using Gridap.ReferenceFEs: _num_facets @@ -36,6 +37,10 @@ import Gridap.Arrays: getindex! import Gridap.Arrays: reindex import Gridap.Arrays: get_array import Gridap.Arrays: lazy_append +import Gridap.CellData: CellField +import Gridap.CellData: CellQuadrature +import Gridap.CellData: QPointCellField +import Gridap.CellData: get_cell_map import Gridap.Fields: field_cache import Gridap.Fields: evaluate_field! @@ -90,20 +95,6 @@ import Gridap.Fields: integrate import Gridap.Arrays: apply_kernel! -export CellField -export GenericCellField -export SkeletonCellField -export RefStyle -export similar_object -export change_ref_style -export test_cell_field -export convert_to_cell_field -export to_ref_space -export to_physical_space -export is_in_physical_space -export is_in_ref_space -export cell_field_from_function - export GridTopology export num_cells export get_polytopes @@ -131,13 +122,13 @@ export get_reffes export get_cell_coordinates export get_cell_reffes export get_cell_shapefuns -export get_cell_map export get_normal_vector export test_triangulation export restrict export get_physical_coordinate export get_cell_id export cell_measure +export get_cell_map export Grid export get_cell_nodes @@ -199,14 +190,10 @@ export GenericBoundaryTriangulation export DiscreteModelPortion export SkeletonPair -export jump -export mean export SkeletonTriangulation export InterfaceTriangulation export get_left_boundary export get_right_boundary -export CellQuadrature -export QPointCellField export RestrictedDiscreteModel @@ -218,8 +205,6 @@ include("GridTopologyMocks.jl") include("UnstructuredGridTopologies.jl") -include("CellFields.jl") - include("SkeletonPairs.jl") include("Triangulations.jl") @@ -256,10 +241,6 @@ include("GenericBoundaryTriangulations.jl") include("SkeletonTriangulations.jl") -include("CellQuadratures.jl") - -include("QPointCellFields.jl") - include("AppendedTriangulations.jl") include("RestrictedDiscreteModels.jl") diff --git a/src/Geometry/GridPortions.jl b/src/Geometry/GridPortions.jl index e1a76b61f..79b5a80ca 100644 --- a/src/Geometry/GridPortions.jl +++ b/src/Geometry/GridPortions.jl @@ -10,7 +10,7 @@ struct GridPortion{Dc,Dp,G} <: Grid{Dc,Dp} oldgrid::G cell_to_oldcell::Vector{Int} node_to_oldnode::Vector{Int} - cell_to_nodes::Table{Int,Int32} + cell_to_nodes::Table{Int,Vector{Int},Vector{Int32}} @doc """ GridPortion(oldgrid::Grid{Dc,Dp},cell_to_oldcell::Vector{Int}) where {Dc,Dp} """ diff --git a/src/Geometry/QPointCellFields.jl b/src/Geometry/QPointCellFields.jl deleted file mode 100644 index a6d22b7b1..000000000 --- a/src/Geometry/QPointCellFields.jl +++ /dev/null @@ -1,74 +0,0 @@ - -""" -""" -function QPointCellField(value::Number,trian::Triangulation,quad::CellQuadrature) - q = get_coordinates(quad) - v_q = [ fill(value,size(qi)) for qi in q ] - array = ArrayOfEvaluatedFields(v_q,q) - cell_map = get_cell_map(trian) - GenericCellField(array, cell_map) -end - -""" -""" -function CellField(value::Number,trian::Triangulation,quad::CellQuadrature) - QPointCellField(value,trian,quad) -end - -struct EvaluatedField{A<:AbstractArray,P<:AbstractArray} <:Field - array::A - points::P -end - -function field_cache(f::EvaluatedField,x) - nothing -end - -function evaluate_field!(cache,f::EvaluatedField,x) - @assert length(x) == length(f.array) - @assert x === f.points || x == f.points - f.array -end - -struct ArrayOfEvaluatedFields{T,N,A,B} <: AbstractArray{EvaluatedField{T},N} - array::A - points::B - function ArrayOfEvaluatedFields(array::AbstractArray{T,N},points::AbstractArray) where {T<:AbstractArray,N} - A = typeof(array) - B = typeof(points) - new{T,N,A,B}(array,points) - end -end - -Base.size(a::ArrayOfEvaluatedFields) = size(a.array) - -Base.IndexStyle(::Type{<:ArrayOfEvaluatedFields{T,N,A}}) where {T,N,A} = IndexStyle(A) - -@inline function Base.getindex(a::ArrayOfEvaluatedFields,i::Integer) - EvaluatedField(a.array[i],a.points[i]) -end - -@inline function Base.getindex(a::ArrayOfEvaluatedFields{T,N},i::Vararg{Int,N}) where {T,N} - EvaluatedField(a.array[i...],a.points[i...]) -end - -function array_cache(a::ArrayOfEvaluatedFields) - ca = array_cache(a.array) - cp = array_cache(a.points) - (ca,cp) -end - -@inline function getindex!(cache,a::ArrayOfEvaluatedFields,i...) - ca, cp = cache - array = getindex!(ca,a.array,i...) - points = getindex!(ca,a.points,i...) - EvaluatedField(array,points) -end - -function evaluate_field_array(a::ArrayOfEvaluatedFields,x::AbstractArray) - @assert a.points === x || a.points == x - @assert length(a) == length(x) - a.array -end - - diff --git a/src/Geometry/Triangulations.jl b/src/Geometry/Triangulations.jl index c3049a422..a8b2b617d 100644 --- a/src/Geometry/Triangulations.jl +++ b/src/Geometry/Triangulations.jl @@ -236,21 +236,45 @@ function restrict(cf::CellField,trian::Triangulation) _cf = to_ref_space(cf) a = get_array(_cf) r = restrict(a,trian) - _restrict_cell_field(r,trian) + axs = reindex(get_cell_axes(cf),trian) + _restrict_cell_field(r,axs,MetaSizeStyle(cf),trian) end -function _restrict_cell_field(r::SkeletonPair,trian) +function _restrict_cell_field(r::AbstractArray,axs::AbstractArray,msize_style::Val,trian) + cm = get_cell_map(trian) + GenericCellField(r,cm,Val(true),axs,msize_style) +end + +function _restrict_cell_field(r::SkeletonPair,axs::SkeletonPair,msize_style::Val,trian) cm = get_cell_map(trian) la = r.left ra = r.right - l = GenericCellField(la,cm) - r = GenericCellField(ra,cm) - SkeletonCellField(l,r) + l = GenericCellField(la,cm,Val(true),axs.left,msize_style) + r = GenericCellField(ra,cm,Val(true),axs.right,msize_style) + merge_cell_fields_at_skeleton(l,r) end -function _restrict_cell_field(r::AbstractArray,trian) - cm = get_cell_map(trian) - GenericCellField(r,cm) +""" + CellQuadrature(trian::Triangulation, degree::Integer) +""" +function CellQuadrature(trian::Triangulation, degree::Integer) + polytopes = map(get_polytope,get_reffes(trian)) + cell_type = get_cell_type(trian) + CellQuadrature(degree,polytopes,cell_type) +end + +""" + integrate(cell_field,trian::Triangulation,quad::CellQuadrature) + +The `cell_field` is aligned with the cells in `trian` +""" +function integrate(cell_field,trian::Triangulation,quad::CellQuadrature) + cell_map = get_cell_map(trian) + integrate(cell_field,cell_map,quad) +end + +function CellField(value::Number,trian::Triangulation,quad::CellQuadrature) + CellField(value,get_cell_map(trian),quad) end """ diff --git a/src/Geometry/UnstructuredDiscreteModels.jl b/src/Geometry/UnstructuredDiscreteModels.jl index 67a86c6dd..e3214d2f7 100644 --- a/src/Geometry/UnstructuredDiscreteModels.jl +++ b/src/Geometry/UnstructuredDiscreteModels.jl @@ -93,11 +93,11 @@ function from_dict(T::Type{UnstructuredDiscreteModel},dict::Dict{Symbol,Any}) vertex_coordinates = get_node_coordinates(grid)[vertex_to_node] nvertices = length(vertex_to_node) - d_dface_to_vertices = Vector{Table{Int,Int32}}(undef,D+1) + d_dface_to_vertices = Vector{Table{Int,Vector{Int},Vector{Int32}}}(undef,D+1) d_dface_to_vertices[0+1] = identity_table(Int,Int32,nvertices) for d in 1:D k = Symbol("face_vertices_$d") - dface_to_vertices = from_dict(Table{Int,Int32},dict[k]) + dface_to_vertices = from_dict(Table{Int,Vector{Int},Vector{Int32}},dict[k]) d_dface_to_vertices[d+1] = dface_to_vertices end diff --git a/src/Geometry/UnstructuredGridTopologies.jl b/src/Geometry/UnstructuredGridTopologies.jl index a48e1d1e9..f3f11ca37 100644 --- a/src/Geometry/UnstructuredGridTopologies.jl +++ b/src/Geometry/UnstructuredGridTopologies.jl @@ -6,7 +6,7 @@ """ struct UnstructuredGridTopology{Dc,Dp,T,O} <: GridTopology{Dc,Dp} vertex_coordinates::Vector{Point{Dp,T}} - n_m_to_nface_to_mfaces::Matrix{Table{Int,Int32}} + n_m_to_nface_to_mfaces::Matrix{Table{Int,Vector{Int},Vector{Int32}}} cell_type::Vector{Int8} polytopes::Vector{Polytope{Dc}} end @@ -30,7 +30,7 @@ function UnstructuredGridTopology( D = num_dims(first(polytopes)) n = D+1 - n_m_to_nface_to_mfaces = Matrix{Table{Int,Int32}}(undef,n,n) + n_m_to_nface_to_mfaces = Matrix{Table{Int,Vector{Int},Vector{Int32}}}(undef,n,n) n_m_to_nface_to_mfaces[D+1,0+1] = cell_vertices vertex_cells = generate_cells_around(cell_vertices,length(vertex_coordinates)) n_m_to_nface_to_mfaces[0+1,D+1] = vertex_cells @@ -64,7 +64,7 @@ function UnstructuredGridTopology( D = num_dims(first(polytopes)) n = D+1 - n_m_to_nface_to_mfaces = Matrix{Table{Int,Int32}}(undef,n,n) + n_m_to_nface_to_mfaces = Matrix{Table{Int,Vector{Int},Vector{Int32}}}(undef,n,n) nvertices = length(vertex_coordinates) for d in 0:D dface_to_vertices = d_to_dface_vertices[d+1] diff --git a/src/Geometry/UnstructuredGrids.jl b/src/Geometry/UnstructuredGrids.jl index e803f81c4..17f023f75 100644 --- a/src/Geometry/UnstructuredGrids.jl +++ b/src/Geometry/UnstructuredGrids.jl @@ -9,7 +9,7 @@ """ struct UnstructuredGrid{Dc,Dp,Tp,O} <: Grid{Dc,Dp} node_coordinates::Vector{Point{Dp,Tp}} - cell_nodes::Table{Int,Int32} + cell_nodes::Table{Int,Vector{Int},Vector{Int32}} reffes::Vector{LagrangianRefFE{Dc}} cell_types::Vector{Int8} @doc """ @@ -140,7 +140,7 @@ function from_dict(::Type{UnstructuredGrid},dict::Dict{Symbol,Any}) T = eltype(x) Dp = dict[:Dp] node_coordinates::Vector{Point{Dp,T}} = reinterpret(Point{Dp,T},x) - cell_nodes = from_dict(Table{Int,Int32},dict[:cell_nodes]) + cell_nodes = from_dict(Table{Int,Vector{Int},Vector{Int32}},dict[:cell_nodes]) reffes = [ from_dict(LagrangianRefFE,reffe) for reffe in dict[:reffes]] cell_type::Vector{Int8} = dict[:cell_type] O::Bool = dict[:orientation] diff --git a/src/Gridap.jl b/src/Gridap.jl index 8f718e012..6d9ed41ab 100644 --- a/src/Gridap.jl +++ b/src/Gridap.jl @@ -16,6 +16,7 @@ The module is structured in the following sub-modules: - [`Gridap.Polynomials`](@ref) - [`Gridap.Integration`](@ref) - [`Gridap.ReferenceFEs`](@ref) +- [`Gridap.CellData`](@ref) - [`Gridap.Geometry`](@ref) - [`Gridap.FESpaces`](@ref) - [`Gridap.MultiField`](@ref) @@ -48,6 +49,8 @@ include("Integration/Integration.jl") include("ReferenceFEs/ReferenceFEs.jl") +include("CellData/CellData.jl") + include("Geometry/Geometry.jl") include("FESpaces/FESpaces.jl") diff --git a/src/Helpers/GridapTypes.jl b/src/Helpers/GridapTypes.jl index 09c210a55..2b065263a 100644 --- a/src/Helpers/GridapTypes.jl +++ b/src/Helpers/GridapTypes.jl @@ -11,9 +11,9 @@ end """ """ function operate(op,a) - s = "Unary operation $op is not defined for objects of type $(typeof(object))\n" + s = "Unary operation $op is not defined for objects of type $(typeof(a))\n" s *= "Possible fix, define:\n" - s *= "Gridap.Helpers.operate(::$(typeof(op)),::$(typeof(object)))" + s *= "Gridap.Helpers.operate(::$(typeof(op)),::$(typeof(a)))" @unreachable s end diff --git a/src/MultiField/MultiField.jl b/src/MultiField/MultiField.jl index 2bce1105c..4ff0c240a 100644 --- a/src/MultiField/MultiField.jl +++ b/src/MultiField/MultiField.jl @@ -14,115 +14,27 @@ using Gridap.Geometry using Gridap.Integration using Gridap.Inference using Gridap.TensorValues +using Gridap.CellData +using Gridap.Fields + using FillArrays using SparseArrays -import LinearAlgebra: mul! -using LinearAlgebra: Transpose -using LinearAlgebra: dot - -using Gridap.Arrays: IdentityVector -using Gridap.FESpaces: _operate_cell_basis -using Gridap.FESpaces: _operate_cell_matrix_field -using Gridap.FESpaces: SkeletonCellBasis -using Gridap.FESpaces: interpolate! -using Gridap.FESpaces: interpolate_everywhere! -using Gridap.FESpaces: interpolate_dirichlet! - -import Gridap.Helpers: operate -import Gridap.Arrays: get_array -import Gridap.Arrays: array_cache -import Gridap.Arrays: getindex! -import Gridap.Arrays: reindex -import Gridap.Arrays: add_to_array! -import Gridap.Arrays: kernel_cache -import Gridap.Arrays: apply_kernel! -using Gridap.FESpaces: DirichletVecKernel -using Gridap.FESpaces: CellMatVecKernel -using Gridap.FESpaces: CellMatKernel -using Gridap.FESpaces: CellVecKernel -import Gridap.Geometry: get_cell_map -import Gridap.Geometry: similar_object -import Gridap.Geometry: change_ref_style -import Gridap.Geometry: restrict -import Gridap.Fields: integrate -import Gridap.Fields: evaluate -import Gridap.FESpaces: TrialStyle -import Gridap.FESpaces: RefStyle -import Gridap.FESpaces: FECellBasisStyle -import Gridap.FESpaces: FEFunctionStyle -import Gridap.FESpaces: num_free_dofs -import Gridap.FESpaces: get_cell_basis -import Gridap.FESpaces: FEFunction -import Gridap.FESpaces: zero_free_values -import Gridap.FESpaces: constraint_style -import Gridap.FESpaces: get_constraint_kernel_matrix_cols -import Gridap.FESpaces: get_constraint_kernel_matrix_rows -import Gridap.FESpaces: get_constraint_kernel_vector -import Gridap.FESpaces: get_cell_isconstrained -import Gridap.FESpaces: get_cell_constraints -import Gridap.FESpaces: get_cell_dofs -import Gridap.FESpaces: get_fe_space -import Gridap.FESpaces: get_free_values -import Gridap.FESpaces: get_cell_values -import Gridap.FESpaces: get_test -import Gridap.FESpaces: get_trial -import Gridap.FESpaces: allocate_vector -import Gridap.FESpaces: assemble_vector! -import Gridap.FESpaces: assemble_vector_add! -import Gridap.FESpaces: allocate_matrix -import Gridap.FESpaces: assemble_matrix! -import Gridap.FESpaces: assemble_matrix_add! -import Gridap.FESpaces: assemble_matrix -import Gridap.FESpaces: allocate_matrix_and_vector -import Gridap.FESpaces: assemble_matrix_and_vector! -import Gridap.FESpaces: assemble_matrix_and_vector_add! -import Gridap.FESpaces: assemble_matrix_and_vector -import Gridap.FESpaces: SparseMatrixAssembler -import Gridap.FESpaces: AffineFEOperator -import Gridap.FESpaces: FEOperator -import Gridap.FESpaces: EvaluationFunction -import Gridap.FESpaces: get_matrix_type -import Gridap.FESpaces: get_vector_type -import Gridap.FESpaces: get_assembly_strategy -import Gridap.FESpaces: count_matrix_nnz_coo -import Gridap.FESpaces: fill_matrix_coo_symbolic! -import Gridap.FESpaces: fill_matrix_coo_numeric! -import Gridap.FESpaces: fill_matrix_and_vector_coo_numeric! -import Gridap.FESpaces: count_matrix_and_vector_nnz_coo -import Gridap.FESpaces: fill_matrix_and_vector_coo_symbolic! -import Gridap.FESpaces: interpolate -import Gridap.FESpaces: interpolate_everywhere -import Gridap.FESpaces: interpolate_dirichlet - -import Base: +, - +using LinearAlgebra +using BlockArrays export num_fields export compute_field_offsets export restrict_to_field +export MultiFieldCellField export MultiFieldFESpace export MultiFieldFEFunction -export MultiFieldSparseMatrixAssembler - -export MultiFieldArray -export get_block_size -export num_blocks -export num_stored_blocks -export has_all_blocks +export MultiFieldStyle +export ConsecutiveMultiFieldStyle -include("MultiFieldArrays.jl") - -include("MultiFieldCellArrays.jl") - -include("MultiFieldCellBases.jl") - -include("MultiFieldCellKernels.jl") +include("MultiFieldCellFields.jl") include("MultiFieldFESpaces.jl") include("MultiFieldFEFunctions.jl") -include("MultiFieldSparseMatrixAssemblers.jl") - -include("MultiFieldFEOperators.jl") - end # module diff --git a/src/MultiField/MultiFieldArrays.jl b/src/MultiField/MultiFieldArrays.jl deleted file mode 100644 index 479f021b8..000000000 --- a/src/MultiField/MultiFieldArrays.jl +++ /dev/null @@ -1,230 +0,0 @@ - -""" -""" -struct MultiFieldArray{T,N,A<:AbstractArray{T,N}} <: GridapType - blocks::Vector{A} - coordinates::Vector{NTuple{N,Int}} - ptrs::Array{Int,N} - block_size::NTuple{N,Int} - - function MultiFieldArray( - blocks::Vector{A}, - coordinates::Vector{NTuple{N,Int}}) where {T,N,A<:AbstractArray{T,N}} - - @assert length(blocks) == length(coordinates) - msg = "Trying to build a MultiFieldArray with repeated blocks" - @assert _no_has_repeaded_blocks(coordinates) msg - ptrs = _prepare_ptrs(coordinates) - block_size = _get_block_size(coordinates) - new{T,N,A}(blocks,coordinates,ptrs,block_size) - end -end - -function _no_has_repeaded_blocks(coordinates::Vector{NTuple{N,Int}}) where N - maxblocks = _get_block_size(coordinates) - touched = zeros(Int,maxblocks) - for c in coordinates - touched[c...] += 1 - end - all( touched .<= 1 ) -end - -function _prepare_ptrs(coordinates) - s = _get_block_size(coordinates) - ptrs = zeros(Int,s) - for (i,c) in enumerate(coordinates) - ptrs[c...] = i - end - ptrs -end - -function _get_block_size(coordinates::Vector{NTuple{N,Int}}) where N - m = zeros(Int,N) - for c in coordinates - for n in 1:N - m[n] = max(m[n],c[n]) - end - end - NTuple{N,Int}(m) -end - -function Base.copy(a::MultiFieldArray) - MultiFieldArray([copy(b) for b in a.blocks],a.coordinates) -end - -""" -""" -function get_block_size(a::MultiFieldArray) - a.block_size -end - -""" -""" -function num_blocks(a::MultiFieldArray) - s = get_block_size(a) - prod(s) -end - -""" -""" -function num_stored_blocks(a::MultiFieldArray) - length(a.coordinates) -end - -""" -""" -function has_all_blocks(a::MultiFieldArray{T,N}) where {T,N} - num_blocks(a) == num_stored_blocks(a) -end - -function Base.:*(a::MultiFieldArray,b::Number) - blocks = [ block*b for block in a.blocks ] - coordinates = a.coordinates - MultiFieldArray(blocks,coordinates) -end - -function Base.:*(b::Number,a::MultiFieldArray) - blocks = [ b*block for block in a.blocks ] - coordinates = a.coordinates - MultiFieldArray(blocks,coordinates) -end - -function Base.show(io::IO,a::MultiFieldArray) - print(io,"MultiFieldArray($(a.blocks),$(a.coordinates))") -end - -function Base.show(io::IO,::MIME"text/plain",a::MultiFieldArray) - println(io,"MultiFieldArray object:") - cis = CartesianIndices(a.ptrs) - for ci in cis - p = a.ptrs[ci] - if p == 0 - println(io,"Block $(Tuple(ci)) -> Empty") - else - println(io,"Block $(Tuple(ci)) -> $(a.blocks[p])") - end - end -end - -function add_to_array!(a::MultiFieldArray{Ta,N},b::MultiFieldArray{Tb,N},combine=+) where {Ta,Tb,N} - for coords in b.coordinates - ak = a[coords...] - bk = b[coords...] - add_to_array!(ak,bk,combine) - end - a -end - -function add_to_array!(a::MultiFieldArray,b::Number,combine=+) - for k in 1:length(a.blocks) - ak = a.blocks[k] - add_to_array!(ak,b,combine) - end -end - -function Base.:*(a::MultiFieldArray{Ta,2},b::MultiFieldArray{Tb,1}) where {Ta,Tb} - @assert num_stored_blocks(a) != 0 - @notimplementedif ! has_all_blocks(b) - - function fun(i,a,b) - ai = a.blocks[i] - ci, cj = a.coordinates[i] - p = b.ptrs[cj] - bi = b.blocks[p] - ai*bi - end - - blocks = [ fun(i,a,b) for i in 1:length(a.blocks)] - coordinates = [ (c[1],) for c in a.coordinates] - - data = _merge_repeated_blocks(blocks,coordinates) - MultiFieldArray(data...) -end - -function Base.fill!(a::MultiFieldArray,b) - for k in 1:length(a.blocks) - ak = a.blocks[k] - fill!(ak,b) - end - a -end - -Base.eltype(::Type{<:MultiFieldArray{T}}) where T = T - -Base.eltype(a::MultiFieldArray{T}) where T = T - -function _merge_repeated_blocks(blocks,coordinates::Vector{NTuple{N,Int}}) where N - @assert length(blocks) == length(coordinates) - s = _get_block_size(coordinates) - ptrs = zeros(Int,s) - A = eltype(blocks) - _blocks = A[] - _coords = NTuple{N,Int}[] - q = 1 - for b in 1:length(blocks) - c = coordinates[b] - block = blocks[b] - p = ptrs[c...] - if p == 0 - push!(_blocks,block) - push!(_coords,c) - ptrs[c...] = q - q += 1 - else - add_to_array!(_blocks[p],block) - end - end - (_blocks,_coords) -end - -function mul!(c::MultiFieldArray{Tc,1},a::MultiFieldArray{Ta,2},b::MultiFieldArray{Tb,1}) where {Tc,Ta,Tb} - for ci in c.blocks - fill!(ci,zero(Tc)) - end - for k in 1:length(a.blocks) - ak = a.blocks[k] - ci, cj = a.coordinates[k] - p = b.ptrs[cj] - bk = b.blocks[p] - q = c.ptrs[ci] - ck = c.blocks[q] - muladd!(ck,ak,bk) - end -end - -function CachedMultiFieldArray(a::MultiFieldArray) - blocks = [ CachedArray(b) for b in a.blocks ] - coordinates = a.coordinates - MultiFieldArray(blocks,coordinates) -end - -function _resize_for_mul!( - c::MultiFieldArray{Tc,1},a::MultiFieldArray{Ta,2},b::MultiFieldArray{Tb,1}) where {Tc,Ta,Tb} - for k in 1:length(a.blocks) - ak = a.blocks[k] - ci, cj = a.coordinates[k] - q = c.ptrs[ci] - ck = c.blocks[q] - setsize!(ck,(size(ak,1),)) - end -end - -function _move_cached_arrays!(r::MultiFieldArray,c::MultiFieldArray) - for k in 1:length(c.blocks) - ck = c.blocks[k] - r.blocks[k] = ck.array - end -end - -function Base.getindex(a::MultiFieldArray{T,N},I::Vararg{Int,N}) where {T,N} - p = a.ptrs[I...] - @assert p > 0 "You are attempting to access a block that is not stored" - a.blocks[p] -end - -function Base.getindex(a::MultiFieldArray,i::Integer) - p = a.ptrs[i] - @assert p > 0 "You are attempting to access a block that is not stored" - a.blocks[p] -end - diff --git a/src/MultiField/MultiFieldCellArrays.jl b/src/MultiField/MultiFieldCellArrays.jl deleted file mode 100644 index 660faf9fb..000000000 --- a/src/MultiField/MultiFieldCellArrays.jl +++ /dev/null @@ -1,158 +0,0 @@ - -struct MultiFieldCellArray{T,N,B<:Tuple} <: AbstractVector{MultiFieldArray{T,N,Array{T,N}}} - blocks::B - block_ids::Vector{NTuple{N,Int}} - function MultiFieldCellArray(_blocks::Tuple,_block_ids::Vector{NTuple{N,Int}}) where N - blocks, block_ids = _merge_repeated_blocks_mca(_blocks,_block_ids) - @assert length(blocks) > 0 - @assert length(blocks) == length(block_ids) - bi, = blocks - @assert isa(bi,AbstractArray) - @assert all( ( size(b) == size(bi) for b in blocks ) ) - @assert all( ( eltype(b) == eltype(bi) for b in blocks ) ) - A = eltype(bi) - @assert A <: Array - @assert ndims(A) == N - T = eltype(A) - B = typeof(blocks) - new{T,N,B}(blocks,block_ids) - end -end - -function _merge_repeated_blocks_mca(blocks,coordinates::Vector{NTuple{N,Int}}) where N - @assert length(blocks) == length(coordinates) - s = _get_block_size(coordinates) - ptrs = zeros(Int,s) - _blocks = [] - _coords = NTuple{N,Int}[] - q = 1 - for b in 1:length(blocks) - c = coordinates[b] - block = blocks[b] - p = ptrs[c...] - if p == 0 - push!(_blocks,block) - push!(_coords,c) - ptrs[c...] = q - q += 1 - else - _blocks[p] = apply(elem(+),_blocks[p],block) - end - end - ( tuple(_blocks...), _coords) -end - -function array_cache(a::MultiFieldCellArray{T,N}) where {T,N} - coordinates = a.block_ids - nblocks = length(coordinates) - blocks = Vector{Array{T,N}}(undef,nblocks) - b = MultiFieldArray(blocks,coordinates) - caches = array_caches(a.blocks...) - (b,caches) -end - -function getindex!(cache,a::MultiFieldCellArray,i::Integer) - b, caches = cache - bis = getitems!(caches,a.blocks,i) - for (k,bk) in enumerate(bis) - b.blocks[k] = bk - end - b -end - -function Base.getindex(a::MultiFieldCellArray,i::Integer) - cache = array_cache(a) - getindex!(cache,a,i) -end - -function Base.size(a::MultiFieldCellArray) - bi, = a.blocks - size(bi) -end - -function reindex(a::MultiFieldCellArray,b::AbstractArray) - f = (ai) -> reindex(ai,b) - blocks = map(f,a.blocks) - MultiFieldCellArray(blocks,a.block_ids) -end - -function reindex(a::MultiFieldCellArray,b::IdentityVector) - a -end - -struct BlockTracker{N} <: GridapType - blocks::Tuple - block_ids::Vector{NTuple{N,Int}} -end - -function operate(::typeof(+),a::BlockTracker) - a -end - -function operate(::typeof(-),a::BlockTracker) - new_blocks = map(-,a.blocks) - BlockTracker(new_blocks,a.block_ids) -end - -function operate(::typeof(+),a::BlockTracker,b::BlockTracker) - new_blocks = (a.blocks...,b.blocks...) - new_block_ids = vcat(a.block_ids,b.block_ids) - BlockTracker(new_blocks,new_block_ids) -end - -function operate(::typeof(-),a::BlockTracker,b::BlockTracker) - new_blocks = (a.blocks...,(-b).blocks...) - new_block_ids = vcat(a.block_ids,b.block_ids) - BlockTracker(new_blocks,new_block_ids) -end - -function operate(op,a::BlockTracker,b::BlockTracker) - msg = "Operation $op not yet implemented in this context" - @notimplementedif !( op in (*,inner,dot) ) msg - new_blocks = [] - new_block_ids = NTuple{2,Int}[] - for i in 1:length(a.blocks) - ai = a.blocks[i] - @notimplementedif ! isa(ai,CellBasisWithFieldID) msg - ai_id, = a.block_ids[i] - for j in 1:length(b.blocks) - bj = b.blocks[j] - @notimplementedif ! isa(bj,CellBasisWithFieldID) msg - bj_id, = b.block_ids[j] - push!(new_blocks, operate(op,ai.cell_basis,bj.cell_basis)) - push!(new_block_ids, (ai_id,bj_id)) - end - end - BlockTracker(Tuple(new_blocks),new_block_ids) -end - -function operate(op,a,b::BlockTracker) - _operate_bt_b(op,a,b) -end - -function operate(op,a::CellField,b::BlockTracker) - _operate_bt_b(op,a,b) -end - -function operate(op,b::BlockTracker,a) - _operate_bt_a(op,b,a) -end - -function operate(op,b::BlockTracker,a::CellField) - _operate_bt_a(op,b,a) -end - -function _operate_bt_b(op,a,b) - msg = "Operation $op not yet implemented in this context" - @notimplementedif !( op in (*,inner) ) msg - new_blocks = map(bi->operate(op,a,bi),b.blocks) - BlockTracker(new_blocks,b.block_ids) -end - -function _operate_bt_a(op,b,a) - msg = "Operation $op not yet implemented in this context" - @notimplementedif !( op in (*,inner) ) msg - new_blocks = map(bi->operate(op,a,bi),b.blocks) - BlockTracker(new_blocks,b.block_ids) -end - diff --git a/src/MultiField/MultiFieldCellBases.jl b/src/MultiField/MultiFieldCellBases.jl deleted file mode 100644 index 86cce8119..000000000 --- a/src/MultiField/MultiFieldCellBases.jl +++ /dev/null @@ -1,251 +0,0 @@ - -struct CellBasisWithFieldID{S,R} <: CellBasis - trial_style::Val{S} - cell_basis::CellBasis - field_id::Int - ref_style::Val{R} - function CellBasisWithFieldID(cell_basis::CellBasis,field_id::Integer) - trial_style = TrialStyle(cell_basis) - S = get_val_parameter(trial_style) - ref_style = RefStyle(cell_basis) - R = get_val_parameter(ref_style) - new{S,R}(trial_style,cell_basis,field_id,ref_style) - end -end - -get_array(cb::CellBasisWithFieldID) = get_array(cb.cell_basis) - -get_cell_map(cb::CellBasisWithFieldID) = get_cell_map(cb.cell_basis) - -TrialStyle(::Type{CellBasisWithFieldID{S,R}}) where {S,R} = Val{S}() - -RefStyle(::Type{CellBasisWithFieldID{S,R}}) where {S,R} = Val{R}() - -function change_ref_style(cf::CellBasisWithFieldID) - cell_basis = change_ref_style(cf.cell_basis) - field_id = cf.field_id - CellBasisWithFieldID(cell_basis,field_id) -end - -function similar_object(cb::CellBasisWithFieldID,array::AbstractArray) - cell_basis = similar_object(cb.cell_basis,array) - field_id = cb.field_id - CellBasisWithFieldID(cell_basis,field_id) -end - -function similar_object(a::CellBasisWithFieldID,b::CellBasisWithFieldID,v::AbstractArray) - _similar_cell_basis_with_field_id(v,a,b,TrialStyle(a),TrialStyle(b)) -end - -function _similar_cell_basis_with_field_id(v,a,b,a_trial::Val{T},b_trial::Val{T}) where T - cell_basis = similar_object(a.cell_basis,b.cell_basis,v) - @assert a.field_id == b.field_id - field_id = a.field_id - CellBasisWithFieldID(cell_basis,field_id) -end - -function _similar_cell_basis_with_field_id(v,a,b,a_trial::Val{false},b_trial::Val{true}) - _similar_cell_basis_with_field_id_test_trial(v,a,b) -end - -function _similar_cell_basis_with_field_id(v,a,b,a_trial::Val{true},b_trial::Val{false}) - _similar_cell_basis_with_field_id_test_trial(v,b,a) -end - -function _similar_cell_basis_with_field_id_test_trial(v,a,b) - field_id_rows = a.field_id - field_id_cols = b.field_id - cell_matrix_field = similar_object(a.cell_basis,b.cell_basis,v) - @assert is_in_ref_space(a) == is_in_ref_space(b) - CellMatrixFieldWithFieldIds(cell_matrix_field,field_id_rows,field_id_cols,RefStyle(a)) -end - -function operate(op,a::CellBasisWithFieldID,b::CellBasisWithFieldID) - _operate_cell_basis_with_field_id(op,a,b,TrialStyle(a),TrialStyle(b)) -end - -function _operate_cell_basis_with_field_id(op,a,b,atrial::Val{T},btrial::Val{T}) where T - if a.field_id == b.field_id - _operate_cell_basis(op,a,b,TrialStyle(a),TrialStyle(b)) - else - _a = BlockTracker(a) - _b = BlockTracker(b) - op(_a,_b) - end -end - -function BlockTracker(a::CellBasisWithFieldID) - blocks = (a,) - block_ids = [(a.field_id,)] - BlockTracker(blocks,block_ids) -end - -operate(op,a::BlockTracker,b::CellBasisWithFieldID) = operate(op,a,BlockTracker(b)) - -operate(op,a::CellBasisWithFieldID,b::BlockTracker) = operate(op,BlockTracker(a),b) - -function _operate_cell_basis_with_field_id(op,a,b,atrial,btrial) - _operate_cell_basis(op,a,b,TrialStyle(a),TrialStyle(b)) -end - -struct CellMatrixFieldWithFieldIds{R} <: CellMatrixField - cell_matrix_field::CellMatrixField - field_id_rows::Int - field_id_cols::Int - ref_style::Val{R} -end - -RefStyle(::Type{CellMatrixFieldWithFieldIds{R}}) where R = Val{R}() - -get_array(a::CellMatrixFieldWithFieldIds) = get_array(a.cell_matrix_field) - -get_cell_map(a::CellMatrixFieldWithFieldIds) = get_cell_map(a.cell_matrix_field) - -function _have_same_field_ids(a::CellMatrixFieldWithFieldIds,b::CellMatrixFieldWithFieldIds) - (a.field_id_rows == b.field_id_rows) && (a.field_id_cols == b.field_id_cols) -end - -function change_ref_style(cf::CellMatrixFieldWithFieldIds) - cell_matrix_field = change_ref_style(cf.cell_matrix_field) - CellMatrixFieldWithFieldIds( - cell_matrix_field,cf.field_id_rows,cf.field_id_cols,RefStyle(cell_matrix_field)) -end - -function similar_object(cf::CellMatrixFieldWithFieldIds,a::AbstractArray) - cell_matrix_field = similar_object(cf.cell_matrix_field,a) - field_id_rows = cf.field_id_rows - field_id_cols = cf.field_id_cols - CellMatrixFieldWithFieldIds(cell_matrix_field,field_id_rows,field_id_cols,RefStyle(cf)) -end - -function similar_object(a::CellMatrixFieldWithFieldIds,b::CellMatrixFieldWithFieldIds,v::AbstractArray) - @assert _have_same_field_ids(a,b) - similar_object(a,v) -end - -function operate(op,a::CellMatrixFieldWithFieldIds,b::CellMatrixFieldWithFieldIds) - if _have_same_field_ids(a,b) - _operate_cell_matrix_field(op,a,b) - else - _a = BlockTracker(a) - _b = BlockTracker(b) - op(_a,_b) - end -end - -function BlockTracker(a::CellMatrixFieldWithFieldIds) - blocks = (a,) - block_ids = [(a.field_id_rows,a.field_id_cols),] - BlockTracker(blocks,block_ids) -end - -operate(op,a::BlockTracker,b::CellMatrixFieldWithFieldIds) = operate(op,a,BlockTracker(b)) - -operate(op,a::CellMatrixFieldWithFieldIds,b::BlockTracker) = operate(op,BlockTracker(a),b) - -# Restrictions - -function restrict(cf::CellBasisWithFieldID,trian::Triangulation) - r = restrict(cf.cell_basis,trian) - _attach_field_id(r,cf.field_id) -end - -function _attach_field_id(r::CellBasis,field_id) - CellBasisWithFieldID(r,field_id) -end - -function _attach_field_id(r::SkeletonCellBasis,field_id) - l = CellBasisWithFieldID(r.left,field_id) - r = CellBasisWithFieldID(r.right,field_id) - SkeletonCellBasis(r.trial_style,l,r) -end - -# Evaluation - -function evaluate(bs::AbstractArray{<:CellBasisWithFieldID},q::AbstractArray) - f = b -> evaluate(b,q) - blocks = tuple(map(f,bs)...) - coordinates = [ (i,1) for i in 1:length(bs)] - MultiFieldCellArray(blocks,coordinates) -end - -# Integration - -function integrate(cb::CellBasisWithFieldID,trian::Triangulation,quad::CellQuadrature) - r = integrate(cb.cell_basis,trian,quad) - bloks = (r,) - block_ids = [(cb.field_id,),] - MultiFieldCellArray(bloks,block_ids) -end - -function integrate(cm::CellMatrixFieldWithFieldIds,trian::Triangulation,quad::CellQuadrature) - r = integrate(cm.cell_matrix_field,trian,quad) - bloks = (r,) - block_ids = [(cm.field_id_rows, cm.field_id_cols),] - MultiFieldCellArray(bloks,block_ids) -end - -function integrate(cb::BlockTracker,trian::Triangulation,quad::CellQuadrature) - f = (b) -> integrate(get_array(b),trian,quad) - blocks = map(f,cb.blocks) - block_ids = cb.block_ids - MultiFieldCellArray(blocks,block_ids) -end - -struct MultiCellBasis{S,R} <: GridapType - blocks::Vector{CellBasisWithFieldID{S}} - function MultiCellBasis(blocks::Vector{<:CellBasis}) - cb = first(blocks) - S = is_trial(cb) - R = is_in_ref_space(cb) - new_blocks = CellBasisWithFieldID{S}[] - for (field_id, cell_basis) in enumerate(blocks) - @assert is_trial(cell_basis) == S "All the provided bases must be of the same type (trial or test)" - @assert is_in_ref_space(cell_basis) == R "All the provided bases must be defined in the same space (reference or physical)" - block = CellBasisWithFieldID(cell_basis,field_id) - push!(new_blocks,block) - end - new{S,R}(new_blocks) - end -end - -FECellBasisStyle(::Type{<:MultiCellBasis}) = Val{true}() - -TrialStyle(::Type{MultiCellBasis{S,R}}) where {S,R} = Val{S}() - -RefStyle(::Type{MultiCellBasis{S,R}}) where {S,R} = Val{R}() - -num_fields(m::MultiCellBasis) = length(m.blocks) - -Base.iterate(m::MultiCellBasis) = iterate(m.blocks) - -Base.iterate(m::MultiCellBasis,state) = iterate(m.blocks,state) - -Base.getindex(m::MultiCellBasis,field_id::Integer) = m.blocks[field_id] - -function restrict(a::MultiCellBasis,trian::Triangulation) - f = (ai) -> restrict(ai,trian) - blocks = map(f,a.blocks) - blocks -end - -# Dirichlet related - -function kernel_cache(k::DirichletVecKernel,mat::MultiFieldArray,vals::MultiFieldArray) - vec = mat*vals - cvec = CachedMultiFieldArray(vec) - (vec, cvec) -end - -@inline function apply_kernel!(cache,k::DirichletVecKernel,mat::MultiFieldArray,vals::MultiFieldArray) - vec, cvec = cache - _resize_for_mul!(cvec,mat,vals) - _move_cached_arrays!(vec,cvec) - mul!(vec,mat,vals) - for vk in vec.blocks - @inbounds for i in eachindex(vk) - vk[i] = -vk[i] - end - end - vec -end diff --git a/src/MultiField/MultiFieldCellFields.jl b/src/MultiField/MultiFieldCellFields.jl new file mode 100644 index 000000000..8cb7c4563 --- /dev/null +++ b/src/MultiField/MultiFieldCellFields.jl @@ -0,0 +1,58 @@ + +struct MultiFieldCellField{R,S} <: CellField + single_fields::Vector{<:CellField} + cell_map::AbstractArray + ref_trait::Val{R} + cell_axes::AbstractArray + metasize::Val{S} + function MultiFieldCellField(single_fields::Vector{<:CellField}) + @assert length(single_fields) > 0 + f1 = first(single_fields) + cell_map = get_cell_map(f1) + ref_style = RefStyle(f1) + cell_axes = get_cell_axes(f1) + metasize = MetaSizeStyle(f1) + R = get_val_parameter(ref_style) + S = get_val_parameter(metasize) + new{R,S}(single_fields,cell_map,ref_style,cell_axes,metasize) + end +end + +Arrays.get_array(a::MultiFieldCellField) = @notimplemented + +CellData.get_memo(a::MultiFieldCellField) = @notimplemented + +CellData.get_cell_map(a::MultiFieldCellField) = a.cell_map + +CellData.get_cell_axes(a::MultiFieldCellField) = a.cell_axes + +CellData.RefStyle(::Type{<:MultiFieldCellField{R}}) where R = Val(R) + +CellData.MetaSizeStyle(::Type{<:MultiFieldCellField{R,S}}) where {R,S} = Val(S) + +Base.length(f::MultiFieldCellField) = length(first(f.single_fields)) + +num_fields(a::MultiFieldCellField) = length(a.single_fields) + +Base.getindex(a::MultiFieldCellField,i) = a.single_fields[i] + +Base.iterate(a::MultiFieldCellField) = iterate(a.single_fields) + +Base.iterate(a::MultiFieldCellField,state) = iterate(a.single_fields,state) + +function Fields.evaluate(cf::MultiFieldCellField,x::AbstractArray) + s = """ + Evaluation of MultiFieldCellField objects is not implemented at this moment. + You need to extract the individual fields and then evaluate them separatelly. + If ever implemented, evaluating a `MultiFieldCellField` directly would provide, + at each evaluation point, a tuple with the value of the different fields. + """ + @notimplemented s +end + +function Geometry.restrict(a::MultiFieldCellField,trian::Triangulation) + f = (ai) -> restrict(ai,trian) + blocks = map(f,a.single_fields) + blocks +end + diff --git a/src/MultiField/MultiFieldCellKernels.jl b/src/MultiField/MultiFieldCellKernels.jl deleted file mode 100644 index e7ab43a51..000000000 --- a/src/MultiField/MultiFieldCellKernels.jl +++ /dev/null @@ -1,127 +0,0 @@ - -function kernel_cache(k::CellMatVecKernel,a::MultiFieldArray,b::MultiFieldArray,c...) - mat = _prepare_multifield_mat(a,b) - vec = _prepare_multifield_vec(a) - cmat = CachedMultiFieldArray(mat) - cvec = CachedMultiFieldArray(vec) - (mat, vec, cmat, cvec) -end - -@inline function apply_kernel!(cache,k::CellMatVecKernel,a::MultiFieldArray,b::MultiFieldArray,c...) - mat, vec, cmat, cvec = cache - _resize_multifield_mat!(cmat,a,b) - _resize_multifield_vec!(cvec,a) - _move_cached_arrays!(mat,cmat) - _move_cached_arrays!(vec,cvec) - z = zero(eltype(mat)) - fill!(mat,z) - fill!(vec,z) - k.op(mat,vec,a,b,c...) - (mat,vec) -end - -function kernel_cache(k::CellMatKernel,a::MultiFieldArray,b::MultiFieldArray,c...) - mat = _prepare_multifield_mat(a,b) - cmat = CachedMultiFieldArray(mat) - (mat, cmat) -end - -@inline function apply_kernel!(cache,k::CellMatKernel,a::MultiFieldArray,b::MultiFieldArray,c...) - mat, cmat = cache - _resize_multifield_mat!(cmat,a,b) - _move_cached_arrays!(mat,cmat) - z = zero(eltype(mat)) - fill!(mat,z) - k.op(mat,a,b,c...) - mat -end - -function kernel_cache(k::CellVecKernel,a::MultiFieldArray,c...) - vec = _prepare_multifield_vec(a) - cvec = CachedMultiFieldArray(vec) - (vec, cvec) -end - -@inline function apply_kernel!(cache,k::CellVecKernel,a::MultiFieldArray,c...) - vec, cvec = cache - _resize_multifield_vec!(cvec,a) - _move_cached_arrays!(vec,cvec) - z = zero(eltype(vec)) - fill!(vec,z) - k.op(vec,a,c...) - vec -end - -function _prepare_multifield_mat(a,b) - - function fun1(i,j,a,b) - ai = a.blocks[i] - bj = b.blocks[j] - Ta = eltype(ai) - Tb = eltype(bj) - T = return_type(inner,Ta,Tb) - m = size(ai,2) - n = size(bj,2) - zeros(T,m,n) - end - - function fun2(i,j,a,b) - ci, = a.coordinates[i] - cj, = b.coordinates[j] - (ci,cj) - end - - na = length(a.blocks) - nb = length(b.blocks) - blocks = [ fun1(i,j,a,b) for i in 1:na for j in 1:nb ] - coordinates = [ fun2(i,j,a,b) for i in 1:na for j in 1:nb ] - MultiFieldArray(blocks,coordinates) -end - -function _prepare_multifield_vec(a) - - function fun1(i,a) - ai = a.blocks[i] - Ta = eltype(ai) - T = return_type(inner,Ta,Ta) - m = size(ai,2) - zeros(T,m) - end - - function fun2(i,a) - ci, = a.coordinates[i] - (ci,) - end - - na = length(a.blocks) - blocks = [ fun1(i,a) for i in 1:na ] - coordinates = [ fun2(i,a) for i in 1:na ] - MultiFieldArray(blocks,coordinates) -end - -function _resize_multifield_mat!(c,a,b) - for i in 1:length(a.blocks) - for j in 1:length(b.blocks) - ai = a.blocks[i] - bj = b.blocks[j] - m = size(ai,2) - n = size(bj,2) - ci, = a.coordinates[i] - cj, = b.coordinates[j] - k = c.ptrs[ci,cj] - ck = c.blocks[k] - setsize!(ck,(m,n)) - end - end -end - -function _resize_multifield_vec!(c,a) - for i in 1:length(a.blocks) - ai = a.blocks[i] - m = size(ai,2) - ci, = a.coordinates[i] - k = c.ptrs[ci] - ck = c.blocks[k] - setsize!(ck,(m,)) - end -end diff --git a/src/MultiField/MultiFieldFEFunctions.jl b/src/MultiField/MultiFieldFEFunctions.jl index 0e847876f..170db0de7 100644 --- a/src/MultiField/MultiFieldFEFunctions.jl +++ b/src/MultiField/MultiFieldFEFunctions.jl @@ -1,58 +1,85 @@ """ - struct MultiFieldFEFunction + struct MultiFieldFEFunction <: CellField # private fields end """ -struct MultiFieldFEFunction - free_values::AbstractVector - space::MultiFieldFESpace - blocks::Vector{<:SingleFieldFEFunction} - cell_vals::MultiFieldCellArray +struct MultiFieldFEFunction{T<:MultiFieldCellField} <: CellField + single_fe_functions::Vector{<:SingleFieldFEFunction} + free_values::AbstractArray + cell_dof_values::AbstractArray + fe_space::MultiFieldFESpace + multi_cell_field::T function MultiFieldFEFunction( free_values::AbstractVector, space::MultiFieldFESpace, - blocks::Vector{<:SingleFieldFEFunction}) + single_fe_functions::Vector{<:SingleFieldFEFunction}) - _blocks = tuple(map(get_cell_values,blocks)...) - _block_ids = [ (i,) for i in 1:length(blocks) ] - cell_vals = MultiFieldCellArray(_blocks,_block_ids) + multi_cell_field = MultiFieldCellField(map(i->i.cell_field,single_fe_functions)) + T = typeof(multi_cell_field) - new(free_values,space,blocks,cell_vals) + + f(i) = get_cell_axes(get_fe_space(i)) + cell_axes = create_array_of_blocked_axes(map(f,single_fe_functions)...) + blocks = Tuple(map(get_cell_values,single_fe_functions)) + blockids = [(i,) for i in 1:length(single_fe_functions)] + cell_dof_values = VectorOfBlockArrayCoo(blocks,blockids,cell_axes) + + new{T}( + single_fe_functions, + free_values, + cell_dof_values, + space, + multi_cell_field) end end -function MultiFieldFEFunction( - space::MultiFieldFESpace, - blocks::Vector{<:SingleFieldFEFunction}) - fv = zero_free_values(space) - xh0 = MultiFieldFEFunction(fv,space,blocks) -end +#function MultiFieldFEFunction( +# space::MultiFieldFESpace, +# blocks::Vector{<:SingleFieldFEFunction}) +# fv = zero_free_values(space) +# xh0 = MultiFieldFEFunction(fv,space,blocks) +#end + +Arrays.get_array(a::MultiFieldFEFunction) = get_array(a.multi_cell_field) + +CellData.get_memo(a::MultiFieldFEFunction) = get_memo(a.multi_cell_field) + +CellData.get_cell_map(a::MultiFieldFEFunction) = get_cell_map(a.multi_cell_field) -FEFunctionStyle(::Type{MultiFieldFEFunction}) = Val{true}() +CellData.get_cell_axes(a::MultiFieldFEFunction) = get_cell_axes(a.multi_cell_field) -get_free_values(f::MultiFieldFEFunction) = f.free_values +CellData.RefStyle(::Type{<:MultiFieldFEFunction{T}}) where T = RefStyle(T) -get_fe_space(f::MultiFieldFEFunction) = f.space +CellData.MetaSizeStyle(::Type{<:MultiFieldFEFunction{T}}) where T = MetaSizeStyle(T) + +FESpaces.FEFunctionStyle(::Type{<:MultiFieldFEFunction}) = Val{true}() + +FESpaces.get_free_values(f::MultiFieldFEFunction) = f.free_values + +FESpaces.get_fe_space(f::MultiFieldFEFunction) = f.fe_space + +Base.length(f::MultiFieldFEFunction) = length(f.multi_cell_field) """ num_fields(m::MultiFieldFEFunction) """ -num_fields(m::MultiFieldFEFunction) = length(m.blocks) +num_fields(m::MultiFieldFEFunction) = length(m.single_fe_functions) -Base.iterate(m::MultiFieldFEFunction) = iterate(m.blocks) +Base.iterate(m::MultiFieldFEFunction) = iterate(m.single_fe_functions) -Base.iterate(m::MultiFieldFEFunction,state) = iterate(m.blocks,state) +Base.iterate(m::MultiFieldFEFunction,state) = iterate(m.single_fe_functions,state) -Base.getindex(m::MultiFieldFEFunction,field_id::Integer) = m.blocks[field_id] +Base.getindex(m::MultiFieldFEFunction,field_id::Integer) = m.single_fe_functions[field_id] -function restrict(a::MultiFieldFEFunction,trian::Triangulation) +function Geometry.restrict(a::MultiFieldFEFunction,trian::Triangulation) f = (ai) -> restrict(ai,trian) - blocks = map(f,a.blocks) + blocks = map(f,a.single_fe_functions) blocks end -function get_cell_values(f::MultiFieldFEFunction) - f.cell_vals +function FESpaces.get_cell_values(f::MultiFieldFEFunction) + f.cell_dof_values end + diff --git a/src/MultiField/MultiFieldFEOperators.jl b/src/MultiField/MultiFieldFEOperators.jl deleted file mode 100644 index 3ec4dd7c4..000000000 --- a/src/MultiField/MultiFieldFEOperators.jl +++ /dev/null @@ -1,66 +0,0 @@ - -function AffineFEOperator( - test::Vector{<:SingleFieldFESpace}, - trial::Vector{<:SingleFieldFESpace}, - assem::Assembler, - terms::FETerm...) - - _test = MultiFieldFESpace(test) - _trial = MultiFieldFESpace(trial) - AffineFEOperator(_test,_trial,assem,terms...) -end - -function AffineFEOperator( - test::Vector{<:SingleFieldFESpace}, - trial::Vector{<:SingleFieldFESpace}, - terms::FETerm...) - - _test = MultiFieldFESpace(test) - _trial = MultiFieldFESpace(trial) - AffineFEOperator(_test,_trial,terms...) -end - -function AffineFEOperator( - mat::Type{<:AbstractSparseMatrix}, - test::Vector{<:SingleFieldFESpace}, - trial::Vector{<:SingleFieldFESpace}, - terms::FETerm...) - - _test = MultiFieldFESpace(test) - _trial = MultiFieldFESpace(trial) - AffineFEOperator(mat,_test,_trial,terms...) -end - -function FEOperator( - test::Vector{<:SingleFieldFESpace}, - trial::Vector{<:SingleFieldFESpace}, - assem::Assembler, - terms::FETerm...) - - _test = MultiFieldFESpace(test) - _trial = MultiFieldFESpace(trial) - FEOperator(_test,_trial,assem,terms...) -end - -function FEOperator( - test::Vector{<:SingleFieldFESpace}, - trial::Vector{<:SingleFieldFESpace}, - terms::FETerm...) - - _test = MultiFieldFESpace(test) - _trial = MultiFieldFESpace(trial) - FEOperator(_test,_trial,terms...) -end - -function FEOperator( - mat::Type{<:AbstractSparseMatrix}, - test::Vector{<:SingleFieldFESpace}, - trial::Vector{<:SingleFieldFESpace}, - terms::FETerm...) - - _test = MultiFieldFESpace(test) - _trial = MultiFieldFESpace(trial) - FEOperator(mat,_test,_trial,terms...) -end - - diff --git a/src/MultiField/MultiFieldFESpaces.jl b/src/MultiField/MultiFieldFESpaces.jl index b66a8ef61..04288f30e 100644 --- a/src/MultiField/MultiFieldFESpaces.jl +++ b/src/MultiField/MultiFieldFESpaces.jl @@ -37,9 +37,9 @@ MultiFieldStyle(f::MultiFieldFESpace) = MultiFieldStyle(typeof(f)) # Implementation of FESpace -constraint_style(::Type{MultiFieldFESpace{S,B}}) where {S,B} = Val{B}() +FESpaces.constraint_style(::Type{MultiFieldFESpace{S,B}}) where {S,B} = Val{B}() -function num_free_dofs(f::MultiFieldFESpace) +function FESpaces.num_free_dofs(f::MultiFieldFESpace) n = 0 for U in f.spaces n += num_free_dofs(U) @@ -47,22 +47,30 @@ function num_free_dofs(f::MultiFieldFESpace) n end -function num_free_dofs(spaces::Vector{<:SingleFieldFESpace}) - f = MultiFieldFESpace(spaces) - num_free_dofs(f) +function FESpaces.get_cell_axes(f::MultiFieldFESpace) + all_axes = map(get_cell_axes,f.spaces) + create_array_of_blocked_axes(all_axes...) end -function get_cell_basis(f::MultiFieldFESpace) - blocks = [ get_cell_basis(U) for U in f.spaces ] - MultiCellBasis(blocks) +function FESpaces.get_cell_axes_with_constraints(f::MultiFieldFESpace) + all_axes = map(get_cell_axes_with_constraints,f.spaces) + create_array_of_blocked_axes(all_axes...) end -function get_cell_basis(spaces::Vector{<:SingleFieldFESpace}) - f = MultiFieldFESpace(spaces) - get_cell_basis(f) +function FESpaces.get_cell_basis(f::MultiFieldFESpace) + all_axes = map(i->get_cell_axes(get_cell_basis(i)),f.spaces) + all_bases = [ + _insert_cell_basis_in_block(i,get_cell_basis(f.spaces[i]),all_axes) + for i in 1:length(f.spaces) ] + MultiFieldCellField(all_bases) end -function FEFunction(fe::MultiFieldFESpace, free_values) +function _insert_cell_basis_in_block(i::Int,cb,all_axes) + array = insert_array_of_bases_in_block(i,get_array(cb),all_axes...) + similar_object(cb,array,array.axes,MetaSizeStyle(cb)) +end + +function FESpaces.FEFunction(fe::MultiFieldFESpace, free_values) blocks = SingleFieldFEFunction[] for (field, U) in enumerate(fe.spaces) free_values_i = restrict_to_field(fe,free_values,field) @@ -72,12 +80,7 @@ function FEFunction(fe::MultiFieldFESpace, free_values) MultiFieldFEFunction(free_values,fe,blocks) end -function FEFunction(spaces::Vector{<:SingleFieldFESpace}, free_values) - f = MultiFieldFESpace(spaces) - FEFunction(f,free_values) -end - -function EvaluationFunction(fe::MultiFieldFESpace, free_values) +function FESpaces.EvaluationFunction(fe::MultiFieldFESpace, free_values) blocks = SingleFieldFEFunction[] for (field, U) in enumerate(fe.spaces) free_values_i = restrict_to_field(fe,free_values,field) @@ -87,158 +90,19 @@ function EvaluationFunction(fe::MultiFieldFESpace, free_values) MultiFieldFEFunction(free_values,fe,blocks) end -function EvaluationFunction(spaces::Vector{<:SingleFieldFESpace}, free_values) - f = MultiFieldFESpace(spaces) - EvaluationFunction(f,free_values) -end - -function zero_free_values(fs::MultiFieldFESpace) - zeros(num_free_dofs(fs)) -end - -function zero_free_values(spaces::Vector{<:SingleFieldFESpace}) - f = MultiFieldFESpace(spaces) - zero_free_values(f) -end - -function get_cell_isconstrained(f::MultiFieldFESpace) - data = map(get_cell_isconstrained,f.spaces) - apply( (args...) -> args, data...) -end - -function get_cell_constraints(f::MultiFieldFESpace) - data = map(get_cell_constraints,f.spaces) - block_ids = [ (i,1) for i in 1:length(f.spaces)] - MultiFieldCellArray(tuple(data...),block_ids) -end - -function get_constraint_kernel_vector(f::MultiFieldFESpace) - MultiFieldVectorConstraintKernel() -end - -struct MultiFieldVectorConstraintKernel <: Kernel end - -function kernel_cache(k::MultiFieldVectorConstraintKernel,vec::MultiFieldArray,isconstr,constr) - v = copy(vec) - cv = CachedMultiFieldArray(v) - v,cv -end - -function apply_kernel!( - cache,k::MultiFieldVectorConstraintKernel,vec::MultiFieldArray,isconstr,constr::MultiFieldArray) - - if any(isconstr) - v, cv = cache - for iblock in 1:length(vec.blocks) - field_id, = vec.coordinates[iblock] - iconstr = constr.blocks[field_id] - n = size(iconstr,1) - setsize!(cv.blocks[iblock],(n,)) - end - _move_cached_arrays!(v,cv) - for iblock in 1:length(vec.blocks) - ivec = vec.blocks[iblock] - field_id, = vec.coordinates[iblock] - iconstr = constr.blocks[field_id] - mul!(v.blocks[iblock],iconstr,ivec) - end - return v - else - return vec - end -end - -function get_constraint_kernel_matrix_rows(f::MultiFieldFESpace) - MultiFieldMatrixRowsConstraintKernel() -end - -struct MultiFieldMatrixRowsConstraintKernel <: Kernel end - -function kernel_cache(k::MultiFieldMatrixRowsConstraintKernel,mat::MultiFieldArray,isconstr,constr) - v = copy(mat) - cv = CachedMultiFieldArray(v) - v,cv -end - -function apply_kernel!( - cache,k::MultiFieldMatrixRowsConstraintKernel,mat::MultiFieldArray,isconstr,constr::MultiFieldArray) - - if any(isconstr) - v, cv = cache - for iblock in 1:length(mat.blocks) - imat = mat.blocks[iblock] - field_id, _ = mat.coordinates[iblock] - iconstr = constr.blocks[field_id] - n = size(iconstr,1) - m = size(imat,2) - setsize!(cv.blocks[iblock],(n,m)) - end - _move_cached_arrays!(v,cv) - for iblock in 1:length(mat.blocks) - imat = mat.blocks[iblock] - field_id,_ = mat.coordinates[iblock] - iconstr = constr.blocks[field_id] - mul!(v.blocks[iblock],iconstr,imat) - end - return v - else - return mat - end -end - -function get_constraint_kernel_matrix_cols(f::MultiFieldFESpace) - MultiFieldMatrixColsConstraintKernel() -end - -struct MultiFieldMatrixColsConstraintKernel <: Kernel end - -function kernel_cache(k::MultiFieldMatrixColsConstraintKernel,mat::MultiFieldArray,isconstr,constr) - v = copy(mat) - cv = CachedMultiFieldArray(v) - v,cv +function CellData.CellField(fe::MultiFieldFESpace,cell_values) + @notimplemented end -function apply_kernel!( - cache,k::MultiFieldMatrixColsConstraintKernel,mat::MultiFieldArray,isconstr,constr::MultiFieldArray) - - if any(isconstr) - v, cv = cache - for iblock in 1:length(mat.blocks) - imat = mat.blocks[iblock] - _,field_id = mat.coordinates[iblock] - iconstr = constr.blocks[field_id] - n = size(iconstr,1) - m = size(imat,1) - setsize!(cv.blocks[iblock],(m,n)) - end - _move_cached_arrays!(v,cv) - for iblock in 1:length(mat.blocks) - imat = mat.blocks[iblock] - _,field_id = mat.coordinates[iblock] - iconstr = constr.blocks[field_id] - mul!(v.blocks[iblock],imat,Transpose(iconstr)) - end - return v - else - return mat +function CellData.CellField(fe::MultiFieldFESpace,cell_values::VectorOfBlockArrayCoo) + single_fields = CellField[] + for field in 1:num_fields(fe) + cf = CellField(fe.spaces[field],cell_values[Block(field)]) + push!(single_fields,cf) end + MultiFieldCellField(single_fields) end -# API for multi field case - -""" - num_fields(f::MultiFieldFESpace) -""" -function num_fields(f::MultiFieldFESpace) - length(f.spaces) -end - -Base.iterate(m::MultiFieldFESpace) = iterate(m.spaces) - -Base.iterate(m::MultiFieldFESpace,state) = iterate(m.spaces,state) - -Base.getindex(m::MultiFieldFESpace,field_id::Integer) = m.spaces[field_id] - """ restrict_to_field(f::MultiFieldFESpace,free_values::AbstractVector,field::Integer) """ @@ -258,7 +122,42 @@ function _restrict_to_field(f,::ConsecutiveMultiFieldStyle,free_values,field) SubVector(free_values,pini,pend) end -function get_cell_dofs(f::MultiFieldFESpace) +""" + compute_field_offsets(f::MultiFieldFESpace) +""" +function compute_field_offsets(f::MultiFieldFESpace) + @assert MultiFieldStyle(f) == ConsecutiveMultiFieldStyle() + U = f.spaces + n = length(U) + offsets = zeros(Int,n) + for i in 1:(n-1) + Ui = U[i] + offsets[i+1] = offsets[i] + num_free_dofs(Ui) + end + offsets +end + +function FESpaces.zero_free_values(fs::MultiFieldFESpace) + zeros(num_free_dofs(fs)) +end + +function FESpaces.get_cell_isconstrained(f::MultiFieldFESpace) + data = map(get_cell_isconstrained,f.spaces) + apply( (args...) -> +(args...)>0, data...) +end + +function FESpaces.get_cell_constraints(f::MultiFieldFESpace) + blocks = Tuple(map(get_cell_constraints,f.spaces)) + blockids = [ (i,i) for i in 1:length(f.spaces)] + all_axs_rows = map(get_cell_axes_with_constraints,f.spaces) + all_axs_cols = map(get_cell_axes,f.spaces) + axs_rows = create_array_of_blocked_axes(all_axs_rows...) + axs_cols = create_array_of_blocked_axes(all_axs_cols...) + axs = apply((r,c) -> (r[1],c[1]),axs_rows,axs_cols) + VectorOfBlockArrayCoo(blocks,blockids,axs) +end + +function FESpaces.get_cell_dofs(f::MultiFieldFESpace) _get_cell_dofs(f,MultiFieldStyle(f)) end @@ -266,7 +165,6 @@ function _get_cell_dofs(f,::MultiFieldStyle) @notimplemented end - function _get_cell_dofs(f,::ConsecutiveMultiFieldStyle) offsets = compute_field_offsets(f) spaces = f.spaces @@ -279,9 +177,10 @@ function _get_cell_dofs(f,::ConsecutiveMultiFieldStyle) o = Fill(offset,length(cell_dofs)) apply(elem(_sum_if_first_positive),cell_dofs,o) end - blocks = [ fun(i,space) for (i,space) in enumerate(spaces) ] - block_ids = [ (i,) for i in 1:length(spaces)] - MultiFieldCellArray(tuple(blocks...),block_ids) + blocks = Tuple([ fun(i,space) for (i,space) in enumerate(spaces) ]) + blockids = [ (i,) for i in 1:length(spaces)] + axs = get_cell_axes(f) + VectorOfBlockArrayCoo(blocks,blockids,axs) end function _sum_if_first_positive(a,b) @@ -292,33 +191,52 @@ function _sum_if_first_positive(a,b) end end -# API for the ConsecutiveMultiFieldStyle +# API for multi field case """ - compute_field_offsets(f::MultiFieldFESpace) + num_fields(f::MultiFieldFESpace) """ -function compute_field_offsets(f::MultiFieldFESpace) - @assert MultiFieldStyle(f) == ConsecutiveMultiFieldStyle() - U = f.spaces - n = length(U) - offsets = zeros(Int,n) - for i in 1:(n-1) - Ui = U[i] - offsets[i+1] = offsets[i] + num_free_dofs(Ui) - end - offsets +function num_fields(f::MultiFieldFESpace) + length(f.spaces) end +Base.iterate(m::MultiFieldFESpace) = iterate(m.spaces) + +Base.iterate(m::MultiFieldFESpace,state) = iterate(m.spaces,state) + +Base.getindex(m::MultiFieldFESpace,field_id::Integer) = m.spaces[field_id] + + +# API for the ConsecutiveMultiFieldStyle +import Gridap.FESpaces: interpolate +import Gridap.FESpaces: interpolate_everywhere +import Gridap.FESpaces: interpolate_dirichlet + +@deprecate( + interpolate(fs::MultiFieldFESpace, object), + interpolate(object, fs::MultiFieldFESpace) +) + +@deprecate( + interpolate_everywhere(fs::MultiFieldFESpace, object), + interpolate_everywhere(object, fs::MultiFieldFESpace) +) + +@deprecate( + interpolate_dirichlet(fs::MultiFieldFESpace, object), + interpolate_dirichlet(object, fs::MultiFieldFESpace) +) + """ The resulting MultiFieldFEFunction is in the space (in particular it fulfills Dirichlet BCs even in the case that the given cell field does not fulfill them) """ -function interpolate(fe::MultiFieldFESpace,objects) +function FESpaces.interpolate(objects, fe::MultiFieldFESpace) free_values = zero_free_values(fe) blocks = SingleFieldFEFunction[] for (field, (U,object)) in enumerate(zip(fe.spaces,objects)) free_values_i = restrict_to_field(fe,free_values,field) - uhi = interpolate!(free_values_i,U,object) + uhi = interpolate!(object, free_values_i,U) push!(blocks,uhi) end MultiFieldFEFunction(free_values,fe,blocks) @@ -328,13 +246,13 @@ end like interpolate, but also compute new degrees of freedom for the dirichlet component. The resulting MultiFieldFEFunction does not necessary belongs to the underlying space """ -function interpolate_everywhere(fe::MultiFieldFESpace,objects) +function FESpaces.interpolate_everywhere(objects, fe::MultiFieldFESpace) free_values = zero_free_values(fe) blocks = SingleFieldFEFunction[] for (field, (U,object)) in enumerate(zip(fe.spaces,objects)) free_values_i = restrict_to_field(fe,free_values,field) dirichlet_values_i = zero_dirichlet_values(U) - uhi = interpolate_everywhere!(free_values_i,dirichlet_values_i,U,object) + uhi = interpolate_everywhere!(object, free_values_i,dirichlet_values_i,U) push!(blocks,uhi) end MultiFieldFEFunction(free_values,fe,blocks) @@ -342,13 +260,13 @@ end """ """ -function interpolate_dirichlet(fe::MultiFieldFESpace,objects) +function FESpaces.interpolate_dirichlet(objects, fe::MultiFieldFESpace) free_values = zero_free_values(fe) blocks = SingleFieldFEFunction[] for (field, (U,object)) in enumerate(zip(fe.spaces,objects)) free_values_i = restrict_to_field(fe,free_values,field) dirichlet_values_i = zero_dirichlet_values(U) - uhi = interpolate_dirichlet!(free_values_i,dirichlet_values_i,U,object) + uhi = interpolate_dirichlet!(object, free_values_i,dirichlet_values_i,U) push!(blocks,uhi) end MultiFieldFEFunction(free_values,fe,blocks) diff --git a/src/MultiField/MultiFieldSparseMatrixAssemblers.jl b/src/MultiField/MultiFieldSparseMatrixAssemblers.jl deleted file mode 100644 index 705faaeb8..000000000 --- a/src/MultiField/MultiFieldSparseMatrixAssemblers.jl +++ /dev/null @@ -1,489 +0,0 @@ - -""" - struct MultiFieldSparseMatrixAssembler{E} <: SparseMatrixAssembler - # private fields - end -""" -struct MultiFieldSparseMatrixAssembler{M,V} <: SparseMatrixAssembler - matrix_type::Type{M} - vector_type::Type{V} - test::MultiFieldFESpace - trial::MultiFieldFESpace - strategy::AssemblyStrategy -end - -function SparseMatrixAssembler( - matrix_type::Type{<:AbstractSparseMatrix}, - vector_type::Type{<:AbstractVector}, - test::MultiFieldFESpace, - trial::MultiFieldFESpace, - strategy::AssemblyStrategy) - MultiFieldSparseMatrixAssembler(matrix_type,vector_type,test,trial,strategy) -end - -function SparseMatrixAssembler( - matrix_type::Type{<:AbstractSparseMatrix}, - vector_type::Type{<:AbstractVector}, - test::MultiFieldFESpace, - trial::MultiFieldFESpace) - strategy = DefaultAssemblyStrategy() - MultiFieldSparseMatrixAssembler(matrix_type,vector_type,test,trial,strategy) -end - -function SparseMatrixAssembler( - matrix_type::Type{<:AbstractSparseMatrix}, - test::MultiFieldFESpace, - trial::MultiFieldFESpace) - SparseMatrixAssembler(matrix_type,Vector{Float64},test,trial) -end - -function SparseMatrixAssembler( - test::MultiFieldFESpace, - trial::MultiFieldFESpace) - matrix_type = SparseMatrixCSC{Float64,Int} - SparseMatrixAssembler(matrix_type,test,trial) -end - -function SparseMatrixAssembler( - matrix_type::Type{<:AbstractSparseMatrix}, - test::Vector{<:SingleFieldFESpace}, - trial::Vector{<:SingleFieldFESpace}) - _test = MultiFieldFESpace(test) - _trial = MultiFieldFESpace(trial) - SparseMatrixAssembler(matrix_type,_test,_trial) -end - -function SparseMatrixAssembler( - test::Vector{<:SingleFieldFESpace}, - trial::Vector{<:SingleFieldFESpace}) - - matrix_type = SparseMatrixCSC{Float64,Int} - _test = MultiFieldFESpace(test) - _trial = MultiFieldFESpace(trial) - SparseMatrixAssembler(matrix_type,_test,_trial) -end - -get_test(a::MultiFieldSparseMatrixAssembler) = a.test - -get_trial(a::MultiFieldSparseMatrixAssembler) = a.trial - -get_matrix_type(a::MultiFieldSparseMatrixAssembler) = a.matrix_type - -get_vector_type(a::MultiFieldSparseMatrixAssembler) = a.vector_type - -get_assembly_strategy(a::MultiFieldSparseMatrixAssembler) = a.strategy - -function assemble_vector_add!(b,a::MultiFieldSparseMatrixAssembler,vecdata) - celldofs = get_cell_dofs(a.test) - for (cellvec, cellids) in zip(vecdata...) - rows = reindex(celldofs,cellids) - vals = apply_constraints_vector(a.test,cellvec,cellids) - rows_cache = array_cache(rows) - vals_cache = array_cache(vals) - _assemble_vector!(b,vals_cache,rows_cache,vals,rows,a.strategy) - end - b -end - -function _assemble_vector!(vec,vals_cache,rows_cache,cell_vals,cell_rows,strategy) - @assert length(cell_vals) == length(cell_rows) - for cell in 1:length(cell_rows) - _rows = getindex!(rows_cache,cell_rows,cell) - _vals = getindex!(vals_cache,cell_vals,cell) - nblocks = length(_vals.blocks) - for block in 1:nblocks - field, = _vals.coordinates[block] - vals = _vals.blocks[block] - rows = _rows.blocks[field] - for (i,gid) in enumerate(rows) - if gid > 0 && row_mask(strategy,gid) - _gid = row_map(strategy,gid) - vec[_gid] += vals[i] - end - end - end - end -end - -function count_matrix_nnz_coo(a::MultiFieldSparseMatrixAssembler,matdata) - celldofs_rows = get_cell_dofs(a.test) - celldofs_cols = get_cell_dofs(a.trial) - n = 0 - for (cellmat_rc,cellidsrows,cellidscols) in zip(matdata...) - cell_rows = reindex(celldofs_rows,cellidsrows) - cell_cols = reindex(celldofs_cols,cellidscols) - cellmat_r = apply_constraints_matrix_cols(a.trial,cellmat_rc,cellidscols) - cellmat = apply_constraints_matrix_rows(a.test,cellmat_r,cellidsrows) - rows_cache = array_cache(cell_rows) - cols_cache = array_cache(cell_cols) - @assert length(cell_cols) == length(cell_rows) - if length(cellmat) > 0 - coords = first(cellmat).coordinates - n += _count_matrix_entries(a.matrix_type,rows_cache,cols_cache,cell_rows,cell_cols,a.strategy,coords) - end - end - n -end - -function count_matrix_and_vector_nnz_coo(a::MultiFieldSparseMatrixAssembler,data) - matvecdata, matdata, vecdata = data - n = count_matrix_nnz_coo(a,matdata) - celldofs_rows = get_cell_dofs(a.test) - celldofs_cols = get_cell_dofs(a.trial) - for (cellmatvec_rc,cellidsrows,cellidscols) in zip(matvecdata...) - cell_rows = reindex(celldofs_rows,cellidsrows) - cell_cols = reindex(celldofs_cols,cellidscols) - cellmatvec_r = apply_constraints_matrix_and_vector_cols(a.trial,cellmatvec_rc,cellidscols) - cellmatvec = apply_constraints_matrix_and_vector_rows(a.test,cellmatvec_r,cellidsrows) - rows_cache = array_cache(cell_rows) - cols_cache = array_cache(cell_cols) - @assert length(cell_cols) == length(cell_rows) - if length(cellmatvec) > 0 - coords = first(cellmatvec)[1].coordinates - n += _count_matrix_entries(a.matrix_type,rows_cache,cols_cache,cell_rows,cell_cols,a.strategy,coords) - end - end - n -end - -@noinline function _count_matrix_entries(::Type{M},rows_cache,cols_cache,cell_rows,cell_cols,strategy,coords) where M - n = 0 - for cell in 1:length(cell_cols) - _rows = getindex!(rows_cache,cell_rows,cell) - _cols = getindex!(cols_cache,cell_cols,cell) - for (field_row,field_col) in coords - cols = _cols.blocks[field_col] - rows = _rows.blocks[field_row] - for gidcol in cols - if gidcol > 0 && col_mask(strategy,gidcol) - _gidcol = col_map(strategy,gidcol) - for gidrow in rows - if gidrow > 0 && row_mask(strategy,gidrow) - _gidrow = row_map(strategy,gidrow) - if is_entry_stored(M,_gidrow,_gidcol) - n += 1 - end - end - end - end - end - end - end - n -end - -function fill_matrix_coo_symbolic!(I,J,a::MultiFieldSparseMatrixAssembler,matdata,n=0) - celldofs_rows = get_cell_dofs(a.test) - celldofs_cols = get_cell_dofs(a.trial) - nini = n - for (cellmat_rc,cellidsrows,cellidscols) in zip(matdata...) - cell_rows = reindex(celldofs_rows,cellidsrows) - cell_cols = reindex(celldofs_cols,cellidscols) - cellmat_r = apply_constraints_matrix_cols(a.trial,cellmat_rc,cellidscols) - cellmat = apply_constraints_matrix_rows(a.test,cellmat_r,cellidsrows) - rows_cache = array_cache(cell_rows) - cols_cache = array_cache(cell_cols) - if length(cellmat) > 0 - coords = first(cellmat).coordinates - nini = _allocate_matrix!(a.matrix_type,nini,I,J,rows_cache,cols_cache,cell_rows,cell_cols,a.strategy,coords) - end - end - nini -end - -function fill_matrix_and_vector_coo_symbolic!(I,J,a::MultiFieldSparseMatrixAssembler,data,n=0) - matvecdata, matdata, vecdata = data - - nini = fill_matrix_coo_symbolic!(I,J,a,matdata,n) - - celldofs_rows = get_cell_dofs(a.test) - celldofs_cols = get_cell_dofs(a.trial) - for (cellmat_rc,cellidsrows,cellidscols) in zip(matvecdata...) - cell_rows = reindex(celldofs_rows,cellidsrows) - cell_cols = reindex(celldofs_cols,cellidscols) - cellmat_r = apply_constraints_matrix_and_vector_cols(a.trial,cellmat_rc,cellidscols) - cellmat = apply_constraints_matrix_and_vector_rows(a.test,cellmat_r,cellidsrows) - rows_cache = array_cache(cell_rows) - cols_cache = array_cache(cell_cols) - if length(cellmat) > 0 - coords = first(cellmat)[1].coordinates - nini = _allocate_matrix!(a.matrix_type,nini,I,J,rows_cache,cols_cache,cell_rows,cell_cols,a.strategy,coords) - end - end - nini -end - -@noinline function _allocate_matrix!( - ::Type{M},nini,I,J,rows_cache,cols_cache,cell_rows,cell_cols,strategy,coords) where M - n = nini - for cell in 1:length(cell_cols) - _rows = getindex!(rows_cache,cell_rows,cell) - _cols = getindex!(cols_cache,cell_cols,cell) - for (field_row,field_col) in coords - @inbounds cols = _cols.blocks[field_col] - @inbounds rows = _rows.blocks[field_row] - for gidcol in cols - if gidcol > 0 && col_mask(strategy,gidcol) - _gidcol = col_map(strategy,gidcol) - for gidrow in rows - if gidrow > 0 && row_mask(strategy,gidrow) - _gidrow = row_map(strategy,gidrow) - if is_entry_stored(M,_gidrow,_gidcol) - n += 1 - @inbounds I[n] = _gidrow - @inbounds J[n] = _gidcol - end - end - end - end - end - end - end - n -end - -function assemble_matrix_add!(mat,a::MultiFieldSparseMatrixAssembler, matdata) - - celldofs_rows = get_cell_dofs(a.test) - celldofs_cols = get_cell_dofs(a.trial) - for (cellmat_rc,cellidsrows,cellidscols) in zip(matdata...) - cell_rows = reindex(celldofs_rows,cellidsrows) - cell_cols = reindex(celldofs_cols,cellidscols) - cellmat_r = apply_constraints_matrix_cols(a.trial,cellmat_rc,cellidscols) - cellmat = apply_constraints_matrix_rows(a.test,cellmat_r,cellidsrows) - rows_cache = array_cache(cell_rows) - cols_cache = array_cache(cell_cols) - vals_cache = array_cache(cellmat) - _assemble_matrix!(mat,vals_cache,rows_cache,cols_cache,cellmat,cell_rows,cell_cols,a.strategy) - end - mat -end - -function _assemble_matrix!(mat,vals_cache,rows_cache,cols_cache,cell_vals,cell_rows,cell_cols,strategy) - for cell in 1:length(cell_cols) - _rows = getindex!(rows_cache,cell_rows,cell) - _cols = getindex!(cols_cache,cell_cols,cell) - _vals = getindex!(vals_cache,cell_vals,cell) - nblocks = length(_vals.blocks) - for block in 1:nblocks - field_row, field_col = _vals.coordinates[block] - vals = _vals.blocks[block] - rows = _rows.blocks[field_row] - cols = _cols.blocks[field_col] - for (j,gidcol) in enumerate(cols) - if gidcol > 0 && col_mask(strategy,gidcol) - _gidcol = col_map(strategy,gidcol) - for (i,gidrow) in enumerate(rows) - if gidrow > 0 && row_mask(strategy,gidrow) - _gidrow = row_map(strategy,gidrow) - v = vals[i,j] - add_entry!(mat,v,_gidrow,_gidcol) - end - end - end - end - end - end -end - -function fill_matrix_coo_numeric!(I,J,V,a::MultiFieldSparseMatrixAssembler,matdata,n=0) - - nini = n - celldofs_rows = get_cell_dofs(a.test) - celldofs_cols = get_cell_dofs(a.trial) - for (cellmat_rc,cellidsrows,cellidscols) in zip(matdata...) - cell_rows = reindex(celldofs_rows,cellidsrows) - cell_cols = reindex(celldofs_cols,cellidscols) - cellmat_r = apply_constraints_matrix_cols(a.trial,cellmat_rc,cellidscols) - cell_vals = apply_constraints_matrix_rows(a.test,cellmat_r,cellidsrows) - rows_cache = array_cache(cell_rows) - cols_cache = array_cache(cell_cols) - vals_cache = array_cache(cell_vals) - nini = _fill_matrix!( - a.matrix_type,nini,I,J,V,rows_cache,cols_cache,vals_cache,cell_rows,cell_cols,cell_vals,a.strategy) - end - - nini -end - -@noinline function _fill_matrix!(::Type{M},nini,I,J,V,rows_cache,cols_cache,vals_cache,cell_rows,cell_cols,cell_vals,strategy) where M - n = nini - for cell in 1:length(cell_cols) - _rows = getindex!(rows_cache,cell_rows,cell) - _cols = getindex!(cols_cache,cell_cols,cell) - _vals = getindex!(vals_cache,cell_vals,cell) - nblocks = length(_vals.blocks) - for block in 1:nblocks - field_row, field_col = _vals.coordinates[block] - vals = _vals.blocks[block] - rows = _rows.blocks[field_row] - cols = _cols.blocks[field_col] - for (j,gidcol) in enumerate(cols) - if gidcol > 0 && col_mask(strategy,gidcol) - _gidcol = col_map(strategy,gidcol) - for (i,gidrow) in enumerate(rows) - if gidrow > 0 && row_mask(strategy,gidrow) - _gidrow = row_map(strategy,gidrow) - if is_entry_stored(M,_gidrow,_gidcol) - n += 1 - @inbounds v = vals[i,j] - @inbounds I[n] = _gidrow - @inbounds J[n] = _gidcol - @inbounds V[n] = v - end - end - end - end - end - end - end - n -end - -function assemble_matrix_and_vector_add!(A,b,a::MultiFieldSparseMatrixAssembler, data) - - matvecdata, matdata, vecdata = data - celldofs_rows = get_cell_dofs(a.test) - celldofs_cols = get_cell_dofs(a.trial) - - for (cellmatvec_rc,cellidsrows,cellidscols) in zip(matvecdata...) - cell_rows = reindex(celldofs_rows,cellidsrows) - cell_cols = reindex(celldofs_cols,cellidscols) - cellmatvec_r = apply_constraints_matrix_and_vector_cols(a.trial,cellmatvec_rc,cellidscols) - cellmatvec = apply_constraints_matrix_and_vector_rows(a.test,cellmatvec_r,cellidsrows) - rows_cache = array_cache(cell_rows) - cols_cache = array_cache(cell_cols) - vals_cache = array_cache(cellmatvec) - _assemble_matrix_and_vector!(A,b,vals_cache,rows_cache,cols_cache,cellmatvec,cell_rows,cell_cols,a.strategy) - end - assemble_matrix_add!(A,a,matdata) - assemble_vector_add!(b,a,vecdata) - A, b -end - -@noinline function _assemble_matrix_and_vector!( - mat,vec,vals_cache,rows_cache,cols_cache,cell_vals,cell_rows,cell_cols,strategy) - - for cell in 1:length(cell_cols) - - _rows = getindex!(rows_cache,cell_rows,cell) - _cols = getindex!(cols_cache,cell_cols,cell) - _vals = getindex!(vals_cache,cell_vals,cell) - _valsmat, _valsvec = _vals - - nblocks = length(_valsmat.blocks) - for block in 1:nblocks - field_row, field_col = _valsmat.coordinates[block] - valsmat = _valsmat.blocks[block] - rows = _rows.blocks[field_row] - cols = _cols.blocks[field_col] - for (j,gidcol) in enumerate(cols) - if gidcol > 0 && col_mask(strategy,gidcol) - _gidcol = col_map(strategy,gidcol) - for (i,gidrow) in enumerate(rows) - if gidrow > 0 && row_mask(strategy,gidrow) - _gidrow = row_map(strategy,gidrow) - v = valsmat[i,j] - add_entry!(mat,v,_gidrow,_gidcol) - end - end - end - end - end - - nblocks = length(_valsvec.blocks) - for block in 1:nblocks - field, = _valsvec.coordinates[block] - valsvec = _valsvec.blocks[block] - rows = _rows.blocks[field] - for (i,gid) in enumerate(rows) - if gid > 0 && row_mask(strategy,gid) - _gid = row_map(strategy,gid) - vec[_gid] += valsvec[i] - end - end - end - - end -end - -function fill_matrix_and_vector_coo_numeric!(I,J,V,b,a::MultiFieldSparseMatrixAssembler,data,n=0) - - matvecdata, matdata, vecdata = data - nini = n - - celldofs_rows = get_cell_dofs(a.test) - celldofs_cols = get_cell_dofs(a.trial) - - for (cellmatvec_rc,cellidsrows,cellidscols) in zip(matvecdata...) - cell_rows = reindex(celldofs_rows,cellidsrows) - cell_cols = reindex(celldofs_cols,cellidscols) - cellmatvec_r = apply_constraints_matrix_and_vector_cols(a.trial,cellmatvec_rc,cellidscols) - cellmatvec = apply_constraints_matrix_and_vector_rows(a.test,cellmatvec_r,cellidsrows) - rows_cache = array_cache(cell_rows) - cols_cache = array_cache(cell_cols) - vals_cache = array_cache(cellmatvec) - @assert length(cell_cols) == length(cell_rows) - @assert length(cellmatvec) == length(cell_rows) - nini = _assemble_matrix_and_vector_fill!( - a.matrix_type,nini,I,J,V,b,vals_cache,rows_cache,cols_cache,cellmatvec,cell_rows,cell_cols,a.strategy) - end - - nini = fill_matrix_coo_numeric!(I,J,V,a,matdata,nini) - assemble_vector_add!(b,a,vecdata) - - nini -end - -@noinline function _assemble_matrix_and_vector_fill!( - ::Type{M},nini,I,J,V,b,vals_cache,rows_cache,cols_cache,cell_vals,cell_rows,cell_cols,strategy) where M - n = nini - for cell in 1:length(cell_cols) - - _rows = getindex!(rows_cache,cell_rows,cell) - _cols = getindex!(cols_cache,cell_cols,cell) - _vals = getindex!(vals_cache,cell_vals,cell) - _valsmat, _valsvec = _vals - - nblocks = length(_valsmat.blocks) - for block in 1:nblocks - field_row, field_col = _valsmat.coordinates[block] - valsmat = _valsmat.blocks[block] - rows = _rows.blocks[field_row] - cols = _cols.blocks[field_col] - for (j,gidcol) in enumerate(cols) - if gidcol > 0 && col_mask(strategy,gidcol) - _gidcol = col_map(strategy,gidcol) - for (i,gidrow) in enumerate(rows) - if gidrow > 0 && row_mask(strategy,gidrow) - _gidrow = row_map(strategy,gidrow) - if is_entry_stored(M,_gidrow,_gidcol) - n += 1 - @inbounds v = valsmat[i,j] - @inbounds I[n] = _gidrow - @inbounds J[n] = _gidcol - @inbounds V[n] = v - end - end - end - end - end - end - - nblocks = length(_valsvec.blocks) - for block in 1:nblocks - field, = _valsvec.coordinates[block] - valsvec = _valsvec.blocks[block] - rows = _rows.blocks[field] - for (i,gid) in enumerate(rows) - if gid > 0 && row_mask(strategy,gid) - _gid = row_map(strategy,gid) - b[_gid] += valsvec[i] - end - end - end - - end - n -end - diff --git a/src/Visualization/Visualization.jl b/src/Visualization/Visualization.jl index 9d1042ef3..8a4f9542a 100644 --- a/src/Visualization/Visualization.jl +++ b/src/Visualization/Visualization.jl @@ -38,6 +38,7 @@ using Gridap.ReferenceFEs: _find_unique_with_indices using Gridap.ReferenceFEs: SerendipityPolytope using Gridap.FESpaces using FillArrays +using Gridap.CellData import Gridap.Geometry: get_reffes import Gridap.Geometry: get_cell_type diff --git a/test/ArraysTests/BlockArraysCooTests.jl b/test/ArraysTests/BlockArraysCooTests.jl new file mode 100644 index 000000000..f270806b8 --- /dev/null +++ b/test/ArraysTests/BlockArraysCooTests.jl @@ -0,0 +1,284 @@ +module BlockArraysCooTests + +using Test +using Gridap.Arrays +using BlockArrays +using LinearAlgebra + +blocks = Matrix{Float64}[ [1 2; 3 4], [5 6; 7 8; 9 10] ] +blockids = [(1,1),(2,1)] +ax = (blockedrange([2,3]), blockedrange([2,4])) + +a = BlockArrayCoo(blocks,blockids,ax) +@test a[Block(1),Block(1)] === blocks[1] +@test a[Block(1,1)] === blocks[1] +@test a[Block(1,2)] === a.zero_blocks[1] +@test a[BlockIndex((1,1),(2,1))] === blocks[1][2,1] +@test a[BlockIndex(1,2),BlockIndex(1,1)] === blocks[1][2,1] +@test a[2,1] === blocks[1][2,1] +@test a[3,2] === blocks[2][1,2] +@test axes(a) === ax +@test size(a) == (5,6) + +@test is_zero_block(a,2,2) == true +@test is_zero_block(a,2,1) == false +@test is_nonzero_block(a,2,1) == true +@test is_zero_block(a,Block(1,2)) == true +@test is_zero_block(a,Block(1),Block(2)) == true + +for (i,b) in enumerateblocks(a) + @test a[i] === b +end + +b21 = zeros(3,2) +getblock!(b21,a,Block(2,1)) +@test b21 == a[Block(2,1)] + +b12 = ones(2,4) +getblock!(b12,a,Block(1,2)) +@test b12 == a[Block(1,2)] + +blocks = Vector{Float64}[ [1,2,3] ] +blockids = [(2,)] +ax = (blockedrange([2,3,4]),) +a = BlockArrayCoo(blocks,blockids,ax) + +@test a[Block(1)] === a.zero_blocks[1] +@test a[Block(2)] === blocks[1] +@test a[Block(3)] === a.zero_blocks[2] +@test a[BlockIndex(2,3)] === blocks[1][3] + +blocks = Matrix{Float64}[ [1 2; 3 4], [5 6 7 8; 9 10 11 12; 13 14 15 16], [1 2 3 4; 5 6 7 8], [1 2 3; 4 5 6; 7 8 9] ] +blockids = [(1,1),(2,2),(1,2),(3,3)] +ax = (blockedrange([2,3,3]), blockedrange([2,4,3])) +a = BlockArrayCoo(blocks,blockids,ax) + +blocks = Vector{Float64}[ 10*[1,2], 20*[1,2,3] ] +blockids = [(1,),(3,)] +ax = (blockedrange([2,4,3]),) +b = BlockArrayCoo(blocks,blockids,ax) + +c = a*b +@test axes(c,1) === axes(a,1) +@test blocksize(c) == (3,) +@test Array(a)*Array(b) == c + +mul!(c,a,b) +@test axes(c,1) === axes(a,1) +@test blocksize(c) == (3,) +@test Array(a)*Array(b) == c + +d = copy(c) +mul!(d,a,b,2,3) +@test axes(d,1) === axes(a,1) +@test blocksize(d) == (3,) +@test 2*Array(a)*Array(b) + 3*Array(c) == d + +b = transpose(a) +@test isa(b,BlockArrayCoo) +c = a*b +@test axes(c,1) === axes(a,1) +@test axes(c,2) === axes(a,1) +@test blocksize(c) == (3,3) +@test Array(a)*Array(b) == c + +mul!(c,a,b) +@test axes(c,1) === axes(a,1) +@test axes(c,2) === axes(a,1) +@test blocksize(c) == (3,3) +@test Array(a)*Array(b) == c + +cc = CachedArray(c) + +axs = (blockedrange([2,3,3]), blockedrange([2,3,3])) +setaxes!(cc,axs) +@test map(blocklasts,axes(cc.array)) == map(blocklasts,axs) +@test cc.array === c + +axs = (blockedrange([4,5,3]), blockedrange([2,4,3])) +setaxes!(cc,axs) +@test map(blocklasts,axes(cc.array)) == map(blocklasts,axs) +fill!(cc.array,0) + +axs = (blockedrange([5,4,3]), blockedrange([4,2,3])) +setaxes!(cc,axs) +@test map(blocklasts,axes(cc.array)) == map(blocklasts,axs) + +axs1 = (blockedrange([5,4,3]), blockedrange([4,2,3])) +axs2 = (blockedrange([4,5,3]), blockedrange([2,4,3])) +axs3 = (blockedrange([4,5,3]), blockedrange([2,4,3])) +@test Arrays._same_axes(axs1,axs2) == false +@test Arrays._same_axes(axs2,axs2) +@test Arrays._same_axes(axs2,axs3) + +blocks = [ 10*[1,2], 20*[1,2,3] ] +blockids = [(1,),(3,)] +axs = (blockedrange([2,4,3]),) +b = BlockArrayCoo(blocks,blockids,axs) + +cb = CachedArray(b) + +setaxes!(cb,axs) +@test map(blocklasts,axes(cb.array)) == map(blocklasts,axs) +@test cb.array === b + +axs = (blockedrange([3,2,3]),) +setaxes!(cb,axs) +@test map(blocklasts,axes(cb.array)) == map(blocklasts,axs) +@test size(cb) == (8,) + +c = copy(a) +@test isa(c,BlockArrayCoo) +@test c == a +@test axes(c) == axes(a) + +fill!(c,0) +copyto!(c,a) +@test c == a +@test axes(c) == axes(a) + +c = 2*a +@test isa(c,BlockArrayCoo) +@test 2*Array(a) == c + +c = a*2 +@test isa(c,BlockArrayCoo) +@test 2*Array(a) == c + +c = a + a +@test isa(c,BlockArrayCoo) +@test 2*Array(a) == c + +blocks = [ [1 2; 3 4], [5 6 7 8; 9 10 11 12; 13 14 15 16], [1 2 3 4; 5 6 7 8], [1 2 3; 4 5 6; 7 8 9] ] +blockids = [(1,1),(2,2),(1,2),(3,3)] +ax = (blockedrange([2,3,3]), blockedrange([2,4,3])) +a = BlockArrayCoo(blocks,blockids,ax) + +blocks = [ [1 2; 3 4], [1 2; 4 5; 8 9], [5 6 7 8; 9 10 11 12; 13 14 15 16] ] +blockids = [(1,1),(2,1),(3,2)] +b = BlockArrayCoo(blocks,blockids,ax) + +c = a + b +@test isa(c,BlockArrayCoo) +@test Array(a)+Array(b) == c + +c = a - 2*b +@test isa(c,BlockArrayCoo) +@test Array(a)-2*Array(b) == c + +@test a[1,2,1] == a[1,2] + +blocks = [ 10*[1,2], 20*[1,2,3] ] +blockids = [(1,),(3,)] +axs = (blockedrange([2,4,3]),) +b = BlockArrayCoo(blocks,blockids,axs) + +@test b[2] == b[2,1] + +axs = (blockedrange([2,4,3]),) + +# Blocks of Blocks + +bL = BlockArrayCoo([[1,2]],[(1,)],axs) +bR = BlockArrayCoo([[2,3],[4,5,6]],[(1,),(3,)],axs) +axs = (blockedrange([axs[1],axs[1]]),) + +bS = BlockArrayCoo([bL,bR],[(1,),(2,)],axs) + +zS = zeros_like(bS) +@test isa(zS,BlockArrayCoo) +@test isa(zS[Block(1)],BlockArrayCoo) +@test isa(zS[Block(2)],BlockArrayCoo) +@test length(zS.blocks) == 0 +@test length(zS[Block(1)].blocks) == 0 +@test length(zS[Block(2)].blocks) == 0 + +cS = 2*bS +@test isa(cS,BlockArrayCoo) +@test isa(cS[Block(1)],BlockArrayCoo) + +bZ = zeros_like(bR) + +dS = BlockArrayCoo([bZ,bR],axs,[false,true]) + +r = cS - dS +@test isa(r,BlockArrayCoo) +@test isa(r[Block(1)],BlockArrayCoo) + +r = cS + dS +@test isa(r,BlockArrayCoo) +@test isa(r[Block(1)],BlockArrayCoo) + +ax = (blockedrange([2,3]), blockedrange([2,4])) +aLL = BlockArrayCoo([[1 2; 3 4],[5 6; 7 8; 9 10] ],[(1,1),(2,1)],ax) +aLR = BlockArrayCoo([[1 2 5 6; 3 4 1 2; 1 2 3 4],[5 6; 7 8; 9 10] ],[(2,2),(2,1)],ax) +aRL = zeros_like(aLL) +aRR = BlockArrayCoo([[1 2; 3 4],[5 6; 7 8; 9 10] ],[(1,1),(2,1)],ax) + +allblocks = Matrix{typeof(aLL)}(undef,2,2) +allblocks[1,1] = aLL +allblocks[1,2] = aLR +allblocks[2,1] = aRL +allblocks[2,2] = aRR + +mask = [true true; false true] + +axs = ( blockedrange([ax[1],ax[1]]) , blockedrange([ax[2],ax[2]])) + +aS = BlockArrayCoo(allblocks,axs,mask) +@test is_zero_block(aS,2,1) +@test is_nonzero_block(aS,2,2) + +aS2 = copy(aS) +@test isa(aS2,BlockArrayCoo) +@test isa(aS2[Block(2),Block(2)],BlockArrayCoo) + +aSt = transpose(aS) +@test Array(aSt) == transpose(Array(aS)) +@test isa(aSt,BlockArrayCoo) +@test isa(aSt[Block(2),Block(2)],BlockArrayCoo) + +rS = aS*aSt +@test rS == Array(aS)*Array(aSt) +@test isa(rS,BlockArrayCoo) +@test isa(rS[Block(2),Block(2)],BlockArrayCoo) + +mul!(rS,aS,aSt) +@test rS == Array(aS)*Array(aSt) +@test isa(rS,BlockArrayCoo) +@test isa(rS[Block(2),Block(2)],BlockArrayCoo) + +axs =(blockedrange([2,4]),) +bL = BlockArrayCoo([[1,2]],[(1,)],axs) +bR = BlockArrayCoo([[2,3],[4,5,6,8]],[(1,),(2,)],axs) +bS = BlockArrayCoo([bL,bR],[(1,),(2,)],(blockedrange([6,6]),)) + +rS = aS*bS +@test rS == Array(aS)*Array(bS) +@test isa(rS,BlockArrayCoo) +@test isa(rS[Block(2)],BlockArrayCoo) + +mul!(rS,aS,bS) +@test rS == Array(aS)*Array(bS) +@test isa(rS,BlockArrayCoo) +@test isa(rS[Block(2)],BlockArrayCoo) + +cS = copy(rS) +mul!(rS,aS,bS,3,2) +@test rS == 3*Array(aS)*Array(bS) + 2*cS +@test isa(rS,BlockArrayCoo) +@test isa(rS[Block(2)],BlockArrayCoo) + +axs1 = (blockedrange([5,4,3]), blockedrange([4,2,3])) +axs2 = (blockedrange([4,5,3]), blockedrange([2,4,3])) +axsA = (blockedrange([axs1[1],axs1[1]]),blockedrange([axs2[2],axs2[2]])) +axsB = (blockedrange([axs2[1],axs2[1]]),blockedrange([axs1[2],axs1[2]])) +axsC = (blockedrange([axs2[1],axs2[1]]),blockedrange([axs1[2],axs1[2]])) +@test Arrays._same_axes(axsA,axsB) == false +@test Arrays._same_axes(axsA,axsA) +@test Arrays._same_axes(axsB,axsC) + +#using BenchmarkTools +#@btime Arrays._same_axes($axsA,$axsA) + +end # module diff --git a/test/ArraysTests/InterfaceTests.jl b/test/ArraysTests/InterfaceTests.jl index 63dc41627..b0b96d25d 100644 --- a/test/ArraysTests/InterfaceTests.jl +++ b/test/ArraysTests/InterfaceTests.jl @@ -8,4 +8,7 @@ a = rand(20,12) test_array(a,a) test_array(a,a,≈) +@test array_caches() == () +@test getitems!((),(),1) == () + end # module diff --git a/test/ArraysTests/KernelsTests.jl b/test/ArraysTests/KernelsTests.jl index 28238a484..9757e0208 100644 --- a/test/ArraysTests/KernelsTests.jl +++ b/test/ArraysTests/KernelsTests.jl @@ -4,6 +4,7 @@ using Test using Gridap.Arrays using Gridap.TensorValues using LinearAlgebra +using BlockArrays test_kernel(+,(3,2),5) @@ -41,4 +42,44 @@ c = zeros(VectorValue{3,Int},2) broadcast!(⋅,c,a,b) test_kernel(f,(a,b),c) +a = rand(3,4) +b = rand(4) +c = rand(3) +k = MulKernel() +test_kernel(k,(a,b),a*b) +k = MulAddKernel(2,3) +test_kernel(k,(a,b,c),2*a*b+3*c,≈) + +a = rand(3,4) +b = rand(4) +k = MulKernel() +test_kernel(k,(a,b),a*b) + +blocks = [ [1 2; 3 4], [5 6 7 8; 9 10 11 12; 13 14 15 16], [1 2 3 4; 5 6 7 8], [1 2 3; 4 5 6; 7 8 9] ] +blockids = [(1,1),(2,2),(1,2),(3,3)] +ax = (blockedrange([2,3,3]), blockedrange([2,4,3])) +a = BlockArrayCoo(blocks,blockids,ax) + +blocks = [ 10*[1,2], 20*[1,2,3] ] +blockids = [(1,),(3,)] +axs = (blockedrange([2,4,3]),) +b = BlockArrayCoo(blocks,blockids,axs) +test_kernel(k,(a,b),a*b) + +c = a*b +k = MulAddKernel(2,3) +test_kernel(k,(a,b,c),2*a*b+3*c) + +#k = MulKernel() +#cache = kernel_cache(k,a,b) +#using BenchmarkTools +#@btime apply_kernel!($cache,$k,$a,$b) +# +# +#k = MulAddKernel(2,3) +#cache = kernel_cache(k,a,b,c) +#@btime apply_kernel!($cache,$k,$a,$b,$c) + + + end # module diff --git a/test/ArraysTests/TablesTests.jl b/test/ArraysTests/TablesTests.jl index a61153ace..b85f206a8 100644 --- a/test/ArraysTests/TablesTests.jl +++ b/test/ArraysTests/TablesTests.jl @@ -1,6 +1,7 @@ module TablesTests using Test +using Gridap using Gridap.Arrays using Gridap.Io using JSON @@ -12,7 +13,7 @@ a = Table(data,ptrs) b = [ data[ptrs[i]:ptrs[i+1]-1] for i in 1:length(ptrs)-1] test_array(a,b) -c = convert(Table{Float64,Int32},a) +c = convert(Table{Float64,Vector{Float64},Vector{Int32}},a) test_array(c,b) data = Fill(1.3,12) @@ -21,6 +22,22 @@ d = Table(data,ptrs) e = [ data[ptrs[i]:ptrs[i+1]-1] for i in 1:length(ptrs)-1] test_array(d,e) +data = Int64[2,3,1,3,6,7,3,2,5,6,3,4] +ptrs = [1,4,4,7,13] +a = Table(data,ptrs) + +data = reinterpret(Int64,Vector{Float64}(undef,12)) +data[1:6] .= a.data[7:12] +data[7:9] .= a.data[4:6] +data[10:12] .= a.data[1:3] + +perm = Vector{Int64}(undef,12) +perm[1:3] .= 10:12 +perm[4:6] .= 7:9 +perm[7:12] .= 1:6 +data = reindex(data,perm) +b = Table(data,ptrs) +test_array(a,b) vv = Array{Array{Int,2},2}(undef,2,2) vv[1,1] = rand(1:10,2,2) @@ -124,11 +141,11 @@ ptrs = [1,4,4,7,13] a = Table(data,ptrs) dict = to_dict(a) -b = from_dict(Table{Float64,Int32},dict) +b = from_dict(Table{Float64,Vector{Float64},Vector{Int32}},dict) @test a == b s = to_json(a) -b = from_json(Table{Float64,Int32},s) +b = from_json(Table{Float64,Vector{Float64},Vector{Int32}},s) @test a == b d = mktempdir() diff --git a/test/ArraysTests/VectorsOfBlockArrayCooTests.jl b/test/ArraysTests/VectorsOfBlockArrayCooTests.jl new file mode 100644 index 000000000..6431b14cc --- /dev/null +++ b/test/ArraysTests/VectorsOfBlockArrayCooTests.jl @@ -0,0 +1,130 @@ +module VectorsOfBlockArrayCooTests + +using Test +using Gridap.Arrays +using BlockArrays +using FillArrays +using LinearAlgebra + +l = 10 +b11 = [ i*[1 2; 3 4] for i in 1:l ] +b21 = [ i*[5 6; 7 8; 9 10] for i in 1:l] +b32 = [ i*[5 6 7 8; 7 8 1 3] for i in 1:l] +blocks = (b11,b21,b32) +blockids = [(1,1),(2,1),(3,2)] +ax = Fill((blockedrange([2,3,2]), blockedrange([2,4])),l) +al = VectorOfBlockArrayCoo(blocks,blockids,ax) + +@test al[Block(1,1)] === b11 +@test al[Block(2,1)] === b21 +@test al[Block(2),Block(1)] === b21 + +@test is_zero_block(al,2,2) == true +@test is_zero_block(al,2,1) == false +@test is_nonzero_block(al,2,1) == true +@test is_zero_block(al,Block(1,2)) == true +@test is_zero_block(al,Block(1),Block(2)) == true + +@test blocksize(al) == (3,2) +@test blocksize(al,1) == 3 +@test blocksize(al,2) == 2 + +for (i,b) in enumerateblocks(al) + @test al[i] === b +end + +b1 = [ i*[3,4] for i in 1:l] +b2 = [ i*[3,4,5,6] for i in 1:l] +blocks = (b1,b2,) +blockids = [(1,),(2,)] +ax = Fill((blockedrange([2,4]),),l) +bl = VectorOfBlockArrayCoo(blocks,blockids,ax) + +b2 = [ i*[3,4,5,6] for i in 1:l] +blocks = (b2,) +blockids = [(2,)] +ax = Fill((blockedrange([2,4]),),l) +bl = VectorOfBlockArrayCoo(blocks,blockids,ax) + +c1 = [ i*[7,8] for i in 1:l] +c2 = [ i*[3,4,5] for i in 1:l] +blocks = (c1,c2) +blockids = [(1,),(2,)] +ax = Fill((blockedrange([2,3,2]),),l) +cl = VectorOfBlockArrayCoo(blocks,blockids,ax) + +dl = apply(MulKernel(),al,bl) +test_array(dl,[ a*b for (a,b) in zip(al,bl) ]) + +dl = apply(MulAddKernel(2,3),al,bl,cl) +test_array(dl,[ 2*a*b + 3*c for (a,b,c) in zip(al,bl,cl) ]) + +dl = apply(transpose,al) +test_array(dl,transpose.(al)) + +dl = apply(MulKernel(),al,apply(transpose,al)) +test_array(dl,[ a*transpose(a) for a in al ]) + +# in-homogeneous case + +l1 = 4 +l2 = 6 +a11 = vcat([i*[1 2; 3 4] for i in 1:l1 ],[i*[1 2 3; 3 4 5; 6 7 8] for i in 1:l2]) +a12 = vcat([10*i*[1 2; 3 4] for i in 1:l1 ],[10*i*[1 2 3; 3 4 5; 6 7 8] for i in 1:l2]) +blocks = (a11,a12) +blockids = [(1,1),(1,2)] +ax1 = (blockedrange([2,2]),blockedrange([2,2])) +ax2 = (blockedrange([3,3]),blockedrange([3,3])) +ax = CompressedArray([ax1,ax2],vcat(fill(1,l1),fill(2,l2))) +al = VectorOfBlockArrayCoo(blocks,blockids,ax) + +b2 = vcat([i*[1,2] for i in 1:l1 ],[i*[1,2,3] for i in 1:l2]) +blocks = (b2,) +blockids = [(2,)] +ax1 = (blockedrange([2,2]),) +ax2 = (blockedrange([3,3]),) +ax = CompressedArray([ax1,ax2],vcat(fill(1,l1),fill(2,l2))) +bl = VectorOfBlockArrayCoo(blocks,blockids,ax) + +dl = apply(MulKernel(),al,bl) +test_array(dl,[ a*b for (a,b) in zip(al,bl) ]) + +dl = apply(MulAddKernel(2,3),al,bl,bl) +test_array(dl,[ 2*a*b + 3*c for (a,b,c) in zip(al,bl,bl) ]) + +dl = apply(transpose,al) +test_array(dl,transpose.(al)) + +dl = apply(MulKernel(),al,apply(transpose,al)) +test_array(dl,[ a*transpose(a) for a in al ]) + +# Blocks of blocks (in-homogeneous case) + +blocks = (al,) +blockids = [(1,2),] +_ax1 = (blockedrange([2,2]),blockedrange([2,2])) +_ax2 = (blockedrange([3,3]),blockedrange([3,3])) +ax1 = (blockedrange([_ax1[1],_ax1[1]]),blockedrange([_ax1[2],_ax1[2]])) +ax2 = (blockedrange([_ax2[1],_ax2[1]]),blockedrange([_ax2[2],_ax2[2]])) +ax = CompressedArray([ax1,ax2],vcat(fill(1,l1),fill(2,l2))) +aBl = VectorOfBlockArrayCoo(blocks,blockids,ax) + +blocks = (bl,) +blockids = [(1,)] +_ax1 = (blockedrange([2,2]),) +_ax2 = (blockedrange([3,3]),) +ax1 = (blockedrange([_ax1[1],_ax1[1]]),) +ax2 = (blockedrange([_ax2[1],_ax2[1]]),) +ax = CompressedArray([ax1,ax2],vcat(fill(1,l1),fill(2,l2))) +bBl = VectorOfBlockArrayCoo(blocks,blockids,ax) + +dl = apply(MulKernel(),aBl,bBl) +test_array(dl,[ a*b for (a,b) in zip(aBl,bBl) ]) + +dl = apply(MulAddKernel(2,3),aBl,bBl,bBl) +test_array(dl,[ 2*a*b + 3*c for (a,b,c) in zip(aBl,bBl,bBl) ]) + +dl = apply(MulKernel(),aBl,apply(transpose,aBl)) +test_array(dl,[ a*transpose(a) for a in aBl ]) + +end # module diff --git a/test/ArraysTests/runtests.jl b/test/ArraysTests/runtests.jl index b1f6885f4..a64e6116d 100644 --- a/test/ArraysTests/runtests.jl +++ b/test/ArraysTests/runtests.jl @@ -4,6 +4,10 @@ using Test @testset "Interfaces" begin include("InterfaceTests.jl") end +@testset "BlockArraysCoo" begin include("BlockArraysCooTests.jl") end + +@testset "VectorsOfBlockArrayCoo" begin include("VectorsOfBlockArrayCooTests.jl") end + @testset "CachedArrays" begin include("CachedArraysTests.jl") end @testset "Kernels" begin include("KernelsTests.jl") end diff --git a/test/CellDataTests/AttachConstraintsTests.jl b/test/CellDataTests/AttachConstraintsTests.jl new file mode 100644 index 000000000..13d1cb1f9 --- /dev/null +++ b/test/CellDataTests/AttachConstraintsTests.jl @@ -0,0 +1,131 @@ +module AttachConstraintsTests + +using Test +using FillArrays +using LinearAlgebra +using Gridap.Helpers +using Gridap.Fields +using Gridap.ReferenceFEs +using Gridap.Arrays +using Gridap.Integration +using Gridap.CellData +using Gridap.TensorValues + +using Gridap.Fields: MockField, MockBasis, OtherMockBasis + +ncells = 10 +ndofs = 3 +ndofs_c = 4 +cellmat = [ rand(ndofs,ndofs) for cell in 1:ncells] +cellvec = [ rand(ndofs) for cell in 1:ncells] +cellmatvec = pair_arrays(cellmat,cellvec) +cellconstr = [ rand(ndofs_c,ndofs) for cell in 1:ncells] + +a = attach_constraints_rows(cellvec,cellconstr) +r = map( (vec,constr) -> constr*vec ,cellvec,cellconstr) +test_array(a,r) + +a = attach_constraints_rows(cellmat,cellconstr) +r = map( (mat,constr) -> constr*mat ,cellmat,cellconstr) +test_array(a,r) + +a = attach_constraints_rows(cellmatvec,cellconstr) +r = map( (mat,vec,constr) -> (constr*mat,constr*vec),cellmat,cellvec,cellconstr) +test_array(a,r) + +a = attach_constraints_cols(cellmat,cellconstr) +r = map( (mat,constr) -> mat*transpose(constr) ,cellmat,cellconstr) +test_array(a,r) + +a = attach_constraints_cols(cellmatvec,cellconstr) +r = map( (mat,vec,constr) -> (mat*transpose(constr),vec),cellmat,cellvec,cellconstr) +test_array(a,r) + +#cache = array_cache(a) +#using BenchmarkTools +#@btime getindex!($cache,$a,2) + +ndofs = 4 + +z = 2.0 +v = VectorValue(3.0,1.5) +w = VectorValue(3.4,3.5) +a = MockBasis{2}(v,ndofs) +b = MockBasis{2}(w,ndofs) +c = fill(1.0,ndofs) +f = OtherMockBasis{2}(ndofs) +g = MockField{2}(v) + +l = 10 +zl = [ z for i in 1:l] +cl = fill(c,l) +fl = Fill(f,l) +ϕl = lincomb(fl,cl) +gl = fill(g,l) +al = Fill(a,l) +bl = fill(b,l) + +cell_axes = Fill((Base.OneTo(ndofs),),l) +gf = GenericCellField(gl,ϕl,Val(true)) +af = GenericCellField(al,ϕl,Val(true),cell_axes,Val((:,))) +bf = GenericCellField(bl,ϕl,Val(true),cell_axes,Val((:,))) +zf = convert_to_cell_field(zl,ϕl) +df = af*zf +dft = trialize_cell_basis(df) + +degree = 3 +quad = CellQuadrature(degree,[QUAD,],ones(Int,l)) + +ndofs_c = 5 +cellconstr = [ rand(ndofs_c,ndofs) for i in 1:l] +cellvals = [ rand(ndofs) for i in 1:l] +cellvec = integrate(bf⋅v,ϕl,quad) +cellmat = integrate(∇(bf)⊙∇(dft),ϕl,quad) +cellmatvec = pair_arrays(cellmat,cellvec) +cellmatvec = attach_dirichlet(cellmatvec,cellvals) +cellmatvec = attach_constraints_rows(cellmatvec,cellconstr) +cellmatvec = attach_constraints_cols(cellmatvec,cellconstr) + +@test size(cellmatvec[1][1]) == (ndofs_c,ndofs_c) +@test size(cellmatvec[1][2]) == (ndofs_c,) + +cellconstr = identity_constraints(cell_axes) +test_array(cellconstr,Fill(Matrix(I,ndofs,ndofs),l)) +@test isa(cellconstr,Fill) + +# Test at skeleton +aS = merge_cell_fields_at_skeleton(af,af) +dSt = merge_cell_fields_at_skeleton(dft,dft) + +axesL = Fill((Base.OneTo(ndofs),),l) +axesR = axesL +cellvalsL = [ rand(ndofs) for i in 1:l] +cellvalsR = cellvalsL +cellvals = merge_cell_dofs_at_skeleton(cellvalsL,cellvalsR,axesL,axesR) +cellconstrL = [ rand(ndofs_c,ndofs) for i in 1:l] +cellconstrR = cellconstrL +axesL_rows = Fill((Base.OneTo(ndofs_c),),l) +axesR_rows = axesL_rows +axesL_cols = axesL +axesR_cols = axesR +cellconstr = merge_cell_constraints_at_skeleton(cellconstrL,cellconstrR,axesL_rows,axesR_rows,axesL_cols,axesR_cols) + +cellvec = integrate(jump(aS⋅v),ϕl,quad) +cellmat = integrate( jump(aS⋅v)*(w⋅dSt.⁻),ϕl,quad) +cellmatvec = pair_arrays(cellmat,cellvec) +cellmatvec = attach_dirichlet(cellmatvec,cellvals) +cellmatvec = attach_constraints_rows(cellmatvec,cellconstr) +cellmatvec = attach_constraints_cols(cellmatvec,cellconstr) +test_array(cellmatvec,collect(cellmatvec)) + +cellconstr = identity_constraints(cell_axes) +cellconstr = merge_cell_constraints_at_skeleton(cellconstr,cellconstr,cell_axes,cell_axes,cell_axes,cell_axes) +@test isa(cellconstr,VectorOfBlockArrayCoo) + +##a = cellmatvec +#a = cellconstr +#cache = array_cache(a) +#using BenchmarkTools +#@btime getindex!($cache,$a,2) + +end # module diff --git a/test/CellDataTests/AttachDirichletTests.jl b/test/CellDataTests/AttachDirichletTests.jl new file mode 100644 index 000000000..ec116717e --- /dev/null +++ b/test/CellDataTests/AttachDirichletTests.jl @@ -0,0 +1,39 @@ +module AttachDirichletTests + +using Gridap.Arrays +using Gridap.CellData + +ncells = 10 +ndofs = 3 +cellmat = [ rand(ndofs,ndofs) for cell in 1:ncells] +cellvec = [ rand(ndofs) for cell in 1:ncells] +cellmatvec = pair_arrays(cellmat,cellvec) +cellvals = [ rand(ndofs) for cell in 1:ncells] + +cellmatvec_with_dbc = attach_dirichlet(cellmatvec,cellvals) +r = collect(cellmatvec_with_dbc) +test_array(cellmatvec_with_dbc,r) + +r = map((mat,vec,vals)-> (mat,vec-mat*vals),cellmat,cellvec,cellvals) +a,b = unpair_arrays(cellmatvec_with_dbc) +ra,rb = unpair_arrays(r) +test_array(a,ra,≈) +test_array(b,rb,≈) + +cellmatvec_with_dbc = attach_dirichlet(cellmat,cellvals) +r = collect(cellmatvec_with_dbc) +test_array(cellmatvec_with_dbc,r) + +r = map((mat,vals)-> (mat,-mat*vals),cellmat,cellvals) +a,b = unpair_arrays(cellmatvec_with_dbc) +ra,rb = unpair_arrays(r) +test_array(a,ra,≈) +test_array(b,rb,≈) + +#a = cellmatvec_with_dbc +#cache = array_cache(a) +#using BenchmarkTools +#@btime getindex!($cache,$a,2) + + +end # module diff --git a/test/CellDataTests/CellDofBasesTests.jl b/test/CellDataTests/CellDofBasesTests.jl new file mode 100644 index 000000000..4a7338739 --- /dev/null +++ b/test/CellDataTests/CellDofBasesTests.jl @@ -0,0 +1,35 @@ +module CellDofBasesTests + +using Test +using FillArrays +using Gridap.Arrays +using Gridap.Fields +using Gridap.ReferenceFEs +using Gridap.CellData +using Gridap.Fields: MockField, OtherMockBasis +using LinearAlgebra + +reffe = QUAD4 +ndofs = 3 +b = get_shapefuns(reffe) +d = get_dof_basis(reffe) +c = fill(1.0,ndofs) +f = OtherMockBasis{2}(ndofs) + +l = 10 +bl = fill(b,l) +dl = Fill(d,l) +cl = fill(c,l) +fl = Fill(f,l) +ϕl = lincomb(fl,cl) + +ref_style = Val(true) +axs = (Base.OneTo(num_dofs(reffe)),) +cell_axes = Fill(axs,l) +cb = GenericCellField(bl,ϕl,ref_style,cell_axes) +cd = GenericCellDofBasis(ref_style,dl) +test_cell_dof_basis(cd,cb) + +@test evaluate(cd,cb) ≈ Fill(Matrix(I,num_dofs(reffe),num_dofs(reffe)),l) + +end # module diff --git a/test/CellDataTests/CellFieldsTests.jl b/test/CellDataTests/CellFieldsTests.jl new file mode 100644 index 000000000..0cc87e44f --- /dev/null +++ b/test/CellDataTests/CellFieldsTests.jl @@ -0,0 +1,105 @@ +module CellFieldsTests + +using Test +using BlockArrays +using FillArrays +using Gridap.Arrays +using Gridap.Fields +using Gridap.TensorValues +using Gridap.Fields: MockField, MockBasis, OtherMockBasis +using Gridap.CellData + +np = 3 +ndofs = 4 + +p = Point(1,2) +x = fill(p,np) +z = 2.0 + +v = VectorValue(3.0,1.5) +w = VectorValue(3.4,3.5) +a = MockBasis{2}(v,ndofs) +b = MockBasis{2}(w,ndofs) +c = fill(1.0,ndofs) +f = OtherMockBasis{2}(ndofs) + +g = MockField{2}(v) + +l = 10 +xl = Fill(x,l) +zl = [ z for i in 1:l] +cl = fill(c,l) +fl = Fill(f,l) +ϕl = lincomb(fl,cl) +gl = fill(g,l) +al = Fill(a,l) +bl = fill(b,l) + +gf = GenericCellField(gl,ϕl,Val(true)) +gf_x = evaluate(gf,xl) +∇gf_x = evaluate(∇(gf),xl) +test_cell_field(gf,xl,gf_x,grad=∇gf_x) + +af = GenericCellField(al,ϕl,Val(true),Fill((Base.OneTo(ndofs),),l),Val((:,))) +bf = GenericCellField(bl,ϕl,Val(true),Fill((Base.OneTo(ndofs),),l),Val((:,))) +zf = convert_to_cell_field(zl,ϕl) +df = af*zf +dft = trialize_cell_basis(df) + +# Check memoization +df_x1 = evaluate(df,xl) +df_x2 = evaluate(df,xl) +@test df_x1 === df_x2 +∇gf1 = ∇(gf) +∇gf2 = ∇(gf) +@test ∇gf1 === ∇gf2 +@test evaluate(∇gf1,xl) === evaluate(∇gf2,xl) +εgf1 = ε(gf) +εgf2 = ε(gf) +@test εgf1 === εgf2 +@test ∇×gf === ∇×gf +@test evaluate(∇×gf,xl) === evaluate(∇×gf,xl) + +@test is_test(af) +@test is_trial(dft) +@test is_basis(af) +@test is_basis(dft) +mf = af⋅dft +@test get_metasize(mf) == (:,:) +mf_x = evaluate(mf,xl) +@test size(mf_x[1]) == (np,ndofs,ndofs) + +@test get_cell_axes(mf) == Fill((Base.OneTo(ndofs),Base.OneTo(ndofs)),l) + +idsL = [ i*collect(1:ndofs) for i in 1:l] +idsR = [ 2*i*collect(1:ndofs) for i in 1:l] +axesL = Fill((Base.OneTo(ndofs),),l) +axesR = Fill((Base.OneTo(ndofs),),l) + +idsS = merge_cell_dofs_at_skeleton(idsL,idsR,axesL,axesR) +@test isa(idsS,VectorOfBlockArrayCoo) + +afS = merge_cell_fields_at_skeleton(af,2*af) +@test isa(afS,SkeletonCellField) + +afL_x = evaluate(afS.left,xl) +afR_x = evaluate(afS.right,xl) +@test isa(afL_x,VectorOfBlockArrayCoo) +@test isa(afR_x,VectorOfBlockArrayCoo) + +@test isa(afS*2,SkeletonCellField) +@test isa(afS+afS,SkeletonCellField) + +# Checks associated with trial bases +df = bf +dft = trialize_cell_basis(df) +@test is_trial(dft) == true +cell_vals = [rand(ndofs) for i in 1:l] +cell_field = lincomb(df,cell_vals) +@test isa(cell_field,CellField) +@test get_metasize(cell_field) == () +cell_field_x = evaluate(cell_field,xl) +@test isa(cell_field_x[1],AbstractVector) + +end # module + diff --git a/test/CellDataTests/CellQuadraturesTests.jl b/test/CellDataTests/CellQuadraturesTests.jl new file mode 100644 index 000000000..d0861ed2d --- /dev/null +++ b/test/CellDataTests/CellQuadraturesTests.jl @@ -0,0 +1,87 @@ +module CellQuadraturesTests + +using Test +using FillArrays +using Gridap.Helpers +using Gridap.Fields +using Gridap.ReferenceFEs +using Gridap.Arrays +using Gridap.Integration +using Gridap.CellData +using Gridap.TensorValues + +using Gridap.Fields: MockField, MockBasis, OtherMockBasis + +degree = 3 +quad = Quadrature(HEX,degree) +test_quadrature(quad) +@test sum(get_weights(quad)) ≈ 1 + +degree = (1,2,3) +quad = Quadrature(HEX,degree) +test_quadrature(quad) +@test sum(get_weights(quad)) ≈ 1 + +degree = 3 +quad = Quadrature(TET,degree) +test_quadrature(quad) +@test sum(get_weights(quad)) ≈ 0.5*1/3 + +l = 10 +quad = CellQuadrature(degree,[QUAD,],Fill(1,l)) +q = get_coordinates(quad) +@test isa(q,Fill) +w = get_weights(quad) +@test isa(w,Fill) + +quad = CellQuadrature(degree,[QUAD,],ones(Int,l)) +q = get_coordinates(quad) +@test isa(q,CompressedArray) +w = get_weights(quad) +@test isa(w,CompressedArray) + +ndofs = 4 + +z = 2.0 +v = VectorValue(3.0,1.5) +w = VectorValue(3.4,3.5) +a = MockBasis{2}(v,ndofs) +b = MockBasis{2}(w,ndofs) +c = fill(1.0,ndofs) +f = OtherMockBasis{2}(ndofs) +g = MockField{2}(v) + +l = 10 +zl = [ z for i in 1:l] +cl = fill(c,l) +fl = Fill(f,l) +ϕl = lincomb(fl,cl) +gl = fill(g,l) +al = Fill(a,l) +bl = fill(b,l) + +gf = GenericCellField(gl,ϕl,Val(true)) +af = GenericCellField(al,ϕl,Val(true),Fill((Base.OneTo(ndofs),),l),Val((:,))) +bf = GenericCellField(bl,ϕl,Val(true),Fill((Base.OneTo(ndofs),),l),Val((:,))) +zf = convert_to_cell_field(zl,ϕl) +df = af*zf +dft = trialize_cell_basis(df) + +@test sum(integrate(1,ϕl,quad)) ≈ 213.33333333333323 +@test sum(integrate(zl,ϕl,quad)) ≈ 426.66666666666646 + +cm = integrate(df⋅dft,ϕl,quad) +@test cm[1] ≈ fill(560.0,4,4) + +cv = integrate(df⋅v,ϕl,quad) +@test cv[1] ≈ fill(359.9999999999998,4) + +quad1 = CellQuadrature(degree,[QUAD,],Fill(1,4)) +quad2 = CellQuadrature(degree,[TRI,],Fill(1,6)) +quad = lazy_append(quad1,quad2) +@test isa(get_coordinates(quad),AppendedArray) +@test isa(get_weights(quad),AppendedArray) +@test isa(get_array(quad),AbstractArray{<:Quadrature}) +@test isa(get_array(quad),AppendedArray) + +end # module diff --git a/test/CellDataTests/LawTests.jl b/test/CellDataTests/LawTests.jl new file mode 100644 index 000000000..78f387bf6 --- /dev/null +++ b/test/CellDataTests/LawTests.jl @@ -0,0 +1,41 @@ +module LawTests + +using Test +using FillArrays +using Gridap.Arrays +using Gridap.ReferenceFEs +using Gridap.Fields +using Gridap.CellData +using Gridap.Fields: OtherMockBasis + +ndofs = num_dofs(QUAD4) +b = get_shapefuns(QUAD4) +c = fill(1,ndofs) +f = OtherMockBasis{2}(ndofs) + +ncells = 10 +cl = fill(c,ncells) +fl = Fill(f,ncells) +ϕl = lincomb(fl,cl) + +degree = 3 +quad = CellQuadrature(degree,[QUAD,],Fill(1,ncells)) +q = get_coordinates(quad) +dv = GenericCellField(Fill(b,ncells),ϕl,Val(true),Fill((Base.OneTo(ndofs),),ncells),Val((:,))) +u = convert_to_cell_field(x->x[2]^2,ϕl) + +@law g(u) = u^2 +@law h(u,dv) = (1+u)*dv + +cf = g(u) +@test isa(cf,CellField) +@test get_metasize(cf) == () +test_array(evaluate(cf,q),evaluate(operate(g,u),q),≈) + +cf = h(u,dv) +@test isa(cf,CellField) +@test get_metasize(cf) == (:,) +test_array(evaluate(cf,q),evaluate(operate(h,u,dv),q),≈) + + +end # module diff --git a/test/CellDataTests/QPointCellFieldsTests.jl b/test/CellDataTests/QPointCellFieldsTests.jl new file mode 100644 index 000000000..14579fd0c --- /dev/null +++ b/test/CellDataTests/QPointCellFieldsTests.jl @@ -0,0 +1,67 @@ +module QPointCellFieldsTests + +using Test +using FillArrays +using Gridap.Helpers +using Gridap.Fields +using Gridap.CellData +using Gridap.TensorValues +using Gridap.ReferenceFEs +using Gridap.Integration + +using Gridap.Fields: MockField, MockBasis, OtherMockBasis + +ndofs = 4 +c = fill(1.0,ndofs) +f = OtherMockBasis{2}(ndofs) + +l = 10 +cl = fill(c,l) +fl = Fill(f,l) +ϕl = lincomb(fl,cl) + +degree = 3 +quad = CellQuadrature(degree,[QUAD],Fill(1,l)) +q = get_coordinates(quad) + +s_q = [i*ones(size(qi)) for (i,qi) in enumerate(q)] +a = CellData.ArrayOfEvaluatedFields(s_q,q) +test_array_of_fields(a,q,s_q) + +v = VectorValue(3.0,4.0) +cf = QPointCellField(v,ϕl,quad) +cf_q = evaluate(cf,q) +test_cell_field(cf,q,cf_q) + +cf = CellField(v,ϕl,quad) +cf_q = evaluate(cf,q) +test_cell_field(cf,q,cf_q) + +cf = CellField(1.0,ϕl,quad) +@test sum(integrate(cf,ϕl,quad)) ≈ 213.33333333333323 + +a = CellField(1.0,ϕl,quad) +b = CellField(1.0,ϕl,quad) +c = CellField(1.0,ϕl,quad) + +function updater(a,b,c) + b_new = 2*b + c_new = 4*c + true, b_new, c_new +end + +@test evaluate(a,q)[1] == fill(1.0,4) +@test evaluate(b,q)[1] == fill(1.0,4) +@test evaluate(c,q)[1] == fill(1.0,4) + +update_state_variables!(updater,quad,a,b,c) +@test evaluate(a,q)[1] == fill(1.0,4) +@test evaluate(b,q)[1] == fill(2.0,4) +@test evaluate(c,q)[1] == fill(4.0,4) + +update_state_variables!(updater,quad,a,b,c) +@test evaluate(a,q)[1] == fill(1.0,4) +@test evaluate(b,q)[1] == fill(4.0,4) +@test evaluate(c,q)[1] == fill(16.0,4) + +end # module diff --git a/test/CellDataTests/runtests.jl b/test/CellDataTests/runtests.jl new file mode 100644 index 000000000..223259d62 --- /dev/null +++ b/test/CellDataTests/runtests.jl @@ -0,0 +1,19 @@ +module CellDataTests + +using Test + +@testset "CellFields" begin include("CellFieldsTests.jl") end + +@testset "CellQuadratures" begin include("CellQuadraturesTests.jl") end + +@testset "QPointCellFields" begin include("QPointCellFieldsTests.jl") end + +@testset "CellDofBases" begin include("CellDofBasesTests.jl") end + +@testset "AttachDirichlet" begin include("AttachDirichletTests.jl") end + +@testset "AttachConstraints" begin include("AttachConstraintsTests.jl") end + +@testset "Law" begin include("LawTests.jl") end + +end # module diff --git a/test/FESpacesTests/AffineFEOperatorsTests.jl b/test/FESpacesTests/AffineFEOperatorsTests.jl index a82df8d78..43b6e5d33 100644 --- a/test/FESpacesTests/AffineFEOperatorsTests.jl +++ b/test/FESpacesTests/AffineFEOperatorsTests.jl @@ -10,6 +10,7 @@ using Gridap.Integration using Gridap.Fields using Gridap.FESpaces using LinearAlgebra +using Gridap.CellData domain =(0,1,0,1,0,1) partition = (3,3,3) @@ -81,42 +82,4 @@ uh = solve(op) e = u_sol - uh @test sum(integrate(e*e,trian,quad)) < tol -q = get_coordinates(quad) -w_q = get_weights(quad) -ϕ = get_cell_map(trian) -jac = ∇(ϕ) -jac_q = evaluate(jac,q) -x_q = evaluate(ϕ,q) - -function poisson_matvec_kernel!(mat,vec,∇v,∇u,v,j,w,x) - Q = length(w) - M,N = size(mat) - for q in 1:Q - dV = det(j[q])*w[q] - f_q = f_fun(x[q]) - for n in 1:N - for m in 1:M - mat[m,n] += ∇v[q,m]⊙∇u[q,n]*dV - end - end - for m in 1:M - vec[m] += v[q,m]*f_q*dV - end - end -end - -function cellmatvec_Ω(v,u) - v_q = evaluate(v,q) - ∇v_q = evaluate(∇(v),q) - apply_cellmatvec(poisson_matvec_kernel!, ∇v_q, ∇v_q, v_q, jac_q, w_q, x_q) -end - -t_Ω = AffineFETermFromCellMatVec(cellmatvec_Ω,trian) - -op = AffineFEOperator(U,V,assem,t_Ω) -uh = solve(op) -e = u_sol - uh -@test sum(integrate(e*e,trian,quad)) < tol - - end # module diff --git a/test/FESpacesTests/AppendedTriangulationsTests.jl b/test/FESpacesTests/AppendedTriangulationsTests.jl new file mode 100644 index 000000000..940453202 --- /dev/null +++ b/test/FESpacesTests/AppendedTriangulationsTests.jl @@ -0,0 +1,59 @@ +module AppendedTriangulationsTests + +using Test +using Gridap.ReferenceFEs +using Gridap.Arrays +using Gridap.Geometry +using Gridap.Fields +using Gridap.Integration +using LinearAlgebra: ⋅ +using Gridap.CellData +using Gridap.FESpaces + +domain = (0,1,0,1) +partition = (10,10) +model = CartesianDiscreteModel(domain,partition) + +ncells = num_cells(model) +nin = ceil(Int,2*ncells/3) +cell_to_mask = fill(false,ncells) +cell_to_mask[1:nin] .= true + +grid = get_grid(model) + +trian_in = RestrictedTriangulation(grid,cell_to_mask) +trian_out = RestrictedTriangulation(grid,collect(Bool, .! cell_to_mask)) + +trian = lazy_append(trian_out,trian_in) +test_triangulation(trian) + +order = 1 +quad = CellQuadrature(trian,2*order) +quad_in = CellQuadrature(trian_in,2*order) +quad_out = CellQuadrature(trian_out,2*order) + +q = get_coordinates(quad) +w = get_weights(quad) +@test isa(q,AppendedArray) +@test isa(w,AppendedArray) + +V = TestFESpace(model=model,valuetype=Float64,order=order,reffe=:Lagrangian,conformity=:H1) + +u(x) = x[1]+x[2] + +_v = interpolate(u,V) +v = restrict(_v,trian) + +e = u - v +el2 = sqrt(sum(integrate(e*e,trian,quad))) +@test el2 < 1.0e-8 + +_dv = get_cell_basis(V) +dv = restrict(_dv,trian) + +cellmat = integrate(∇(dv)⋅∇(dv),trian,quad) +@test isa(cellmat,AppendedArray) +@test isa(cellmat.a,CompressedArray) +@test isa(cellmat.b,CompressedArray) + +end # module diff --git a/test/FESpacesTests/CDLagrangianFESpacesTests.jl b/test/FESpacesTests/CDLagrangianFESpacesTests.jl index f7899172c..06541fdf8 100644 --- a/test/FESpacesTests/CDLagrangianFESpacesTests.jl +++ b/test/FESpacesTests/CDLagrangianFESpacesTests.jl @@ -1,10 +1,12 @@ module CDLagrangianFESpacesTests using Test -using Gridap using Gridap.Geometry using Gridap.ReferenceFEs using Gridap.FESpaces +using Gridap.CellData +using Gridap.TensorValues +using Gridap.Fields domain =(0,1,0,1) partition = (3,3) @@ -23,7 +25,7 @@ test_single_field_fe_space(V) u(x) = x U = TrialFESpace(V,u) -uh = interpolate(U,u) +uh = interpolate(u,U) e = u - uh trian = Triangulation(model) quad = CellQuadrature(trian,order) @@ -33,7 +35,7 @@ el2 = sqrt(sum(integrate(inner(e,e),trian,quad))) reffe = LagrangianRefFE(T,QUAD,2) V = FESpace(model=model,reffe=reffe,conformity=CDConformity((CONT,DISC))) U = TrialFESpace(V,u) -uh = interpolate(U,u) +uh = interpolate(u,U) e = u - uh el2 = sqrt(sum(integrate(inner(e,e),trian,quad))) @test el2 < 1.0e-10 @@ -41,7 +43,7 @@ el2 = sqrt(sum(integrate(inner(e,e),trian,quad))) reffe = LagrangianRefFE(T,QUAD,(2,1)) V = FESpace(model=model,reffe=reffe,conformity=CDConformity((DISC,CONT))) U = TrialFESpace(V,u) -uh = interpolate(U,u) +uh = interpolate(u,U) e = u - uh el2 = sqrt(sum(integrate(inner(e,e),trian,quad))) @test el2 < 1.0e-10 @@ -50,7 +52,7 @@ reffe = LagrangianRefFE(T,QUAD,(2,0)) V = FESpace(model=model,reffe=reffe,conformity=CDConformity((CONT,DISC))) u(x) = VectorValue(x[1],0.0) U = TrialFESpace(V,u) -uh = interpolate(U,u) +uh = interpolate(u,U) e = u - uh el2 = sqrt(sum(integrate(inner(e,e),trian,quad))) @test el2 < 1.0e-10 @@ -59,7 +61,7 @@ reffe = LagrangianRefFE(T,QUAD,(2,0)) V = FESpace(model=model,reffe=reffe,conformity=CDConformity((DISC,DISC))) u(x) = VectorValue(x[1],0.0) U = TrialFESpace(V,u) -uh = interpolate(U,u) +uh = interpolate(u,U) e = u - uh el2 = sqrt(sum(integrate(inner(e,e),trian,quad))) @test el2 < 1.0e-10 diff --git a/test/FESpacesTests/CLagrangianFESpacesTests.jl b/test/FESpacesTests/CLagrangianFESpacesTests.jl index b3571d465..f46844c42 100644 --- a/test/FESpacesTests/CLagrangianFESpacesTests.jl +++ b/test/FESpacesTests/CLagrangianFESpacesTests.jl @@ -6,6 +6,7 @@ using Gridap.Geometry using Gridap.TensorValues using Gridap.Arrays using Gridap.FESpaces +using Gridap.CellData domain = (0,1,0,1) partition = (2,2) @@ -25,7 +26,7 @@ test_single_field_fe_space(V,matvecdata,matdata,vecdata) @test V.node_and_comp_to_dof == V.dof_to_node u(x) = x[1]+x[2] -uh = interpolate(V,u) +uh = interpolate(u,V) uhx = get_free_values(uh) ux = u.(x) @test uhx ≈ ux @@ -39,7 +40,7 @@ test_single_field_fe_space(V,matvecdata,matdata,vecdata) @test V.node_and_comp_to_dof == VectorValue{2,Int}[(1,2),(3,4),(5,6),(7,8),(9,10),(11,12),(13,14),(15,16),(17,18)] u(x) = VectorValue(x[1]+x[2],x[2]) -uh = interpolate(V,u) +uh = interpolate(u,V) uhx = get_free_values(uh) ux = u.(x) @test uhx ≈ collect1d(reinterpret(ux)) diff --git a/test/FESpacesTests/CellBasesTests.jl b/test/FESpacesTests/CellBasesTests.jl deleted file mode 100644 index 037af5fd5..000000000 --- a/test/FESpacesTests/CellBasesTests.jl +++ /dev/null @@ -1,224 +0,0 @@ -module CellBasesTests - -using Test -using Gridap.Arrays -using Gridap.TensorValues -using Gridap.ReferenceFEs -using Gridap.Geometry -using Gridap.Integration -using Gridap.Fields -using Gridap.FESpaces -using Gridap.FESpaces: SkeletonCellBasis -using Gridap.FESpaces: ReducedSkeletonCellBasis -using Gridap.FESpaces: SkeletonCellVector -using Gridap.FESpaces: SkeletonCellMatrixField -using Gridap.FESpaces: SkeletonCellMatrix - -using Gridap.Fields: MockField, MockBasis - -domain =(0,1,0,1) -partition = (3,3) -model = CartesianDiscreteModel(domain,partition) - -order = 2 -grid_topology = get_grid_topology(model) -polytopes = get_polytopes(grid_topology) -reffes = [LagrangianRefFE(Float64,p,order) for p in polytopes] - -dirichlet_tags = ["tag_1","tag_6"] -V0 = GradConformingFESpace(reffes,model,dirichlet_tags) - -trian = get_triangulation(model) - -degree = 2 -quad = CellQuadrature(trian,degree) -q = get_coordinates(quad) - -cell_basis = get_cell_basis(V0) - -cbx = collect(evaluate(cell_basis,q)) - -f(x) = sin(4*pi*(x[1]-x[2]^2))+1 - -uh = interpolate_everywhere(V0,f) -uhx = collect(evaluate(uh,q)) - -v = GenericCellBasis(Val{false}(),get_array(cell_basis),get_cell_map(cell_basis),Val{true}()) -u = GenericCellBasis(Val{true}(),get_array(cell_basis),get_cell_map(cell_basis),Val{true}()) - -dv = v -du = u - -a = rand(length(v)) - -r = operate(+,uh,2*uh,a) -@test isa(r,CellField) -rq = collect(evaluate(r,q)) - -r = operate(+,du,uh,a) -@test isa(r,CellBasis) -@test is_trial(r) -rq = collect(evaluate(r,q)) - -r = operate(+,uh,du,a) -@test isa(r,CellBasis) -@test is_trial(r) -rq = collect(evaluate(r,q)) - -r = operate(+,du,du,uh,a) -@test isa(r,CellBasis) -@test is_trial(r) -rq = collect(evaluate(r,q)) - -r = u*2 -test_cell_basis(r,q,2*cbx) -@test is_trial(r) -@test ! is_test(r) - -r = 2*u -test_cell_basis(r,q,2*cbx) -@test is_trial(r) - -r = u + uh -rr = [ ai .+ bi for (ai,bi) in zip(cbx,uhx)] -test_cell_basis(r,q,rr) -@test is_trial(r) - -r = v*2 -test_cell_basis(r,q,2*cbx) -@test is_test(r) -@test ! is_trial(r) - -r = 2*v -test_cell_basis(r,q,2*cbx) -@test is_test(r) - -r = v + uh -rr = [ ai .+ bi for (ai,bi) in zip(cbx,uhx)] -test_cell_basis(r,q,rr) -@test is_test(r) - -w = inner(u,v) -@test isa(w,CellMatrixField) - -w = u * v -@test isa(w,CellMatrixField) -wx = collect(evaluate(w,q)) - -s = 2*w -test_cell_matrix_field(s,q,2*wx,≈) - -s = w*2 -test_cell_matrix_field(s,q,2*wx,≈) - -s = w+w -test_cell_matrix_field(s,q,2*wx,≈) - -s = (3*w)-w -test_cell_matrix_field(s,q,2*wx,≈) - -mat = integrate(w,trian,quad) -mat = collect(mat) - -vec = integrate(v,trian,quad) -vec = collect(vec) - -mat2 = integrate(2*w,trian,quad) -test_array(mat2,2*mat) - -vec2 = integrate(2*v,trian,quad) -test_array(vec2,2*vec) - -# Testing boundary - -btrian = BoundaryTriangulation(model) -bquad = CellQuadrature(btrian,degree) -bq = get_coordinates(bquad) - -bv = restrict(v,btrian) -@test isa(bv,CellBasis) -@test is_test(bv) -bvec = integrate(bv,btrian,bquad) -bvec = collect(bvec) - -bvec2 = integrate(2*bv,btrian,bquad) -test_array(bvec2,2*bvec) - -bu = restrict(u,btrian) -@test isa(bv,CellBasis) -@test is_trial(bu) - -bw = bv * bu -@test isa(bw,CellMatrixField) -bmat = integrate(bw,btrian,bquad) -bmat = collect(bmat) - -bmat2 = integrate(bw*2,btrian,bquad) -test_array(bmat2,2*bmat) - -# Testing Skeleton - -strian = SkeletonTriangulation(model) -squad = CellQuadrature(strian,degree) -sq = get_coordinates(squad) - -sv = restrict(v,strian) -@test isa(sv,SkeletonCellBasis) -@test is_test(sv) -_sv = sv.inward -@test isa(_sv,ReducedSkeletonCellBasis) -@test is_test(_sv) -@test evaluate(sv.inward.left,sq) == evaluate(sv.left,sq) -@test evaluate(sv.outward.right,sq) == evaluate(sv.right,sq) - -_sv = sv.outward -@test isa(_sv,ReducedSkeletonCellBasis) -@test is_test(_sv) - -_sv = jump(2*∇(sv)) -@test isa(_sv,ReducedSkeletonCellBasis) -@test is_test(_sv) - -_sv = jump(∇(sv)*f) -@test isa(_sv,ReducedSkeletonCellBasis) -@test is_test(_sv) - -sv = jump(sv) -@test isa(sv,ReducedSkeletonCellBasis) -@test is_test(sv) - -su = restrict(u,strian) -@test isa(su,SkeletonCellBasis) -@test is_trial(su) - -su = jump(su) -@test isa(su,ReducedSkeletonCellBasis) -@test is_trial(su) - -svec = integrate(sv,strian,squad) -@test isa(svec,SkeletonCellVector) -svec_left = collect(svec.left) -svec_right = collect(svec.right) - -svec2 = integrate(2*sv,strian,squad) -test_array(svec2.left,2*svec_left) -test_array(svec2.right,2*svec_right) - -sw = sv * su -@test isa(sw,SkeletonCellMatrixField) - -smat = integrate(sw,strian,squad) -@test isa(smat,SkeletonCellMatrix) - -smat_ll = collect(smat.ll) -smat_lr = collect(smat.lr) -smat_rl = collect(smat.rl) -smat_rr = collect(smat.rr) - -smat2 = integrate(2*sw,strian,squad) -test_array(smat2.ll,2*smat_ll) -test_array(smat2.lr,2*smat_lr) -test_array(smat2.rl,2*smat_rl) -test_array(smat2.rr,2*smat_rr) - -end # module diff --git a/test/FESpacesTests/CellDofBasesTests.jl b/test/FESpacesTests/CellDofBasesTests.jl index a39d3ff2c..3680b36c5 100644 --- a/test/FESpacesTests/CellDofBasesTests.jl +++ b/test/FESpacesTests/CellDofBasesTests.jl @@ -5,6 +5,7 @@ using Gridap.Geometry using Gridap.FESpaces using Gridap.Arrays using Gridap.Fields +using Gridap.CellData domain =(0,1,0,1) partition = (3,3) diff --git a/test/FESpacesTests/CellKernelsTests.jl b/test/FESpacesTests/CellKernelsTests.jl deleted file mode 100644 index 8c13333cc..000000000 --- a/test/FESpacesTests/CellKernelsTests.jl +++ /dev/null @@ -1,99 +0,0 @@ -module CellKernelsTests - -using Test -using Gridap.Fields -using Gridap.Arrays -using Gridap.Geometry -using Gridap.Integration -using Gridap.FESpaces -using LinearAlgebra -using Gridap.TensorValues - -function poisson_matvec_kernel!(mat,vec,∇u,∇v,v,j,w) - Q = length(w) - M,N = size(mat) - for q in 1:Q - - dV = det(j[q])*w[q] - - for n in 1:N - for m in 1:M - mat[m,n] += ∇v[q,m]⊙∇u[q,n]*dV - end - end - - for m in 1:M - vec[m] += v[q,m]*dV - end - - end -end - -function poisson_mat_kernel!(mat,∇u,∇v,j,w) - Q = length(w) - M,N = size(mat) - for q in 1:Q - - dV = det(j[q])*w[q] - - for n in 1:N - for m in 1:M - mat[m,n] += ∇v[q,m]⊙∇u[q,n]*dV - end - end - - end -end - -function poisson_vec_kernel!(vec,v,j,w) - Q = length(w) - M = length(vec) - for q in 1:Q - - dV = det(j[q])*w[q] - - for m in 1:M - vec[m] += v[q,m]*dV - end - - end -end - -domain = (0,1,0,1) -partition = (2,2) -model = CartesianDiscreteModel(domain,partition) - -order = 1 -V = TestFESpace(model=model,valuetype=Float64,reffe=:Lagrangian,order=order,conformity=:H1) -U = TrialFESpace(V) - -trian = Triangulation(model) -quad = CellQuadrature(trian,order) - -v = get_cell_basis(V) -u = get_cell_basis(U) - -q = get_coordinates(quad) -w = get_weights(quad) -j = ∇(get_cell_map(trian)) - -v_q = evaluate(v,q) -∇v_q = evaluate(∇(v),q) -j_q = evaluate(j,q) - -cellmatvec = apply_cellmatvec(poisson_matvec_kernel!, ∇v_q, ∇v_q, v_q, j_q, w) -cellmat = apply_cellmatrix(poisson_mat_kernel!, ∇v_q, ∇v_q, j_q, w) -cellvec = apply_cellvector(poisson_vec_kernel!, v_q, j_q, w) - -a(v,u) = ∇(v)⊙∇(u) -l(v) = v - -cellmat2 = integrate(a(v,u),trian,quad) -cellvec2 = integrate(l(v),trian,quad) -cellmatvec2 = pair_arrays(cellmat2,cellvec2) - -@test cellmatvec == cellmatvec2 -@test cellmat == cellmat2 -@test cellvec == cellvec2 - -end # module diff --git a/test/FESpacesTests/CurlConformingFESpacesTests.jl b/test/FESpacesTests/CurlConformingFESpacesTests.jl index 2b81540de..dfbd44a01 100644 --- a/test/FESpacesTests/CurlConformingFESpacesTests.jl +++ b/test/FESpacesTests/CurlConformingFESpacesTests.jl @@ -1,9 +1,12 @@ module CurlConformingFESpacesTests using Test -using Gridap using LinearAlgebra using Gridap.FESpaces +using Gridap.Geometry +using Gridap.TensorValues +using Gridap.CellData +using Gridap.Fields using Gridap.ReferenceFEs domain =(0,1,0,1,0,1) @@ -28,7 +31,7 @@ test_single_field_fe_space(V) U = TrialFESpace(V,u) -uh = interpolate(U,u) +uh = interpolate(u,U) e = u - uh @@ -45,7 +48,7 @@ test_single_field_fe_space(V) U = TrialFESpace(V,u) -uh = interpolate(U,u) +uh = interpolate(u,U) el2 = sqrt(sum(integrate(inner(e,e),trian,quad))) @test el2 < 1.0e-10 diff --git a/test/FESpacesTests/DirichletFESpacesTests.jl b/test/FESpacesTests/DirichletFESpacesTests.jl index 439b73bb0..4fa5b2adf 100644 --- a/test/FESpacesTests/DirichletFESpacesTests.jl +++ b/test/FESpacesTests/DirichletFESpacesTests.jl @@ -4,6 +4,7 @@ using Test using Gridap.Algebra using Gridap.Geometry using Gridap.FESpaces +using Gridap.CellData n = 2 mesh = (n,n) diff --git a/test/FESpacesTests/DiscontinuousFESpacesTests.jl b/test/FESpacesTests/DiscontinuousFESpacesTests.jl index c5e7c517f..6238ae684 100644 --- a/test/FESpacesTests/DiscontinuousFESpacesTests.jl +++ b/test/FESpacesTests/DiscontinuousFESpacesTests.jl @@ -23,7 +23,7 @@ U = TrialFESpace(V) f(x) = sin(pi*x[1])*cos(2*pi*x[2]) -fh = interpolate(U,f) +fh = interpolate(f,U) uh = FEFunction(V,rand(num_free_dofs(V))) diff --git a/test/FESpacesTests/DivConformingFESpacesTests.jl b/test/FESpacesTests/DivConformingFESpacesTests.jl index 1c4134f15..5bbf2a52e 100644 --- a/test/FESpacesTests/DivConformingFESpacesTests.jl +++ b/test/FESpacesTests/DivConformingFESpacesTests.jl @@ -1,10 +1,12 @@ module DivConformingFESpacesTests using Test -using Gridap using Gridap.Geometry using Gridap.ReferenceFEs using Gridap.FESpaces +using Gridap.CellData +using Gridap.TensorValues +using Gridap.Fields domain =(0,1,0,1) partition = (3,3) @@ -25,7 +27,7 @@ test_single_field_fe_space(V) U = TrialFESpace(V,u) -uh = interpolate(U,u) +uh = interpolate(u,U) e = u - uh @@ -42,7 +44,7 @@ test_single_field_fe_space(V) U = TrialFESpace(V,u) -uh = interpolate(U,u) +uh = interpolate(u,U) el2 = sqrt(sum(integrate(inner(e,e),trian,quad))) @test el2 < 1.0e-10 diff --git a/test/FESpacesTests/ExtendedFESpacesTests.jl b/test/FESpacesTests/ExtendedFESpacesTests.jl index 0f2f90e20..90d596d43 100644 --- a/test/FESpacesTests/ExtendedFESpacesTests.jl +++ b/test/FESpacesTests/ExtendedFESpacesTests.jl @@ -10,6 +10,7 @@ using Gridap.FESpaces using Gridap.FESpaces: ExtendedVector using Gridap.Integration using Gridap.Fields +using Gridap.CellData oldcell_to_cell = [1,2,-1,3,-2,-3,-4] @@ -75,7 +76,6 @@ reffes = [LagrangianRefFE(VectorValue{2,Float64},get_polytope(p),order) for p in V_in = DiscontinuousFESpace(reffes,trian_in) V = ExtendedFESpace(V_in, trian_in) - test_single_field_fe_space(V) U = TrialFESpace(V) @@ -83,7 +83,7 @@ test_single_field_fe_space(U) u(x) = VectorValue(x[1]+x[2], x[1]) -uh = interpolate(U,u) +uh = interpolate(u,U) uh_in = restrict(uh,trian_in) @@ -143,9 +143,11 @@ V = TestFESpace(triangulation=trian,valuetype=Float64,reffe=:Lagrangian,order=2, V_in = TestFESpace(model=model_in,valuetype=Float64,reffe=:Lagrangian,order=2,conformity=:H1) V = TestFESpace(model=model,valuetype=Float64,reffe=:Lagrangian,order=2,conformity=:H1) -vh_in = interpolate(V_in,x->x[1]) -vh_in = interpolate(V_in,vh_in) -vh = interpolate(V,vh_in) +vh_in = interpolate(V_in) do x + x[1] +end +vh_in = interpolate(vh_in, V_in) +vh = interpolate(vh_in, V) #using Gridap.Visualization #writevtk(trian,"trian",cellfields=["vh"=>vh,"vh_in"=>vh_in]) diff --git a/test/FESpacesTests/FEAutodiffTests.jl b/test/FESpacesTests/FEAutodiffTests.jl index 9f988ab41..e9dea07a6 100644 --- a/test/FESpacesTests/FEAutodiffTests.jl +++ b/test/FESpacesTests/FEAutodiffTests.jl @@ -6,6 +6,8 @@ using Gridap.Arrays using Gridap.Fields using Gridap.Geometry using Gridap.TensorValues +using Gridap.CellData + domain = (0,1,0,1) partition = (2,2) model = CartesianDiscreteModel(domain,partition) diff --git a/test/FESpacesTests/FEFunctionsTests.jl b/test/FESpacesTests/FEFunctionsTests.jl index 19fd0f8e4..85b27783c 100644 --- a/test/FESpacesTests/FEFunctionsTests.jl +++ b/test/FESpacesTests/FEFunctionsTests.jl @@ -1,3 +1,37 @@ module FEFunctionsTests +using FillArrays +using Test +using Gridap.Arrays +using Gridap.TensorValues +using Gridap.ReferenceFEs +using Gridap.Geometry +using Gridap.FESpaces +using Gridap.CellData +using LinearAlgebra + +order = 1 +domain =(0,1,0,1) +partition = (3,3) +model = CartesianDiscreteModel(domain,partition) +grid_topology = get_grid_topology(model) +polytopes = get_polytopes(grid_topology) +reffes = [LagrangianRefFE(Float64,p,order) for p in polytopes] +dirichlet_tags = ["tag_1","tag_6"] +V = GradConformingFESpace(reffes,model,dirichlet_tags) + +vh = FEFunction(V,rand(num_free_dofs(V))) +@test is_a_fe_function(vh) +test_fe_function(vh) + +cellids = [1,3,5,2] +cell_vals = get_cell_values(vh,cellids) +@test cell_vals == reindex(get_cell_values(vh),cellids) + +cellidsL = cellids +cellidsR = [2,4,3,1] +cellidsS = SkeletonPair(cellidsL,cellidsR) +cell_vals = get_cell_values(vh,cellidsS) +@test isa(cell_vals[1],BlockArrayCoo) + end # module diff --git a/test/FESpacesTests/FEOperatorsFromTermsTests.jl b/test/FESpacesTests/FEOperatorsFromTermsTests.jl index f66bc02ce..4d00ffd22 100644 --- a/test/FESpacesTests/FEOperatorsFromTermsTests.jl +++ b/test/FESpacesTests/FEOperatorsFromTermsTests.jl @@ -10,6 +10,7 @@ using Gridap.Geometry using Gridap.Integration using Gridap.Fields using Gridap.FESpaces +using Gridap.CellData import Gridap.Fields: ∇ diff --git a/test/FESpacesTests/FESolversTests.jl b/test/FESpacesTests/FESolversTests.jl index 6c657fd0b..72a56fe07 100644 --- a/test/FESpacesTests/FESolversTests.jl +++ b/test/FESpacesTests/FESolversTests.jl @@ -9,6 +9,7 @@ using Gridap.Geometry using Gridap.Integration using Gridap.Fields using Gridap.FESpaces +using Gridap.CellData domain =(0,1,0,1,0,1) partition = (3,3,3) diff --git a/test/FESpacesTests/FESpaceFactoriesTests.jl b/test/FESpacesTests/FESpaceFactoriesTests.jl index 6a086c774..96b79904d 100644 --- a/test/FESpacesTests/FESpaceFactoriesTests.jl +++ b/test/FESpacesTests/FESpaceFactoriesTests.jl @@ -7,6 +7,7 @@ using Gridap.Arrays using Gridap.TensorValues using Gridap.ReferenceFEs using Gridap.FESpaces +using Gridap.CellData domain = (0,1,0,1) partition = (3,3) diff --git a/test/FESpacesTests/FESpacesInterfacesTests.jl b/test/FESpacesTests/FESpacesInterfacesTests.jl index 954cc4b49..2a4b1d11e 100644 --- a/test/FESpacesTests/FESpacesInterfacesTests.jl +++ b/test/FESpacesTests/FESpacesInterfacesTests.jl @@ -1,3 +1,64 @@ module FESpacesInterfacesTests +using FillArrays +using Test +using Gridap.Arrays +using Gridap.TensorValues +using Gridap.ReferenceFEs +using Gridap.Geometry +using Gridap.FESpaces +using Gridap.CellData +using LinearAlgebra + +order = 1 +domain =(0,1,0,1) +partition = (3,3) +model = CartesianDiscreteModel(domain,partition) +grid_topology = get_grid_topology(model) +polytopes = get_polytopes(grid_topology) +reffes = [LagrangianRefFE(Float64,p,order) for p in polytopes] +dirichlet_tags = ["tag_1","tag_6"] +V = GradConformingFESpace(reffes,model,dirichlet_tags) +test_fe_space(V) + +zh = zero(V) +@test is_a_fe_function(zh) +@test has_constraints(V) == false + +cellids = [1,3,5,2] +@test get_cell_dofs(V,cellids) == [[-1, 1, 4, 5], [2, 3, 6, 7], [5, 6, 9, 10], [1, 2, 5, 6]] + +cellidsL = cellids +cellidsR = [2,4,3,1] +cellidsS = SkeletonPair(cellidsL,cellidsR) +@test isa(get_cell_dofs(V,cellidsS)[1],BlockArrayCoo) +@test get_cell_dofs(V,cellidsS)[1] == [-1, 1, 4, 5, 1, 2, 5, 6] + +@test get_cell_axes(V) == get_cell_axes_with_constraints(V) + +cell_constr = get_cell_constraints(V) +@test cell_constr == [Matrix(I,4,4) for cell in 1:num_cells(model)] + +cell_constr = get_cell_constraints(V,cellids) +@test cell_constr == [Matrix(I,4,4) for cell in 1:length(cellids)] + +cell_constr = get_cell_constraints(V,cellidsS) +@test isa(cell_constr[1],BlockArrayCoo) + +@test get_cell_isconstrained(V,cellids) == Fill(false,length(cellids)) + +@test get_cell_isconstrained(V,cellidsS) == Fill(false,length(cellids)) + +cellmat = [rand(4,4) for cell in 1:num_cells(model)] +cellvec = [rand(4) for cell in 1:num_cells(model)] +cellmatvec = pair_arrays(cellmat,cellvec) +cellids = identity_vector(num_cells(model)) +matdata = (cellmat,cellids,cellids) +vecdata = (cellvec,cellids) +matvecdata = (cellmatvec,cellids,cellids) + +@test cellmat === attach_constraints_rows(V,cellmat,cellids) +@test cellmat === attach_constraints_cols(V,cellmat,cellids) +test_fe_space(V,matvecdata,matdata,vecdata) + end # module diff --git a/test/FESpacesTests/FESpacesWithLastDofRemovedTests.jl b/test/FESpacesTests/FESpacesWithLastDofRemovedTests.jl index 523644bf1..b55d7614c 100644 --- a/test/FESpacesTests/FESpacesWithLastDofRemovedTests.jl +++ b/test/FESpacesTests/FESpacesWithLastDofRemovedTests.jl @@ -21,9 +21,9 @@ V = TestFESpace( V0 = FESpaceWithLastDofRemoved(V) test_single_field_fe_space(V0) -fun(x) = sin(4*pi*(x[1]+x[2]^2)) + 3 -uh0 = interpolate(V0,fun) - +uh0 = interpolate(V0) do x + sin(4*pi*(x[1]+x[2]^2)) + 3 +end #using Gridap.Visualization # #writevtk(trian,"trian",nsubcells=20,cellfields=["uh0"=>uh0]) diff --git a/test/FESpacesTests/FESpacesWithLinearConstraintsTests.jl b/test/FESpacesTests/FESpacesWithLinearConstraintsTests.jl index 8d6e24c95..3556c6107 100644 --- a/test/FESpacesTests/FESpacesWithLinearConstraintsTests.jl +++ b/test/FESpacesTests/FESpacesWithLinearConstraintsTests.jl @@ -7,6 +7,7 @@ using Gridap.Geometry using Gridap.FESpaces using Test using LinearAlgebra +using Gridap.CellData domain = (0,1,0,1) partition = (2,2) @@ -39,6 +40,9 @@ Vc = FESpaceWithLinearConstraints( test_single_field_fe_space(Vc) @test has_constraints(Vc) +scellids = SkeletonPair([1,2,1,3],[2,4,3,4]) +@test isa(get_cell_constraints(Vc,scellids)[1],BlockArrayCoo) + @test Vc.n_fdofs == 6 @test Vc.n_fmdofs == 4 @@ -49,7 +53,7 @@ r = [[-1.0, -1.5, 1.0, 1.0], [-1.5, -2.0, 1.0, 2.0], [1.0, 1.0, 3.0, 3.5], [1.0, @test get_cell_values(vch) ≈ r v(x) = sin(4*x[1]+0.4)*cos(5*x[2]+0.7) -vch = interpolate(Vc,v) +vch = interpolate(v,Vc) #using Gridap.Visualization #writevtk(trian,"trian",nsubcells=10,cellfields=["vh"=>vh,"vch"=>vch]) @@ -58,7 +62,7 @@ u(x) = x[1] + 2*x[2] f(x) = -Δ(u)(x) Uc = TrialFESpace(Vc,u) @test has_constraints(Uc) -uch = interpolate(Uc,u) +uch = interpolate(u,Uc) btrian = BoundaryTriangulation(model,"neumann") @@ -67,12 +71,17 @@ bquad = CellQuadrature(btrian,2) bn = get_normal_vector(btrian) +strian = SkeletonTriangulation(model) +squad = CellQuadrature(strian,2) + a(u,v) = ∇(v)⋅∇(u) b1(v) = v*f b2(v) = v*(bn⋅∇(u)) +a3(u,v) = jump(u)*jump(v) t1 = AffineFETerm(a,b1,trian,quad) t2 = FESource(b2,btrian,bquad) -op = AffineFEOperator(Uc,Vc,t1,t2) +t3 = LinearFETerm(a3,strian,squad) +op = AffineFEOperator(Uc,Vc,t1,t2,t3) uch = solve(op) #using Gridap.Visualization diff --git a/test/FESpacesTests/FETermsTests.jl b/test/FESpacesTests/FETermsTests.jl index bbd7ed556..7d408fd06 100644 --- a/test/FESpacesTests/FETermsTests.jl +++ b/test/FESpacesTests/FETermsTests.jl @@ -9,6 +9,7 @@ using Gridap.Geometry using Gridap.Integration using Gridap.Fields using Gridap.FESpaces +using Gridap.CellData using LinearAlgebra domain =(0,1,0,1) @@ -40,7 +41,7 @@ assem = SparseMatrixAssembler(U,V) uhd = zero(U) v = get_cell_basis(V) u = get_cell_basis(U) -uh = interpolate(U,u_sol) +uh = interpolate(u_sol,U) a(u,v) = ∇(v)⊙∇(u) l(v) = f*v @@ -127,27 +128,10 @@ jac = ∇(ϕ) jac_q = evaluate(jac,q) x_q = evaluate(ϕ,q) -function poisson_matvec_kernel!(mat,vec,∇v,∇u,v,j,w,x) - Q = length(w) - M,N = size(mat) - for q in 1:Q - dV = det(j[q])*w[q] - f_q = f(x[q]) - for n in 1:N - for m in 1:M - mat[m,n] += ∇v[q,m]⊙∇u[q,n]*dV - end - end - for m in 1:M - vec[m] += v[q,m]*f_q*dV - end - end -end - function matvecfun(u,v) - v_q = evaluate(v,q) - ∇v_q = evaluate(∇(v),q) - apply_cellmatvec(poisson_matvec_kernel!, ∇v_q, ∇v_q, v_q, jac_q, w_q, x_q) + cellmat = integrate(∇(u)⋅∇(v),trian,quad) + cellvec = integrate(v*f,trian,quad) + pair_arrays(cellmat,cellvec) end t_matvec_Ω = AffineFETermFromCellMatVec(matvecfun,trian) @@ -165,30 +149,10 @@ assemble_matrix_and_vector!(A,b,assem,data) x = A \ b @test x ≈ get_free_values(uh) -function poisson_jacres_kernel!(jac,res,∇v,∇du,v,∇uh,j,w,x) - Q = length(w) - M,N = size(jac) - for q in 1:Q - dV = det(j[q])*w[q] - f_q = f(x[q]) - for m in 1:M - for n in 1:N - jac[m,n] += ∇v[q,m]⊙∇du[q,n]*dV - end - res[m] += ∇v[q,m]⊙∇uh[q]*dV - end - for m in 1:M - res[m] -= v[q,m]*f_q*dV - end - end -end - function jacresfun(uh,du,v) - v_q = evaluate(v,q) - ∇v_q = evaluate(∇(v),q) - ∇du_q = ∇v_q - ∇uh_q = evaluate(∇(uh),q) - apply_cellmatvec(poisson_jacres_kernel!, ∇v_q, ∇du_q, v_q, ∇uh_q, jac_q, w_q, x_q) + cellmat = integrate(∇(du)⋅∇(v),trian,quad) + cellvec = integrate(∇(uh)⋅∇(v)-v*f,trian,quad) + pair_arrays(cellmat,cellvec) end t_jacres_Ω = FETermFromCellJacRes(jacresfun,trian) diff --git a/test/FESpacesTests/FETermsWithAutodiffTests.jl b/test/FESpacesTests/FETermsWithAutodiffTests.jl index 6df63c9fa..51aef9f74 100644 --- a/test/FESpacesTests/FETermsWithAutodiffTests.jl +++ b/test/FESpacesTests/FETermsWithAutodiffTests.jl @@ -5,6 +5,7 @@ using Gridap.FESpaces using Gridap.Arrays using Gridap.Fields using Gridap.Geometry +using Gridap.CellData domain = (0,1,0,1) partition = (2,2) diff --git a/test/FESpacesTests/LawTests.jl b/test/FESpacesTests/LawTests.jl index 5e8663a8e..c8281102a 100644 --- a/test/FESpacesTests/LawTests.jl +++ b/test/FESpacesTests/LawTests.jl @@ -9,6 +9,7 @@ using Gridap.Geometry using Gridap.Integration using Gridap.Fields using Gridap.FESpaces +using Gridap.CellData #e = @macroexpand @law function l(a) # println("a is Any") @@ -42,7 +43,8 @@ r = ν(u,x) @test evaluate(r,q) == evaluate(operate(ν,u,x),q) dr = dν(du,x) -@test isa(dr,CellBasis) +@test isa(dr,CellField) +@test is_basis(dr) @test is_trial(dr) @test evaluate(dr,q) == evaluate(operate(dν,du,x),q) diff --git a/test/FESpacesTests/PhysicalBasesTests.jl b/test/FESpacesTests/PhysicalBasesTests.jl index 2ce8ecc47..d0500ce35 100644 --- a/test/FESpacesTests/PhysicalBasesTests.jl +++ b/test/FESpacesTests/PhysicalBasesTests.jl @@ -1,6 +1,6 @@ module PhysicalBasesTests -using Gridap +using FillArrays using Gridap.ReferenceFEs using Gridap.Geometry using Gridap.Arrays @@ -8,6 +8,8 @@ using Gridap.Fields using Gridap.FESpaces using Gridap.Polynomials using Gridap.Integration +using Gridap.CellData +using Gridap.TensorValues using Test # Start with a PhysicalSpaceCellBasis @@ -39,23 +41,23 @@ reffes = [LagrangianRefFE(T,p,order) for p in polytopes] dof_bases = map(get_dof_basis,reffes) -FEM = Gridap.FESpaces -cell_dof_basis = FEM._cell_dof_basis_physical_space(dof_bases,cell_to_ctype,cell_map) +cell_dof_basis = FESpaces._cell_dof_basis_physical_space(dof_bases,cell_to_ctype,cell_map) cell_dof_basis = GenericCellDofBasis(Val{false}(),cell_dof_basis) prebasis = map(get_prebasis,reffes) cell_prebasis = CompressedArray(prebasis,cell_to_ctype) -cell_prebasis_new = GenericCellBasis(Val{false}(),cell_prebasis,cell_map,Val{false}()) -typeof(cell_prebasis) -isa(cell_prebasis,CellBasis) +ncells = num_cells(model) +ndofs = num_dofs(first(reffes)) +cell_prebasis_new = GenericCellField(cell_prebasis,cell_map,Val{false}(),Fill((Base.OneTo(ndofs),),ncells),Val((:,))) + # cell_matrix = evaluate(cell_dof_basis,cell_prebasis) # cell_shapefuns = _cell_shape_functions_physical_space(cell_prebasis,cell_dof_basis,cell_map) -psfs, x = Gridap.FESpaces.compute_cell_space_physical(reffes, cell_to_ctype, cell_map) -sfs, x = Gridap.FESpaces.compute_cell_space(reffes, cell_to_ctype, cell_map) +psfs, x = FESpaces.compute_cell_space_physical(reffes, cell_to_ctype, cell_map) +sfs, x = FESpaces.compute_cell_space(reffes, cell_to_ctype, cell_map) # T = VectorValue{2,Float64} # reffes = [LagrangianRefFE(T,p,order) for p in polytopes] @@ -71,8 +73,8 @@ rgp = evaluate(gradient(psfs),q) T = VectorValue{2,Float64} reffes = [LagrangianRefFE(T,p,order) for p in polytopes] -psfs, x = Gridap.FESpaces.compute_cell_space_physical(reffes, cell_to_ctype, cell_map) -sfs, x = Gridap.FESpaces.compute_cell_space(reffes, cell_to_ctype, cell_map) +psfs, x = FESpaces.compute_cell_space_physical(reffes, cell_to_ctype, cell_map) +sfs, x = FESpaces.compute_cell_space(reffes, cell_to_ctype, cell_map) r = evaluate(sfs,q) rg = evaluate(gradient(sfs),q) @@ -93,8 +95,8 @@ T = Float64 order = 0 reffes = [RaviartThomasRefFE(T,p,order) for p in polytopes] -psfs, dofp = Gridap.FESpaces.compute_cell_space_physical(reffes, cell_to_ctype, cell_map) -sfs, dof = Gridap.FESpaces.compute_cell_space(reffes, cell_to_ctype, cell_map) +psfs, dofp = FESpaces.compute_cell_space_physical(reffes, cell_to_ctype, cell_map) +sfs, dof = FESpaces.compute_cell_space(reffes, cell_to_ctype, cell_map) r = evaluate(sfs,q) rg = evaluate(gradient(sfs),q) diff --git a/test/FESpacesTests/PhysicalFESpacesTests.jl b/test/FESpacesTests/PhysicalFESpacesTests.jl index 647026504..1532ef8cd 100644 --- a/test/FESpacesTests/PhysicalFESpacesTests.jl +++ b/test/FESpacesTests/PhysicalFESpacesTests.jl @@ -1,12 +1,13 @@ module PhysicalFESpacesTests -using Gridap using Gridap.ReferenceFEs using Gridap.Geometry using Gridap.Arrays using Gridap.Fields using Gridap.FESpaces using Gridap.Polynomials +using Gridap.CellData +using Gridap.TensorValues using Test # domain = (0,1) @@ -79,28 +80,27 @@ rp = evaluate(Up.cell_basis,q) @test all(collect(r) .≈ collect(rp)) -@test Gridap.FESpaces.RefStyle(Up.space.cell_dof_basis) == Val{false}() -@test Gridap.FESpaces.RefStyle(U.space.cell_dof_basis) == Val{true}() +@test RefStyle(Up.space.cell_dof_basis) == Val{false}() +@test RefStyle(U.space.cell_dof_basis) == Val{true}() -@test Gridap.FESpaces.RefStyle(Up.space.cell_basis) == Val{false}() -@test Gridap.FESpaces.RefStyle(U.space.cell_basis) == Val{true}() +@test RefStyle(Up.space.cell_basis) == Val{false}() +@test RefStyle(U.space.cell_basis) == Val{true}() -@test Gridap.FESpaces.RefStyle(Vp.cell_basis) == Val{false}() -@test Gridap.FESpaces.RefStyle(V.cell_basis) == Val{true}() +@test RefStyle(Vp.cell_basis) == Val{false}() +@test RefStyle(V.cell_basis) == Val{true}() -uhf = Gridap.FESpaces.interpolate(Up,u) -uhd = Gridap.FESpaces.interpolate_dirichlet(Up,u) -uhdf = Gridap.FESpaces.interpolate_everywhere(Up,u) +uhf = interpolate(u,Up) +uhd = interpolate_dirichlet(u,Up) +uhdf = interpolate_everywhere(u,Up) uhf.dirichlet_values uhdf.dirichlet_values uhd.dirichlet_values -uhf_r = Gridap.FESpaces.interpolate(U,u) -uhd_r= Gridap.FESpaces.interpolate_dirichlet(U,u) -uhdf_r = Gridap.FESpaces.interpolate_everywhere(U,u) +uhf_r = interpolate(u,U) +uhd_r= interpolate_dirichlet(u,U) +uhdf_r = interpolate_everywhere(u,U) uhd_r.dirichlet_values - @test uhf.free_values == uhf_r.free_values @test uhf.dirichlet_values == uhf_r.dirichlet_values @test uhd.dirichlet_values == uhd_r.dirichlet_values diff --git a/test/FESpacesTests/SingleFieldFESpacesTests.jl b/test/FESpacesTests/SingleFieldFESpacesTests.jl index 08cecfdee..e886c3366 100644 --- a/test/FESpacesTests/SingleFieldFESpacesTests.jl +++ b/test/FESpacesTests/SingleFieldFESpacesTests.jl @@ -25,13 +25,11 @@ test_single_field_fe_space(V0,matvecdata,matdata,vecdata) cell_map = get_cell_map(V0) -cell_shapefuns = get_cell_shapefuns(V0) - f(x) = sin(4*pi*(x[1]-x[2]^2))+1 -fh = interpolate_everywhere(V0,f) +fh = interpolate_everywhere(f, V0) -fh = interpolate_dirichlet(V0,f) +fh = interpolate_dirichlet(f, V0) dirichlet_values = compute_dirichlet_values_for_tags(V0,[1,2]) diff --git a/test/FESpacesTests/SparseMatrixAssemblersTests.jl b/test/FESpacesTests/SparseMatrixAssemblersTests.jl index 1e8045833..8a62f49e4 100644 --- a/test/FESpacesTests/SparseMatrixAssemblersTests.jl +++ b/test/FESpacesTests/SparseMatrixAssemblersTests.jl @@ -10,6 +10,7 @@ using Gridap.Fields using Gridap.Algebra using SparseArrays using Gridap.FESpaces +using Gridap.CellData domain =(0,1,0,1) partition = (2,2) @@ -77,7 +78,7 @@ for T in mtypes data = (matvecdata,matdata,vecdata) assem = SparseMatrixAssembler(T,Vector{Float64},U,V) - test_assembler(assem,matdata,vecdata,data) + test_sparse_matrix_assembler(assem,matdata,vecdata,data) matdata = ([cellmat],[cellids],[cellids]) vecdata = ([cellvec],[cellids]) @@ -125,4 +126,29 @@ for T in mtypes end +strian = SkeletonTriangulation(model) +squad = CellQuadrature(strian,degree) + +su = restrict(u,strian) +sv = restrict(v,strian) + +scellmat = integrate(jump(sv)*su.⁻,strian,squad) +scellvec = integrate(mean(sv*3),strian,squad) +scellmatvec = pair_arrays(scellmat,scellvec) +scellids = get_cell_id(strian) +zh = zero(V) +scellvals = get_cell_values(zh,scellids) +scellmatvec = attach_dirichlet(scellmatvec,scellvals) + +matvecdata = ([scellmatvec],[scellids],[scellids]) +matdata = ([scellmat],[scellids],[scellids]) +vecdata = ([scellvec],[scellids]) +data = (matvecdata,matdata,vecdata) + +assem = SparseMatrixAssembler(U,V) +test_sparse_matrix_assembler(assem,matdata,vecdata,data) + +A = assemble_matrix(assem,matdata) +@test A == zeros(num_free_dofs(V),num_free_dofs(U)) + end # module diff --git a/test/FESpacesTests/StateLawsTests.jl b/test/FESpacesTests/StateLawsTests.jl deleted file mode 100644 index b5459cbc9..000000000 --- a/test/FESpacesTests/StateLawsTests.jl +++ /dev/null @@ -1,66 +0,0 @@ -module StateLawsTests - -using Test -using Gridap.Arrays -using Gridap.Geometry -using Gridap.Integration -using Gridap.FESpaces -using Gridap.Fields - -domain = (0,1,0,1) -n = 3 -partition = (n,n) -model = CartesianDiscreteModel(domain,partition) - -order = 3 -V = TestFESpace(model=model,reffe=:Lagrangian,valuetype=Float64,order=order,conformity=:L2) -U = TrialFESpace(V) - -v = get_cell_basis(V) -du = get_cell_basis(V) -uh = FEFunction(U,rand(num_free_dofs(U))) - -@statelaw function foo(u,s,r) - w = u - w, s, r+1 -end - -trian = Triangulation(model) -degree = 2*order -quad = CellQuadrature(trian,degree) - -s = QPointCellField(0.0,trian,quad) -r = QPointCellField(0.0,trian,quad) - -wh = foo(uh,s,r) - -q = get_coordinates(quad) -wh_q = evaluate(wh,q) -uh_q = evaluate(uh,q) - - -function loop(a) - cache = array_cache(a) - for k in 1:length(a) - ak = getindex!(cache,a,k) - end -end - -r_q = evaluate(r,q) -@test r_q[end] == zeros(size(q[end])) -@test r_q[1] == zeros(size(q[1])) - -_ = testitem(wh_q) -loop(wh_q) - -@test r_q[1] == ones(size(q[1])) -@test r_q[end] == ones(size(q[end])) - -update_state_variables!(quad,foo,uh,s,r) -update_state_variables!(quad,foo,uh,s,r) - -@test r_q[1] == 3*ones(size(q[1])) -@test r_q[end] == 3*ones(size(q[end])) - - -end # module diff --git a/test/FESpacesTests/TrialFESpacesTests.jl b/test/FESpacesTests/TrialFESpacesTests.jl index 6aa452232..56341c315 100644 --- a/test/FESpacesTests/TrialFESpacesTests.jl +++ b/test/FESpacesTests/TrialFESpacesTests.jl @@ -8,6 +8,7 @@ using Gridap.Geometry using Gridap.Integration using Gridap.Fields using Gridap.FESpaces +using Gridap.CellData domain =(0,1,0,1,0,1) partition = (3,3,3) @@ -31,14 +32,11 @@ ud = compute_dirichlet_values_for_tags!(v,V,[4,3]) test_single_field_fe_space(U) U = TrialFESpace!(v,V,[4,3]) - matvecdata = ([],[],[]) matdata = ([],[],[]) vecdata = ([],[]) test_single_field_fe_space(U,matvecdata,matdata,vecdata) -uh = interpolate(U,0) - @test get_dirichlet_values(U) == [4.0, 3.0, 3.0, 3.0, 3.0, 3.0] TrialFESpace!(U,[1,2]) @test get_dirichlet_values(U) == [1.0, 2.0, 2.0, 2.0, 2.0, 2.0] @@ -54,6 +52,27 @@ U0 = HomogeneousTrialFESpace!(v,V) @test v == zeros(6) @test get_dirichlet_values(U0) == zeros(6) +u(x) = x[1] +U = TrialFESpace(V,u) +uh = interpolate(u,U) +e = u - uh +trian = Triangulation(model) +quad = CellQuadrature(trian,order) + +el2 = sqrt(sum(integrate(inner(e,e),trian,quad))) +@test el2 < 1.0e-10 + +uh = zero(U) +cellidsL = [4,2,1,3] +cellidsR = [2,4,3,1] +cellidsS = SkeletonPair(cellidsL,cellidsR) +cell_vals = get_cell_values(uh,cellidsS) +@test isa(cell_vals[1],BlockArrayCoo) + +cell_dofs = get_cell_dofs(U,cellidsS) +@test isa(cell_dofs[1],BlockArrayCoo) + + #trian = get_triangulation(model) # #using Gridap.Visualization diff --git a/test/FESpacesTests/UnconstrainedFESpacesTests.jl b/test/FESpacesTests/UnconstrainedFESpacesTests.jl index a29d3ee6c..096c24f67 100644 --- a/test/FESpacesTests/UnconstrainedFESpacesTests.jl +++ b/test/FESpacesTests/UnconstrainedFESpacesTests.jl @@ -21,12 +21,12 @@ V0 = GradConformingFESpace(reffes,model,dirichlet_tags) f(x) = sin(4*pi*(x[1]-x[2]^2))+1 -fh = interpolate(V0,f) +fh = interpolate(f,V0) @test get_dirichlet_values(fh) == get_dirichlet_values(V0) -fh = interpolate_everywhere(V0,f) +fh = interpolate_everywhere(f,V0) -fh = interpolate_dirichlet(V0,f) +fh = interpolate_dirichlet(f,V0) @test get_free_values(fh) == zero_free_values(V0) #trian = get_triangulation(model) diff --git a/test/FESpacesTests/ZeroMeanFESpacesTests.jl b/test/FESpacesTests/ZeroMeanFESpacesTests.jl index 96a1b9b7e..1669b0662 100644 --- a/test/FESpacesTests/ZeroMeanFESpacesTests.jl +++ b/test/FESpacesTests/ZeroMeanFESpacesTests.jl @@ -5,6 +5,7 @@ using Gridap.Geometry using Gridap.Fields using Gridap.Integration using Gridap.FESpaces +using Gridap.CellData domain = (0,1,0,1) partition = (4,4) @@ -36,7 +37,7 @@ test_single_field_fe_space(U,matvecdata,matdata,vecdata) @test is_trial(get_cell_basis(U)) fun(x) = sin(4*pi*(x[1]+x[2]^2)) + 3 -uh = interpolate(U,fun) +uh = interpolate(fun, U) mean1 = sum(integrate(uh,trian,quad)) diff --git a/test/FESpacesTests/runtests.jl b/test/FESpacesTests/runtests.jl index 776263b7f..a41664b9f 100644 --- a/test/FESpacesTests/runtests.jl +++ b/test/FESpacesTests/runtests.jl @@ -1,73 +1,6 @@ module FESpacesTests -using Test - -@testset "CellBases" begin include("CellBasesTests.jl") end - -@testset "CellDofBases" begin include("CellDofBasesTests.jl") end - -@testset "Law" begin include("LawTests.jl") end - -@testset "FEFunctions" begin include("FEFunctionsTests.jl") end - -@testset "FESpacesInterfaces" begin include("FESpacesInterfacesTests.jl") end - -@testset "Assemblers" begin include("AssemblersTests.jl") end - -@testset "FEOperators" begin include("FEOperatorsTests.jl") end - -@testset "SingleFieldFESpaces" begin include("SingleFieldFESpacesTests.jl") end - -@testset "SingleFieldFEFunctions" begin include("SingleFieldFEFunctionsTests.jl") end - -@testset "TrialFESpaces" begin include("TrialFESpacesTests.jl") end - -@testset "SparseMatrixAssemblers" begin include("SparseMatrixAssemblersTests.jl") end - -@testset "UnconstrainedFESpaces" begin include("UnconstrainedFESpacesTests.jl") end - -@testset "ConformingFESpaces" begin include("ConformingFESpacesTests.jl") end - -@testset "DivConformingFESpaces" begin include("DivConformingFESpacesTests.jl") end - -@testset "CurlConformingFESpaces" begin include("CurlConformingFESpacesTests.jl") end - -@testset "DiscontinuousFESpaces" begin include("DiscontinuousFESpacesTests.jl") end - -@testset "CDLagrangianFESpaces" begin include("CDLagrangianFESpacesTests.jl") end - -@testset "FETerms" begin include("FETermsTests.jl") end - -@testset "CellKernels" begin include("CellKernelsTests.jl") end - -@testset "AffineFEOperators" begin include("AffineFEOperatorsTests.jl") end - -@testset "FEOperatorsFromTerms" begin include("FEOperatorsFromTermsTests.jl") end - -@testset "FESolvers" begin include("FESolversTests.jl") end - -@testset "FESpacesWithLastDofRemoved" begin include("FESpacesWithLastDofRemovedTests.jl") end - -@testset "ZeroMeanFESpaces" begin include("ZeroMeanFESpacesTests.jl") end - -@testset "CLagrangianFESpaces" begin include("CLagrangianFESpacesTests.jl") end - -@testset "DirichletFESpaces" begin include("DirichletFESpacesTests.jl") end - -@testset "ExtendedFESpaces" begin include("ExtendedFESpacesTests.jl") end - -@testset "FESpacesWithLinearConstraints" begin include("FESpacesWithLinearConstraintsTests.jl") end - -@testset "PhysicalBasesTests" begin include("PhysicalBasesTests.jl") end - -@testset "PhysicalFESpaces" begin include("PhysicalFESpacesTests.jl") end - -@testset "FESpaceFactories" begin include("FESpaceFactoriesTests.jl") end - -@testset "StateLaws" begin include("StateLawsTests.jl") end - -@testset "FEAutodiff" begin include("FEAutodiffTests.jl") end - -@testset "FETermsWithAutodiff" begin include("FETermsWithAutodiffTests.jl") end +include("runtests_1.jl") +include("runtests_2.jl") end # module diff --git a/test/FESpacesTests/runtests_1.jl b/test/FESpacesTests/runtests_1.jl new file mode 100644 index 000000000..ee0672e91 --- /dev/null +++ b/test/FESpacesTests/runtests_1.jl @@ -0,0 +1,40 @@ +module FESpacesTests1 + +using Test + +@testset "FEFunctions" begin include("FEFunctionsTests.jl") end + +@testset "FESpacesInterfaces" begin include("FESpacesInterfacesTests.jl") end + +@testset "SingleFieldFESpaces" begin include("SingleFieldFESpacesTests.jl") end + +@testset "SingleFieldFEFunctions" begin include("SingleFieldFEFunctionsTests.jl") end + +@testset "UnconstrainedFESpaces" begin include("UnconstrainedFESpacesTests.jl") end + +@testset "ConformingFESpaces" begin include("ConformingFESpacesTests.jl") end + +@testset "TrialFESpaces" begin include("TrialFESpacesTests.jl") end + +@testset "DivConformingFESpaces" begin include("DivConformingFESpacesTests.jl") end + +@testset "CurlConformingFESpaces" begin include("CurlConformingFESpacesTests.jl") end + +@testset "DiscontinuousFESpaces" begin include("DiscontinuousFESpacesTests.jl") end + +@testset "Assemblers" begin include("AssemblersTests.jl") end + +@testset "SparseMatrixAssemblers" begin include("SparseMatrixAssemblersTests.jl") end + +@testset "FETerms" begin include("FETermsTests.jl") end + +@testset "FEOperators" begin include("FEOperatorsTests.jl") end + +@testset "AffineFEOperators" begin include("AffineFEOperatorsTests.jl") end + +@testset "FEOperatorsFromTerms" begin include("FEOperatorsFromTermsTests.jl") end + +@testset "FESolvers" begin include("FESolversTests.jl") end + + +end # module diff --git a/test/FESpacesTests/runtests_2.jl b/test/FESpacesTests/runtests_2.jl new file mode 100644 index 000000000..2e1a9f740 --- /dev/null +++ b/test/FESpacesTests/runtests_2.jl @@ -0,0 +1,35 @@ +module FESpacesTests2 + +using Test + +@testset "FESpacesWithLastDofRemoved" begin include("FESpacesWithLastDofRemovedTests.jl") end + +@testset "ZeroMeanFESpaces" begin include("ZeroMeanFESpacesTests.jl") end + +@testset "CLagrangianFESpaces" begin include("CLagrangianFESpacesTests.jl") end + +@testset "DirichletFESpaces" begin include("DirichletFESpacesTests.jl") end + +@testset "ExtendedFESpaces" begin include("ExtendedFESpacesTests.jl") end + +@testset "FESpacesWithLinearConstraints" begin include("FESpacesWithLinearConstraintsTests.jl") end + +@testset "FEAutodiff" begin include("FEAutodiffTests.jl") end + +@testset "FETermsWithAutodiff" begin include("FETermsWithAutodiffTests.jl") end + +@testset "CellDofBases" begin include("CellDofBasesTests.jl") end + +@testset "Law" begin include("LawTests.jl") end + +@testset "CDLagrangianFESpaces" begin include("CDLagrangianFESpacesTests.jl") end + +@testset "PhysicalBasesTests" begin include("PhysicalBasesTests.jl") end + +@testset "PhysicalFESpaces" begin include("PhysicalFESpacesTests.jl") end + +@testset "FESpaceFactories" begin include("FESpaceFactoriesTests.jl") end + +@testset "AppendedTriangulations" begin include("AppendedTriangulationsTests.jl") end + +end # module diff --git a/test/FieldsTests/CellFieldsTests.jl b/test/FieldsTests/CellFieldsTests.jl new file mode 100644 index 000000000..c3dc0ddf0 --- /dev/null +++ b/test/FieldsTests/CellFieldsTests.jl @@ -0,0 +1,96 @@ +module CellFieldsTests + +#This is a first steps to decouple CellFields from the Geometry + +using Test +using BlockArrays +using FillArrays +using Gridap.Arrays +using Gridap.Fields +using Gridap.Fields: IntKernel +using Gridap.Fields: FieldOpKernel +using Gridap.Fields: trialize_basis_value +using Gridap.TensorValues +using Gridap.Fields: MockField, MockBasis, OtherMockBasis + +# In this furure all this shoul be exported from Fields +using Gridap.Geometry: GenericCellField, get_cell_axes +using Gridap.Geometry: convert_to_cell_field, get_metasize +using Gridap.Geometry: CellField, similar_object, trialize_cell_basis +using Gridap.Geometry: merge_skeleton_dof_ids, merge_skeleton_cell_fields +using Gridap.Geometry: is_basis, is_test, is_trial + +np = 3 +ndofs = 4 + +p = Point(1,2) +x = fill(p,np) +z = 2.0 + +v = VectorValue(3.0,1.5) +w = VectorValue(3.4,3.5) +a = MockBasis{2}(v,ndofs) +b = MockBasis{2}(w,ndofs) +c = fill(1.0,ndofs) +f = OtherMockBasis{2}(ndofs) + +g = MockField{2}(v) + +l = 10 +xl = Fill(x,l) +zl = [ z for i in 1:l] +cl = fill(c,l) +fl = Fill(f,l) +ϕl = lincomb(fl,cl) +gl = fill(g,l) +al = Fill(a,l) +bl = fill(b,l) + +gf = GenericCellField(gl,ϕl,Val(true)) +af = GenericCellField(al,ϕl,Val(true),Fill((Base.OneTo(ndofs),),l),Val((:,))) +bf = GenericCellField(bl,ϕl,Val(true),Fill((Base.OneTo(ndofs),),l),Val((:,))) +zf = convert_to_cell_field(zl,ϕl) +df = af*zf +dft = trialize_cell_basis(df) + +# Check memoization +df_x1 = evaluate(df,xl) +df_x2 = evaluate(df,xl) +@test df_x1 === df_x2 +∇gf1 = ∇(gf) +∇gf2 = ∇(gf) +@test ∇gf1 === ∇gf2 +@test evaluate(∇gf1,xl) === evaluate(∇gf2,xl) +εgf1 = ε(gf) +εgf2 = ε(gf) +@test εgf1 === εgf2 +@test ∇×gf === ∇×gf +@test evaluate(∇×gf,xl) === evaluate(∇×gf,xl) + +@test is_test(af) +@test is_trial(dft) +@test is_basis(af) +@test is_basis(dft) +mf = af⋅dft +@test get_metasize(mf) == (:,:) +mf_x = evaluate(mf,xl) +@test size(mf_x[1]) == (np,ndofs,ndofs) + +@test get_cell_axes(mf) == Fill((Base.OneTo(ndofs),Base.OneTo(ndofs)),l) + +idsL = [ i*collect(1:ndofs) for i in 1:l] +idsR = [ 2*i*collect(1:ndofs) for i in 1:l] +axesL = Fill((Base.OneTo(ndofs),),l) +axesR = Fill((Base.OneTo(ndofs),),l) + +idsS = merge_skeleton_dof_ids(idsL,idsR,axesL,axesR) +@test isa(idsS,VectorOfBlockArrayCoo) + +afL, afR = merge_skeleton_cell_fields(af,2*af) + +afL_x = evaluate(afL,xl) +afR_x = evaluate(afR,xl) +@test isa(afL_x,VectorOfBlockArrayCoo) +@test isa(afR_x,VectorOfBlockArrayCoo) + +end # module diff --git a/test/FieldsTests/DiffOperatorsTests.jl b/test/FieldsTests/DiffOperatorsTests.jl index 4f4ca467f..85dfc34f6 100644 --- a/test/FieldsTests/DiffOperatorsTests.jl +++ b/test/FieldsTests/DiffOperatorsTests.jl @@ -13,38 +13,59 @@ x = fill(p,np) v = 3.0 d = 2 -_f = MockField{d}(v) +f = MockField{d}(v) + +@test ∇(f) == gradient(f) + +@test divergence(f) == tr(gradient(f)) + +@test curl(f) == grad2curl(gradient(f)) + +@test ∇⋅f == divergence(f) + +@test cross(∇,f) == curl(f) + +@test ∇×f == curl(f) + +@test outer(∇,f) == ∇(f) + +@test ∇⊗f == ∇(f) + +@test outer(f,∇) == transpose(∇(f)) + +@test f⊗∇ == transpose(∇(f)) + +@test ε(f) == symmetric_part(gradient(f)) + +@test Δ(f) == ∇⋅∇(f) + l = 10 -_af = Fill(_f,l) +f = Fill(f,l) -for f in (_f,_af) +@test ∇(f) == gradient(f) - @test ∇(f) == gradient(f) - - @test divergence(f) == tr(gradient(f)) - - @test curl(f) == grad2curl(gradient(f)) - - @test ∇⋅f == divergence(f) - - @test cross(∇,f) == curl(f) +@test divergence(f) == operate_arrays_of_fields(tr,gradient(f)) - @test ∇×f == curl(f) - - @test outer(∇,f) == ∇(f) +@test curl(f) == operate_arrays_of_fields(grad2curl,gradient(f)) - @test ∇⊗f == ∇(f) - - @test outer(f,∇) == transpose(∇(f)) +@test ε(f) == operate_arrays_of_fields(symmetric_part,gradient(f)) - @test f⊗∇ == transpose(∇(f)) +@test ∇⋅f == divergence(f) - @test ε(f) == symmetric_part(gradient(f)) +@test cross(∇,f) == curl(f) - @test Δ(f) == ∇⋅∇(f) +@test ∇×f == curl(f) -end +@test outer(∇,f) == ∇(f) + +@test ∇⊗f == ∇(f) + +@test outer(f,∇) == transpose(∇(f)) + +@test f⊗∇ == transpose(∇(f)) + +@test Δ(f) == ∇⋅∇(f) # Test automatic differentiation diff --git a/test/FieldsTests/FieldApplyTests.jl b/test/FieldsTests/FieldApplyTests.jl index a087f9c78..64d818ed8 100644 --- a/test/FieldsTests/FieldApplyTests.jl +++ b/test/FieldsTests/FieldApplyTests.jl @@ -6,9 +6,9 @@ using Gridap.Fields using FillArrays using Gridap.TensorValues -using Gridap.Fields: MockField, MockBasis +using Gridap.Fields: MockField, MockBasis, FieldOpKernel -k = bcast(-) +k = FieldOpKernel(-) v = 3.0 d = 2 diff --git a/test/FieldsTests/FieldArraysTests.jl b/test/FieldsTests/FieldArraysTests.jl index 6d4ba9e07..0b0ef26f0 100644 --- a/test/FieldsTests/FieldArraysTests.jl +++ b/test/FieldsTests/FieldArraysTests.jl @@ -4,7 +4,7 @@ using Test using Gridap.Arrays using Gridap.Fields using Gridap.Fields: MockField, MockBasis -using Gridap.Fields: Valued +using Gridap.Fields: Valued, FieldOpKernel using FillArrays using Gridap.TensorValues @@ -25,7 +25,7 @@ afx = fill(fx,l) a∇fx = fill(∇fx,l) test_array_of_fields(af,ax,afx,grad=a∇fx) -ag = apply_to_field_array(bcast(+),af,af) +ag = apply_to_field_array(FieldOpKernel(+),af,af) gx = fill(v+v,np) ∇gx = fill(VectorValue(v+v,0.0),np) agx = fill(gx,l) @@ -34,25 +34,25 @@ test_array_of_fields(ag,ax,agx,grad=a∇gx) struct FieldPlaceHolder <: Field end -ag = apply_to_field_array(FieldPlaceHolder,bcast(+),af,af) +ag = apply_to_field_array(FieldPlaceHolder,FieldOpKernel(+),af,af) test_array(evaluate_field_array(ag,ax),agx) w = 2.0 aw = fill(w,l) -ag = apply_to_field_array(bcast(+),af,aw) +ag = apply_to_field_array(FieldOpKernel(+),af,aw) gx = fill(v+w,np) ∇gx = fill(VectorValue(v,0.0),np) agx = fill(gx,l) a∇gx = fill(∇gx,l) test_array_of_fields(ag,ax,agx,grad=a∇gx) -ag = apply_to_field_array(FieldPlaceHolder,bcast(+),af,aw) +ag = apply_to_field_array(FieldPlaceHolder,FieldOpKernel(+),af,aw) test_array(evaluate_field_array(ag,ax),agx) l = 10 af = Fill(f,l) ax = Fill(x,l) -ag = apply_to_field_array(bcast(+),af,af) +ag = apply_to_field_array(FieldOpKernel(+),af,af) r1 = evaluate(ag,ax) @test isa(r1,Fill) @@ -70,7 +70,7 @@ f = MockBasis{d}(v,ndof) af = Fill(f,l) ax = fill(x,l) aw = fill(w,l) -ag = apply_to_field_array(bcast(+),af,aw) +ag = apply_to_field_array(FieldOpKernel(+),af,aw) agx = fill(r,l) a∇gx = fill(∇fx,l) test_array_of_fields(ag,ax,agx,grad=a∇gx) @@ -85,7 +85,7 @@ f = MockField{d}(v) af = Fill(f,l) ax = fill(x,l) aw = fill(w,l) -ag = apply_to_field_array(bcast(+),af,aw) +ag = apply_to_field_array(FieldOpKernel(+),af,aw) agx = fill(r,l) a∇gx = fill(∇r,l) test_array_of_fields(ag,ax,agx,grad=a∇gx) diff --git a/test/FieldsTests/FieldOperationsTests.jl b/test/FieldsTests/FieldOperationsTests.jl index 989272a3e..e39cfa377 100644 --- a/test/FieldsTests/FieldOperationsTests.jl +++ b/test/FieldsTests/FieldOperationsTests.jl @@ -1,124 +1,395 @@ module FieldOperationsTests +using BlockArrays using Gridap.Arrays using Gridap.Fields -using Gridap.Fields: MockField, MockBasis +using Gridap.Fields: IntKernel +using Gridap.Fields: FieldOpKernel +using Gridap.Fields: trialize_basis_value using Gridap.TensorValues +using Gridap.Fields: MockField, MockBasis + +using Test using FillArrays +using LinearAlgebra + +s = field_operation_metasize((),(:,),(1,:)) +@test s == (:,:) + +s = field_operation_metasize((),(),(:,)) +@test s == (:,) -p1 = Point(2,2) -p2 = Point(4,2) -p3 = Point(1,3) -p4 = Point(5,2) -x = [p1,p2,p3,p4] -np = length(x) - -va = 3.0 -vb = 3.3 -d = 2 -fa = MockField{d}(va) -fb = MockField{d}(vb) -fax = evaluate(fa,x) -fbx = evaluate(fb,x) -∇fax = evaluate(gradient(fa),x) -∇fbx = evaluate(gradient(fb),x) - -wa = 4.5 -wb = 4.5 -ndofa = 8 -ndofb = 5 -ba = MockBasis{d}(wa,ndofa) -bb = MockBasis{d}(wb,ndofb) -bax = evaluate(ba,x) -bbx = evaluate(bb,x) -∇bax = evaluate(gradient(ba),x) -∇bbx = evaluate(gradient(bb),x) +s = field_operation_metasize((1,:),(1,:)) +@test s == (1,:) + +ndofs1 = 5 +ndofs2 = 4 +np = 7 +ax1 = (Base.OneTo(ndofs1),) +ax2 = (1,Base.OneTo(ndofs2),) +ax3 = () +ax = field_operation_axes(ax1,ax2,ax3) +@test ax == (Base.OneTo(ndofs1),Base.OneTo(ndofs2)) + +ax1 = (Base.OneTo(np),Base.OneTo(ndofs1),) +ax2 = (Base.OneTo(np),1,Base.OneTo(ndofs2),) +ax3 = (Base.OneTo(np),) +ax = field_operation_axes(ax3,ax2,ax1) +@test ax == (Base.OneTo(np),Base.OneTo(ndofs1),Base.OneTo(ndofs2)) + +ax1 = (blockedrange([ndofs1,ndofs2]),) +ax2 = (blockedrange([1]),blockedrange([ndofs2,ndofs1])) +ax3 = () +ax = field_operation_axes(ax3,ax2,ax1) +@test ax == (blockedrange([ndofs1,ndofs2]),blockedrange([ndofs2,ndofs1])) l = 10 -ax = fill(x,l) -afa = Fill(fa,l) -afb = Fill(fb,l) -aba = Fill(ba,l) -abb = Fill(bb,l) - -g = field_operation(inner,fa,fb) -gx = [inner(ai,bj) for (ai,bj) in zip(fax,fbx)] -test_field(g,x,gx) - -ag = field_array_operation(inner,afa,afb) -agx = fill(gx,l) -test_array_of_fields(ag,ax,agx) - -struct FieldPlaceHolder <: Field end - -ag = field_array_operation(FieldPlaceHolder,inner,fill(fa,l),afb) -test_array(evaluate_field_array(ag,ax),agx) - -g = field_operation(inner,ba,fb) -gx = zeros(size(bax)) -for p in 1:np - for i in 1:ndofa - gx[p,i] = inner(bax[p,i],fbx[p]) - end -end -test_field(g,x,gx) - -ag = field_array_operation(inner,aba,afb) -agx = fill(gx,l) -test_array_of_fields(ag,ax,agx) - -g = field_operation(inner,fa,bb) -gx = zeros(size(bbx)) -for p in 1:np - for i in 1:ndofb - gx[p,i] = inner(fax[p],bbx[p,i]) - end -end -test_field(g,x,gx) - -ag = field_array_operation(inner,afa,abb) -agx = fill(gx,l) -test_array_of_fields(ag,ax,agx) - -g = field_operation(inner,ba,bb) -gx = zeros(np,ndofa,ndofb) -for p in 1:np - for i in 1:ndofa - for j in 1:ndofb - gx[p,i,j] = inner(bax[p,i],bbx[p,j]) - end - end -end -test_field(g,x,gx) - -ag = field_array_operation(inner,aba,abb) -agx = fill(gx,l) -test_array_of_fields(ag,ax,agx) - -g = field_operation(+,fa,fb) -gx = [+(ai,bj) for (ai,bj) in zip(fax,fbx)] -∇gx = [+(ai,bj) for (ai,bj) in zip(∇fax,∇fbx)] -test_field(g,x,gx,grad=∇gx) - -ag = field_array_operation(+,afa,afb) -agx = fill(gx,l) -∇agx = fill(∇gx,l) -test_array_of_fields(ag,ax,agx,grad=∇agx) - -g = field_operation(+,fa) -gx = [+ai for ai in fax] -∇gx = [+ai for ai in ∇fax] -test_field(g,x,gx,grad=∇gx) - -ag = field_array_operation(+,afa) -agx = fill(gx,l) -∇agx = fill(∇gx,l) -test_array_of_fields(ag,ax,agx,grad=∇agx) - -g = field_operation(*,va,fa) -gx = [*(va,ai) for ai in fax] -∇gx = [*(va,ai) for ai in ∇fax] -test_field(g,x,gx,grad=∇gx) +np = 3 +ndofs = 4 + +# Operations between fields and array of fields + +p = Point(1,2) +x = fill(p,np) +z = 2.0 + +v = VectorValue(3.0,1.5) +w = VectorValue(3.4,3.5) +test_basis = MockBasis{2}(v,ndofs) +test_basis_2 = MockBasis{2}(w,ndofs) + +t1x = evaluate(test_basis,x) +t2x = evaluate(test_basis_2,x) +∇t1x = evaluate(∇(test_basis),x) +∇t2x = evaluate(∇(test_basis_2),x) + +b = operate_fields(+,test_basis,test_basis_2) +r = broadcast(+,t1x,t2x) +∇r = broadcast(+,∇t1x,∇t2x) +test_field(b,x,r,grad=∇r) + +b = operate_fields(-,test_basis,test_basis_2) +r = broadcast(-,t1x,t2x) +∇r = broadcast(-,∇t1x,∇t2x) +test_field(b,x,r,grad=∇r) + +b = operate_fields(⋅,test_basis,test_basis_2) +r = broadcast(⋅,t1x,t2x) +∇r = broadcast(⋅,∇t1x,t2x) + broadcast(⋅,t1x,∇t2x) +test_field(b,x,r,grad=∇r) + +b = operate_fields(*,test_basis,z) +r = broadcast(*,t1x,z) +∇r = broadcast(*,∇t1x,z) +test_field(b,x,r,grad=∇r) + +b = operate_fields(+,test_basis,z) +test_field(b,x,fill(v+z,np,ndofs)) + +trial_basis = trialize_basis(test_basis) +r = reshape(evaluate(test_basis,x),(np,1,ndofs)) +∇r = reshape(evaluate(∇(test_basis),x),(np,1,ndofs)) +test_field(trial_basis,x,r,grad=∇r) + +xl = Fill(x,l) +fl = [ z for i in 1:l] + +test_basis_array = Fill(test_basis,l) +test_basis_2_array = fill(test_basis_2,l) + +bl = operate_arrays_of_fields(Nothing,*,test_basis_array,fl) +test_array_of_fields(bl,xl,fill(fill(z*v,np,ndofs),l)) + +bl = operate_arrays_of_fields(*,test_basis_array,fl) +test_array_of_fields(bl,xl,fill(fill(z*v,np,ndofs),l)) + +bl = operate_arrays_of_fields(+,test_basis_array,test_basis_2_array) +r = fill(broadcast(+,t1x,t2x),l) +∇r = fill(broadcast(+,∇t1x,∇t2x),l) +test_array_of_fields(bl,xl,r,grad=∇r) + +bl = operate_arrays_of_fields(⋅,test_basis_array,test_basis_2_array) +r = fill(broadcast(⋅,t1x,t2x),l) +∇r = fill(broadcast(⋅,∇t1x,t2x) + broadcast(⋅,t1x,∇t2x),l) +test_array_of_fields(bl,xl,r,grad=∇r) + +trial_basis_array = trialize_array_of_bases(operate_arrays_of_fields(*,test_basis_array,fl)) + +trial_basis_array_x = evaluate(trial_basis_array,xl) +@test trial_basis_array_x.g.value === trialize_basis_value + +bl = operate_arrays_of_fields(⋅,trial_basis_array,test_basis_array) +r = fill(fill(z*v⋅v,np,ndofs,ndofs),l) +bl_x = evaluate(bl,xl) +test_array_of_fields(bl,xl,r) +@test bl_x.g.value == FieldOpKernel(⋅) + +# Operations between values + +al = [rand(np,ndofs) for k in 1:l] +bl = [rand(np) for k in 1:l] +cl = [rand(np,ndofs) for k in 1:l] + +f(a,b) = 2*a-b*a +dl = apply(FieldOpKernel(f),bl,bl) +test_array(dl,map((a,b)->f.(a,b),bl,bl)) + +f(a,b) = 2*a-b*a +dl = apply(FieldOpKernel(f),al,bl) +test_array(dl,map((a,b)->f.(a,b),al,bl)) + +f(a,b) = 2*a-b +dl = apply(FieldOpKernel(f),al,cl) +test_array(dl,map((a,b)->f.(a,b),al,cl)) + +f(a,b,c) = b*(2*a-c) +dl = apply(FieldOpKernel(f),al,bl,cl) +test_array(dl,map((a,b,c)->f.(a,b,c),al,bl,cl)) + +dl = apply(trialize_basis_value,al) +test_array(dl,map(a->reshape(a,(size(a,1),1,size(a,2))),al)) + +atl = apply(trialize_basis_value,al) +ctl = apply(trialize_basis_value,cl) + +f(a,b) = 2*a*b +dl = apply(FieldOpKernel(f),al,atl) +test_array(dl,map((a,b)->f.(a,b),al,atl)) + +f(a,c,at,ct) = 2*(a+c)*(2*at-ct) +dl = apply(FieldOpKernel(f),al,cl,atl,ctl) +test_array(dl,map((a,c,at,ct)->f.(a,c,at,ct),al,cl,atl,ctl)) + +@test size(dl[1]) == (np,ndofs,ndofs) + + + + + +# Blocks + +blocks = (al,) +blockids = [(1,1)] +axs_i = (blockedrange([np]),blockedrange([ndofs,ndofs])) +axs = Fill(axs_i,l) +aBl = VectorOfBlockArrayCoo(blocks,blockids,axs) + +blocks = (cl,) +blockids = [(1,2)] +cBl = VectorOfBlockArrayCoo(blocks,blockids,axs) + +atBl = apply(trialize_basis_value,aBl) +ctBl = apply(trialize_basis_value,cBl) +@test isa(atBl,VectorOfBlockArrayCoo) + +f(a) = 2*a +dl = apply(FieldOpKernel(f),aBl) +@test isa(dl,VectorOfBlockArrayCoo) +test_array(dl,map((a)->f.(a),aBl)) + +f(a,b) = 2*a + a*b +dl = apply(FieldOpKernel(f),aBl,bl) +@test isa(dl,VectorOfBlockArrayCoo) +test_array(dl,map((a,b)->f.(a,b),aBl,bl)) + +f(b,a) = 2*a + a*b +dl = apply(FieldOpKernel(f),bl,atBl) +@test isa(dl,VectorOfBlockArrayCoo) +test_array(dl,map((a,b)->f.(a,b),bl,atBl)) + +f(b,a) = 2*a + b +dl = apply(FieldOpKernel(f),atBl,ctBl) +@test isa(dl,VectorOfBlockArrayCoo) +test_array(dl,map((a,b)->f.(a,b),atBl,ctBl)) + +dl = apply(FieldOpKernel(+),atBl,ctBl) +@test isa(dl,VectorOfBlockArrayCoo) +test_array(dl,map((a,b)->a+b,atBl,ctBl)) + +dl = apply(FieldOpKernel(-),atBl,ctBl) +@test isa(dl,VectorOfBlockArrayCoo) +test_array(dl,map((a,b)->a-b,atBl,ctBl)) + +f(b,a) = 2*a*b +dl = apply(FieldOpKernel(f),aBl,ctBl) +@test isa(dl,VectorOfBlockArrayCoo) +test_array(dl,map((a,b)->f.(a,b),aBl,ctBl)) + +f(b,a) = 2*a*b +dl = apply(FieldOpKernel(f),atBl,cBl) +@test isa(dl,VectorOfBlockArrayCoo) +test_array(dl,map((a,b)->f.(a,b),atBl,cBl)) + +# BlockWise integration + +cj = [ fill(TensorValue(1,0,0,2),np) for cell in 1:l ] +cw = [ rand(np) for cell in 1:l ] + +f(a,b) = 2*a + a*b +vl = apply(FieldOpKernel(f),aBl,bl) +dl = apply(IntKernel(),vl,cw,cj) +@test isa(dl,VectorOfBlockArrayCoo) +test_array(dl,map( (v,w,j) -> reshape(sum( broadcast(*,v,w,det.(j)), dims=1),(2*ndofs,)), vl,cw,cj )) + +vl = apply(FieldOpKernel(*),aBl,ctBl) +dl = apply(IntKernel(),vl,cw,cj) +@test isa(dl,VectorOfBlockArrayCoo) +test_array(dl,map( (v,w,j) -> reshape(sum( broadcast(*,v,w,det.(j)), dims=1),(2*ndofs,2*ndofs)), vl,cw,cj )) + +# Blocks of Blocks + +a0Bl = zeros_like(aBl) +c0Bl = zeros_like(cBl) +@test isa(a0Bl,VectorOfBlockArrayCoo) +@test blocksize(a0Bl) == blocksize(aBl) +@test length(a0Bl.blocks) == 0 + +blockids = [(1,1)] +ax1 = blockedrange([np]) +ax2 = blockedrange([ndofs,ndofs]) +axs_i = (blockedrange([ax1]),blockedrange([ax2,ax2])) +axs = Fill(axs_i,l) +aLl = VectorOfBlockArrayCoo((aBl,),blockids,axs,(a0Bl,)) +cLl = VectorOfBlockArrayCoo((cBl,),blockids,axs,(c0Bl,)) + +@test isa(aLl,VectorOfBlockArrayCoo) +@test aBl === aLl[Block(1,1)] +@test al === aLl[Block(1,1)][Block(1,1)] +@test isa(aLl[Block(1,1)],VectorOfBlockArrayCoo) +@test isa(aLl[Block(1,2)],VectorOfBlockArrayCoo) + +blockids = [(1,2)] +aRl = VectorOfBlockArrayCoo((aBl,),blockids,axs,(a0Bl,)) +cRl = VectorOfBlockArrayCoo((cBl,),blockids,axs,(c0Bl,)) + +a0tBl = zeros_like(atBl) +c0tBl = zeros_like(ctBl) + +blockids = [(1,1,1)] +axs_i = (blockedrange([ax1]),blockedrange([blockedrange([1])]),blockedrange([ax2,ax2])) +axs = Fill(axs_i,l) +atLl = VectorOfBlockArrayCoo((atBl,),blockids,axs,(a0tBl,)) +ctLl = VectorOfBlockArrayCoo((ctBl,),blockids,axs,(c0tBl,)) + +@test isa(atLl,VectorOfBlockArrayCoo) +@test atBl === atLl[Block(1,1,1)] +@test atl === atLl[Block(1,1,1)][Block(1,1,1)] +@test isa(atLl[Block(1,1,1)],VectorOfBlockArrayCoo) +@test isa(atLl[Block(1,1,2)],VectorOfBlockArrayCoo) + +blockids = [(1,1,2)] +atRl = VectorOfBlockArrayCoo((atBl,),blockids,axs,(a0tBl,)) +ctRl = VectorOfBlockArrayCoo((ctBl,),blockids,axs,(c0tBl,)) + +f(a) = 2*a +dl = apply(FieldOpKernel(f),aLl) +@test isa(dl,VectorOfBlockArrayCoo) +@test isa(dl[Block(1,1)],VectorOfBlockArrayCoo) +@test isa(dl[Block(1,2)],VectorOfBlockArrayCoo) +@test isa(dl[1][Block(1,1)],BlockArrayCoo) +@test isa(dl[1][Block(1,2)],BlockArrayCoo) +test_array(dl,map((a)->f.(a),aLl)) + +f(a,b) = 2*a + a*b +dl = apply(FieldOpKernel(f),aRl,bl) +@test isa(dl,VectorOfBlockArrayCoo) +@test isa(dl[Block(1,1)],VectorOfBlockArrayCoo) +@test isa(dl[Block(1,2)],VectorOfBlockArrayCoo) +@test isa(dl[1][Block(1,1)],BlockArrayCoo) +@test isa(dl[1][Block(1,2)],BlockArrayCoo) +test_array(dl,map((a,b)->f.(a,b),aRl,bl)) + +f(b,a) = 2*a + b +dl = apply(FieldOpKernel(f),atRl,ctLl) +@test isa(dl,VectorOfBlockArrayCoo) +@test isa(dl[Block(1,1,1)],VectorOfBlockArrayCoo) +@test isa(dl[Block(1,1,2)],VectorOfBlockArrayCoo) +@test isa(dl[1][Block(1,1,1)],BlockArrayCoo) +@test isa(dl[1][Block(1,1,2)],BlockArrayCoo) +test_array(dl,map((a,b)->f.(a,b),atRl,ctLl)) + +f(b,a) = 2*a + b +dl = apply(FieldOpKernel(f),aRl,cLl) +@test isa(dl,VectorOfBlockArrayCoo) +@test isa(dl[Block(1,1)],VectorOfBlockArrayCoo) +@test isa(dl[Block(1,2)],VectorOfBlockArrayCoo) +@test isa(dl[1][Block(1,1)],BlockArrayCoo) +@test isa(dl[1][Block(1,2)],BlockArrayCoo) +test_array(dl,map((a,b)->f.(a,b),aRl,cLl)) + +f(b,a) = 2*a + b +dl = apply(FieldOpKernel(f),aRl,aRl) +@test isa(dl,VectorOfBlockArrayCoo) +@test isa(dl[Block(1,1)],VectorOfBlockArrayCoo) +@test isa(dl[Block(1,2)],VectorOfBlockArrayCoo) +@test isa(dl[1][Block(1,1)],BlockArrayCoo) +@test isa(dl[1][Block(1,2)],BlockArrayCoo) +test_array(dl,map((a,b)->f.(a,b),aRl,aRl)) + +f(b,a) = a * b +dl = apply(FieldOpKernel(f),aLl,ctRl) +@test isa(dl,VectorOfBlockArrayCoo) +@test is_zero_block(dl,Block(1,1,1)) +@test is_nonzero_block(dl,Block(1,1,2)) +@test is_zero_block(dl,Block(1,2,1)) +@test is_zero_block(dl,Block(1,2,2)) +@test isa(dl[Block(1,1,1)],VectorOfBlockArrayCoo) +@test isa(dl[Block(1,1,2)],VectorOfBlockArrayCoo) +@test isa(dl[Block(1,2,1)],VectorOfBlockArrayCoo) +@test isa(dl[Block(1,2,2)],VectorOfBlockArrayCoo) +@test isa(dl[1][Block(1,1,1)],BlockArrayCoo) +@test isa(dl[1][Block(1,1,2)],BlockArrayCoo) +@test isa(dl[1][Block(1,2,1)],BlockArrayCoo) +@test isa(dl[1][Block(1,2,2)],BlockArrayCoo) +test_array(dl,map((a,b)->f.(a,b),aLl,ctRl)) + +f(b,a) = a * b +v = apply(FieldOpKernel(-),ctLl,ctRl) +dl = apply(FieldOpKernel(f),v,aLl) +@test isa(dl,VectorOfBlockArrayCoo) +@test is_nonzero_block(dl,Block(1,1,1)) +@test is_nonzero_block(dl,Block(1,1,2)) +@test is_zero_block(dl,Block(1,2,1)) +@test is_zero_block(dl,Block(1,2,2)) +@test isa(dl[Block(1,1,1)],VectorOfBlockArrayCoo) +@test isa(dl[Block(1,1,2)],VectorOfBlockArrayCoo) +@test isa(dl[Block(1,2,1)],VectorOfBlockArrayCoo) +@test isa(dl[Block(1,2,2)],VectorOfBlockArrayCoo) +@test isa(dl[1][Block(1,1,1)],BlockArrayCoo) +@test isa(dl[1][Block(1,1,2)],BlockArrayCoo) +@test isa(dl[1][Block(1,2,1)],BlockArrayCoo) +@test isa(dl[1][Block(1,2,2)],BlockArrayCoo) +test_array(dl,map((a,b)->f.(a,b),v,aLl)) + +# Integration of Blocks of Blocks + +f(a,b) = 2*a + a*b +vl = apply(FieldOpKernel(f),aRl,bl) +dl = apply(IntKernel(),vl,cw,cj) +test_array(dl,map( (v,w,j) -> reshape(sum( broadcast(*,v,w,det.(j)), dims=1),(4*ndofs,)), vl,cw,cj )) +@test isa(dl,VectorOfBlockArrayCoo) +@test is_zero_block(dl,Block(1)) +@test is_nonzero_block(dl,Block(2)) +@test isa(dl[Block(1)],VectorOfBlockArrayCoo) +@test isa(dl[Block(2)],VectorOfBlockArrayCoo) + +f(b,a) = a * b +v = apply(FieldOpKernel(-),ctLl,ctRl) +vl = apply(FieldOpKernel(f),v,aLl) +dl = apply(IntKernel(),vl,cw,cj) +test_array(dl,map( (v,w,j) -> reshape(sum( broadcast(*,v,w,det.(j)), dims=1),(4*ndofs,4*ndofs)), vl,cw,cj )) +@test isa(dl,VectorOfBlockArrayCoo) +@test is_nonzero_block(dl,Block(1,1)) +@test is_nonzero_block(dl,Block(1,2)) +@test is_zero_block(dl,Block(2,1)) +@test is_zero_block(dl,Block(2,2)) +@test isa(dl[Block(1,1)],VectorOfBlockArrayCoo) +@test isa(dl[Block(1,2)],VectorOfBlockArrayCoo) +@test isa(dl[Block(2,1)],VectorOfBlockArrayCoo) +@test isa(dl[Block(2,2)],VectorOfBlockArrayCoo) +#using BenchmarkTools +#cache = array_cache(dl) +#@btime getindex!($cache,$dl,3) end # module diff --git a/test/FieldsTests/VectorsOfBlockBasisCooTests.jl b/test/FieldsTests/VectorsOfBlockBasisCooTests.jl new file mode 100644 index 000000000..ba34f8352 --- /dev/null +++ b/test/FieldsTests/VectorsOfBlockBasisCooTests.jl @@ -0,0 +1,156 @@ +module InsertInBlocksTests + +using Test +using BlockArrays +using FillArrays +using Gridap.Arrays +using Gridap.Fields +using Gridap.TensorValues +using Gridap.Fields: MockField, MockBasis + +l = 10 +np = 3 +ndofs1 = 4 +ndofs2 = 6 + +p = Point(1,2) +x = fill(p,np) +z = 2.0 + +v = VectorValue(3.0,1.5) +w = VectorValue(3.4,3.5) +a = MockBasis{2}(v,ndofs2) +b = MockBasis{2}(w,ndofs1) + +al = Fill(a,l) +atl = trialize_array_of_bases(al) +bl = Fill(b,l) +xl = Fill(x,l) + +ax1 = Fill((Base.OneTo(ndofs1),),l) +ax2 = Fill((Base.OneTo(ndofs2),),l) +aBl = insert_array_of_bases_in_block(2,al,ax1,ax2) +aBl_x = evaluate(aBl,xl) +@test isa(aBl,VectorOfBlockBasisCoo) +@test isa(aBl_x,VectorOfBlockArrayCoo) + +ax1 = Fill((Base.OneTo(ndofs1),),l) +ax2 = Fill((Base.OneTo(ndofs2),),l) +aBl = insert_array_of_bases_in_block(3,al,ax1,ax2,ax2) +aBl_x = evaluate(aBl,xl) +@test isa(aBl,VectorOfBlockBasisCoo) +@test isa(aBl_x,VectorOfBlockArrayCoo) + +bBl = insert_array_of_bases_in_block(1,bl,ax1,ax2) +bBl_x = evaluate(bBl,xl) +@test isa(bBl,VectorOfBlockBasisCoo) +@test isa(bBl_x,VectorOfBlockArrayCoo) + +ax1 = Fill((Base.OneTo(1),Base.OneTo(ndofs1)),l) +ax2 = Fill((Base.OneTo(1),Base.OneTo(ndofs2)),l) +atBl = insert_array_of_bases_in_block(2,atl,ax1,ax2) +atBl_x = evaluate(atBl,xl) +@test isa(atBl,VectorOfBlockBasisCoo) +@test isa(atBl_x,VectorOfBlockArrayCoo) + +ax1 = Fill((Base.OneTo(1),Base.OneTo(ndofs1)),l) +ax2 = Fill((Base.OneTo(1),Base.OneTo(ndofs2)),l) +atBl = insert_array_of_bases_in_block(3,atl,ax1,ax2,ax2) +atBl_x = evaluate(atBl,xl) +@test isa(atBl,VectorOfBlockBasisCoo) +@test isa(atBl_x,VectorOfBlockArrayCoo) + +ax1 = aBl.axes +ax2 = aBl.axes +aSl = insert_array_of_bases_in_block(2,aBl,ax1,ax2) +@test isa(aSl,VectorOfBlockBasisCoo) +aSl_x = evaluate(aSl,xl) +@test isa(aSl_x,VectorOfBlockArrayCoo) + +ax1 = atBl.axes +ax2 = atBl.axes +atSl = insert_array_of_bases_in_block(1,atBl,ax1,ax2) +@test isa(atSl,VectorOfBlockBasisCoo) +atSl_x = evaluate(atSl,xl) +@test isa(atSl_x,VectorOfBlockArrayCoo) + +blocks = (al,) +blockids = [(2,)] +ranges_i = (blockedrange([ndofs1,ndofs2]),) +ranges = Fill(ranges_i,l) +aBl = VectorOfBlockBasisCoo(blocks,blockids,ranges) + +blocks = (bl,) +blockids = [(1,)] +bBl = VectorOfBlockBasisCoo(blocks,blockids,ranges) + +blocks = (atl,) +blockids = [(1,2)] +ranges_i = (blockedrange([1]),blockedrange([ndofs1,ndofs2])) +ranges = Fill(ranges_i,l) +atBl = VectorOfBlockBasisCoo(blocks,blockids,ranges) + +aBl_x = evaluate(aBl,xl) +@test isa(aBl_x,VectorOfBlockArrayCoo) +@test isa(aBl_x.axes,Fill) +@test aBl_x.axes[1] == (blockedrange([np]),blockedrange([ndofs1,ndofs2])) + +bBl_x = evaluate(bBl,xl) +@test isa(bBl_x,VectorOfBlockArrayCoo) + +atBl_x = evaluate(atBl,xl) +@test isa(atBl_x,VectorOfBlockArrayCoo) +@test isa(atBl_x.axes,Fill) +@test atBl_x.axes[1] == (blockedrange([np]),blockedrange([1]),blockedrange([ndofs1,ndofs2])) + +atBl = trialize_array_of_bases(aBl) +atBl_x = evaluate(atBl,xl) +@test isa(atBl_x,VectorOfBlockArrayCoo) + +btBl = trialize_array_of_bases(bBl) +btBl_x = evaluate(btBl,xl) +@test isa(btBl_x,VectorOfBlockArrayCoo) + +∇aBl = ∇(aBl) +@test isa(∇aBl,VectorOfBlockBasisCoo) +∇aBl_x = evaluate(∇aBl,xl) +@test isa(∇aBl_x,VectorOfBlockArrayCoo) + +cl = operate_arrays_of_fields(-,aBl,bBl) +cl_x = evaluate(cl,xl) +@test isa(cl_x,VectorOfBlockArrayCoo) +∇cl = ∇(cl) +∇cl_x = evaluate(∇cl,xl) +@test isa(cl_x,VectorOfBlockArrayCoo) + +cl = operate_arrays_of_fields(⋅,atBl,cl) +cl_x = evaluate(cl,xl) +@test isa(cl_x,VectorOfBlockArrayCoo) +@test is_zero_block(cl_x,Block(1,1,1)) +@test is_nonzero_block(cl_x,Block(1,1,2)) +@test is_zero_block(cl_x,Block(1,2,1)) +@test is_nonzero_block(cl_x,Block(1,2,2)) + +ids = [2,3,5,1,2] +cj = reindex(aBl,ids) +xj = reindex(xl,ids) +@test isa(cj,VectorOfBlockBasisCoo) +cj_x = evaluate(cj,xj) +@test isa(cj_x.axes,Fill) +@test cj_x.axes[1] == (blockedrange([np]),blockedrange([ndofs1,ndofs2])) +@test length(cj_x) == length(ids) +@test length(cj) == length(ids) + +v = VectorValue(1.0,2.0,3.0) +f = MockField{2}(v) +fl = Fill(f,l) + +cl = compose_field_arrays(aBl,fl) +@test isa(cl,VectorOfBlockBasisCoo) + + +#cache = array_cache(cl_x) +#using BenchmarkTools +#@btime getindex!($cache,$cl_x,3) + +end # module diff --git a/test/FieldsTests/runtests.jl b/test/FieldsTests/runtests.jl index e3e5cd518..59f4fac35 100644 --- a/test/FieldsTests/runtests.jl +++ b/test/FieldsTests/runtests.jl @@ -26,6 +26,8 @@ using Test @testset "FieldOperations" begin include("FieldOperationsTests.jl") end +@testset "VectorsOfBlockBasisCoo" begin include("VectorsOfBlockBasisCooTests.jl") end + @testset "DiffOperators" begin include("DiffOperatorsTests.jl") end end # module diff --git a/test/GeometryTests/AppendedTriangulationsTests.jl b/test/GeometryTests/AppendedTriangulationsTests.jl index af4a17a02..ccab101cf 100644 --- a/test/GeometryTests/AppendedTriangulationsTests.jl +++ b/test/GeometryTests/AppendedTriangulationsTests.jl @@ -4,11 +4,10 @@ using Test using Gridap.ReferenceFEs using Gridap.Arrays using Gridap.Geometry -using Gridap.Visualization -using Gridap.FESpaces using Gridap.Fields using Gridap.Integration using LinearAlgebra: ⋅ +using Gridap.CellData domain = (0,1,0,1) partition = (10,10) @@ -37,29 +36,6 @@ w = get_weights(quad) @test isa(q,AppendedArray) @test isa(w,AppendedArray) -V = TestFESpace(model=model,valuetype=Float64,order=order,reffe=:Lagrangian,conformity=:H1) - -u(x) = x[1]+x[2] - -_v = interpolate(V,u) -v = restrict(_v,trian) - -e = u - v -el2 = sqrt(sum(integrate(e*e,trian,quad))) -@test el2 < 1.0e-8 - -_dv = get_cell_basis(V) -dv = restrict(_dv,trian) - -cellmat = integrate(∇(dv)⋅∇(dv),trian,quad) -@test isa(cellmat,AppendedArray) -@test isa(cellmat.a,CompressedArray) -@test isa(cellmat.b,CompressedArray) - -#writevtk(trian_in,"trian_in") -#writevtk(trian_out,"trian_out") -#writevtk(trian,"trian",cellfields=["v"=>v]) - # Append triangulations of different cell type domain = (0,1,0,1) @@ -73,9 +49,4 @@ grid2 = simplexify(CartesianGrid(domain,partition)) trian = lazy_append(grid1,grid2) test_triangulation(trian) -d = mktempdir() -f = joinpath(d,"trian") -writevtk(trian,f) -rm(d,recursive=true) - end # module diff --git a/test/GeometryTests/CellFieldsTests.jl b/test/GeometryTests/CellFieldsTests.jl index 1fff46d29..4b810ac8d 100644 --- a/test/GeometryTests/CellFieldsTests.jl +++ b/test/GeometryTests/CellFieldsTests.jl @@ -7,6 +7,7 @@ using Gridap.Fields using Gridap.TensorValues using FillArrays using LinearAlgebra +using Gridap.CellData import Gridap.Fields: ∇ @@ -29,14 +30,14 @@ r = [[0.0], [2.0], [0.0], [2.0]] g = Vector{VectorValue{2,Float64}}[[(1, 0)], [(1, 0)], [(1, 0)], [(1, 0)]] test_cell_field(cf1,q,r,grad=g) -isa(cf1,Geometry.CellFieldLike) +isa(cf1,Geometry.CellField) @test RefStyle(cf1) == Val{true}() indices = [3,2,3] _cf1 = reindex(cf1,indices) @test length(_cf1) == length(indices) test_cell_field(_cf1,reindex(q,indices),reindex(r,indices),grad=reindex(g,indices)) -isa(_cf1,Geometry.CellFieldLike) +isa(_cf1,Geometry.CellField) @test RefStyle(_cf1) == Val{true}() cf2 = cf1 + 4 diff --git a/test/GeometryTests/CellQuadraturesTests.jl b/test/GeometryTests/CellQuadraturesTests.jl index 67a692ecf..94a959766 100644 --- a/test/GeometryTests/CellQuadraturesTests.jl +++ b/test/GeometryTests/CellQuadraturesTests.jl @@ -8,6 +8,7 @@ using Gridap.ReferenceFEs using Gridap.Geometry using Gridap.Arrays using Gridap.Integration +using Gridap.CellData using Gridap.Geometry: GridMock diff --git a/test/GeometryTests/GridsTests.jl b/test/GeometryTests/GridsTests.jl index 3c5446e52..1f82b3554 100644 --- a/test/GeometryTests/GridsTests.jl +++ b/test/GeometryTests/GridsTests.jl @@ -5,6 +5,7 @@ using Gridap.Arrays using Gridap.Geometry using Gridap.Fields using Gridap.ReferenceFEs +using Gridap.CellData using Gridap.Geometry: GridMock diff --git a/test/GeometryTests/QPointCellFieldsTests.jl b/test/GeometryTests/QPointCellFieldsTests.jl index 85fd4e065..2a6455a09 100644 --- a/test/GeometryTests/QPointCellFieldsTests.jl +++ b/test/GeometryTests/QPointCellFieldsTests.jl @@ -1,9 +1,9 @@ module QPointCellFields using Gridap.Geometry -using Gridap.Geometry: ArrayOfEvaluatedFields using Gridap.Fields using Gridap.Integration +using Gridap.CellData domain = (0,1,0,1) n = 3 @@ -13,13 +13,9 @@ model = CartesianDiscreteModel(domain,partition) trian = Triangulation(model) degree = 4 quad = CellQuadrature(trian,degree) - q = get_coordinates(quad) -s_q = [i*ones(size(qi)) for (i,qi) in enumerate(q)] -a = ArrayOfEvaluatedFields(s_q,q) -test_array_of_fields(a,q,s_q) -r = QPointCellField(0.0,trian,quad) +r = CellField(0.0,trian,quad) r_q = evaluate(r,q) test_cell_field(r,q,r_q) diff --git a/test/GeometryTests/TriangulationsTests.jl b/test/GeometryTests/TriangulationsTests.jl index 9562aa5cb..15c69c73c 100644 --- a/test/GeometryTests/TriangulationsTests.jl +++ b/test/GeometryTests/TriangulationsTests.jl @@ -9,6 +9,7 @@ using Gridap.Arrays using Gridap.TensorValues using Gridap.Fields using Gridap.ReferenceFEs +using Gridap.CellData import Gridap.Geometry: get_cell_type import Gridap.Geometry: get_reffes diff --git a/test/GridapTests/IsotropicDamageTests.jl b/test/GridapTests/IsotropicDamageTests.jl index 88499175b..58bb5058f 100644 --- a/test/GridapTests/IsotropicDamageTests.jl +++ b/test/GridapTests/IsotropicDamageTests.jl @@ -120,7 +120,7 @@ function main(;n,nsteps) uh_out, = solve!(uh0,solver,op) - update_state_variables!(quad,update,ε(uh_out),r,d) + update_state_variables!(update,quad,ε(uh_out),r,d) uh_out end diff --git a/test/GridapTests/PhysicalPoissonTests.jl b/test/GridapTests/PhysicalPoissonTests.jl index 79dfcd83b..87359119e 100644 --- a/test/GridapTests/PhysicalPoissonTests.jl +++ b/test/GridapTests/PhysicalPoissonTests.jl @@ -73,7 +73,7 @@ for data in [ vector_data, scalar_data ] U = TrialFESpace(V,u) - uh = interpolate(U,u) + uh = interpolate(u,U) a(u,v) = inner(∇(v),∇(u)) l(v) = v⊙f diff --git a/test/GridapTests/PoissonTests.jl b/test/GridapTests/PoissonTests.jl index 911944f8b..0f1c6ba73 100644 --- a/test/GridapTests/PoissonTests.jl +++ b/test/GridapTests/PoissonTests.jl @@ -78,7 +78,7 @@ for data in [ vector_data, scalar_data ] U = TrialFESpace(V,u) - uh = interpolate(U,u) + uh = interpolate(u, U) a(u,v) = ∇(v)⊙∇(u) l(v) = v⊙f diff --git a/test/MultiFieldTests/MultiFieldArraysTests.jl b/test/MultiFieldTests/MultiFieldArraysTests.jl deleted file mode 100644 index 7b1162895..000000000 --- a/test/MultiFieldTests/MultiFieldArraysTests.jl +++ /dev/null @@ -1,91 +0,0 @@ -module MultiFieldArraysTests - -using Test -using Gridap.Arrays -using Gridap.MultiField -using LinearAlgebra - -using Gridap.MultiField: _resize_for_mul! -using Gridap.MultiField: _move_cached_arrays! -using Gridap.MultiField: CachedMultiFieldArray - -B1 = 10*ones(Int,3) -B2 = 20*ones(Int,5) -blocks = [B1,B2] -coordinates = [(1,),(2,)] -b = MultiFieldArray(blocks,coordinates) - -C1 = 1*ones(Int,3) -C2 = 2*ones(Int,5) -blocks = [C2] -coordinates = [(2,)] -c = MultiFieldArray(blocks,coordinates) - -add_to_array!(b,c) -@test b.blocks == [[10, 10, 10], [22, 22, 22, 22, 22]] - -A11 = ones(Int,2,3) -A21 = 2*ones(Int,4,3) -A12 = 3*ones(Int,2,5) -blocks = [A11,A21,A12] -coordinates = [(1,1),(2,1),(1,2)] -a = MultiFieldArray(blocks,coordinates) - -@test a.blocks == blocks -@test a.coordinates == coordinates -@test a.ptrs == [1 3; 2 0] -@test num_blocks(a) == 4 -@test num_stored_blocks(a) == 3 -@test get_block_size(a) == (2,2) -@test has_all_blocks(a) == false -@test a[1,1] == A11 -@test a[2,1] == A21 - -B1 = 10*ones(Int,3) -B2 = 20*ones(Int,5) -blocks = [B1,B2] -coordinates = [(1,),(2,)] -b = MultiFieldArray(blocks,coordinates) - -c = a*b - -@test c.blocks[1] == A11*B1 + A12*B2 -@test c.blocks[2] == A21*B1 -@test c.coordinates == [(1,),(2,)] - -mul!(c,a,b) - -@test c.blocks[1] == A11*B1 + A12*B2 -@test c.blocks[2] == A21*B1 -@test c.coordinates == [(1,),(2,)] - -c = a*b -r = CachedMultiFieldArray(c) - -_resize_for_mul!(r,a,b) -_move_cached_arrays!(c,r) -mul!(c,10*a,b) - -_resize_for_mul!(r,a,b) -_move_cached_arrays!(c,r) -mul!(c,a,b) - -A11 = ones(Int,7,3) -A21 = 2*ones(Int,4,3) -A12 = 3*ones(Int,7,5) -blocks = [A11,A21,A12] -coordinates = [(1,1),(2,1),(1,2)] -_a = MultiFieldArray(blocks,coordinates) - -_resize_for_mul!(r,_a,b) -_move_cached_arrays!(c,r) -mul!(c,_a,b) - -_resize_for_mul!(r,a,b) -_move_cached_arrays!(c,r) -mul!(c,a,b) - -add_to_array!(c,c) -add_to_array!(c,10) - -end # module diff --git a/test/MultiFieldTests/MultiFieldCellArraysTests.jl b/test/MultiFieldTests/MultiFieldCellArraysTests.jl deleted file mode 100644 index c396775fa..000000000 --- a/test/MultiFieldTests/MultiFieldCellArraysTests.jl +++ /dev/null @@ -1,17 +0,0 @@ -module MultiFieldCellArraysTests - -using Test -using Gridap.MultiField -using Gridap.MultiField: MultiFieldCellArray - -l = 10 -a = [rand(2,3) for i in 1:l] -b = [rand(2,2) for i in 1:l] -c = [rand(3,3) for i in 1:l] - -block_ids = [(1,1),(1,2),(2,1)] - -mca = MultiFieldCellArray((a,b,c),block_ids) -mcb = collect(mca) - -end # module diff --git a/test/MultiFieldTests/MultiFieldCellBasesTests.jl b/test/MultiFieldTests/MultiFieldCellBasesTests.jl deleted file mode 100644 index cf8e7b938..000000000 --- a/test/MultiFieldTests/MultiFieldCellBasesTests.jl +++ /dev/null @@ -1,204 +0,0 @@ -module MultiFieldCellBasesTests - -using Test -using Gridap.Geometry -using Gridap.Fields -using Gridap.Integration -using Gridap.FESpaces - -using Gridap.MultiField -using Gridap.MultiField: CellBasisWithFieldID -using Gridap.MultiField: CellMatrixFieldWithFieldIds -using Gridap.MultiField: MultiFieldCellArray - -domain =(0,1,0,1) -partition = (3,3) -model = CartesianDiscreteModel(domain,partition) -order = 1 - -trian = get_triangulation(model) -degree = order -quad = CellQuadrature(trian,degree) -q = get_coordinates(quad) - -V = TestFESpace(model=model,reffe=:Lagrangian,order=order,conformity=:H1,valuetype=Float64) -Vp = TestFESpace(model=model,reffe=:Lagrangian,order=order,conformity=:H1,valuetype=Float64,dof_space=:physical) -U = TrialFESpace(V) - -cell_basis_v = get_cell_basis(V) -field_id_v = 3 -v = CellBasisWithFieldID(cell_basis_v,field_id_v) -vq = collect(evaluate(v,q)) -test_cell_basis(v,q,vq) -@test is_in_ref_space(v) - -field_id_a = 2 -a = CellBasisWithFieldID(cell_basis_v,field_id_a) -aq = collect(evaluate(a,q)) - -cell_basis_u = get_cell_basis(U) -field_id_u = 4 -u = CellBasisWithFieldID(cell_basis_u,field_id_u) -uq = collect(evaluate(u,q)) - -field_id_b = 5 -b = CellBasisWithFieldID(cell_basis_u,field_id_b) -bq = collect(evaluate(b,q)) - -cell_basis_vp = get_cell_basis(Vp) -field_id_vp = 6 -vp = CellBasisWithFieldID(cell_basis_vp,field_id_vp) -vpq = collect(evaluate(vp,q)) -test_cell_basis(vp,q,vpq) -@test !is_in_ref_space(vp) - -r = 2*v -test_cell_basis(r,q,2*vq) -@test isa(r,CellBasisWithFieldID) -@test r.field_id == field_id_v -@test is_test(r) - -r = u*2 -test_cell_basis(r,q,2*uq) -@test isa(r,CellBasisWithFieldID) -@test r.field_id == field_id_u -@test is_trial(r) - -r = u + u -test_cell_basis(r,q,2*uq) -@test isa(r,CellBasisWithFieldID) -@test r.field_id == field_id_u -@test is_trial(r) - -r = ∇(u) -@test isa(r,CellBasisWithFieldID) -@test r.field_id == field_id_u -@test is_trial(r) - -r = v * u -test_cell_matrix_field(r,q,collect(evaluate(r,q))) -@test isa(r,CellMatrixFieldWithFieldIds) -@test r.field_id_rows == v.field_id -@test r.field_id_cols == u.field_id - -r = u * v -test_cell_matrix_field(r,q,collect(evaluate(r,q))) -@test isa(r,CellMatrixFieldWithFieldIds) -@test r.field_id_rows == v.field_id -@test r.field_id_cols == u.field_id - -s = a+v -@test s.blocks[1] === a -@test s.blocks[2] === v -@test s.block_ids[1] == (field_id_a,) -@test s.block_ids[2] == (field_id_v,) - -s = a-v -@test s.blocks[1] === a -@test s.block_ids[1] == (field_id_a,) -@test s.block_ids[2] == (field_id_v,) - -s = (a+v)*(b-u) -@test s.block_ids[1] == (field_id_a,field_id_b) -@test s.block_ids[2] == (field_id_a,field_id_u) -@test s.block_ids[3] == (field_id_v,field_id_b) -@test s.block_ids[4] == (field_id_v,field_id_u) -sau = s.blocks[2] -test_cell_matrix_field(sau,q,-1*collect(evaluate(a*u,q))) -sab = s.blocks[1] -test_cell_matrix_field(sab,q,collect(evaluate(a*b,q))) - -s = 4*(b+u) -@test s.block_ids[1] == (field_id_b,) -@test s.block_ids[2] == (field_id_u,) -s4b = s.blocks[1] -test_cell_basis(s4b,q,4*collect(evaluate(b,q))) -s4u = s.blocks[2] -test_cell_basis(s4u,q,4*collect(evaluate(u,q))) - -s = (b+u)*4 -@test s.block_ids[1] == (field_id_b,) -@test s.block_ids[2] == (field_id_u,) -s4b = s.blocks[1] -test_cell_basis(s4b,q,4*collect(evaluate(b,q))) -s4u = s.blocks[2] -test_cell_basis(s4u,q,4*collect(evaluate(u,q))) - -r = u*v -s = a*b - -z = r + s -@test z.blocks[1] === r -@test z.blocks[2] === s -@test z.block_ids[1] == (field_id_v,field_id_u) -@test z.block_ids[2] == (field_id_a,field_id_b) - -# Restrictions - -btrian = BoundaryTriangulation(model) -bdegree = order -bquad = CellQuadrature(btrian,bdegree) - -u_Γb = restrict(u,btrian) -@test isa(u_Γb,CellBasisWithFieldID) -@test is_trial(u_Γb) -@test u_Γb.field_id == field_id_u - -strian = SkeletonTriangulation(model) -sdegree = order -squad = CellQuadrature(strian,sdegree) - -u_Γs = restrict(u,strian) -@test isa(u_Γs.left,CellBasisWithFieldID) -@test isa(u_Γs.right,CellBasisWithFieldID) -@test u_Γs.left.field_id == field_id_u -@test u_Γs.right.field_id == field_id_u - -jump_u_Γs = jump(u_Γs) -@test isa(jump_u_Γs.left,CellBasisWithFieldID) -@test isa(jump_u_Γs.right,CellBasisWithFieldID) -@test jump_u_Γs.left.field_id == field_id_u -@test jump_u_Γs.right.field_id == field_id_u - -v_Γs = restrict(v,strian) - -r = jump(u_Γs)*jump(v_Γs) -@test r.ll.field_id_rows == field_id_v -@test r.ll.field_id_cols == field_id_u - -a_Γs = restrict(a,strian) -s = jump(u_Γs)*jump(a_Γs) -@test s.ll.field_id_rows == field_id_a -@test s.ll.field_id_cols == field_id_u - -z = r + s -@test z.ll.block_ids == [(field_id_v,field_id_u), (field_id_a,field_id_u)] - -# Integration - -vec = integrate(v,trian,quad) -@test isa(vec,MultiFieldCellArray{Float64,1}) - -vec = integrate(v + a,trian,quad) -@test isa(vec,MultiFieldCellArray{Float64,1}) - -mat = integrate(v*u,trian,quad) -@test isa(mat,MultiFieldCellArray{Float64,2}) - -mat = integrate(v*u + a*b,trian,quad) -@test isa(mat,MultiFieldCellArray{Float64,2}) - -vec = integrate(jump(v_Γs),strian,squad) -@test isa(vec.left,MultiFieldCellArray{Float64,1}) - -vec = integrate(jump(v_Γs) + jump(a_Γs),strian,squad) -@test isa(vec.left,MultiFieldCellArray{Float64,1}) -@test vec.left.block_ids == [(field_id_v,), (field_id_a,)] - -mat = integrate(jump(v_Γs)*jump(u_Γs),strian,squad) -@test isa(mat.ll,MultiFieldCellArray{Float64,2}) - -mat = integrate(jump(v_Γs)*jump(u_Γs) + jump(a_Γs)*jump(u_Γs),strian,squad) -@test isa(mat.ll,MultiFieldCellArray{Float64,2}) - -end # module diff --git a/test/MultiFieldTests/MultiFieldCellFieldsTests.jl b/test/MultiFieldTests/MultiFieldCellFieldsTests.jl new file mode 100644 index 000000000..2687f0495 --- /dev/null +++ b/test/MultiFieldTests/MultiFieldCellFieldsTests.jl @@ -0,0 +1,93 @@ +module MultiFieldCellFieldsTests + +using BlockArrays +using Gridap.Arrays +using Gridap.Geometry +using Gridap.FESpaces +using Gridap.Fields +using Gridap.Integration +using Gridap.CellData +using Gridap.MultiField +using Gridap.TensorValues +using Test + +domain = (0,1,0,1) +cells = (2,2) +model = CartesianDiscreteModel(domain,cells) + +trian = Triangulation(model) + +u1(x) = sin(x[1]) +cf1 = CellField(u1,trian) + +u2(x) = cos(x[2]) +cf2 = CellField(u2,trian) + +cf = MultiFieldCellField([cf1,cf2]) + +@test cf1 === cf[1] +@test cf2 === cf[2] + +_cf1, _cf2 = cf + +@test cf1 === _cf1 +@test cf2 === _cf2 + +order = 2 + +domain = (0,1,0,1) +partition = (3,3) +model = CartesianDiscreteModel(domain,partition) + +degree = order + +trian = get_triangulation(model) +quad = CellQuadrature(trian,degree) +q = get_coordinates(quad) + +trian_Γ = SkeletonTriangulation(model) +quad_Γ = CellQuadrature(trian_Γ,degree) +q_Γ = get_coordinates(quad_Γ) + +V = TestFESpace(model=model,order=order,reffe=:Lagrangian,conformity=:H1,valuetype=VectorValue{2,Float64}) +Q = TestFESpace(model=model,order=order-1,reffe=:Lagrangian,conformity=:L2,valuetype=Float64) + +U = TrialFESpace(V) +P = TrialFESpace(Q) + +Y = MultiFieldFESpace([V,Q]) +X = MultiFieldFESpace([U,P]) + +dv, dq = get_cell_basis(Y) +du, dp = get_cell_basis(X) + +n = VectorValue(1,2) + +cellmat = integrate( (n⋅dv)*dp + dq*dp, trian, quad) +cellvec = integrate( n⋅dv, trian, quad) +@test isa(cellmat,VectorOfBlockArrayCoo) +@test isa(cellvec,VectorOfBlockArrayCoo) + +dv_Γ, dq_Γ = restrict(get_cell_basis(Y), trian_Γ) +du_Γ, dp_Γ = restrict(get_cell_basis(X), trian_Γ) + +cellmat_Γ = integrate( jump(n⋅dv_Γ)*dp_Γ.⁺ + mean(dq_Γ)*jump(dp_Γ), trian_Γ,quad_Γ) +cellvec_Γ = integrate( jump(n⋅dv_Γ) + mean(dq_Γ), trian_Γ,quad_Γ) +L = 1 +R = 2 +@test isa(cellmat_Γ,VectorOfBlockArrayCoo) +@test isa(cellmat_Γ[Block(L,R)],VectorOfBlockArrayCoo) +@test isa(cellvec_Γ,VectorOfBlockArrayCoo) +@test isa(cellvec_Γ[Block(L)],VectorOfBlockArrayCoo) + +cell = 1 +@test isa(cellmat_Γ[cell][Block(L,R)],BlockArrayCoo) +@test isa(cellvec_Γ[cell][Block(L)],BlockArrayCoo) + +#a = cellmat_Γ +#using BenchmarkTools +#cache = array_cache(a) +#@btime getindex!($cache,$a,2) + + +end # module diff --git a/test/MultiFieldTests/MultiFieldCellKernelsTests.jl b/test/MultiFieldTests/MultiFieldCellKernelsTests.jl deleted file mode 100644 index 04d99aaac..000000000 --- a/test/MultiFieldTests/MultiFieldCellKernelsTests.jl +++ /dev/null @@ -1,8 +0,0 @@ -module MultiFieldCellKernelsTests - - - - - - -end # module diff --git a/test/MultiFieldTests/MultiFieldFEFunctionsTests.jl b/test/MultiFieldTests/MultiFieldFEFunctionsTests.jl index a26e38766..c89a4fefb 100644 --- a/test/MultiFieldTests/MultiFieldFEFunctionsTests.jl +++ b/test/MultiFieldTests/MultiFieldFEFunctionsTests.jl @@ -1,4 +1,45 @@ module MultiFieldFEFunctionsTests +using BlockArrays +using Gridap.Arrays +using Gridap.Geometry +using Gridap.FESpaces +using Gridap.Fields +using Gridap.Integration +using Gridap.CellData +using Gridap.MultiField +using Test + +order = 2 + +domain = (0,1,0,1) +partition = (3,3) +model = CartesianDiscreteModel(domain,partition) + +trian = get_triangulation(model) +degree = order +quad = CellQuadrature(trian,degree) +q = get_coordinates(quad) + +V = TestFESpace(model=model,order=order,reffe=:Lagrangian,conformity=:H1,valuetype=Float64) +Q = TestFESpace(model=model,order=order-1,reffe=:Lagrangian,conformity=:L2,valuetype=Float64) + +U = TrialFESpace(V) +P = TrialFESpace(Q) + +Y = MultiFieldFESpace([V,Q]) +X = MultiFieldFESpace([U,P]) + +free_values = rand(num_free_dofs(X)) +xh = FEFunction(X,free_values) +test_fe_function(xh) +@test is_a_fe_function(xh) +uh, ph = xh +@test is_a_fe_function(uh) +@test is_a_fe_function(ph) + +cell_values = get_cell_values(xh) +@test isa(cell_values,VectorOfBlockArrayCoo) + end # module diff --git a/test/MultiFieldTests/MultiFieldFEOperatorsTests.jl b/test/MultiFieldTests/MultiFieldFEOperatorsTests.jl index f49ef1150..23767dcda 100644 --- a/test/MultiFieldTests/MultiFieldFEOperatorsTests.jl +++ b/test/MultiFieldTests/MultiFieldFEOperatorsTests.jl @@ -6,6 +6,8 @@ using Gridap.Geometry using Gridap.FESpaces using Gridap.Fields using Gridap.Integration +using Gridap.MultiField +using Gridap.CellData using SparseArrays using Test using LinearAlgebra @@ -65,68 +67,5 @@ b = residual(op,xh) A = jacobian(op,xh) test_fe_operator(op,get_free_values(xh),b) -op = FEOperator(SparseMatrixCSR,X,Y,t_Ω,t_Γ) - -q = get_coordinates(quad) -w_q = get_weights(quad) -ϕ = get_cell_map(trian) -jac = ∇(ϕ) -jac_q = evaluate(jac,q) -x_q = evaluate(ϕ,q) - -function cell_kernel!(A,B,y,x,j,w) - - A_vu = A[1,1] - A_vp = A[1,2] - A_qp = A[2,2] - B_v = B[1] - B_q = B[2] - u = x[1] - p = x[2] - v = y[1] - q = y[2] - - N_v, N_u = size(A_vu) - N_q, N_p = size(A_qp) - S = length(w) - - for s in 1:S - dV = det(j[s])*w[s] - for n_v in 1:N_v - for n_u in 1:N_u - A_vu[n_v,n_u] += v[s,n_v]*u[s,n_u]*dV - end - for n_p in 1:N_p - A_vp[n_v,n_p] += v[s,n_v]*p[s,n_p]*dV - end - end - for n_q in 1:N_q - for n_p in 1:N_p - A_qp[n_q,n_p] -= q[s,n_q]*p[s,n_p]*dV - end - end - for n_v in 1:N_v - B_v[n_v] += v[s,n_v]*4*dV - end - for n_q in 1:N_q - B_q[n_q] += q[s,n_q]*dV - end - end - -end - -function cellmat_Ω(x,y) - x_q = evaluate(x,q) - y_q = evaluate(y,q) - apply_cellmatvec(cell_kernel!,y_q,x_q,jac_q,w_q) -end - -t2_Ω = AffineFETermFromCellMatVec(cellmat_Ω,trian) - -op = AffineFEOperator(X,Y,t_Ω) -op2 = AffineFEOperator(X,Y,t2_Ω) - -@test get_matrix(op) == get_matrix(op2) -@test get_vector(op) == get_vector(op2) end # module diff --git a/test/MultiFieldTests/MultiFieldFESpacesTests.jl b/test/MultiFieldTests/MultiFieldFESpacesTests.jl index d093259fd..d070b4f54 100644 --- a/test/MultiFieldTests/MultiFieldFESpacesTests.jl +++ b/test/MultiFieldTests/MultiFieldFESpacesTests.jl @@ -1,16 +1,16 @@ module MultiFieldFESpacesTests +using BlockArrays +using FillArrays using Gridap.Arrays using Gridap.Geometry using Gridap.FESpaces using Gridap.Fields using Gridap.Integration +using Gridap.CellData using Test using Gridap.MultiField -using Gridap.MultiField: MultiFieldFESpace -using Gridap.MultiField: MultiFieldCellArray -using Gridap.MultiField: ConsecutiveMultiFieldStyle order = 2 @@ -21,11 +21,12 @@ model = CartesianDiscreteModel(domain,partition) trian = get_triangulation(model) degree = order quad = CellQuadrature(trian,degree) +q = get_coordinates(quad) ref_style = [:reference,:physical] for ref_st in ref_style - + V = TestFESpace(model=model,order=order,reffe=:Lagrangian,conformity=:H1,valuetype=Float64,dof_space=ref_st) Q = TestFESpace(model=model,order=order-1,reffe=:Lagrangian,conformity=:L2,valuetype=Float64,dof_space=ref_st) @@ -37,17 +38,15 @@ for ref_st in ref_style Y = MultiFieldFESpace([V,Q],multi_field_style) X = MultiFieldFESpace([U,P],multi_field_style) + cell_axes = get_cell_axes(Y) + @test isa(cell_axes[1][1],BlockedUnitRange) + + cell_axes = get_cell_axes(X) + @test isa(cell_axes[1][1],BlockedUnitRange) + @test num_free_dofs(X) == num_free_dofs(U) + num_free_dofs(P) @test num_free_dofs(X) == num_free_dofs(Y) - free_values = rand(num_free_dofs(X)) - xh = FEFunction(X,free_values) - test_fe_function(xh) - @test is_a_fe_function(xh) - uh, ph = xh - @test is_a_fe_function(uh) - @test is_a_fe_function(ph) - dy = get_cell_basis(Y) @test is_test(dy) @test is_a_fe_cell_basis(dy) @@ -66,30 +65,47 @@ for ref_st in ref_style cellvec = integrate(dv*2,trian,quad) cellids = get_cell_id(trian) cellmatvec = pair_arrays(cellmat,cellvec) + @test isa(cellmat, VectorOfBlockArrayCoo) + @test is_nonzero_block(cellmat,1,1) + @test is_zero_block(cellmat,1,2) + @test isa(cellvec, VectorOfBlockArrayCoo) + @test is_nonzero_block(cellvec,1) + @test is_zero_block(cellvec,2) matvecdata = (cellmatvec,cellids,cellids) matdata = (cellmat,cellids,cellids) vecdata = (cellvec,cellids) - test_fe_space(V,matvecdata,matdata,vecdata) - test_fe_space(U,matvecdata,matdata,vecdata) + free_values = rand(num_free_dofs(X)) + xh = FEFunction(X,free_values) + test_fe_function(xh) + @test is_a_fe_function(xh) + uh, ph = xh + @test is_a_fe_function(uh) + @test is_a_fe_function(ph) + + cell_isconstr = get_cell_isconstrained(X) + @test cell_isconstr == Fill(false,num_cells(model)) - #using Gridap.Visualization - #writevtk(trian,"trian";nsubcells=30,cellfields=["uh" => uh, "ph"=> ph]) + cell_constr = get_cell_constraints(X) + @test isa(cell_constr,VectorOfBlockArrayCoo) - cell_dofs = get_cell_dofs(X) - @test isa(cell_dofs,MultiFieldCellArray) + cell_dof_ids = get_cell_dofs(X) + @test isa(cell_dof_ids,VectorOfBlockArrayCoo) - cellids = [3,5,2] + cf = CellField(X,get_cell_dofs(X)) + @test isa(cf,MultiFieldCellField) - cell_dofs_new = reindex(cell_dofs,cellids) - @test isa(cell_dofs_new,MultiFieldCellArray) - @test cell_dofs_new.block_ids == cell_dofs.block_ids + test_fe_space(X,matvecdata,matdata,vecdata) + test_fe_space(Y,matvecdata,matdata,vecdata) + + #using Gridap.Visualization + #writevtk(trian,"trian";nsubcells=30,cellfields=["uh" => uh, "ph"=> ph]) f(x) = sin(4*pi*(x[1]-x[2]^2))+1 - fh = interpolate(X,[f,f]) - fh = interpolate_everywhere(X,[f,f]) - fh = interpolate_dirichlet(X,[f,f]) + fh = interpolate([f,f],X) + fh = interpolate_everywhere([f,f],X) + fh = interpolate_dirichlet([f,f],X) end end # module diff --git a/test/MultiFieldTests/MultiFieldFESpacesWithLinearConstraintsTests.jl b/test/MultiFieldTests/MultiFieldFESpacesWithLinearConstraintsTests.jl index 90ea40e98..74866c9b0 100644 --- a/test/MultiFieldTests/MultiFieldFESpacesWithLinearConstraintsTests.jl +++ b/test/MultiFieldTests/MultiFieldFESpacesWithLinearConstraintsTests.jl @@ -7,6 +7,7 @@ using Gridap.Geometry using Gridap.FESpaces using Gridap.TensorValues using Gridap.MultiField +using Gridap.CellData using Test domain = (0,1,0,1) @@ -22,10 +23,12 @@ add_tag_from_tags!(labels,"neumann_2",[5,6,8]) trian = Triangulation(model) btrian1 = BoundaryTriangulation(model,"neumann_1") btrian2 = BoundaryTriangulation(model,"neumann_2") +strian = SkeletonTriangulation(model) quad = CellQuadrature(trian,2) bquad1 = CellQuadrature(btrian1,2) bquad2 = CellQuadrature(btrian2,2) +squad = CellQuadrature(strian,2) bn1 = get_normal_vector(btrian1) bn2 = get_normal_vector(btrian2) @@ -87,11 +90,25 @@ function B2_Γ(v) b_Γ(v2,u2,bn2) end +# This is only to stress skeleton machinery +# since shape functions are continuous +function As(u,v) + u1,u2 = u + v1,v2 = v + jump(v1)*jump(u2) + jump(v2)*jump(u2) +end + +function Bs(v) + v1,v2 = v + jump(v2) +end + t_Ω = AffineFETerm(A,B,trian,quad) t1_Γ = FESource(B1_Γ,btrian1,bquad1) t2_Γ = FESource(B2_Γ,btrian2,bquad2) +t_s = AffineFETerm(As,Bs,strian,squad) -op = AffineFEOperator(U,V,t_Ω,t1_Γ,t2_Γ) +op = AffineFEOperator(U,V,t_Ω,t1_Γ,t2_Γ,t_s) uh = solve(op) uh1, uh2 = uh diff --git a/test/MultiFieldTests/MultiFieldSparseMatrixAssemblersTests.jl b/test/MultiFieldTests/MultiFieldSparseMatrixAssemblersTests.jl index 3a764fd17..0a227da59 100644 --- a/test/MultiFieldTests/MultiFieldSparseMatrixAssemblersTests.jl +++ b/test/MultiFieldTests/MultiFieldSparseMatrixAssemblersTests.jl @@ -7,6 +7,8 @@ using Gridap.FESpaces using Gridap.Fields using Gridap.Integration using SparseArrays +using Gridap.CellData +using Gridap.MultiField using Test @@ -16,18 +18,21 @@ domain = (0,1,0,1) partition = (3,3) model = CartesianDiscreteModel(domain,partition) -trian = get_triangulation(model) degree = order +trian = get_triangulation(model) quad = CellQuadrature(trian,degree) +trian_Γ = SkeletonTriangulation(model) +quad_Γ = CellQuadrature(trian_Γ,degree) + V = TestFESpace(model=model,order=order,reffe=:Lagrangian,conformity=:H1,valuetype=Float64) Q = TestFESpace(model=model,order=order-1,reffe=:Lagrangian,conformity=:L2,valuetype=Float64) U = TrialFESpace(V) P = TrialFESpace(Q) -Y = [V,Q] -X = [U,P] +Y = MultiFieldFESpace([V,Q]) +X = MultiFieldFESpace([U,P]) free_values = rand(num_free_dofs(X)) xh = FEFunction(X,free_values) @@ -43,11 +48,18 @@ cellvec = integrate(dv*2,trian,quad) cellids = get_cell_id(trian) cellmatvec = pair_arrays(cellmat,cellvec) +dv_Γ, dq_Γ = restrict(get_cell_basis(Y), trian_Γ) +du_Γ, dp_Γ = restrict(get_cell_basis(X), trian_Γ) +cellmat_Γ = integrate( jump(dv_Γ)*dp_Γ.⁺ + mean(dq_Γ)*jump(dp_Γ), trian_Γ,quad_Γ) +cellvec_Γ = integrate( jump(dv_Γ) + mean(dq_Γ), trian_Γ,quad_Γ) +cellmatvec_Γ = pair_arrays(cellmat_Γ,cellvec_Γ) +cellids_Γ = get_cell_id(trian_Γ) + assem = SparseMatrixAssembler(SparseMatrixCSR{0},X,Y) -matvecdata = ([cellmatvec],[cellids],[cellids]) -matdata = ([cellmat],[cellids],[cellids]) -vecdata = ([cellvec],[cellids]) +matvecdata = ([cellmatvec,cellmatvec_Γ],[cellids,cellids_Γ],[cellids,cellids_Γ]) +matdata = ([cellmat,cellmat_Γ],[cellids,cellids_Γ],[cellids,cellids_Γ]) +vecdata = ([cellvec,cellvec_Γ],[cellids,cellids_Γ]) data = (matvecdata,matdata,vecdata) test_assembler(assem,matdata,vecdata,data) diff --git a/test/MultiFieldTests/runtests.jl b/test/MultiFieldTests/runtests.jl index 9841b97f0..a5d7ed28d 100644 --- a/test/MultiFieldTests/runtests.jl +++ b/test/MultiFieldTests/runtests.jl @@ -2,13 +2,7 @@ module MultiFieldTests using Test -@testset "MultiFieldArrays" begin include("MultiFieldArraysTests.jl") end - -@testset "MultiFieldCellArrays" begin include("MultiFieldCellArraysTests.jl") end - -@testset "MultiFieldCellBases" begin include("MultiFieldCellBasesTests.jl") end - -@testset "MultiFieldCellKernels" begin include("MultiFieldCellKernelsTests.jl") end +@testset "MultiFieldCellFields" begin include("MultiFieldCellFieldsTests.jl") end @testset "MultiFieldFESpaces" begin include("MultiFieldFESpacesTests.jl") end diff --git a/test/VisualizationTests/PrintOpTreesTests.jl b/test/VisualizationTests/PrintOpTreesTests.jl index ff58ec874..5760db4de 100644 --- a/test/VisualizationTests/PrintOpTreesTests.jl +++ b/test/VisualizationTests/PrintOpTreesTests.jl @@ -1,8 +1,13 @@ module PrintOpTrees using FillArrays -using Gridap +using Gridap.Arrays +using Gridap.Geometry +using Gridap.CellData +using Gridap.FESpaces +using Gridap.Fields using Gridap.Arrays: CompressedArray +using Gridap.Visualization io = IOBuffer() diff --git a/test/VisualizationTests/VisualizationDataTests.jl b/test/VisualizationTests/VisualizationDataTests.jl index 807acfe1f..8d18310e5 100644 --- a/test/VisualizationTests/VisualizationDataTests.jl +++ b/test/VisualizationTests/VisualizationDataTests.jl @@ -1,7 +1,11 @@ module TestVisualizationData using Test -using Gridap +using Gridap.Geometry +using Gridap.CellData +using Gridap.FESpaces +using Gridap.TensorValues +using Gridap.Algebra using Gridap.Visualization using Gridap.ReferenceFEs using Gridap.Geometry: get_reffes diff --git a/test/VisualizationTests/VtkTests.jl b/test/VisualizationTests/VtkTests.jl index 61a9e117a..f9da7d2b3 100644 --- a/test/VisualizationTests/VtkTests.jl +++ b/test/VisualizationTests/VtkTests.jl @@ -113,6 +113,20 @@ paraview_collection(f) do pvd vtk_save(pvd) end +# Visualize AppendedTriangulation + +domain = (0,1,0,1) +partition = (10,10) +grid1 = CartesianGrid(domain,partition) + +domain = (1,2,0,1) +partition = (10,10) +grid2 = simplexify(CartesianGrid(domain,partition)) + +trian = lazy_append(grid1,grid2) + +f = joinpath(d,"trian") +writevtk(trian,f) rm(d,recursive=true) end # module diff --git a/test/issue_349.jl b/test/issue_349.jl new file mode 100644 index 000000000..4474aeaf2 --- /dev/null +++ b/test/issue_349.jl @@ -0,0 +1,71 @@ +module TestIssue349 +using Test +using Gridap + +# solve +# E = - ∇ϕ +# ρ = divergence(E) + +ϕ_e(pt) = -1/2*pt[1]^2 +E_e(pt) = pt +ρ(pt) = 1 + +model = CartesianDiscreteModel((-1,1), 10) +order = 1 + +V_E = TestFESpace( + reffe=:Lagrangian, conformity=:H1, valuetype=VectorValue{1,Float64}, + model=model, order=order, +) + +V_ϕ = TestFESpace( + reffe=:Lagrangian, conformity=:H1, valuetype=Float64, + model=model, order=order, dirichlet_tags="boundary", +) + +U_ϕ = TrialFESpace(V_ϕ, ϕ_e) +U_E = TrialFESpace(V_E) + +V = MultiFieldFESpace([V_ϕ, V_E]) +U = MultiFieldFESpace([U_ϕ, U_E]) + +function A_works(u, v) + ϕ, E = u + v_ϕ, v_E = v + -∇(ϕ) ⊙ v_E - E ⊙ v_E + divergence(E) ⊙ v_ϕ +end + +function A_fails(u, v) + ϕ, E = u + v_ϕ, v_E = v + (-∇(ϕ) - E) ⊙ v_E + divergence(E) ⊙ v_ϕ +end + +function b(v) + v_ϕ, v_E = v + ρ ⊙ v_ϕ +end + +function errornorm(u_e, u, train, quad) + arr = integrate((u_e - u)⊙(u_e - u), trian, quad) + sqrt(sum(arr)) +end + +trian = Triangulation(model) +quad = CellQuadrature(trian, 2) +op_works = AffineFEOperator(U, V, AffineFETerm(A_works, b, trian, quad)) +op_fails = AffineFEOperator(U, V, AffineFETerm(A_fails, b, trian, quad)) +sol = solve(op_works) # works in #349 +ϕ_sol, E_sol = sol +@test errornorm(ϕ_e, ϕ_sol, trian, quad) < 1e-2 +@test errornorm(E_e, E_sol, trian, quad) < 1e-4 +@test begin + ϕ_sol2, E_sol2 = solve(op_fails) # throws LinearAlgebra.SingularException(0) in #349 + @test errornorm(ϕ_e, ϕ_sol, trian, quad) ≈ + errornorm(ϕ_e, ϕ_sol2, trian, quad) + @test errornorm(E_e, E_sol, trian, quad) ≈ + errornorm(E_e, E_sol2, trian, quad) + true +end + +end#module diff --git a/test/issue_368.jl b/test/issue_368.jl new file mode 100644 index 000000000..dcaf42837 --- /dev/null +++ b/test/issue_368.jl @@ -0,0 +1,35 @@ +module TestIssue368 +# Boundary integrals throw error trying to call zero(::Union{}) +using Test +using LinearAlgebra +using Gridap + +function solve_weak_dirichlet(model) + V = TestFESpace(reffe=:Lagrangian, order=1, model=model, valuetype=Float64) + + u_e(pt) = -1/2*pt[1]^2 + + F(u, v) = u ⊙ v - u_e ⊙ v + B(u, v) = u ⊙ v - u_e ⊙ v + + trian = Triangulation(model) + quad = CellQuadrature(trian, 2) + t_inner = FETerm(F, trian, quad) + + btrian = BoundaryTriangulation(model, "boundary") + bquad = CellQuadrature(btrian, 2) + t_bdry = FETerm(B, btrian, bquad) + + U = TrialFESpace(V) + op = FEOperator(U,V,t_inner, t_bdry) + sol = solve(op) + @test norm(integrate(sol - u_e, trian, quad)) < 1e3 + does_not_throw = true +end + +model1d = CartesianDiscreteModel((0,1), 10) +model2d = CartesianDiscreteModel((0,1, 0, 1), (10,10)) + +@test_broken solve_weak_dirichlet(model1d) +@test solve_weak_dirichlet(model2d) +end diff --git a/test/runtests.jl b/test/runtests.jl index aba32dc08..f7239fa97 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -22,14 +22,23 @@ using Test @time @testset "ReferenceFEs" begin include("ReferenceFEsTests/runtests.jl") end +@time @testset "CellData" begin include("CellDataTests/runtests.jl") end + @time @testset "Geometry" begin include("GeometryTests/runtests.jl") end -@time @testset "FESpaces" begin include("FESpacesTests/runtests.jl") end +@time @testset "FESpaces (1/2)" begin include("FESpacesTests/runtests_1.jl") end + +@time @testset "FESpaces (2/2)" begin include("FESpacesTests/runtests_2.jl") end @time @testset "MultiField" begin include("MultiFieldTests/runtests.jl") end @time @testset "Visualization" begin include("VisualizationTests/runtests.jl") end +@time @testset "Issues" begin + include("issue_349.jl") + include("issue_368.jl") +end + include("GridapTests/runtests.jl") include("../bench/runbenchs.jl")