diff --git a/NEWS.md b/NEWS.md index 62cd4a45a..22252b39f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,23 @@ 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.17.0] - 2021-10-22 + +### Added + +- Aliases `Interior`, `Boundary`, `Skeleton`, and `Interface` for the `Triangulation`, `BoundaryTriangulation`, `SkeletonTriangulation`, and `InterfaceTriangulation` constructors. Since PR [#662](https://github.com/gridap/Gridap.jl/pull/662). +- Function `create_pvtk_file` for exporting results in `pvtu` format. Since PR [#685](https://github.com/gridap/Gridap.jl/pull/685). + +### Changed + +- Major refactoring in the `Triangulation` interface to properly support the solution of PDEs defined on domains of different dimension. The major change from the user perspective is that `Triangulation` objects can be used both to integrate the weak form (as before) but also to define FE spaces (except for unfitted triangulations obviously). It is still possible to define FE spaces from `DiscreteModels`, but it is safer and more idiomatic (closer to the math notation) to use `Triangulation` objects from now on. Since PR [#662](https://github.com/gridap/Gridap.jl/pull/662). +- Changes in assembly interface to allow optimization when assembling matrices and vectors simultaneously. Since PR [#685](https://github.com/gridap/Gridap.jl/pull/685). + +### Removed + +- `BoundaryDiscreteModel`, `RestrictedDiscreteMdeol`, `RestrictedTriangulation`, `TriangulationStyle`, `BackgroundTriangulation`, `SubTriangulation`, `get_cell_to_bgcell`, `get_cell_ref_map`, `get_background_triangulation`, and `have_compatible_domains`. Since PR [#662](https://github.com/gridap/Gridap.jl/pull/662). +- Functions `scale_entries!` and `fill_entries!`. Replaced by Julia functions `LinearAlgebra.rmul!` and `LinearAlgebra.fillstored!`. Since PR [#680](https://github.com/gridap/Gridap.jl/pull/680). + ## [0.16.5] - 2021-09-08 ### Added diff --git a/Project.toml b/Project.toml index b6c829715..002e42c71 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Gridap" uuid = "56d4f2e9-7ea1-5844-9cf6-b9c51ca7ce8e" authors = ["Santiago Badia ", "Francesc Verdugo "] -version = "0.16.5" +version = "0.17.0" [deps] AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" @@ -43,9 +43,9 @@ LineSearches = "7.0.1" NLsolve = "4.3.0" NearestNeighbors = "0.4.8" QuadGK = "2.3.1, 2.4" -SparseMatricesCSR = "0.6" StaticArrays = "0.12.1, 1.0" -WriteVTK = "1.7, 1.8" +WriteVTK = "=1.11.0" +SparseMatricesCSR = "0.6.4" julia = "1.3" [extras] diff --git a/src/Algebra/Algebra.jl b/src/Algebra/Algebra.jl index cdf8bd7e3..60479f04e 100644 --- a/src/Algebra/Algebra.jl +++ b/src/Algebra/Algebra.jl @@ -26,7 +26,6 @@ export allocate_matrix_and_vector export allocate_in_domain export allocate_in_range export add_entries! -export scale_entries! export muladd! export nz_counter export nz_allocation @@ -45,7 +44,6 @@ export is_entry_stored export finalize_coo! export sparse_from_coo export add_entry! -export fill_entries! export copy_entries! export allocate_coo_vectors export push_coo! diff --git a/src/Algebra/AlgebraInterfaces.jl b/src/Algebra/AlgebraInterfaces.jl index 5bf839c8b..45d18f6dc 100644 --- a/src/Algebra/AlgebraInterfaces.jl +++ b/src/Algebra/AlgebraInterfaces.jl @@ -61,17 +61,6 @@ function allocate_in_domain(::Type{V},matrix) where V allocate_vector(V,n) end -""" - fill_entries!(a,v) - -Fill the entries of array `a` with the value `v`. Returns `a`. -For sparse matrices it only fills the non-zero entries. -""" -function fill_entries!(a,v) - fill!(a,v) - a -end - """ copy_entries!(a,b) @@ -196,19 +185,6 @@ end A end -""" - scale_entries!(a,v) - -Scale the entries of array `a` with the value `v`. Returns `a`. -""" -function scale_entries!(a,b) - @inbounds for i in eachindex(a) - a[i] = b*a[i] - end - a -end - -# Base.mul! """ muladd!(c,a,b) @@ -280,7 +256,7 @@ end # We can also do a loop and update # the entries of c # -# fill_entries!(c,0) +# fill!(c,0) or LinearAlgebra.fillstored!(c,0) # add_entry!(c,v,i,j) # add_entries!(c,vs,is,js) # @@ -290,6 +266,20 @@ struct DoNotLoop end LoopStyle(::Type) = DoNotLoop() LoopStyle(::T) where T = LoopStyle(T) +# By default process, matrix and vector separately +# but, in some situations, create_from_nz of the vector +# can reuse data from the one computed in +# create_from_nz for the matrix (e.g., GridapDistributed) +function create_from_nz(a,b) + A = create_from_nz(a) + B = create_from_nz(b) + A,B +end +# See comment above for create_from_nz. The same applies here +# for nz_allocation. +function nz_allocation(a,b) + nz_allocation(a),nz_allocation(b) +end # For dense arrays @@ -342,34 +332,34 @@ SparseMatrixBuilder(a::SparseMatrixBuilder) = a get_array_type(::SparseMatrixBuilder{T}) where T = T -mutable struct SparseMatrixCounter{T,A} +mutable struct CounterCOO{T,A} nnz::Int axes::A - function SparseMatrixCounter{T}(axes::A) where {T,A<:NTuple{2,AbstractUnitRange}} + function CounterCOO{T}(axes::A) where {T,A<:NTuple{2,AbstractUnitRange}} nnz = 0 new{T,A}(nnz,axes) end end -LoopStyle(::Type{<:SparseMatrixCounter}) = Loop() +LoopStyle(::Type{<:CounterCOO}) = Loop() -@inline function add_entry!(::Function,a::SparseMatrixCounter{T},v,i,j) where T +@inline function add_entry!(::Function,a::CounterCOO{T},v,i,j) where T if is_entry_stored(T,i,j) a.nnz = a.nnz + 1 end a end -struct CooAllocation{T,A,B,C} - counter::SparseMatrixCounter{T,A} +struct AllocationCOO{T,A,B,C} + counter::CounterCOO{T,A} I::B J::B V::C end -LoopStyle(::Type{<:CooAllocation}) = Loop() +LoopStyle(::Type{<:AllocationCOO}) = Loop() -@inline function add_entry!(::typeof(+),a::CooAllocation{T},::Nothing,i,j) where T +@inline function add_entry!(::typeof(+),a::AllocationCOO{T},::Nothing,i,j) where T if is_entry_stored(T,i,j) a.counter.nnz = a.counter.nnz + 1 k = a.counter.nnz @@ -379,7 +369,7 @@ LoopStyle(::Type{<:CooAllocation}) = Loop() nothing end -@inline function add_entry!(::typeof(+),a::CooAllocation{T},v,i,j) where T +@inline function add_entry!(::typeof(+),a::AllocationCOO{T},v,i,j) where T if is_entry_stored(T,i,j) a.counter.nnz = a.counter.nnz + 1 k = a.counter.nnz @@ -391,20 +381,20 @@ end end #function nz_counter(::Type{T},axes) where T<:AbstractSparseMatrix -# SparseMatrixCounter{T}(axes) +# CounterCOO{T}(axes) #end function nz_counter(::SparseMatrixBuilder{T},axes) where T<:AbstractSparseMatrix - SparseMatrixCounter{T}(axes) + CounterCOO{T}(axes) end -function nz_allocation(a::SparseMatrixCounter{T}) where T - counter = SparseMatrixCounter{T}(a.axes) +function nz_allocation(a::CounterCOO{T}) where T + counter = CounterCOO{T}(a.axes) I,J,V = allocate_coo_vectors(T,a.nnz) - CooAllocation(counter,I,J,V) + AllocationCOO(counter,I,J,V) end -function create_from_nz(a::CooAllocation{T}) where T +function create_from_nz(a::AllocationCOO{T}) where T m,n = map(length,a.counter.axes) finalize_coo!(T,a.I,a.J,a.V,m,n) sparse_from_coo(T,a.I,a.J,a.V,m,n) @@ -466,13 +456,7 @@ function copy_entries!(a::T,b::T) where T<:AbstractSparseMatrix end end -function fill_entries!(A::AbstractSparseMatrix,v) - nonzeros(A) .= v - A -end - function allocate_coo_vectors( ::Type{<:AbstractSparseMatrix{Tv,Ti}},n::Integer) where {Tv,Ti} (zeros(Ti,n), zeros(Ti,n), zeros(Tv,n)) end - diff --git a/src/Algebra/LinearSolvers.jl b/src/Algebra/LinearSolvers.jl index 33faff873..7182f3a5c 100644 --- a/src/Algebra/LinearSolvers.jl +++ b/src/Algebra/LinearSolvers.jl @@ -43,7 +43,7 @@ end function zero_initial_guess(op::AffineOperator) x = allocate_in_domain(typeof(op.vector),op.matrix) - fill_entries!(x,zero(eltype(x))) + fill!(x,zero(eltype(x))) x end @@ -174,12 +174,12 @@ function solve!(x::AbstractVector, ls::LinearSolver, op::NonlinearOperator, cache::Nothing) - fill_entries!(x,zero(eltype(x))) + fill!(x,zero(eltype(x))) b = residual(op, x) A = jacobian(op, x) ss = symbolic_setup(ls, A) ns = numerical_setup(ss,A) - scale_entries!(b,-1) + rmul!(b,-1) solve!(x,ns,b) LinearSolverCache(A,b,ns) end @@ -188,13 +188,13 @@ function solve!(x::AbstractVector, ls::LinearSolver, op::NonlinearOperator, cache) - fill_entries!(x,zero(eltype(x))) + fill!(x,zero(eltype(x))) b = cache.b A = cache.A ns = cache.ns residual!(b, op, x) numerical_setup!(ns,A) - scale_entries!(b,-1) + ruml!(b,-1) solve!(x,ns,b) cache end diff --git a/src/Algebra/NLSolvers.jl b/src/Algebra/NLSolvers.jl index 8948c1bb9..c83a044ea 100644 --- a/src/Algebra/NLSolvers.jl +++ b/src/Algebra/NLSolvers.jl @@ -54,7 +54,7 @@ function _solve_nr!(x,A,b,dx,ns,nls,op) for nliter in 1:nls.max_nliters # Solve linearized problem - scale_entries!(b,-1) + rmul!(b,-1) solve!(dx,ns,b) x .+= dx @@ -183,5 +183,3 @@ function _update_nlsolve_cache!(cache,x0,op) numerical_setup!(ns,j0) NLSolversCache(f0,j0,df,ns,nothing) end - - diff --git a/src/Arrays/AlgebraMaps.jl b/src/Arrays/AlgebraMaps.jl index 561c11d9c..fa8d82feb 100644 --- a/src/Arrays/AlgebraMaps.jl +++ b/src/Arrays/AlgebraMaps.jl @@ -60,8 +60,3 @@ end function evaluate!(cache,k::TouchEntriesMap,A,v,i) add_entries!(+,A,nothing,i) end - - - - - diff --git a/src/Arrays/AppendedArrays.jl b/src/Arrays/AppendedArrays.jl index 6a75f4006..c44e37007 100644 --- a/src/Arrays/AppendedArrays.jl +++ b/src/Arrays/AppendedArrays.jl @@ -111,6 +111,19 @@ function lazy_map(::typeof(evaluate),::Type{T},b::Fill,a::AppendedArray...) wher end end +function lazy_map(::typeof(evaluate),::Type{T},b::Fill,a::AppendedArray) where T + f = b.value + ra = lazy_map(f,a.a) + rb = lazy_map(f,a.b) + lazy_append(ra,rb) +end + +function lazy_map(k::Reindex{<:LazyArray},j_to_i::AppendedArray) + a = lazy_map(k,j_to_i.a) + b = lazy_map(k,j_to_i.b) + lazy_append(a,b) +end + # In that case we don't implement it for ::Type{T} variant since we want to # avoid to run type inference since the first entry in a can have non-concrete # eltype diff --git a/src/Arrays/Arrays.jl b/src/Arrays/Arrays.jl index c5dadb357..e8c2ef783 100644 --- a/src/Arrays/Arrays.jl +++ b/src/Arrays/Arrays.jl @@ -25,9 +25,6 @@ import Base: getindex, setindex! import Base: similar import Base: IndexStyle -import Gridap.Algebra: scale_entries! -import Gridap.Algebra: fill_entries! - # CachedArray export CachedArray diff --git a/src/Arrays/PosNegReindex.jl b/src/Arrays/PosNegReindex.jl index 00cfb8dc8..327f9828e 100644 --- a/src/Arrays/PosNegReindex.jl +++ b/src/Arrays/PosNegReindex.jl @@ -211,3 +211,4 @@ all_neg(a::PosNegPartition) = length(a.ipos_to_i)==0 # i = j_to_i[j] # i_to_v[i]=v # end + diff --git a/src/CellData/AttachDirichlet.jl b/src/CellData/AttachDirichlet.jl index 042f8de6c..78aa008e4 100644 --- a/src/CellData/AttachDirichlet.jl +++ b/src/CellData/AttachDirichlet.jl @@ -83,11 +83,9 @@ end cm, cv = cache if mask vec_with_bcs = evaluate!(cm,*,mat,vals) - scale_entries!(vec_with_bcs,-1) + rmul!(vec_with_bcs,-1) else vec_with_bcs = evaluate!(cv,ZeroVectorMap(),mat) end (mat, vec_with_bcs) end - - diff --git a/src/CellData/CellData.jl b/src/CellData/CellData.jl index 8a1ce1a07..ecbbfc6ed 100644 --- a/src/CellData/CellData.jl +++ b/src/CellData/CellData.jl @@ -32,7 +32,7 @@ import Gridap.Geometry: num_cells import Gridap.Geometry: get_triangulation import Gridap.TensorValues: inner, outer, double_contraction, symmetric_part -import LinearAlgebra: det, tr, cross, dot, ⋅ +import LinearAlgebra: det, tr, cross, dot, ⋅, rmul! import Base: inv, abs, abs2, *, +, -, /, adjoint, transpose, real, imag, conj export gradient, ∇ diff --git a/src/CellData/CellDofs.jl b/src/CellData/CellDofs.jl index 541d452f6..9a77709cc 100644 --- a/src/CellData/CellDofs.jl +++ b/src/CellData/CellDofs.jl @@ -18,18 +18,74 @@ function change_domain(a::CellDof,::PhysicalDomain,::ReferenceDomain) @notimplemented end -function change_domain(a::CellDof,target_trian::Triangulation,target_domain::DomainStyle) - @notimplemented +function change_domain(a::CellDof,ttrian::Triangulation,target_domain::DomainStyle) + change_domain(a,DomainStyle(a),ttrian,target_domain) +end + +function change_domain(a::CellDof,::ReferenceDomain,ttrian::Triangulation,::ReferenceDomain) + msg = """\n + We cannot move the given CellDof to the reference domain of the requested triangulation. + Make sure that the given triangulation is either the same as the triangulation on which the + CellDof is defined, or that the latter triangulation is the background of the former. + """ + strian = get_triangulation(a) + if strian === ttrian + return a + end + @assert is_change_possible(strian,ttrian) msg + D = num_cell_dims(strian) + sglue = get_glue(strian,Val(D)) + tglue = get_glue(ttrian,Val(D)) + change_domain_ref_ref(a,ttrian,sglue,tglue) +end + +function change_domain(a::CellDof,::PhysicalDomain,ttrian::Triangulation,::PhysicalDomain) + msg = """\n + We cannot move the given CellDof to the physical domain of the requested triangulation. + Make sure that the given triangulation is either the same as the triangulation on which the + CellDof is defined, or that the latter triangulation is the background of the former. + """ + strian = get_triangulation(a) + if strian === ttrian + return a + end + @assert is_change_possible(strian,ttrian) msg + D = num_cell_dims(strian) + sglue = get_glue(strian,Val(D)) + tglue = get_glue(ttrian,Val(D)) + change_domain_phys_phys(a,ttrian,sglue,tglue) +end + +function change_domain(a::CellDof,::PhysicalDomain,trian::Triangulation,::ReferenceDomain) + a_trian = change_domain(a,trian,PhysicalDomain()) + change_domain(a_trian,ReferenceDomain()) +end + +function change_domain(a::CellDof,::ReferenceDomain,trian::Triangulation,::PhysicalDomain) + a_phys = change_domain(a,PhysicalDomain()) + change_domain(a_phys,trian,PhysicalDomain()) +end + +function change_domain_ref_ref( + a::CellDof,ttrian::Triangulation,sglue::FaceToFaceGlue,tglue::FaceToFaceGlue) + sface_to_dof = get_data(a) + mface_to_sface = sglue.mface_to_tface + tface_to_mface = tglue.tface_to_mface + tface_to_mface_map = tglue.tface_to_mface_map + mface_to_dof = extend(sface_to_dof,mface_to_sface) + tface_to_dof = lazy_map(Reindex(mface_to_dof),tface_to_mface) + @notimplementedif ! isa(tface_to_mface_map,AbstractArray{<:GenericField{typeof(identity)}}) + CellDof(tface_to_dof,ttrian,ReferenceDomain()) end -function change_domain(a::CellDof,target_trian::RestrictedTriangulation,target_domain::DomainStyle) - @notimplementedif DomainStyle(a) != target_domain - trian_a = get_triangulation(a) - @notimplementedif ! have_compatible_domains(trian_a,get_background_triangulation(target_trian)) - cell_dof = get_data(a) - tcell_to_cell = get_cell_to_bgcell(target_trian) - tcell_dof = lazy_map(Reindex(cell_dof),tcell_to_cell) - CellDof(tcell_dof,target_trian,DomainStyle(a)) +function change_domain_phys_phys( + a::CellDof,ttrian::Triangulation,sglue::FaceToFaceGlue,tglue::FaceToFaceGlue) + sface_to_dof = get_data(a) + mface_to_sface = sglue.mface_to_tface + tface_to_mface = tglue.tface_to_mface + mface_to_dof = extend(sface_to_dof,mface_to_sface) + tface_to_dof = lazy_map(Reindex(mface_to_dof),tface_to_mface) + CellDof(tface_to_dof,ttrian,PhysicalDomain()) end function get_cell_points(dofs::CellDof) diff --git a/src/CellData/CellFields.jl b/src/CellData/CellFields.jl index c9952dfc2..4ca12fd59 100644 --- a/src/CellData/CellFields.jl +++ b/src/CellData/CellFields.jl @@ -61,6 +61,10 @@ end """ abstract type CellField <: CellDatum end +function similar_cell_field(f::CellField,cell_data,trian,ds) + GenericCellField(cell_data,trian,ds) +end + function Base.show(io::IO,::MIME"text/plain",f::CellField) show(io,f) print(io,":") @@ -102,7 +106,10 @@ end function get_normal_vector(trian::Triangulation) cell_normal = get_facet_normal(trian) - @assert ! isa(cell_normal,SkeletonPair) + get_normal_vector(trian,cell_normal) +end + +function get_normal_vector(trian::Triangulation,cell_normal::AbstractArray) GenericCellField(cell_normal,trian,ReferenceDomain()) end @@ -114,7 +121,7 @@ function change_domain(a::CellField,::ReferenceDomain,::PhysicalDomain) cell_invmap = lazy_map(inverse_map,cell_map) cell_field_ref = get_data(a) cell_field_phys = lazy_map(Broadcasting(∘),cell_field_ref,cell_invmap) - GenericCellField(cell_field_phys,trian,PhysicalDomain()) + similar_cell_field(a,cell_field_phys,trian,PhysicalDomain()) end function change_domain(a::CellField,::PhysicalDomain,::ReferenceDomain) @@ -122,59 +129,45 @@ function change_domain(a::CellField,::PhysicalDomain,::ReferenceDomain) cell_map = get_cell_map(trian) cell_field_phys = get_data(a) cell_field_ref = lazy_map(Broadcasting(∘),cell_field_phys,cell_map) - GenericCellField(cell_field_ref,trian,ReferenceDomain()) + similar_cell_field(a,cell_field_ref,trian,ReferenceDomain()) end -""" -""" function change_domain(a::CellField,target_trian::Triangulation,target_domain::DomainStyle) change_domain(a,DomainStyle(a),target_trian,target_domain) end -function change_domain(a::CellField,::ReferenceDomain,trian::Triangulation,::ReferenceDomain) - trian_a = get_triangulation(a) - if have_compatible_domains(trian_a,trian) +function change_domain(a::CellField,::ReferenceDomain,ttrian::Triangulation,::ReferenceDomain) + msg = """\n + We cannot move the given CellField to the reference domain of the requested triangulation. + Make sure that the given triangulation is either the same as the triangulation on which the + CellField is defined, or that the latter triangulation is the background of the former. + """ + strian = get_triangulation(a) + if strian === ttrian return a - elseif have_compatible_domains( - trian_a,get_background_triangulation(trian)) || have_compatible_domains( - get_background_triangulation(trian_a),get_background_triangulation(trian)) - - cell_id = get_cell_to_bgcell(trian,trian_a) - @assert ! isa(cell_id,SkeletonPair) - cell_a_q = lazy_map(Reindex(get_data(a)),cell_id) - cell_s2q = get_cell_ref_map(trian,trian_a) - cell_field = lazy_map(Broadcasting(∘),cell_a_q,cell_s2q) - GenericCellField(cell_field,trian,ReferenceDomain()) - elseif have_compatible_domains( - trian_a,get_background_triangulation(get_background_triangulation(trian))) - bg_trian = get_background_triangulation(trian) - bg_a = change_domain(a,bg_trian,DomainStyle(a)) - change_domain(bg_a,trian,DomainStyle(a)) - else - @unreachable """\n - We cannot move the given CellField to the reference domain of the requested triangulation. - Make sure that the given triangulation is either the same as the triangulation on which the - CellField is defined, or that the latter triangulation is the background of the former. - """ end + @assert is_change_possible(strian,ttrian) msg + D = num_cell_dims(strian) + sglue = get_glue(strian,Val(D)) + tglue = get_glue(ttrian,Val(D)) + change_domain_ref_ref(a,ttrian,sglue,tglue) end -function change_domain(a::CellField,::PhysicalDomain,trian::Triangulation,::PhysicalDomain) - trian_a = get_triangulation(a) - if have_compatible_domains(trian_a,trian) +function change_domain(a::CellField,::PhysicalDomain,ttrian::Triangulation,::PhysicalDomain) + msg = """\n + We cannot move the given CellField to the physical domain of the requested triangulation. + Make sure that the given triangulation is either the same as the triangulation on which the + CellField is defined, or that the latter triangulation is the background of the former. + """ + strian = get_triangulation(a) + if strian === ttrian return a - elseif have_compatible_domains(trian_a,get_background_triangulation(trian)) - cell_id = get_cell_to_bgcell(trian) - @assert ! isa(cell_id,SkeletonPair) - cell_field = lazy_map(Reindex(get_data(a)),cell_id) - GenericCellField(cell_field,trian,PhysicalDomain()) - else - @unreachable """\n - We cannot move the given CellField to the physical domain of the requested triangulation. - Make sure that the given triangulation is either the same as the triangulation on which the - CellField is defined, or that the latter triangulation is the background of the former. - """ end + @assert is_change_possible(strian,ttrian) msg + D = num_cell_dims(strian) + sglue = get_glue(strian,Val(D)) + tglue = get_glue(ttrian,Val(D)) + change_domain_phys_phys(a,ttrian,sglue,tglue) end function change_domain(a::CellField,::PhysicalDomain,trian::Triangulation,::ReferenceDomain) @@ -187,6 +180,28 @@ function change_domain(a::CellField,::ReferenceDomain,trian::Triangulation,::Phy change_domain(a_phys,trian,PhysicalDomain()) end +function change_domain_ref_ref( + a::CellField,ttrian::Triangulation,sglue::FaceToFaceGlue,tglue::FaceToFaceGlue) + sface_to_field = get_data(a) + mface_to_sface = sglue.mface_to_tface + tface_to_mface = tglue.tface_to_mface + tface_to_mface_map = tglue.tface_to_mface_map + mface_to_field = extend(sface_to_field,mface_to_sface) + tface_to_field_s = lazy_map(Reindex(mface_to_field),tface_to_mface) + tface_to_field_t = lazy_map(Broadcasting(∘),tface_to_field_s,tface_to_mface_map) + similar_cell_field(a,tface_to_field_t,ttrian,ReferenceDomain()) +end + +function change_domain_phys_phys( + a::CellField,ttrian::Triangulation,sglue::FaceToFaceGlue,tglue::FaceToFaceGlue) + sface_to_field = get_data(a) + mface_to_sface = sglue.mface_to_tface + tface_to_mface = tglue.tface_to_mface + mface_to_field = extend(sface_to_field,mface_to_sface) + tface_to_field = lazy_map(Reindex(mface_to_field),tface_to_mface) + similar_cell_field(a,tface_to_field,ttrian,PhysicalDomain()) +end + """ """ struct GenericCellField{DS} <: CellField @@ -206,7 +221,9 @@ end get_data(f::GenericCellField) = f.cell_field get_triangulation(f::GenericCellField) = f.trian DomainStyle(::Type{GenericCellField{DS}}) where DS = DS() - +function similar_cell_field(f::GenericCellField,cell_data,trian,ds) + GenericCellField(cell_data,trian,ds) +end """ dist = distance(polytope::ExtrusionPolytope, @@ -253,7 +270,8 @@ function return_cache(f::CellField,x::Point) end function _point_to_cell_cache(trian::Triangulation) - topo = GridTopology(trian) + model = get_background_model(trian) + topo = get_grid_topology(model) vertex_coordinates = Geometry.get_vertex_coordinates(topo) kdtree = KDTree(map(nc -> SVector(Tuple(nc)), vertex_coordinates)) D = num_cell_dims(trian) @@ -392,32 +410,8 @@ function evaluate!(cache,f::CellField,x::CellPoint) end function _to_common_domain(f::CellField,x::CellPoint) - trian_f = get_triangulation(f) trian_x = get_triangulation(x) - - if have_compatible_domains(trian_f,trian_x) - nothing - elseif have_compatible_domains(trian_f,get_background_triangulation(trian_x)) - nothing - elseif have_compatible_domains(trian_f,get_background_triangulation(get_background_triangulation(trian_x))) - nothing - elseif have_compatible_domains(trian_x,get_background_triangulation(trian_f)) - @unreachable """\n - CellField objects defined on a sub-triangulation cannot be evaluated - on the underlying background mesh. - - This happens e.g. when trying to evaluate a CellField defined on a Neumann boundary - at a CellPoint defined on the underlying background mesh. - """ - else - @unreachable """\n - Your are trying to evaluate a CellField on a CellPoint object defined on incompatible - triangulations. Verify that either the two objects are defined in the same triangulation - or that the triangulaiton of the CellField is the background triangulation of the CellPoint. - """ - end - f_on_trian_x = change_domain(f,trian_x,DomainStyle(x)) f_on_trian_x, x end @@ -432,7 +426,7 @@ function gradient(a::CellField) cell_map = get_cell_map(get_triangulation(a)) g = lazy_map(Broadcasting(push_∇),cell_∇a,cell_map) end - GenericCellField(g,get_triangulation(a),DomainStyle(a)) + similar_cell_field(a,g,get_triangulation(a),DomainStyle(a)) end function DIV(a::CellField) @@ -440,10 +434,9 @@ function DIV(a::CellField) if DomainStyle(a) == PhysicalDomain() @notimplemented end - GenericCellField(DIVa,get_triangulation(a),DomainStyle(a)) + similar_cell_field(a,DIVa,get_triangulation(a),DomainStyle(a)) end - function ∇∇(a::CellField) cell_∇∇a = lazy_map(Broadcasting(∇∇),get_data(a)) if DomainStyle(a) == PhysicalDomain() @@ -452,7 +445,7 @@ function ∇∇(a::CellField) cell_map = get_cell_map(get_triangulation(a)) h = lazy_map(Broadcasting(push_∇∇),cell_∇∇a,cell_map) end - GenericCellField(h,get_triangulation(a),DomainStyle(a)) + similar_cell_field(a,h,get_triangulation(a),DomainStyle(a)) end # This function has to be removed when ∇⋅∇(a) is implemented @@ -495,7 +488,7 @@ struct OperationCellField{DS} <: CellField trian = get_triangulation(first(args)) domain_style = DomainStyle(first(args)) @check all( map(i->DomainStyle(i)==domain_style,args) ) - @check all( map(i->have_compatible_domains(get_triangulation(i),trian),args) ) + #@check all( map(i->get_triangulation(i)===trian,args) ) if num_cells(trian)>0 x = _get_cell_points(args...) @@ -614,23 +607,23 @@ function _to_common_domain(a::CellField...) target_trian = first(trian_candidates) elseif length(trian_candidates) == 2 trian_a, trian_b = trian_candidates - if have_compatible_domains(trian_a,trian_b) + sa_tb = is_change_possible(trian_a,trian_b) + sb_ta = is_change_possible(trian_b,trian_a) + if sa_tb && sb_ta + target_trian = best_target(trian_a,trian_b) + elseif !sa_tb && sb_ta target_trian = trian_a - elseif have_compatible_domains(trian_a,get_background_triangulation(trian_b)) + elseif sa_tb && !sb_ta target_trian = trian_b - elseif have_compatible_domains(trian_b,get_background_triangulation(trian_a)) - target_trian = trian_a - elseif have_compatible_domains(trian_a,get_background_triangulation(get_background_triangulation(trian_b))) - target_trian = trian_b - elseif have_compatible_domains(trian_b,get_background_triangulation(get_background_triangulation(trian_a))) - target_trian = trian_a - elseif have_compatible_domains(get_background_triangulation(trian_a),get_background_triangulation(trian_b)) - @unreachable msg else @unreachable msg end else - @unreachable msg + m = """\n + Cannote operate cellfields defined over more than 2 different + triangulations at this moment. + """ + @notimplemented end map(i->change_domain(i,target_trian,target_domain),a) end @@ -726,18 +719,19 @@ get_triangulation(f::CellFieldAt) = get_triangulation(f.parent) DomainStyle(::Type{CellFieldAt{T,F}}) where {T,F} = DomainStyle(F) gradient(a::CellFieldAt{P}) where P = CellFieldAt{P}(gradient(a.parent)) ∇∇(a::CellFieldAt{P}) where P = CellFieldAt{P}(∇∇(a.parent)) +function similar_cell_field(f::CellFieldAt{T},cell_data,trian,ds) where T + parent = similar_cell_field(f.parent,cell_data,trian,ds) + CellFieldAt{T}(parent) +end function CellFieldAt{T}(parent::OperationCellField) where T args = map(i->CellFieldAt{T}(i),parent.args) OperationCellField(parent.op,args...) end -function get_normal_vector(trian::SkeletonTriangulation) - cell_normal_plus = get_facet_normal(trian.plus) - #cell_normal_minus = get_facet_normal(trian.minus) - cell_normal_minus = lazy_map(Broadcasting(Operation(-)),cell_normal_plus) - plus = GenericCellField(cell_normal_plus,trian,ReferenceDomain()) - minus = GenericCellField(cell_normal_minus,trian,ReferenceDomain()) +function get_normal_vector(trian::Triangulation,cell_normal::SkeletonPair) + plus = get_normal_vector(trian,cell_normal.plus) + minus = get_normal_vector(trian,cell_normal.minus) SkeletonPair(plus,minus) end @@ -768,78 +762,41 @@ _mean(x,y) = 0.5*x + 0.5*y # This is the fundamental part to make operations on the skeleton work. -function change_domain(a::CellField,target_trian::SkeletonTriangulation,target_domain::DomainStyle) - trian_a = get_triangulation(a) - if have_compatible_domains(trian_a,target_trian) - return change_domain(a,target_domain) - elseif have_compatible_domains(trian_a,get_background_triangulation(target_trian)) - # In this case, we can safely take either plus or minus arbitrarily. - if isa(a,GenericCellField) && isa(get_array(a.cell_field),Fill{<:ConstantField}) - a_on_target_trian = change_domain(a,target_trian.plus,target_domain) - return GenericCellField(get_data(a_on_target_trian),target_trian,target_domain) - elseif isa(a,GenericCellField) && isa(get_array(a.cell_field),Fill{<:GenericField{<:Function}}) - a_on_target_trian = change_domain(a,target_trian.plus,target_domain) - return GenericCellField(get_data(a_on_target_trian),target_trian,target_domain) - else - @unreachable """\n - It is not possible to use the given CellField on a SkeletonTriangulation. - Make sure that you are specifying which of the two possible traces, - either plus (aka ⁺) or minus (aka ⁻) you want to use. - """ - end - elseif have_compatible_domains(trian_a,get_background_triangulation(get_background_triangulation(target_trian))) - @unreachable """\n - It is not possible to use the given CellField on a SkeletonTriangulation. - Make sure that you are specifying which of the two possible traces, - either plus (aka ⁺) or minus (aka ⁻) you want to use. - """ - else - @unreachable """\n - We cannot move the given CellField to the requested triangulation. - Make sure that the given CellField is defined on the triangulation you want to work with. - """ - end -end +for fun in (:change_domain_ref_ref,:change_domain_phys_phys) + @eval begin -function change_domain(a::CellFieldAt,trian::SkeletonTriangulation,target_domain::DomainStyle) - trian_a = get_triangulation(a) - if have_compatible_domains(trian_a,get_background_triangulation(trian)) || - have_compatible_domains(trian_a,get_background_triangulation(get_background_triangulation(trian))) - plus, minus = change_domain_skeleton(a.parent,trian,target_domain) - if isa(a,CellFieldAt{:plus}) - return plus - elseif isa(a,CellFieldAt{:minus}) - return minus - else - @unreachable + function $fun( + a::CellField,ttrian::Triangulation,sglue::FaceToFaceGlue,tglue::SkeletonPair) + msg = """\n + It is not possible to use the given CellField on a SkeletonTriangulation. + Make sure that you are specifying which of the two possible traces, + either plus (aka ⁺) or minus (aka ⁻) you want to use. + """ + # If the underlying array is Fill it does not matter if we restrict if from + # the plus or minus side. + @check isa(get_array(a.cell_field),Fill) + plus = $fun(a,ttrian,sglue,tglue.plus) + plus end - else - @unreachable """\n - It is not allowd to writte `u.⁺` of `u.⁻` for the given CellField. - Make sure that the CellField `u` is either defined on the background mesh - or it is a normal vector extracted from a SkeletonTriangulation. - """ - end -end -function change_domain_skeleton(a::CellField,trian::SkeletonTriangulation,target_domain::DomainStyle) - a_on_plus_trian = change_domain(a,trian.plus,target_domain) - a_on_minus_trian = change_domain(a,trian.minus,target_domain) - plus = GenericCellField(get_data(a_on_plus_trian),trian,target_domain) - minus = GenericCellField(get_data(a_on_minus_trian),trian,target_domain) - plus, minus -end + function $fun( + a::CellFieldAt,ttrian::Triangulation,sglue::FaceToFaceGlue,tglue::SkeletonPair) + if isa(a,CellFieldAt{:plus}) + $fun(a,ttrian,sglue,tglue.plus) + elseif isa(a,CellFieldAt{:minus}) + $fun(a,ttrian,sglue,tglue.minus) + else + @unreachable + end + end -function change_domain(f::OperationCellField,target_trian::SkeletonTriangulation,target_domain::DomainStyle) - args = map(i->change_domain(i,target_trian,target_domain),f.args) - OperationCellField(f.op,args...) -end + function $fun( + f::OperationCellField,ttrian::Triangulation,sglue::FaceToFaceGlue,tglue::SkeletonPair) + args = map(i->$fun(i,ttrian,sglue,tglue),f.args) + OperationCellField(f.op,args...) + end -function change_domain_skeleton(f::OperationCellField,target_trian::SkeletonTriangulation,target_domain::DomainStyle) - args = map(i->change_domain_skeleton(i,target_trian,target_domain),f.args) - plus = map(i->i[1],args) - minus = map(i->i[2],args) - OperationCellField(f.op,plus...), OperationCellField(f.op,minus...) + end end # Just to provide more meaningful error messages diff --git a/src/CellData/CellQuadratures.jl b/src/CellData/CellQuadratures.jl index ee214ee6b..5c632ae65 100644 --- a/src/CellData/CellQuadratures.jl +++ b/src/CellData/CellQuadratures.jl @@ -134,27 +134,12 @@ function integrate(f::CellField,quad::CellQuadrature) where DDS trian_f = get_triangulation(f) trian_x = get_triangulation(quad) - if have_compatible_domains(trian_f,trian_x) - nothing - elseif have_compatible_domains(trian_f,get_background_triangulation(trian_x)) - nothing - elseif have_compatible_domains(get_background_triangulation(trian_f),get_background_triangulation(trian_x)) - nothing - elseif have_compatible_domains(trian_x,get_background_triangulation(trian_f)) - @unreachable """\n - CellField objects defined on a sub-triangulation cannot be integrated - with a CellQuadrature defined on the underlying background mesh. - - This happens e.g. when trying to integrate a CellField defined on a Neumann boundary - with a CellQuadrature defined on the underlying background mesh. - """ - else - @unreachable """\n + msg = """\n Your are trying to integrate a CellField using a CellQuadrature defined on incompatible triangulations. Verify that either the two objects are defined in the same triangulation or that the triangulaiton of the CellField is the background triangulation of the CellQuadrature. """ - end + @check is_change_possible(trian_f,trian_x) msg b = change_domain(f,quad.trian,quad.data_domain_style) x = get_cell_points(quad) @@ -196,23 +181,37 @@ const ∫ = Integrand (*)(b::CellQuadrature,a::Integrand) = integrate(a.object,b) # Cell measure -""" -Contributions added to the cells of the background Triangulation. -""" + function get_cell_measure(trian::Triangulation) quad = CellQuadrature(trian,0) cell_to_dV = integrate(1,quad) - cell_to_bgcell = get_cell_to_bgcell(trian) - bgtrian = get_background_triangulation(trian) - bgcell_to_dV = zeros(num_cells(bgtrian)) - _meas_K_fill!(bgcell_to_dV,cell_to_dV,cell_to_bgcell) - bgcell_to_dV -end - -function _meas_K_fill!(bgcell_to_dV,cell_to_dV,cell_to_bgcell) - cache = array_cache(cell_to_dV) - for (cell, bgcell) in enumerate(cell_to_bgcell) - dV = getindex!(cache,cell_to_dV,cell) - bgcell_to_dV[bgcell] += dV - end end + +function get_cell_measure(strian::Triangulation,ttrian::Triangulation) + scell_measure = get_cell_measure(strian) + move_contributions(scell_measure,strian,ttrian) |> collect +end + +#""" +#Contributions added to the cells of the background Triangulation. +#""" +#function get_cell_measure(trian::Triangulation) +# quad = CellQuadrature(trian,0) +# cell_to_dV = integrate(1,quad) +# model = get_background_model(trian) +# bgtrian = Triangulation(model) +# D = num_cell_dims(model) +# glue = get_glue(trian,Val(D)) +# cell_to_bgcell = glue.tface_to_mface +# bgcell_to_dV = zeros(num_cells(bgtrian)) +# _meas_K_fill!(bgcell_to_dV,cell_to_dV,cell_to_bgcell) +# bgcell_to_dV +#end +# +#function _meas_K_fill!(bgcell_to_dV,cell_to_dV,cell_to_bgcell) +# cache = array_cache(cell_to_dV) +# for (cell, bgcell) in enumerate(cell_to_bgcell) +# dV = getindex!(cache,cell_to_dV,cell) +# bgcell_to_dV[bgcell] += dV +# end +#end diff --git a/src/CellData/DiracDeltas.jl b/src/CellData/DiracDeltas.jl index 1ae443902..4cfea2f3f 100644 --- a/src/CellData/DiracDeltas.jl +++ b/src/CellData/DiracDeltas.jl @@ -14,13 +14,15 @@ function DiracDelta{D}( D should be in [0,$(num_cell_dims(model))). """ + topo = get_grid_topology(model) bgface_grid = Grid(ReferenceFE{D},model) - face_trian = RestrictedTriangulation(bgface_grid,face_to_bgface) - cell_trian = Triangulation(model) + face_grid = view(bgface_grid,face_to_bgface) + cell_grid = get_grid(model) bgface_to_lcell = Fill(1,num_faces(model,D)) - glue = Geometry.FaceToCellGlue(topo,cell_trian,face_trian,face_to_bgface,bgface_to_lcell) - Γ = BoundaryTriangulation(face_trian,cell_trian,glue) + glue = Geometry.FaceToCellGlue(topo,cell_grid,face_grid,face_to_bgface,bgface_to_lcell) + trian = BodyFittedTriangulation(model,face_grid,face_to_bgface) + Γ = BoundaryTriangulation(trian,glue) dΓ = Measure(Γ,degree) DiracDelta(Γ,dΓ) end diff --git a/src/Exports.jl b/src/Exports.jl index 826ca42cf..000c1db5f 100644 --- a/src/Exports.jl +++ b/src/Exports.jl @@ -102,7 +102,7 @@ using Gridap.TensorValues: ⊗; export ⊗ @publish Geometry get_cell_coordinates @publish Geometry get_cell_ref_coordinates @publish Geometry get_cell_map -@publish Geometry get_cell_to_bgcell +@publish Geometry get_glue @publish Geometry CartesianGrid @publish Geometry CartesianDiscreteModel @publish Geometry DiscreteModel @@ -115,8 +115,14 @@ using Gridap.TensorValues: ⊗; export ⊗ @publish Geometry add_tag_from_tags! @publish Geometry BoundaryTriangulation @publish Geometry SkeletonTriangulation -@publish Geometry RestrictedTriangulation @publish Geometry InterfaceTriangulation +@publish Geometry Interior +@publish Geometry Boundary +@publish Geometry Skeleton +@publish Geometry Interface +@publish Geometry move_contributions +@publish Geometry get_background_model +@publish Geometry get_active_model @publish CellData CellQuadrature @publish CellData Measure diff --git a/src/FESpaces/AffineFEOperators.jl b/src/FESpaces/AffineFEOperators.jl index dfaa887b1..261018e7e 100644 --- a/src/FESpaces/AffineFEOperators.jl +++ b/src/FESpaces/AffineFEOperators.jl @@ -67,32 +67,32 @@ get_vector(feop::AffineFEOperator) = get_vector(feop.op) get_algebraic_operator(feop::AffineFEOperator) = feop.op -function allocate_residual(feop::AffineFEOperator,u::FEFunction) +function allocate_residual(feop::AffineFEOperator,u) x = get_free_dof_values(u) allocate_residual(feop.op,x) end -function residual!(b::AbstractVector,feop::AffineFEOperator,u::FEFunction) +function residual!(b::AbstractVector,feop::AffineFEOperator,u) x = get_free_dof_values(u) residual!(b,feop.op,x) end -function residual(feop::AffineFEOperator,u::FEFunction) +function residual(feop::AffineFEOperator,u) x = get_free_dof_values(u) residual(feop.op,x) end -function allocate_jacobian(feop::AffineFEOperator,u::FEFunction) +function allocate_jacobian(feop::AffineFEOperator,u) x = get_free_dof_values(u) allocate_jacobian(feop.op,x) end -function jacobian!(A::AbstractMatrix,feop::AffineFEOperator,u::FEFunction) +function jacobian!(A::AbstractMatrix,feop::AffineFEOperator,u) x = get_free_dof_values(u) jacobian!(A,feop.op,x) end -function jacobian(feop::AffineFEOperator,u::FEFunction) +function jacobian(feop::AffineFEOperator,u) x = get_free_dof_values(u) jacobian(feop.op,x) end diff --git a/src/FESpaces/Assemblers.jl b/src/FESpaces/Assemblers.jl index 5182deb03..80540042c 100644 --- a/src/FESpaces/Assemblers.jl +++ b/src/FESpaces/Assemblers.jl @@ -393,16 +393,20 @@ function collect_cell_matrix(trial::FESpace,test::FESpace,a::DomainContribution) w = [] r = [] c = [] - for trian in get_domains(a) - cell_mat = get_contribution(a,trian) + for strian in get_domains(a) + scell_mat = get_contribution(a,strian) + cell_mat, trian = move_contributions(scell_mat,strian) @assert ndims(eltype(cell_mat)) == 2 cell_mat_c = attach_constraints_cols(trial,cell_mat,trian) cell_mat_rc = attach_constraints_rows(test,cell_mat_c,trian) rows = get_cell_dof_ids(test,trian) cols = get_cell_dof_ids(trial,trian) - push!(w,compress_contributions(cell_mat_rc,trian)) - push!(r,compress_ids(rows,trian)) - push!(c,compress_ids(cols,trian)) + #push!(w,compress_contributions(cell_mat_rc,trian)) + #push!(r,compress_ids(rows,trian)) + #push!(c,compress_ids(cols,trian)) + push!(w,cell_mat_rc) + push!(r,rows) + push!(c,cols) end (w,r,c) end @@ -410,13 +414,16 @@ end function collect_cell_vector(test::FESpace,a::DomainContribution) w = [] r = [] - for trian in get_domains(a) - cell_vec = get_contribution(a,trian) + for strian in get_domains(a) + scell_vec = get_contribution(a,strian) + cell_vec, trian = move_contributions(scell_vec,strian) @assert ndims(eltype(cell_vec)) == 1 cell_vec_r = attach_constraints_rows(test,cell_vec,trian) rows = get_cell_dof_ids(test,trian) - push!(w,compress_contributions(cell_vec_r,trian)) - push!(r,compress_ids(rows,trian)) + #push!(w,compress_contributions(cell_vec_r,trian)) + #push!(r,compress_ids(rows,trian)) + push!(w,cell_vec_r) + push!(r,rows) end (w,r) end @@ -425,16 +432,20 @@ function _collect_cell_matvec(trial::FESpace,test::FESpace,a::DomainContribution w = [] r = [] c = [] - for trian in get_domains(a) - cell_mat = get_contribution(a,trian) + for strian in get_domains(a) + scell_mat = get_contribution(a,strian) + cell_mat, trian = move_contributions(scell_mat,strian) @assert eltype(cell_mat) <: Tuple cell_mat_c = attach_constraints_cols(trial,cell_mat,trian) cell_mat_rc = attach_constraints_rows(test,cell_mat_c,trian) rows = get_cell_dof_ids(test,trian) cols = get_cell_dof_ids(trial,trian) - push!(w,compress_contributions(cell_mat_rc,trian)) - push!(r,compress_ids(rows,trian)) - push!(c,compress_ids(cols,trian)) + #push!(w,compress_contributions(cell_mat_rc,trian)) + #push!(r,compress_ids(rows,trian)) + #push!(c,compress_ids(cols,trian)) + push!(w,cell_mat_rc) + push!(r,rows) + push!(c,cols) end (w,r,c) end diff --git a/src/FESpaces/CLagrangianFESpaces.jl b/src/FESpaces/CLagrangianFESpaces.jl index 3d3065d75..701f1b0c7 100644 --- a/src/FESpaces/CLagrangianFESpaces.jl +++ b/src/FESpaces/CLagrangianFESpaces.jl @@ -17,29 +17,31 @@ struct NodeToDofGlue{T} end """ - CLagrangianFESpace(::Type{T},grid::Grid) where T + CLagrangianFESpace(::Type{T},grid::Triangulation) where T """ -function CLagrangianFESpace(::Type{T},grid::Grid) where T +function CLagrangianFESpace(::Type{T},grid::Triangulation,trian::Triangulation=grid) where T vector_type = Vector{_dof_type(T)} node_to_tag = fill(Int8(UNSET),num_nodes(grid)) tag_to_mask = fill(_default_mask(T),0) - CLagrangianFESpace(T,grid,vector_type,node_to_tag,tag_to_mask) + CLagrangianFESpace(T,grid,vector_type,node_to_tag,tag_to_mask,trian) end """ CLagrangianFESpace( ::Type{T}, - grid::Grid, + grid::Triangulation, vector_type::Type, node_to_tag::AbstractVector, tag_to_mask::AbstractVector) where T """ function CLagrangianFESpace( ::Type{T}, - grid::Grid, + grid::Triangulation, vector_type::Type, node_to_tag::AbstractVector{<:Integer}, - tag_to_masks::AbstractVector) where T + tag_to_masks::AbstractVector, + trian::Triangulation=grid + ) where T z = zero(T) glue, dirichlet_dof_tag = _generate_node_to_dof_glue_component_major( @@ -50,7 +52,7 @@ function CLagrangianFESpace( cell_dof_basis = lazy_map(get_dof_basis,cell_reffe) rd = ReferenceDomain() fe_basis, fe_dof_basis = compute_cell_space( - cell_shapefuns,cell_dof_basis,rd,rd,grid) + cell_shapefuns,cell_dof_basis,rd,rd,trian) cell_is_dirichlet = _generate_cell_is_dirichlet(cell_dofs_ids) nfree = length(glue.free_dof_to_node) @@ -78,7 +80,7 @@ function _use_clagrangian(trian,cell_reffe,conf) false end -function _use_clagrangian(trian::Grid,cell_reffe,conf::H1Conformity) +function _use_clagrangian(trian::Triangulation,cell_reffe,conf::H1Conformity) ctype_reffe1, cell_ctype1 = compress_cell_data(cell_reffe) ctype_reffe2 = get_reffes(trian) if length(ctype_reffe1) != 1 || length(ctype_reffe2) != 1 @@ -101,7 +103,8 @@ function _unsafe_clagrangian( labels, vector_type, dirichlet_tags, - dirichlet_masks) + dirichlet_masks, + trian=grid) ctype_reffe, cell_ctype = compress_cell_data(cell_reffe) prebasis = get_prebasis(first(ctype_reffe)) @@ -110,7 +113,7 @@ function _unsafe_clagrangian( node_to_tag = get_face_tag_index(labels,dirichlet_tags,0) _vector_type = vector_type === nothing ? Vector{Float64} : vector_type tag_to_mask = dirichlet_masks === nothing ? fill(_default_mask(T),length(dirichlet_tags)) : dirichlet_masks - CLagrangianFESpace(T,grid,_vector_type,node_to_tag,tag_to_mask) + CLagrangianFESpace(T,grid,_vector_type,node_to_tag,tag_to_mask,trian) end # Helpers diff --git a/src/FESpaces/ConformingFESpaces.jl b/src/FESpaces/ConformingFESpaces.jl index cd4ad7df4..82a2404f0 100644 --- a/src/FESpaces/ConformingFESpaces.jl +++ b/src/FESpaces/ConformingFESpaces.jl @@ -138,7 +138,8 @@ function _ConformingFESpace( face_labeling::FaceLabeling, cell_fe::CellFE, dirichlet_tags, - dirichlet_components) + dirichlet_components, + trian = Triangulation(model)) grid_topology = get_grid_topology(model) ntags = length(dirichlet_tags) @@ -146,7 +147,6 @@ function _ConformingFESpace( cell_dofs_ids, nfree, ndirichlet, dirichlet_dof_tag, dirichlet_cells = compute_conforming_cell_dofs( cell_fe,CellConformity(cell_fe),grid_topology,face_labeling,dirichlet_tags,dirichlet_components) - trian = Triangulation(model) cell_shapefuns, cell_dof_basis = compute_cell_space(cell_fe,trian) cell_is_dirichlet = fill(false,num_cells(trian)) diff --git a/src/FESpaces/DivConformingFESpaces.jl b/src/FESpaces/DivConformingFESpaces.jl index 7c7eb5eb7..201a322a4 100644 --- a/src/FESpaces/DivConformingFESpaces.jl +++ b/src/FESpaces/DivConformingFESpaces.jl @@ -119,7 +119,7 @@ function get_sign_flip(model::DiscreteModel, cell_reffe::AbstractArray{<:GenericRefFE{RaviartThomas}}) lazy_map(SignFlipMap(model), cell_reffe, - get_cell_to_bgcell(model)) + IdentityVector(Int32(num_cells(model)))) end function return_cache(::TransformRTDofBasis{Dc,Dp}, diff --git a/src/FESpaces/ExtendedFESpaces.jl b/src/FESpaces/ExtendedFESpaces.jl deleted file mode 100644 index ccd7fcdbc..000000000 --- a/src/FESpaces/ExtendedFESpaces.jl +++ /dev/null @@ -1,176 +0,0 @@ - -""" -""" -struct ExtendedFESpace{S<:SingleFieldFESpace} <: SingleFieldFESpace - space::S - model::RestrictedDiscreteModel - partition::PosNegPartition - function ExtendedFESpace(space::SingleFieldFESpace,model::RestrictedDiscreteModel) - model_portion = model.model - @check get_triangulation(model_portion) === get_triangulation(space) - @notimplementedif ConstraintStyle(space) == Constrained() - full_cell_to_cell = Geometry.get_cell_to_parent_cell(model) - partition = PosNegPartition(full_cell_to_cell,num_cells(get_parent_model(model))) - new{typeof(space)}(space,model,partition) - end -end - -ConstraintStyle(::Type{ExtendedFESpace{S}}) where S = ConstraintStyle(S) - -function get_cell_dof_ids(f::ExtendedFESpace) - nfull, nvoid = Arrays.pos_and_neg_length(f.partition) - fullcell_to_ids = get_cell_dof_ids(f.space) - @check length(fullcell_to_ids) == nfull - T = eltype(fullcell_to_ids) - voidcell_to_ids = Fill(similar(T,0),nvoid) - lazy_map( PosNegReindex(fullcell_to_ids,voidcell_to_ids), f.partition) -end - -function get_fe_basis(f::ExtendedFESpace) - nfull, nvoid = Arrays.pos_and_neg_length(f.partition) - dv = get_fe_basis(f.space) - data = get_data(dv) - fullcell_shapefuns = lazy_map(VoidBasisMap(false),data) - @check length(fullcell_shapefuns) == nfull - voidcell_shapefuns = Fill(VoidBasis(testitem(data),true),nvoid) - a = lazy_map( PosNegReindex(fullcell_shapefuns,voidcell_shapefuns),f.partition) - SingleFieldFEBasis(a,get_triangulation(f),TestBasis(),DomainStyle(dv)) -end - -function get_fe_dof_basis(f::ExtendedFESpace) - nfull, nvoid = Arrays.pos_and_neg_length(f.partition) - s = get_fe_dof_basis(f.space) - data = get_data(s) - fullcell_dof_basis = lazy_map(VoidBasisMap(false),data) - @check length(fullcell_dof_basis) == nfull - voidcell_dof_basis = Fill(VoidBasis(testitem(data),true),nvoid) - a = lazy_map( PosNegReindex(fullcell_dof_basis,voidcell_dof_basis),f.partition) - CellDof(a,get_triangulation(f),DomainStyle(s)) -end - -function scatter_free_and_dirichlet_values(f::ExtendedFESpace,fv,dv) - nfull, nvoid = Arrays.pos_and_neg_length(f.partition) - fullcell_val = scatter_free_and_dirichlet_values(f.space,fv,dv) - @check length(fullcell_val) == nfull - T = eltype(fullcell_val) - voidcell_val = Fill(similar(T,0),nvoid) - lazy_map( PosNegReindex(fullcell_val,voidcell_val), f.partition) -end - -function gather_free_and_dirichlet_values!(fv,dv,f::ExtendedFESpace,cv) - _cv = lazy_map(Reindex(cv),f.partition.ipos_to_i) - gather_free_and_dirichlet_values!(fv,dv,f.space,_cv) -end - -# Delegated functions - -function get_free_dof_ids(f::ExtendedFESpace) - get_free_dof_ids(f.space) -end - -function get_vector_type(f::ExtendedFESpace) - get_vector_type(f.space) -end - -function get_dirichlet_dof_ids(f::ExtendedFESpace) - get_dirichlet_dof_ids(f.space) -end - -function num_dirichlet_tags(f::ExtendedFESpace) - num_dirichlet_tags(f.space) -end - -function get_dirichlet_dof_tag(f::ExtendedFESpace) - get_dirichlet_dof_tag(f.space) -end - -function get_triangulation(f::ExtendedFESpace) - get_triangulation(get_parent_model(f.model)) -end - -# Helpers - -struct VoidBasisMap <: Map - isvoid::Bool -end - -@inline Arrays.evaluate!(cache,k::VoidBasisMap,b) = VoidBasis(b,k.isvoid) - -struct VoidBasis{T,A} <: AbstractVector{T} - basis::A - isvoid::Bool - function VoidBasis(basis::AbstractVector{T},isvoid::Bool) where T - new{T,typeof(basis)}(basis,isvoid) - end -end - -function Base.size(a::VoidBasis) - if a.isvoid - (0,) - else - size(a.basis) - end -end - -Base.IndexStyle(::Type{<:VoidBasis}) = IndexLinear() - -function Base.getindex(a::VoidBasis,i::Integer) - if a.isvoid - @unreachable "Unable to access 0-length array" - else - a.basis[i] - end -end - -Arrays.testitem(a::VoidBasis) = testitem(a.basis) - -function Fields.return_cache(a::VoidBasis,x::Point) - cb = return_cache(a.basis,x) - bx = return_value(a.basis,x) - r = similar(bx,(0,)) - cb,r -end - -function Fields.return_cache(a::VoidBasis,x::Field) - cb = return_cache(a.basis,x) - bx = return_value(a.basis,x) - r = similar(bx,(0,)) - cb,r -end - -function Fields.return_cache(a::VoidBasis,x::AbstractVector{<:Point}) - cb = return_cache(a.basis,x) - bx = return_value(a.basis,x) - r = similar(bx,(length(x),0)) - cb,r -end - -function Fields.return_cache(a::VoidBasis,v::AbstractVector{<:Field}) - cb = return_cache(a.basis,v) - bx = return_value(a.basis,v) - r = similar(bx,(0,length(v))) - cb,r -end - -for T in (:Point,:Field,:(AbstractVector{<:Point}),:(AbstractVector{<:Field})) - @eval begin - - @inline function Fields.evaluate!(cache,a::VoidBasis,x::$T) - cb, r = cache - if a.isvoid - r - else - evaluate!(cb,a.basis,x) - end - end - - end -end - -function Fields.evaluate!(cache,k::Broadcasting{typeof(∇)},a::VoidBasis) - VoidBasis(k(a.basis),a.isvoid) -end - -function Fields.evaluate!(cache,k::Broadcasting{typeof(∇∇)},a::VoidBasis) - VoidBasis(k(a.basis),a.isvoid) -end diff --git a/src/FESpaces/FEAutodiff.jl b/src/FESpaces/FEAutodiff.jl index 3a37dcb2f..bde59856a 100644 --- a/src/FESpaces/FEAutodiff.jl +++ b/src/FESpaces/FEAutodiff.jl @@ -19,13 +19,31 @@ function _gradient(f,uh,fuh::DomainContribution) for trian in get_domains(fuh) g = _change_argument(gradient,f,trian,uh) cell_u = get_cell_dof_values(uh) - cell_id = get_cell_to_bgcell(trian) + glue = get_glue(trian,Val(num_cell_dims(get_triangulation(uh)))) + cell_id = _compute_cell_ids(uh,trian) cell_grad = autodiff_array_gradient(g,cell_u,cell_id) add_contribution!(terms,trian,cell_grad) end terms end +function _compute_cell_ids(uh,ttrian) + strian = get_triangulation(uh) + if strian === ttrian + return collect(IdentityVector(Int32(num_cells(strian)))) + end + @check is_change_possible(strian,ttrian) + D = num_cell_dims(strian) + sglue = get_glue(strian,Val(D)) + tglue = get_glue(ttrian,Val(D)) + @notimplementedif !isa(sglue,FaceToFaceGlue) + @notimplementedif !isa(tglue,FaceToFaceGlue) + scells = IdentityVector(Int32(num_cells(strian))) + mcells = extend(scells,sglue.mface_to_tface) + tcells = lazy_map(Reindex(mcells),tglue.tface_to_mface) + collect(tcells) +end + function jacobian(f::Function,uh::FEFunction) fuh = f(uh) _jacobian(f,uh,fuh) @@ -45,7 +63,7 @@ function _jacobian(f,uh,fuh::DomainContribution) for trian in get_domains(fuh) g = _change_argument(jacobian,f,trian,uh) cell_u = get_cell_dof_values(uh) - cell_id = get_cell_to_bgcell(trian) + cell_id = _compute_cell_ids(uh,trian) cell_grad = autodiff_array_jacobian(g,cell_u,cell_id) add_contribution!(terms,trian,cell_grad) end @@ -71,7 +89,7 @@ function _hessian(f,uh,fuh::DomainContribution) for trian in get_domains(fuh) g = _change_argument(hessian,f,trian,uh) cell_u = get_cell_dof_values(uh) - cell_id = get_cell_to_bgcell(trian) + cell_id = _compute_cell_ids(uh,trian) cell_grad = autodiff_array_hessian(g,cell_u,cell_id) add_contribution!(terms,trian,cell_grad) end @@ -87,4 +105,3 @@ function _change_argument(op,f,trian,uh::SingleFieldFEFunction) end g end - diff --git a/src/FESpaces/FEOperators.jl b/src/FESpaces/FEOperators.jl index a81b36c43..10cfd99b4 100644 --- a/src/FESpaces/FEOperators.jl +++ b/src/FESpaces/FEOperators.jl @@ -1,4 +1,9 @@ +## In the code related with FEOperators we cannot +#qualify u with ::FEFunction since it would prevent to +# reuse this code in GridapDistributed because of lack +# of multiple inheritence in Julia. We just use duck typing. + """ abstract type FEOperator <: GridapType @@ -22,7 +27,7 @@ end """ """ -function allocate_residual(op::FEOperator,u::FEFunction) +function allocate_residual(op::FEOperator,u) @abstractmethod end @@ -31,7 +36,7 @@ end Inplace version of [`residual`](@ref). """ -function residual!(b::AbstractVector,op::FEOperator,u::FEFunction) +function residual!(b::AbstractVector,op::FEOperator,u) @abstractmethod end @@ -40,7 +45,7 @@ end Compute the residual of `op` at `u`. See also [`residual_and_jacobian`](@ref) """ -function residual(op::FEOperator,u::FEFunction) +function residual(op::FEOperator,u) b = allocate_residual(op,u) residual!(b,op,u) b @@ -48,7 +53,7 @@ end """ """ -function allocate_jacobian(op::FEOperator,u::FEFunction) +function allocate_jacobian(op::FEOperator,u) @abstractmethod end @@ -57,7 +62,7 @@ end Inplace version of [`jacobian`](@ref). """ -function jacobian!(A::AbstractMatrix,op::FEOperator,u::FEFunction) +function jacobian!(A::AbstractMatrix,op::FEOperator,u) @abstractmethod end @@ -67,7 +72,7 @@ end Compute the jacobian of an operator `op`. See also [`get_algebraic_operator`](@ref), [`residual_and_jacobian!`](@ref). """ -function jacobian(op::FEOperator,u::FEFunction) +function jacobian(op::FEOperator,u) A = allocate_jacobian(op,u) jacobian!(A,op,u) A @@ -78,7 +83,7 @@ end Inplace version of [`residual_and_jacobian`](@ref). """ -function residual_and_jacobian!(b::AbstractVector,A::AbstractMatrix,op::FEOperator,u::FEFunction) +function residual_and_jacobian!(b::AbstractVector,A::AbstractMatrix,op::FEOperator,u) residual!(b,op,u) jacobian!(A,op,u) (b,A) @@ -92,7 +97,7 @@ Depending on the nature of `op` the point `u` can either be a plain array or a ` See also [`jacobian`](@ref), [`residual`](@ref), [`get_algebraic_operator`](@ref). """ -function residual_and_jacobian(op::FEOperator,u::FEFunction) +function residual_and_jacobian(op::FEOperator,u) b = residual(op,u) A = jacobian(op,u) (b,A) diff --git a/src/FESpaces/FEOperatorsFromWeakForm.jl b/src/FESpaces/FEOperatorsFromWeakForm.jl index 7046c37ce..4ade67035 100644 --- a/src/FESpaces/FEOperatorsFromWeakForm.jl +++ b/src/FESpaces/FEOperatorsFromWeakForm.jl @@ -47,14 +47,14 @@ end get_test(op::FEOperatorFromWeakForm) = op.test get_trial(op::FEOperatorFromWeakForm) = op.trial -function allocate_residual(op::FEOperatorFromWeakForm,uh::FEFunction) +function allocate_residual(op::FEOperatorFromWeakForm,uh) V = get_test(op) v = get_fe_basis(V) vecdata = collect_cell_vector(V,op.res(uh,v)) allocate_vector(op.assem, vecdata) end -function residual!(b::AbstractVector,op::FEOperatorFromWeakForm,uh::FEFunction) +function residual!(b::AbstractVector,op::FEOperatorFromWeakForm,uh) V = get_test(op) v = get_fe_basis(V) vecdata = collect_cell_vector(V,op.res(uh,v)) @@ -62,7 +62,7 @@ function residual!(b::AbstractVector,op::FEOperatorFromWeakForm,uh::FEFunction) b end -function allocate_jacobian(op::FEOperatorFromWeakForm,uh::FEFunction) +function allocate_jacobian(op::FEOperatorFromWeakForm,uh) U = get_trial(op) V = get_test(op) du = get_trial_fe_basis(U) @@ -71,7 +71,7 @@ function allocate_jacobian(op::FEOperatorFromWeakForm,uh::FEFunction) allocate_matrix(op.assem, matdata) end -function jacobian!(A::AbstractMatrix,op::FEOperatorFromWeakForm,uh::FEFunction) +function jacobian!(A::AbstractMatrix,op::FEOperatorFromWeakForm,uh) U = get_trial(op) V = get_test(op) du = get_trial_fe_basis(U) @@ -82,7 +82,7 @@ function jacobian!(A::AbstractMatrix,op::FEOperatorFromWeakForm,uh::FEFunction) end function residual_and_jacobian!( - b::AbstractVector,A::AbstractMatrix,op::FEOperatorFromWeakForm,uh::FEFunction) + b::AbstractVector,A::AbstractMatrix,op::FEOperatorFromWeakForm,uh) U = get_trial(op) V = get_test(op) du = get_trial_fe_basis(U) @@ -92,7 +92,7 @@ function residual_and_jacobian!( (b,A) end -function residual_and_jacobian(op::FEOperatorFromWeakForm,uh::FEFunction) +function residual_and_jacobian(op::FEOperatorFromWeakForm,uh) U = get_trial(op) V = get_test(op) du = get_trial_fe_basis(U) diff --git a/src/FESpaces/FESolvers.jl b/src/FESpaces/FESolvers.jl index 2fb9004f9..306f66bf0 100644 --- a/src/FESpaces/FESolvers.jl +++ b/src/FESpaces/FESolvers.jl @@ -10,7 +10,7 @@ This function changes the state of the input and can render it in a corrupted st It is recommended to rewrite the input `uh` with the output as illustrated to prevent any issue. """ -function solve!(uh::FEFunction,solver::FESolver,op::FEOperator) +function solve!(uh,solver::FESolver,op::FEOperator) solve!(uh,solver,op,nothing) end @@ -21,7 +21,7 @@ This function changes the state of the input and can render it in a corrupted st It is recommended to rewrite the input `uh` with the output as illustrated to prevent any issue. If `cache===nothing`, then it creates a new cache object. """ -function solve!(uh::FEFunction,solver::FESolver,op::FEOperator,cache) +function solve!(uh,solver::FESolver,op::FEOperator,cache) @abstractmethod end @@ -87,11 +87,11 @@ function LinearFESolver() LinearFESolver(ls) end -function solve!(uh::FEFunction,solver::LinearFESolver,op::FEOperator, cache) +function solve!(uh,solver::LinearFESolver,op::FEOperator, cache) @unreachable "Cannot solve a generic FEOperator with a LinearFESolver" end -function solve!(u::FEFunction,solver::LinearFESolver,feop::AffineFEOperator,cache::Nothing) +function solve!(u,solver::LinearFESolver,feop::AffineFEOperator,cache::Nothing) x = get_free_dof_values(u) op = get_algebraic_operator(feop) cache = solve!(x,solver.ls,op) @@ -100,7 +100,7 @@ function solve!(u::FEFunction,solver::LinearFESolver,feop::AffineFEOperator,cach (u_new, cache) end -function solve!(u::FEFunction,solver::LinearFESolver,feop::AffineFEOperator, cache) +function solve!(u,solver::LinearFESolver,feop::AffineFEOperator, cache) x = get_free_dof_values(u) op = get_algebraic_operator(feop) cache = solve!(x,solver.ls,op,cache) @@ -133,7 +133,7 @@ function NonlinearFESolver() NonlinearFESolver(nls) end -function solve!(u::FEFunction,solver::NonlinearFESolver,feop::FEOperator,cache::Nothing) +function solve!(u,solver::NonlinearFESolver,feop::FEOperator,cache::Nothing) x = get_free_dof_values(u) op = get_algebraic_operator(feop) cache = solve!(x,solver.nls,op) @@ -142,7 +142,7 @@ function solve!(u::FEFunction,solver::NonlinearFESolver,feop::FEOperator,cache:: (u_new, cache) end -function solve!(u::FEFunction,solver::NonlinearFESolver,feop::FEOperator,cache) +function solve!(u,solver::NonlinearFESolver,feop::FEOperator,cache) x = get_free_dof_values(u) op = get_algebraic_operator(feop) cache = solve!(x,solver.nls,op,cache) diff --git a/src/FESpaces/FESpaceFactories.jl b/src/FESpaces/FESpaceFactories.jl index 7d55ccd6e..fa67bae28 100644 --- a/src/FESpaces/FESpaceFactories.jl +++ b/src/FESpaces/FESpaceFactories.jl @@ -1,18 +1,24 @@ +function FESpace(t::Triangulation,reffes;trian=nothing, kwargs...) + @assert trian === nothing + model = get_active_model(t) + FESpace(model,reffes;trian=t,kwargs...) +end + function FESpace( model::DiscreteModel, cell_fe::CellFE; + trian = Triangulation(model), labels = get_face_labeling(model), dirichlet_tags=Int[], dirichlet_masks=nothing, constraint=nothing, - vector_type::Union{Nothing,Type}=nothing) + vector_type=nothing) @assert num_cells(cell_fe) == num_cells(model) """\n The number of cells provided in the `cell_fe` argument ($(cell_fe.num_cells) cells) does not match the number of cells ($(num_cells(model)) cells) in the provided DiscreteModel. """ - trian = Triangulation(model) _vector_type = _get_vector_type(vector_type,cell_fe,trian) F = _ConformingFESpace( _vector_type, @@ -20,7 +26,8 @@ function FESpace( labels, cell_fe, dirichlet_tags, - dirichlet_masks) + dirichlet_masks, + trian) V = _add_constraint(F,cell_fe.max_order,constraint) V end @@ -56,55 +63,42 @@ function _add_constraint(F,order,constraint) end function FESpace( - model::RestrictedDiscreteModel, + t::Triangulation, cell_reffe::AbstractArray{<:ReferenceFE}; - conformity=nothing, - constraint=nothing,kwargs...) - model_portion = model.model - conf = Conformity(testitem(cell_reffe),conformity) - cell_fe = CellFE(model,cell_reffe,conf) - V_portion = FESpace(model_portion,cell_fe;constraint=nothing,kwargs...) - F = ExtendedFESpace(V_portion,model) - V = _add_constraint(F,cell_fe.max_order,constraint) - V -end - -function FESpace( - model::RestrictedDiscreteModel, - cell_fe::CellFE; - constraint=nothing,kwargs...) - model_portion = model.model - V_portion = FESpace(model_portion,cell_fe;constraint=nothing,kwargs...) - F = ExtendedFESpace(V_portion,model) - V = _add_constraint(F,cell_fe.max_order,constraint) - V + trian=nothing, + kwargs...) + @assert trian === nothing + # TODO for L2 conformity and no dirichlet conditions + # no needed to build the active model + model = get_active_model(t) + FESpace(model,cell_reffe;trian=t,kwargs...) end function FESpace( model::DiscreteModel, cell_reffe::AbstractArray{<:ReferenceFE}; conformity=nothing, + trian = Triangulation(model), labels = get_face_labeling(model), dirichlet_tags=Int[], dirichlet_masks=nothing, constraint=nothing, - vector_type::Union{Nothing,Type}=nothing) + vector_type=nothing) - trian = Triangulation(model) conf = Conformity(testitem(cell_reffe),conformity) - if _use_clagrangian(trian,cell_reffe,conf) && constraint === nothing && num_vertices(model) == num_nodes(model) V = _unsafe_clagrangian( cell_reffe, - trian, + Triangulation(model), labels, vector_type, dirichlet_tags, - dirichlet_masks) + dirichlet_masks, + trian) return V end @@ -115,6 +109,7 @@ function FESpace( V = _add_constraint(F,cell_fe.max_order,constraint) else V = FESpace(model,cell_fe; + trian=trian, labels=labels, dirichlet_tags=dirichlet_tags, dirichlet_masks=dirichlet_masks, @@ -124,7 +119,6 @@ function FESpace( return V end - function FESpace(model::DiscreteModel, reffe::Tuple{<:ReferenceFEName,Any,Any}; kwargs...) basis, reffe_args,reffe_kwargs = reffe cell_reffe = ReferenceFE(model,basis,reffe_args...;reffe_kwargs...) diff --git a/src/FESpaces/FESpaceInterface.jl b/src/FESpaces/FESpaceInterface.jl index 937311b2b..527d18fd6 100644 --- a/src/FESpaces/FESpaceInterface.jl +++ b/src/FESpaces/FESpaceInterface.jl @@ -13,27 +13,35 @@ function get_cell_dof_values(f::FEFunction) @abstractmethod end -function get_cell_dof_entries(cell_entries::AbstractArray,cellids::AbstractArray) - lazy_map(Reindex(cell_entries),cellids) +function get_cell_dof_values(f::FEFunction,ttrian::Triangulation) + get_cell_fe_data(get_cell_dof_values,f,ttrian) end -function get_cell_is_dirichlet(f::FEFunction,args...) - V = get_fe_space(f) - get_cell_is_dirichlet(V,args...) -end - -function get_cell_dof_entries(cell_entries::AbstractArray,cellids::SkeletonPair) - cell_entries_plus = get_cell_dof_entries(cell_entries,cellids.plus) - cell_entries_minus = get_cell_dof_entries(cell_entries,cellids.minus) - lazy_map(BlockMap(2,[1,2]),cell_entries_plus,cell_entries_minus) +function get_cell_fe_data(fun,f,ttrian) + sface_to_data = fun(f) + strian = get_triangulation(f) + if strian === ttrian + return sface_to_data + end + @assert is_change_possible(strian,ttrian) + D = num_cell_dims(strian) + sglue = get_glue(strian,Val(D)) + tglue = get_glue(ttrian,Val(D)) + get_cell_fe_data(fun,sface_to_data,sglue,tglue) end -function get_cell_dof_values(f::FEFunction,cellids) - get_cell_dof_entries(get_cell_dof_values(f),cellids) +function get_cell_fe_data(fun,sface_to_data,sglue::FaceToFaceGlue,tglue::FaceToFaceGlue) + mface_to_sface = sglue.mface_to_tface + tface_to_mface = tglue.tface_to_mface + mface_to_data = extend(sface_to_data,mface_to_sface) + tface_to_data = lazy_map(Reindex(mface_to_data),tface_to_mface) + tface_to_data end -function get_cell_dof_values(cell_entries::AbstractArray,cellids) - get_cell_dof_entries(cell_entries,cellids) +function get_cell_fe_data(fun,sface_to_data,sglue::FaceToFaceGlue,tglue::SkeletonPair) + plus = get_cell_fe_data(fun,sface_to_data,sglue,tglue.plus) + minus = get_cell_fe_data(fun,sface_to_data,sglue,tglue.minus) + lazy_map(BlockMap(2,[1,2]),plus,minus) end """ @@ -42,6 +50,14 @@ function get_fe_space(f::FEFunction) @abstractmethod end +function get_cell_is_dirichlet(f::FEFunction) + get_cell_is_dirichlet(get_fe_space(f)) +end + +function get_cell_is_dirichlet(f::FEFunction,ttrian::Triangulation) + get_cell_is_dirichlet(get_fe_space(f),ttrian) +end + """ """ function test_fe_function(f::FEFunction) @@ -121,12 +137,8 @@ function get_cell_dof_ids(f::FESpace) @abstractmethod end -function get_cell_dof_ids(f::FESpace,cellids) - get_cell_dof_entries(get_cell_dof_ids(f),cellids) -end - -function get_cell_dof_ids(cell_entries::AbstractArray,cellids) - get_cell_dof_entries(cell_entries,cellids) +function get_cell_dof_ids(f::FESpace,ttrian::Triangulation) + get_cell_fe_data(get_cell_dof_ids,f,ttrian) end """ @@ -155,7 +167,7 @@ function get_trial_fe_basis(f::FESpace) v = get_fe_basis(f) cell_v = get_data(v) cell_u = lazy_map(transpose,cell_v) - SingleFieldFEBasis(cell_u,get_triangulation(v),TrialBasis(),DomainStyle(v)) + similar_fe_basis(v,cell_u,get_triangulation(v),TrialBasis(),DomainStyle(v)) end function get_cell_shapefuns_trial(f::FESpace) @@ -163,7 +175,7 @@ function get_cell_shapefuns_trial(f::FESpace) error(msg) end -# Skeleton-related +# Basis related abstract type BasisStyle end struct TrialBasis <: BasisStyle end @@ -194,33 +206,32 @@ get_data(f::SingleFieldFEBasis) = f.cell_basis get_triangulation(f::SingleFieldFEBasis) = f.trian BasisStyle(::Type{SingleFieldFEBasis{BS,DS}}) where {BS,DS} = BS() DomainStyle(::Type{SingleFieldFEBasis{BS,DS}}) where {BS,DS} = DS() -function gradient(a::SingleFieldFEBasis) - f = GenericCellField(a.cell_basis,a.trian,a.domain_style) - SingleFieldFEBasis(get_data(gradient(f)),a.trian,a.basis_style,a.domain_style) -end -function ∇∇(a::SingleFieldFEBasis) - f = GenericCellField(a.cell_basis,a.trian,a.domain_style) - SingleFieldFEBasis(get_data(∇∇(f)),a.trian,a.basis_style,a.domain_style) -end -function DIV(f::SingleFieldFEBasis) - df=DIV(get_data(f)) - SingleFieldFEBasis(df,f.trian,f.basis_style,f.domain_style) -end -function change_domain(a::SingleFieldFEBasis,trian::Triangulation,target_domain::DomainStyle) - f = GenericCellField(a.cell_basis,a.trian,a.domain_style) - g = change_domain(f,trian,target_domain) - SingleFieldFEBasis(get_data(g),trian,a.basis_style,target_domain) -end +function CellData.similar_cell_field(f::SingleFieldFEBasis,cell_data,trian,ds::DomainStyle) + SingleFieldFEBasis(cell_data,trian,BasisStyle(f),ds) +end +function similar_fe_basis(f::SingleFieldFEBasis,cell_data,trian,bs::BasisStyle,ds::DomainStyle) + SingleFieldFEBasis(cell_data,trian,bs,ds) +end + +for fun in (:change_domain_ref_ref,:change_domain_phys_phys) + @eval begin + + function $fun( + a::CellData.CellFieldAt{S,<:FEBasis} where S,ttrian::Triangulation,sglue::FaceToFaceGlue,tglue::SkeletonPair) + a_on_plus_trian = $fun(a.parent,ttrian,sglue,tglue.plus) + a_on_minus_trian = $fun(a.parent,ttrian,sglue,tglue.minus) + pair_in = SkeletonPair(get_data(a_on_plus_trian),get_data(a_on_minus_trian)) + pair_out = _fix_cell_basis_dofs_at_skeleton(pair_in,BasisStyle(a.parent)) + if isa(a,CellData.CellFieldAt{:plus}) + return CellData.similar_cell_field(a.parent,pair_out.plus,ttrian,DomainStyle(a.parent)) + elseif isa(a,CellData.CellFieldAt{:minus}) + return CellData.similar_cell_field(a.parent,pair_out.minus,ttrian,DomainStyle(a.parent)) + else + @unreachable + end + end -# We implement this for FEBasis since extensions of FEBasis might want to re-use this code -function change_domain_skeleton(a::FEBasis,trian::SkeletonTriangulation,target_domain::DomainStyle) - a_on_plus_trian = change_domain(a,trian.plus,target_domain) - a_on_minus_trian = change_domain(a,trian.minus,target_domain) - pair_in = SkeletonPair(get_data(a_on_plus_trian),get_data(a_on_minus_trian)) - pair_out = _fix_cell_basis_dofs_at_skeleton(pair_in,BasisStyle(a)) - plus = GenericCellField(pair_out.plus,trian,target_domain) - minus = GenericCellField(pair_out.minus,trian,target_domain) - plus, minus + end end function _fix_cell_basis_dofs_at_skeleton(pair,::TestBasis) @@ -248,118 +259,94 @@ has_constraints(::Type{T}) where T <:FESpace = ConstraintStyle(T) == Constrained has_constraints(::T) where T <: FESpace = has_constraints(T) function get_cell_constraints(f::FESpace) - get_cell_constraints(f,get_triangulation(f),ConstraintStyle(f)) -end - -function get_cell_constraints(f::FESpace,trian::Triangulation) - get_cell_constraints(f,trian,ConstraintStyle(f)) + get_cell_constraints(f,ConstraintStyle(f)) end -function get_cell_constraints(f,trian::Triangulation,::UnConstrained) - cell_ids = get_cell_dof_ids(f,trian) +function get_cell_constraints(f::FESpace,::UnConstrained) + cell_ids = get_cell_dof_ids(f) cell_axes = lazy_map(axes,cell_ids) identity_constraints(cell_axes) end -function get_cell_constraints(f,::Triangulation,::Constrained) +function get_cell_constraints(f::FESpace,::Constrained) @abstractmethod end -function get_cell_constraints(f::FESpace,cellids::AbstractArray) - get_cell_dof_entries(get_cell_constraints(f),cellids) -end - -function get_cell_constraints(cell_entries::AbstractArray,cellids::AbstractArray) - get_cell_dof_entries(cell_entries,cellids) -end - -function get_cell_constraints(cell_entries::AbstractArray,cellids::SkeletonPair) - cell_constraints_plus = get_cell_constraints(cell_entries,cellids.plus) - cell_constraints_minus = get_cell_constraints(cell_entries,cellids.minus) - lazy_map( - BlockMap((2,2),[(1,1),(2,2)]), - cell_constraints_plus, - cell_constraints_minus) +function get_cell_constraints(f::FESpace,ttrian::Triangulation) + get_cell_fe_data(get_cell_constraints,f,ttrian) end -function get_cell_constraints(f::FESpace,cellids::SkeletonPair) - get_cell_constraints(get_cell_constraints(f),cellids) +function get_cell_fe_data(fun::typeof(get_cell_constraints),sface_to_data,sglue::FaceToFaceGlue,tglue::SkeletonPair) + plus = get_cell_fe_data(fun,sface_to_data,sglue,tglue.plus) + minus = get_cell_fe_data(fun,sface_to_data,sglue,tglue.minus) + lazy_map(BlockMap((2,2),[(1,1),(2,2)]),plus,minus) end function get_cell_isconstrained(f::FESpace) - trian = get_triangulation(f) - get_cell_isconstrained(f,trian,ConstraintStyle(f)) -end - -function get_cell_isconstrained(f::FESpace,trian::Triangulation) - get_cell_isconstrained(f,trian,ConstraintStyle(f)) + get_cell_isconstrained(f,ConstraintStyle(f)) end -function get_cell_isconstrained(f,trian::Triangulation,::UnConstrained) +function get_cell_isconstrained(f::FESpace,::UnConstrained) + trian = get_triangulation(f) Fill(false,num_cells(trian)) end -function get_cell_isconstrained(f,trian::Triangulation,::Constrained) +function get_cell_isconstrained(f::FESpace,::Constrained) @abstractmethod end -function get_cell_isconstrained(f::FESpace,cellids) - get_cell_isconstrained(get_cell_isconstrained(f),cellids) -end - -function get_cell_isconstrained(cell_entries::AbstractArray,cellids::AbstractArray) - get_cell_dof_entries(cell_entries,cellids) +function get_cell_isconstrained(f::FESpace,ttrian::Triangulation) + get_cell_fe_data(get_cell_isconstrained,f,ttrian) end -function get_cell_isconstrained(cell_entries::AbstractArray,cellids::SkeletonPair) - plus = get_cell_isconstrained(cell_entries,cellids.plus) - minus = get_cell_isconstrained(cell_entries,cellids.minus) +function get_cell_fe_data( + fun::typeof(get_cell_isconstrained),sface_to_data,sglue::FaceToFaceGlue,tglue::SkeletonPair) + plus = get_cell_fe_data(fun,sface_to_data,sglue,tglue.plus) + minus = get_cell_fe_data(fun,sface_to_data,sglue,tglue.minus) lazy_map((l,r)-> l||r,plus,minus) end -function attach_constraints_rows(f::FESpace,cellarr,cellids) - attach_constraints_rows(f,cellarr,cellids,ConstraintStyle(f)) +function attach_constraints_rows(f::FESpace,cellarr,ttrian::Triangulation) + attach_constraints_rows(f,cellarr,ttrian,ConstraintStyle(f)) end -function attach_constraints_rows(f::FESpace,cellarr,cellids,::UnConstrained) +function attach_constraints_rows(f::FESpace,cellarr,ttrian,::UnConstrained) cellarr end -function attach_constraints_rows(f::FESpace,cellarr,cellids,::Constrained) - cellconstr = get_cell_constraints(f,cellids) - cellmask = get_cell_isconstrained(f,cellids) +function attach_constraints_rows(f::FESpace,cellarr,ttrian,::Constrained) + cellconstr = get_cell_constraints(f,ttrian) + cellmask = get_cell_isconstrained(f,ttrian) attach_constraints_rows(cellarr,cellconstr,cellmask) end -function attach_constraints_cols(f::FESpace,cellarr,cellids) - attach_constraints_cols(f,cellarr,cellids,ConstraintStyle(f)) +function attach_constraints_cols(f::FESpace,cellarr,ttrian::Triangulation) + attach_constraints_cols(f,cellarr,ttrian,ConstraintStyle(f)) end -function attach_constraints_cols(f::FESpace,cellarr,cellids,::UnConstrained) +function attach_constraints_cols(f::FESpace,cellarr,ttrian,::UnConstrained) cellarr end -function attach_constraints_cols(f::FESpace,cellarr,cellids,::Constrained) - cellconstr = get_cell_constraints(f,cellids) - cellmask = get_cell_isconstrained(f,cellids) +function attach_constraints_cols(f::FESpace,cellarr,ttrian,::Constrained) + cellconstr = get_cell_constraints(f,ttrian) + cellmask = get_cell_isconstrained(f,ttrian) attach_constraints_cols(cellarr,cellconstr,cellmask) end -function get_cell_is_dirichlet(f::FESpace,trian::Triangulation) - @abstractmethod -end - -function get_cell_is_dirichlet(f::FESpace,cellids) - get_cell_is_dirichlet(get_cell_is_dirichlet(f),cellids) +function get_cell_is_dirichlet(f::FESpace) + trian = get_triangulation(f) + Fill(true,num_cells(trian)) end -function get_cell_is_dirichlet(cell_entries::AbstractArray,cellids::AbstractArray) - get_cell_dof_entries(cell_entries,cellids) +function get_cell_is_dirichlet(f::FESpace,ttrian::Triangulation) + get_cell_fe_data(get_cell_is_dirichlet,f,ttrian) end -function get_cell_is_dirichlet(cell_entries::AbstractArray,cellids::SkeletonPair) - plus = get_cell_is_dirichlet(cell_entries,cellids.plus) - minus = get_cell_is_dirichlet(cell_entries,cellids.minus) +function get_cell_fe_data( + fun::typeof(get_cell_is_dirichlet),sface_to_data,sglue::FaceToFaceGlue,tglue::SkeletonPair) + plus = get_cell_fe_data(fun,sface_to_data,sglue,tglue.plus) + minus = get_cell_fe_data(fun,sface_to_data,sglue,tglue.minus) lazy_map((l,r)-> l||r,plus,minus) end @@ -383,33 +370,30 @@ function test_fe_space(f::FESpace) @test CellField(f,get_cell_dof_ids(f,trian)) != nothing end -function test_fe_space(f::FESpace,matvecdata,matdata,vecdata) +function test_fe_space(f::FESpace,cell_matvec,cell_mat,cell_vec,trian) test_fe_space(f) - cellmat, cellidsrows, cellidscols = matdata - cm = attach_constraints_cols(f,cellmat,cellidscols) + cm = attach_constraints_cols(f,cell_mat,trian) if ! has_constraints(f) - @test cm === cellmat + @test cm === cell_mat end - cm = attach_constraints_rows(f,cellmat,cellidsrows) + cm = attach_constraints_rows(f,cell_mat,trian) if ! has_constraints(f) - @test cm === cellmat + @test cm === cell_mat end - cellvec, cellidsrows = vecdata - cv = attach_constraints_rows(f,cellvec,cellidsrows) + cv = attach_constraints_rows(f,cell_vec,trian) if ! has_constraints(f) - @test cv === cellvec + @test cv === cell_vec end - cellmatvec, cellidsrows, cellidscols = matvecdata - cmv = attach_constraints_cols(f,cellmatvec,cellidscols) + cmv = attach_constraints_cols(f,cell_matvec,trian) if ! has_constraints(f) - @test cmv === cellmatvec + @test cmv === cell_matvec end - cmv = attach_constraints_rows(f,cellmatvec,cellidsrows) + cmv = attach_constraints_rows(f,cell_matvec,trian) if ! has_constraints(f) - @test cmv === cellmatvec + @test cmv === cell_matvec end end diff --git a/src/FESpaces/FESpaces.jl b/src/FESpaces/FESpaces.jl index 6b7ec7fdc..3508eee38 100644 --- a/src/FESpaces/FESpaces.jl +++ b/src/FESpaces/FESpaces.jl @@ -36,8 +36,9 @@ import Gridap.CellData: attach_constraints_cols import Gridap.CellData: CellField import Gridap.CellData: get_data import Gridap.CellData: DomainStyle -import Gridap.CellData: change_domain_skeleton import Gridap.CellData: change_domain +import Gridap.CellData: change_domain_ref_ref +import Gridap.CellData: change_domain_phys_phys import Gridap.Algebra: allocate_residual import Gridap.Algebra: allocate_jacobian @@ -223,7 +224,7 @@ include("CLagrangianFESpaces.jl") include("DirichletFESpaces.jl") -include("ExtendedFESpaces.jl") +#include("ExtendedFESpaces.jl") include("FESpacesWithLinearConstraints.jl") diff --git a/src/FESpaces/SingleFieldFESpaces.jl b/src/FESpaces/SingleFieldFESpaces.jl index abc7ca22f..ba0d88b41 100644 --- a/src/FESpaces/SingleFieldFESpaces.jl +++ b/src/FESpaces/SingleFieldFESpaces.jl @@ -43,97 +43,6 @@ function gather_free_and_dirichlet_values!(free_values, dirichlet_values,fs::Sin @abstractmethod end -""" -""" -function get_cell_dof_ids(V::SingleFieldFESpace,trian::Triangulation) - trian_V = get_triangulation(V) - if have_compatible_domains(trian_V,trian) - get_cell_dof_ids(V) - elseif have_compatible_domains(trian_V,get_background_triangulation(trian)) - get_cell_dof_ids(V,get_cell_to_bgcell(trian)) - elseif have_compatible_domains( - get_background_triangulation(trian_V),get_background_triangulation(trian)) - cell_to_Vcell = get_cell_to_bgcell(trian,trian_V) - get_cell_dof_ids(V,cell_to_Vcell) - elseif have_compatible_domains( - trian_V,get_background_triangulation(get_background_triangulation(trian))) - bg_trian = get_background_triangulation(trian) - bg_cell_dof_ids = get_cell_dof_ids(V,bg_trian) - cell_to_bgcell = get_cell_to_bgcell(trian) - get_cell_dof_ids(bg_cell_dof_ids,cell_to_bgcell) - else - @unreachable - end -end - -function get_cell_isconstrained(V::SingleFieldFESpace,trian::Triangulation) - trian_V = get_triangulation(V) - if have_compatible_domains(trian_V,trian) - get_cell_isconstrained(V) - elseif have_compatible_domains(trian_V,get_background_triangulation(trian)) - get_cell_isconstrained(V,get_cell_to_bgcell(trian)) - elseif have_compatible_domains( - get_background_triangulation(trian_V),get_background_triangulation(trian)) - cell_to_Vcell = get_cell_to_bgcell(trian,trian_V) - get_cell_isconstrained(V,cell_to_Vcell) - elseif have_compatible_domains( - trian_V,get_background_triangulation(get_background_triangulation(trian))) - bg_trian = get_background_triangulation(trian) - bg_cell_isconstrained = get_cell_isconstrained(V,bg_trian) - cell_to_bgcell = get_cell_to_bgcell(trian) - get_cell_isconstrained(bg_cell_isconstrained,cell_to_bgcell) - else - @unreachable - end -end - -function get_cell_constraints(V::SingleFieldFESpace,trian::Triangulation) - trian_V = get_triangulation(V) - if have_compatible_domains(trian_V,trian) - get_cell_constraints(V) - elseif have_compatible_domains(trian_V,get_background_triangulation(trian)) - get_cell_constraints(V,get_cell_to_bgcell(trian)) - elseif have_compatible_domains( - get_background_triangulation(trian_V),get_background_triangulation(trian)) - cell_to_Vcell = get_cell_to_bgcell(trian,trian_V) - get_cell_constraints(V,cell_to_Vcell) - elseif have_compatible_domains( - trian_V,get_background_triangulation(get_background_triangulation(trian))) - bg_trian = get_background_triangulation(trian) - bg_cell_constraints = get_cell_constraints(V,bg_trian) - cell_to_bgcell = get_cell_to_bgcell(trian) - get_cell_constraints(bg_cell_constraints,cell_to_bgcell) - else - @unreachable - end -end - -function get_cell_is_dirichlet(V::SingleFieldFESpace,trian::Triangulation) - trian_V = get_triangulation(V) - if have_compatible_domains(trian_V,trian) - get_cell_is_dirichlet(V) - elseif have_compatible_domains(trian_V,get_background_triangulation(trian)) - get_cell_is_dirichlet(V,get_cell_to_bgcell(trian)) - elseif have_compatible_domains( - get_background_triangulation(trian_V),get_background_triangulation(trian)) - cell_to_Vcell = get_cell_to_bgcell(trian,trian_V) - get_cell_is_dirichlet(V,cell_to_Vcell) - elseif have_compatible_domains( - trian_V,get_background_triangulation(get_background_triangulation(trian))) - bg_trian = get_background_triangulation(trian) - bg_cell_is_dirichlet = get_cell_is_dirichlet(V,bg_trian) - cell_to_bgcell = get_cell_to_bgcell(trian) - get_cell_is_dirichlet(bg_cell_is_dirichlet,cell_to_bgcell) - else - @unreachable - end -end - -function get_cell_is_dirichlet(V::SingleFieldFESpace) - trian = get_triangulation(V) - Fill(true,num_cells(trian)) -end - """ """ function test_single_field_fe_space(f::SingleFieldFESpace,pred=(==)) @@ -166,9 +75,9 @@ function test_single_field_fe_space(f::SingleFieldFESpace,pred=(==)) @test isa(cell_dof_basis,CellDof) end -function test_single_field_fe_space(f,matvecdata,matdata,vecdata,pred=(==)) +function test_single_field_fe_space(f,cell_matvec,cell_mat,cell_vec,trian,pred=(==)) test_single_field_fe_space(f,pred) - test_fe_space(f,matvecdata,matdata,vecdata) + test_fe_space(f,cell_matvec,cell_mat,cell_vec,trian) end # Some default API @@ -242,27 +151,6 @@ get_free_dof_values(f::SingleFieldFEFunction) = f.free_values get_cell_dof_values(f::SingleFieldFEFunction) = f.cell_dof_values get_fe_space(f::SingleFieldFEFunction) = f.fe_space -function get_cell_dof_values(f::SingleFieldFEFunction,trian::Triangulation) - trian_f = get_triangulation(f) - if have_compatible_domains(trian_f,trian) - get_cell_dof_values(f) - elseif have_compatible_domains(trian_f,get_background_triangulation(trian)) - get_cell_dof_values(f,get_cell_to_bgcell(trian)) - elseif have_compatible_domains( - get_background_triangulation(trian_f),get_background_triangulation(trian)) - cell_to_Vcell = get_cell_to_bgcell(trian,trian_f) - get_cell_dof_values(f,cell_to_Vcell) - elseif have_compatible_domains( - trian_f,get_background_triangulation(get_background_triangulation(trian))) - bg_trian = get_background_triangulation(trian) - bg_cell_dof_values = get_cell_dof_values(f,bg_trian) - cell_to_bgcell = get_cell_to_bgcell(trian) - get_cell_dof_values(bg_cell_dof_values,cell_to_bgcell) - else - @unreachable - end -end - """ FEFunction( fs::SingleFieldFESpace, free_values::AbstractVector, dirichlet_values::AbstractVector) @@ -299,7 +187,6 @@ function interpolate!(object, free_values,fs::SingleFieldFESpace) FEFunction(fs,free_values) end - function _cell_vals(fs::SingleFieldFESpace,object) s = get_fe_dof_basis(fs) trian = get_triangulation(s) diff --git a/src/FESpaces/SparseMatrixAssemblers.jl b/src/FESpaces/SparseMatrixAssemblers.jl index 43380266d..da52e69a0 100644 --- a/src/FESpaces/SparseMatrixAssemblers.jl +++ b/src/FESpaces/SparseMatrixAssemblers.jl @@ -63,7 +63,7 @@ function allocate_vector(a::SparseMatrixAssembler,vecdata) end function assemble_vector!(b,a::SparseMatrixAssembler,vecdata) - fill_entries!(b,zero(eltype(b))) + fill!(b,zero(eltype(b))) assemble_vector_add!(b,a,vecdata) end @@ -91,7 +91,7 @@ function allocate_matrix(a::SparseMatrixAssembler,matdata) end function assemble_matrix!(mat,a::SparseMatrixAssembler,matdata) - fill_entries!(mat,zero(eltype(mat))) + LinearAlgebra.fillstored!(mat,zero(eltype(mat))) assemble_matrix_add!(mat,a,matdata) end @@ -113,35 +113,29 @@ function allocate_matrix_and_vector(a::SparseMatrixAssembler,data) m1 = nz_counter(get_matrix_builder(a),(get_rows(a),get_cols(a))) v1 = nz_counter(get_vector_builder(a),(get_rows(a),)) symbolic_loop_matrix_and_vector!(m1,v1,a,data) - m2 = nz_allocation(m1) - v2 = nz_allocation(v1) + m2,v2 = nz_allocation(m1,v1) symbolic_loop_matrix_and_vector!(m2,v2,a,data) - m3 = create_from_nz(m2) - v3 = create_from_nz(v2) - m3,v3 + create_from_nz(m2,v2) end function assemble_matrix_and_vector!(A,b,a::SparseMatrixAssembler, data) - fill_entries!(A,zero(eltype(A))) - fill_entries!(b,zero(eltype(b))) + LinearAlgebra.fillstored!(A,zero(eltype(A))) + fill!(b,zero(eltype(b))) assemble_matrix_and_vector_add!(A,b,a,data) end function assemble_matrix_and_vector_add!(A,b,a::SparseMatrixAssembler,data) numeric_loop_matrix_and_vector!(A,b,a,data) - create_from_nz(A), create_from_nz(b) + create_from_nz(A,b) end function assemble_matrix_and_vector(a::SparseMatrixAssembler, data) m1 = nz_counter(get_matrix_builder(a),(get_rows(a),get_cols(a))) v1 = nz_counter(get_vector_builder(a),(get_rows(a),)) symbolic_loop_matrix_and_vector!(m1,v1,a,data) - m2 = nz_allocation(m1) - v2 = nz_allocation(v1) + m2,v2 = nz_allocation(m1,v1) numeric_loop_matrix_and_vector!(m2,v2,a,data) - m3 = create_from_nz(m2) - v3 = create_from_nz(v2) - m3,v3 + create_from_nz(m2,v2) end function test_sparse_matrix_assembler(a::SparseMatrixAssembler,matdata,vecdata,data) @@ -269,10 +263,35 @@ end end function symbolic_loop_vector!(b,a::GenericSparseMatrixAssembler,vecdata) - @notimplementedif LoopStyle(b) == Loop() + get_vec(a::Tuple) = a[1] + get_vec(a) = a + if LoopStyle(b) == DoNotLoop() + return b + end + for (cellvec,_cellids) in zip(vecdata...) + cellids = map_cell_rows(a.strategy,_cellids) + rows_cache = array_cache(cellids) + if length(cellids) > 0 + vec1 = get_vec(first(cellvec)) + rows1 = getindex!(rows_cache,cellids,1) + touch! = TouchEntriesMap() + touch_cache = return_cache(touch!,b,vec1,rows1) + caches = touch_cache, rows_cache + _symbolic_loop_vector!(b,caches,cellids,vec1) + end + end b end +@noinline function _symbolic_loop_vector!(A,caches,cellids,vec1) + touch_cache, rows_cache = caches + touch! = TouchEntriesMap() + for cell in 1:length(cellids) + rows = getindex!(rows_cache,cellids,cell) + evaluate!(touch_cache,touch!,A,vec1,rows) + end +end + function numeric_loop_vector!(b,a::GenericSparseMatrixAssembler,vecdata) for (cellvec, _cellids) in zip(vecdata...) cellids = map_cell_rows(a.strategy,_cellids) @@ -347,4 +366,3 @@ end evaluate!(add_vec_cache,add!,b,vecvals,rows) end end - diff --git a/src/Fields/ApplyOptimizations.jl b/src/Fields/ApplyOptimizations.jl index fbda9dfe6..9914cc022 100644 --- a/src/Fields/ApplyOptimizations.jl +++ b/src/Fields/ApplyOptimizations.jl @@ -273,6 +273,15 @@ function lazy_map( a end +function lazy_map( + k::typeof(∘), + ::Type{T}, + a::AbstractArray, + b::Fill{<:GenericField{typeof(identity)}}) where T + @assert length(a) == length(b) + a +end + # Memoization struct MemoArray{T,N,A} <: AbstractArray{T,N} diff --git a/src/Fields/ArrayBlocks.jl b/src/Fields/ArrayBlocks.jl index f387e5709..434f2c9a3 100644 --- a/src/Fields/ArrayBlocks.jl +++ b/src/Fields/ArrayBlocks.jl @@ -1022,10 +1022,10 @@ function Base.:*(a::ArrayBlock{A,2},b::ArrayBlock{B,2}) where {A,B} ArrayBlock(array,touched) end -function Algebra.scale_entries!(a::ArrayBlock,β) +function LinearAlgebra.rmul!(a::ArrayBlock,β) for i in eachindex(a.touched) if a.touched[i] - scale_entries!(a.array[i],β) + rmul!(a.array[i],β) end end end @@ -1057,7 +1057,7 @@ function LinearAlgebra.mul!( @check nj == size(b.array,1) for i in 1:ni if β!=1 && c.touched[i] - scale_entries!(c.array[i],β) + rmul!(c.array[i],β) end for j in 1:nj if a.touched[i,j] && b.touched[j] @@ -1085,7 +1085,7 @@ function LinearAlgebra.mul!( for i in 1:ni for j in 1:nj if β!=1 && c.touched[i,j] - scale_entries!(c.array[i,j],β) + rmul!(c.array[i,j],β) end for k in 1:nk if a.touched[i,k] && b.touched[k,j] diff --git a/src/Fields/DensifyInnerMostBlockLevelMaps.jl b/src/Fields/DensifyInnerMostBlockLevelMaps.jl new file mode 100644 index 000000000..26f93ef2a --- /dev/null +++ b/src/Fields/DensifyInnerMostBlockLevelMaps.jl @@ -0,0 +1,325 @@ +struct DensifyInnerMostBlockLevelMap <: Map +end + +function return_cache(k::DensifyInnerMostBlockLevelMap, + a::VectorBlock{<:Vector{T}}) where {T} + @check all(a.touched) + # Precompute the size of each row block. + # We are assuming that the size of each row + # block is going to be equivalent for all cells + s=0 + brs=Vector{Int}(undef,size(a)[1]) + for i=1:size(a)[1] + s=s+length(a.array[i]) + brs[i]=length(a.array[i]) + end + CachedArray(Vector{T}(undef,(s,))),brs +end + +function return_cache(k :: DensifyInnerMostBlockLevelMap, + brs :: Vector{<:Integer}, + a :: VectorBlock{<:Vector{T}}) where {T} + @check length(brs)==size(a)[1] + CachedArray(Vector{T}(undef,(sum(brs),))) +end + + +function return_cache(k::DensifyInnerMostBlockLevelMap, + a::MatrixBlock{<:Vector{T}}) where {T} + @check _check_preconditions(k,a) + s=Vector{Int}(undef,2) + s[1]=0 + s[2]=size(a)[2] + # Precompute the size of each row block. + # We are assuming that the size of each row + # block is going to be equivalent for all cells + brs=Vector{Int}(undef,size(a)[1]) + for i=1:size(a)[1] + for j=1:size(a)[2] + if (a.touched[i,j]) + s[1]=s[1]+length(a.array[i,j]) + brs[i]=length(a.array[i,j]) + break + end + end + end + CachedArray(Array{T,2}(undef,Tuple(s))),brs +end + +function return_cache(k :: DensifyInnerMostBlockLevelMap, + brs :: Vector{<:Integer}, + a :: MatrixBlock{<:Vector{T}}) where {T} + @check length(brs)==size(a)[1] + CachedArray(Array{T,2}(undef,(sum(brs),size(a)[2]))) +end + +function _check_preconditions(k::DensifyInnerMostBlockLevelMap, + a::MatrixBlock{<:Vector{T}}) where {T} + # Double check that, for each row, there is at least one non-zero block + found=false + for i=1:size(a)[1] + found=false + for j=1:size(a)[2] + if (a.touched[i,j]) + found = true + break + end + end + if !found + break + end + end + found +end + +function return_cache(k::DensifyInnerMostBlockLevelMap, + a::VectorBlock{<:Matrix{T}}) where {T} + @check all(a.touched) + s=Vector{Int}(undef,2) + s[1]=0 + s[2]=size(a.array[1])[2] + for i=1:size(a)[1] + s[1]=s[1]+size(a.array[i])[1] + end + CachedArray(Array{T,2}(undef,Tuple(s))) +end + +function return_cache(k ::DensifyInnerMostBlockLevelMap, + brs::Vector{<:Integer}, + cs ::Integer, + a ::VectorBlock{<:Matrix{T}}) where {T} + CachedArray(Array{T,2}(undef,(sum(brs),cs))) +end + + +function return_cache(k::DensifyInnerMostBlockLevelMap, + a::MatrixBlock{<:Matrix{T}}) where {T} + @check _check_preconditions(k,a) + s=Vector{Int}(undef,2) + s[1]=0 + s[2]=0 + # Precompute the size of each row/col block. + # We are assuming that the size of each row/col + # block is going to be equivalent for all cells + brs=Vector{Int}(undef,size(a)[1]) + bcs=Vector{Int}(undef,size(a)[2]) + # Row traversal + for i=1:size(a)[1] + for j=1:size(a)[2] + if (a.touched[i,j]) + s[1]=s[1]+size(a.array[i,j])[1] + brs[i]=size(a.array[i,j])[1] + break + end + end + end + #Column traversal + for j=1:size(a)[2] + for i=1:size(a)[1] + if (a.touched[i,j]) + s[2]=s[2]+size(a.array[i,j])[2] + bcs[j]=size(a.array[i,j])[2] + break + end + end + end + CachedArray(Array{T,2}(undef,Tuple(s))),brs,bcs +end + +function _check_preconditions(k::DensifyInnerMostBlockLevelMap, + a::MatrixBlock{<:Matrix{T}}) where {T} + # Double check that, for each row, + # there is at least one non-zero block + found=false + for i=1:size(a)[1] + found=false + for j=1:size(a)[2] + if (a.touched[i,j]) + found = true + break + end + end + if !found + break + end + end + # Double check that, for each col, + # there is at least one non-zero block + if (found) + for j=1:size(a)[2] + found=false + for i=1:size(a)[1] + if (a.touched[i,j]) + found = true + break + end + end + if !found + break + end + end + end + found +end + +function return_cache(k::DensifyInnerMostBlockLevelMap, + brs::Vector{<:Integer}, + bcs::Vector{<:Integer}, + a::MatrixBlock{<:Matrix{T}}) where {T} + CachedArray(Array{T,2}(undef,(sum(brs),sum(bcs)))) +end + + +function evaluate!(cache, + k::DensifyInnerMostBlockLevelMap, + a::VectorBlock{<:Vector{T}}) where {T} + cache_array, brs = cache + _evaluate!(cache_array,brs,a) +end + +function evaluate!(cache, + k :: DensifyInnerMostBlockLevelMap, + brs :: Vector{<:Integer}, + a :: VectorBlock{<:Vector{T}}) where {T} + _evaluate!(cache,brs,a) +end + +function _evaluate!(cache, + brs::Vector{<:Integer}, + a::VectorBlock{<:Vector{T}}) where {T} + output = cache.array + output .= zero(eltype(output)) + current_i=1 + for i=1:size(a)[1] + range = current_i:current_i+brs[i]-1 + if (a.touched[i]) + output[range] = a.array[i] + end + current_i = current_i + length(range) + end + output +end + +function evaluate!(cache, + k::DensifyInnerMostBlockLevelMap, + a::MatrixBlock{<:Vector{T}}) where {T} + cache_array, brs = cache + _evaluate!(cache_array,brs,a) +end + +function evaluate!(cache, + k :: DensifyInnerMostBlockLevelMap, + brs :: Vector{<:Integer}, + a :: MatrixBlock{<:Vector{T}}) where {T} + _evaluate!(cache,brs,a) +end + +function _evaluate!(cache, + brs::Vector{<:Integer}, + a::MatrixBlock{<:Vector{T}}) where {T} + output = cache.array + output .= zero(eltype(output)) + for j=1:size(a)[2] + current_i=1 + for i=1:size(a)[1] + range = current_i:current_i+brs[i]-1 + if (a.touched[i,j]) + output[range,j] = a.array[i,j] + end + current_i = current_i + length(range) + end + end + output +end + +function evaluate!(cache, + k::DensifyInnerMostBlockLevelMap, + a::MatrixBlock{<:Matrix{T}}) where {T} + cache_array, brs, bcs = cache + _evaluate!(cache_array, brs, bcs,a) +end + +function evaluate!(cache, + k::DensifyInnerMostBlockLevelMap, + brs::Vector{<:Integer}, + bcs::Vector{<:Integer}, + a::MatrixBlock{<:Matrix{T}}) where {T} + _evaluate!(cache, brs, bcs, a) +end + +function _evaluate!(cache_array, brs, bcs, a) + output = cache_array.array + output .= zero(eltype(output)) + current_j=1 + for j=1:size(a)[2] + current_i=1 + range_j = current_j:current_j+bcs[j]-1 + for i=1:size(a)[1] + range_i = current_i:current_i+brs[i]-1 + if (a.touched[i,j]) + output[range_i,range_j] = a.array[i,j] + end + current_i = current_i + brs[i] + end + current_j = current_j + bcs[j] + end + output +end + +function evaluate!(cache, + k::DensifyInnerMostBlockLevelMap, + a::VectorBlock{<:Matrix{T}}) where {T} + @check all(a.touched) + output = cache.array + current_i=1 + n=size(a.array[1])[2] + for i=1:size(a)[1] + range=current_i:current_i+size(a.array[i])[1]-1 + output[range,1:n] = a.array[i] + current_i=current_i+length(range) + end + output +end + +function return_cache(k::DensifyInnerMostBlockLevelMap, + a::ArrayBlock{<:ArrayBlock{T,M} where {T,M},N}) where {N} + cache_touched=a.touched + i=findfirst(isone, cache_touched) + cache_block=return_cache(k,a.array[i]) + cache_array=Array{typeof(cache_block),N}(undef,size(a)) + output_array=Array{return_type(k,a.array[i]),N}(undef,size(a)) + linds=LinearIndices(size(a)) + cinds=CartesianIndices(size(a)) + while i != nothing + cache_array[i]=cache_block + if (linds[i]+1 <= length(linds)) + i=findnext(isone, cache_touched, cinds[linds[i]+1]) + if (i!=nothing) + cache_block=return_cache(k,a.array[i]) + end + else + i=nothing + end + end + ArrayBlock(cache_array,cache_touched), + ArrayBlock(output_array,cache_touched), + linds, + cinds +end + +function evaluate!(cache, + k::DensifyInnerMostBlockLevelMap, + a::ArrayBlock{<:ArrayBlock{T,M} where {T,M},N}) where {N} + cache_array, output_array, linds, cinds = cache + @check cache_array.touched == a.touched + i=findfirst(isone, cache_array.touched) + while i != nothing + output_array.array[i]=evaluate!(cache_array.array[i],k,a.array[i]) + if (linds[i]+1 <= length(linds)) + i=findnext(isone, cache_array.touched, cinds[linds[i]+1]) + else + i=nothing + end + end + output_array +end diff --git a/src/Fields/Fields.jl b/src/Fields/Fields.jl index d073a9e10..1786d6111 100644 --- a/src/Fields/Fields.jl +++ b/src/Fields/Fields.jl @@ -10,7 +10,6 @@ using Gridap.Helpers: @abstractmethod, @notimplemented using Gridap.Helpers: @notimplementedif, @unreachable, @check using Gridap.Algebra: mul! -using Gridap.Algebra: fill_entries! using Gridap.TensorValues using Gridap.Algebra @@ -88,6 +87,13 @@ export VectorBlock export MatrixBlock export BlockMap +export VoidField +export VoidFieldMap +export VoidBasis +export VoidBasisMap + +export DensifyInnerMostBlockLevelMap + include("FieldsInterfaces.jl") include("FieldArrays.jl") @@ -106,4 +112,6 @@ include("ArrayBlocks.jl") include("InverseFields.jl") +include("DensifyInnerMostBlockLevelMaps.jl") + end diff --git a/src/Fields/FieldsInterfaces.jl b/src/Fields/FieldsInterfaces.jl index ac069188e..869e36aac 100644 --- a/src/Fields/FieldsInterfaces.jl +++ b/src/Fields/FieldsInterfaces.jl @@ -639,3 +639,161 @@ function test_field(f::Field, x, v, cmp=(==); grad=nothing, gradgrad=nothing) end true end + +struct VoidFieldMap <: Map + isvoid::Bool +end + +@inline Arrays.evaluate!(cache,k::VoidFieldMap,b) = VoidField(b,k.isvoid) + +struct VoidField{F} <: Field + field::F + isvoid::Bool +end + +function return_cache(f::VoidField,x::Point) + c = return_cache(f.field,x) + fx = evaluate!(c,f.field,x) + c, zero(fx) +end + +function evaluate!(cache,f::VoidField,x::Point) + c,z = cache + if f.isvoid + z + else + evaluate!(c,f.field,x) + end +end + +function return_cache(f::VoidField,x::AbstractVector{<:Point}) + c = return_cache(f.field,x) + fx = evaluate!(c,f.field,x) + z = similar(fx) + c, CachedArray(z) +end + +function evaluate!(cache,f::VoidField,x::AbstractVector{<:Point}) + c,z = cache + if f.isvoid + setsize!(z,size(x)) + fill!(z,zero(eltype(z))) + z.array + else + evaluate!(c,f.field,x) + end +end + +testvalue(::Type{VoidField{F}}) where F = VoidField(testvalue(F),false) + +@inline gradient(z::VoidField) = VoidField(gradient(z.field),z.isvoid) + +function lazy_map(::typeof(evaluate),a::LazyArray{<:Fill{VoidFieldMap}},x::AbstractArray) + p = a.maps.value + @notimplementedif p.isvoid + lazy_map(evaluate,a.args[1],x) +end + +struct VoidBasisMap <: Map + isvoid::Bool +end + +@inline Arrays.evaluate!(cache,k::VoidBasisMap,b) = VoidBasis(b,k.isvoid) + +struct VoidBasis{T,N,A} <: AbstractArray{T,N} + basis::A + isvoid::Bool + function VoidBasis(basis::AbstractArray{T,N},isvoid::Bool) where {T,N} + new{T,N,typeof(basis)}(basis,isvoid) + end +end + +function Base.size(a::VoidBasis) + if a.isvoid + 0 .* size(a.basis) + else + size(a.basis) + end +end + +Base.IndexStyle(::Type{<:VoidBasis}) = IndexLinear() + +function Base.getindex(a::VoidBasis,i::Integer) + if a.isvoid + @unreachable "Unable to access 0-length array" + else + a.basis[i] + end +end + +Arrays.testitem(a::VoidBasis) = testitem(a.basis) + +function _zero_size(a::VoidBasis{T,1} where T) + (0,) +end + +function _zero_size(a::VoidBasis{T,2} where T) + @check size(a,1) == 1 + (1,0) +end + +function Fields.return_cache(a::VoidBasis,x::Point) + cb = return_cache(a.basis,x) + bx = return_value(a.basis,x) + zs = _zero_size(a) + r = similar(bx,zs) + cb,r +end + +function Fields.return_cache(a::VoidBasis,x::Field) + @notimplementedif ndims(a) != 1 + cb = return_cache(a.basis,x) + bx = return_value(a.basis,x) + r = similar(bx,(0,)) + cb,r +end + +function Fields.return_cache(a::VoidBasis,x::AbstractVector{<:Point}) + cb = return_cache(a.basis,x) + bx = return_value(a.basis,x) + zs = _zero_size(a) + r = similar(bx,(length(x),zs...)) + cb,r +end + +function Fields.return_cache(a::VoidBasis,v::AbstractVector{<:Field}) + @notimplementedif ndims(a) != 1 + cb = return_cache(a.basis,v) + bx = return_value(a.basis,v) + r = similar(bx,(0,length(v))) + cb,r +end + +for T in (:Point,:Field,:(AbstractVector{<:Point}),:(AbstractVector{<:Field})) + @eval begin + + @inline function Fields.evaluate!(cache,a::VoidBasis,x::$T) + cb, r = cache + if a.isvoid + r + else + evaluate!(cb,a.basis,x) + end + end + + end +end + +function Fields.evaluate!(cache,k::Broadcasting{typeof(∇)},a::VoidBasis) + VoidBasis(k(a.basis),a.isvoid) +end + +function Fields.evaluate!(cache,k::Broadcasting{typeof(∇∇)},a::VoidBasis) + VoidBasis(k(a.basis),a.isvoid) +end + +function lazy_map(::typeof(evaluate),a::LazyArray{<:Fill{VoidBasisMap}},x::AbstractArray) + p = a.maps.value + @notimplementedif p.isvoid + lazy_map(evaluate,a.args[1],x) +end diff --git a/src/Geometry/AppendedTriangulations.jl b/src/Geometry/AppendedTriangulations.jl index 6a4db06ef..c8d42c1bf 100644 --- a/src/Geometry/AppendedTriangulations.jl +++ b/src/Geometry/AppendedTriangulations.jl @@ -1,74 +1,140 @@ -function lazy_append(a::Triangulation,b::Triangulation) - AppendedTriangulation(a,b) +function lazy_append(a::Grid,b::Grid) + AppendedGrid(a,b) end -struct AppendedTriangulation{Dc,Dp} <: Triangulation{Dc,Dp} - a::Triangulation{Dc,Dp} - b::Triangulation{Dc,Dp} - function AppendedTriangulation(a::Triangulation{Dc,Dp},b::Triangulation{Dc,Dp}) where {Dc,Dp} - @assert get_background_triangulation(a) === get_background_triangulation(b) - new{Dc,Dp}(a,b) +struct AppendedGrid{Dc,Dp,A,B} <: Grid{Dc,Dp} + a::A + b::B + function AppendedGrid( a::Grid{Dc,Dp}, b::Grid{Dc,Dp}) where {Dc,Dp} + new{Dc,Dp,typeof(a),typeof(b)}(a,b) end end -TriangulationStyle(::Type{<:AppendedTriangulation}) = SubTriangulation() +function get_node_coordinates(t::AppendedGrid) + xa = get_node_coordinates(t.a) + xb = get_node_coordinates(t.b) + if xa === xb + xa + else + lazy_append(xa,xb) + end +end -get_background_triangulation(trian::AppendedTriangulation) = get_background_triangulation(trian.a) +function get_cell_node_ids(t::AppendedGrid) + xa = get_node_coordinates(t.a) + xb = get_node_coordinates(t.b) + idsa = get_cell_node_ids(t.a) + idsb = get_cell_node_ids(t.b) + if xa === xb + lazy_append(idsa,idsb) + else + nxa = Int32(length(xa)) + idsc = lazy_map(Broadcasting(i->i+nxa),idsb) + lazy_append(idsa,idsc) + end +end -function get_cell_coordinates(trian::AppendedTriangulation) +function get_reffes(t::AppendedGrid) + ra = get_reffes(t.a) + rb = get_reffes(t.b) + if ra === rb + ra + else + vcat(ra,rb) + end +end + +function get_cell_type(t::AppendedGrid) + ra = get_reffes(t.a) + rb = get_reffes(t.b) + a = get_cell_type(t.a) + b = get_cell_type(t.b) + if ra === rb + lazy_append(a,b) + else + nra = Int8(length(ra)) + c = lazy_map(i->i+nra,b) + lazy_append(a,c) + end +end + +function get_cell_coordinates(trian::AppendedGrid) a = get_cell_coordinates(trian.a) b = get_cell_coordinates(trian.b) lazy_append(a,b) end -function get_cell_ref_coordinates(trian::AppendedTriangulation) +function get_cell_ref_coordinates(trian::AppendedGrid) a = get_cell_ref_coordinates(trian.a) b = get_cell_ref_coordinates(trian.b) lazy_append(a,b) end -function get_reffes(trian::AppendedTriangulation) - vcat(get_reffes(trian.a),get_reffes(trian.b)) -end +# In this case, we do not want a lazy_append since it will become difficult to +# compress / expand the reffes. +#function get_cell_reffe(trian::AppendedGrid) +# a = get_cell_reffe(trian.a) +# b = get_cell_reffe(trian.b) +# lazy_append(a,b) +#end -function get_cell_type(trian::AppendedTriangulation) - a = get_cell_type(trian.a) - b = get_cell_type(trian.b) .+ Int8(length(get_reffes(trian.a))) +function get_cell_shapefuns(trian::AppendedGrid) + a = get_cell_shapefuns(trian.a) + b = get_cell_shapefuns(trian.b) lazy_append(a,b) end -#function reindex(f::AbstractArray,trian::AppendedTriangulation) -# a = reindex(f,trian.a) -# b = reindex(f,trian.b) -# lazy_append(a,b) -#end +function get_cell_map(trian::AppendedGrid) + a = get_cell_map(trian.a) + b = get_cell_map(trian.b) + lazy_append(a,b) +end -function get_cell_to_bgcell(trian::AppendedTriangulation) - a = get_cell_to_bgcell(trian.a) - b = get_cell_to_bgcell(trian.b) +function get_facet_normal(trian::AppendedGrid) + cm = get_cell_map(trian) + a = get_facet_normal(trian.a) + b = get_facet_normal(trian.b) lazy_append(a,b) end -function get_cell_ref_map(trian::AppendedTriangulation) - a = get_cell_ref_map(trian.a) - b = get_cell_ref_map(trian.b) +function lazy_append(a::Triangulation,b::Triangulation) + AppendedTriangulation(a,b) +end + +struct AppendedTriangulation{Dc,Dp,A,B} <: Triangulation{Dc,Dp} + a::A + b::B + function AppendedTriangulation( + a::Triangulation{Dc,Dp}, b::Triangulation{Dc,Dp}) where {Dc,Dp} + @assert get_background_model(a) === get_background_model(b) + new{Dc,Dp,typeof(a),typeof(b)}(a,b) + end +end + +get_background_model(t::AppendedTriangulation) = get_background_model(t.a) + +function get_grid(t::AppendedTriangulation) + a = get_grid(t.a) + b = get_grid(t.b) lazy_append(a,b) end -#function restrict(f::AbstractArray,trian::AppendedTriangulation) -# a = restrict(f,trian.a) -# b = restrict(f,trian.b) -# lazy_append(a,b) -#end +function get_glue(t::AppendedTriangulation,::Val{D}) where D + a = get_glue(t.a,Val(D)) + b = get_glue(t.b,Val(D)) + if a==nothing || b==nothing + return nothing + end + lazy_append(a,b) +end -# In this case, we do not want a lazy_append since it will become difficult to -# compress / expand the reffes. -#function get_cell_reffe(trian::AppendedTriangulation) -# a = get_cell_reffe(trian.a) -# b = get_cell_reffe(trian.b) -# lazy_append(a,b) -#end +function lazy_append(a::FaceToFaceGlue,b::FaceToFaceGlue) + tface_to_mface = lazy_append(a.tface_to_mface,b.tface_to_mface) + tface_to_mface_map = lazy_append(a.tface_to_mface_map,b.tface_to_mface_map) + mface_to_tface = nothing + FaceToFaceGlue(tface_to_mface,tface_to_mface_map,mface_to_tface) +end function get_cell_shapefuns(trian::AppendedTriangulation) a = get_cell_shapefuns(trian.a) @@ -89,15 +155,17 @@ function get_facet_normal(trian::AppendedTriangulation) lazy_append(a,b) end -#function CellQuadrature(trian::AppendedTriangulation,degree1::Integer,degree2::Integer) -# quad1 = CellQuadrature(trian.a,degree1) -# quad2 = CellQuadrature(trian.b,degree2) -# lazy_append(quad1,quad2) -#end -# -#function CellQuadrature(trian::AppendedTriangulation,degree::Integer) -# CellQuadrature(trian,degree,degree) -#end +function move_contributions( + cell_mat::AppendedArray, trian::AppendedTriangulation) + + if length(cell_mat.a) == num_cells(trian.a) && length(cell_mat.b) == num_cells(trian.b) + a,ta = move_contributions(cell_mat.a,trian.a) + b,tb = move_contributions(cell_mat.b,trian.b) + return lazy_append(a,b), lazy_append(ta,tb) + else + return cell_mat, trian + end +end #function compress_contributions(cell_mat::AppendedArray,trian::AppendedTriangulation) # if length(cell_mat.a) == num_cells(trian.a) && length(cell_mat.b) == num_cells(trian.b) @@ -118,14 +186,3 @@ end # return cell_ids # end #end - -function compress_contributions(cell_mat,trian::AppendedTriangulation) - cell_to_bgcell = get_cell_to_bgcell(trian) - ccell_mat = compress_contributions(cell_mat,cell_to_bgcell) - ccell_mat -end - -function compress_ids(cell_ids,trian::AppendedTriangulation) - cell_to_bgcell = get_cell_to_bgcell(trian) - compress_ids(cell_ids,cell_to_bgcell) -end diff --git a/src/Geometry/BoundaryDiscreteModels.jl b/src/Geometry/BoundaryDiscreteModels.jl deleted file mode 100644 index 270a8ffa7..000000000 --- a/src/Geometry/BoundaryDiscreteModels.jl +++ /dev/null @@ -1,24 +0,0 @@ -struct BoundaryDiscreteModel{Dc,Dp} <:DiscreteModel{Dc,Dp} - model::DiscreteModel{Dc,Dp} - bgmodel::DiscreteModel - trian::BoundaryTriangulation -end - -function BoundaryDiscreteModel( - ::Type{<:Polytope{Df}}, - bgmodel::DiscreteModel, - bgface_to_mask::AbstractArray) where Df - - @assert Df < num_cell_dims(bgmodel) - - bgmodel_Df = DiscreteModel(Polytope{Df},bgmodel) - model = DiscreteModelPortion(bgmodel_Df,bgface_to_mask) - trian = BoundaryTriangulation(bgmodel,bgface_to_mask) - BoundaryDiscreteModel(model,bgmodel,trian) -end - -get_grid(model::BoundaryDiscreteModel) = get_grid(model.model) -get_grid_topology(model::BoundaryDiscreteModel) = get_grid_topology(model.model) -get_face_labeling(model::BoundaryDiscreteModel) = get_face_labeling(model.model) -get_triangulation(a::BoundaryDiscreteModel) = a.trian -Triangulation(a::BoundaryDiscreteModel) = a.trian diff --git a/src/Geometry/BoundaryTriangulations.jl b/src/Geometry/BoundaryTriangulations.jl index 6af99566c..21327297d 100644 --- a/src/Geometry/BoundaryTriangulations.jl +++ b/src/Geometry/BoundaryTriangulations.jl @@ -1,6 +1,4 @@ -""" -""" struct FaceToCellGlue{A,B,C,D} <: GridapType face_to_bgface::A bgface_to_lcell::B @@ -15,13 +13,13 @@ end function FaceToCellGlue( topo::GridTopology, - cell_trian::Triangulation, - face_trian::Triangulation, + cell_grid::Grid, + face_grid::Grid, face_to_bgface::AbstractVector, bgface_to_lcell::AbstractVector) - D = num_cell_dims(cell_trian) - cD = num_cell_dims(face_trian) + D = num_cell_dims(cell_grid) + cD = num_cell_dims(face_grid) bgface_to_cells = get_faces(topo,cD,D) cell_to_bgfaces = get_faces(topo,D,cD) cell_to_lface_to_pindex = Table(get_cell_permutations(topo,cD)) @@ -34,9 +32,9 @@ function FaceToCellGlue( face_to_lcell = collect(Int8,lazy_map(Reindex(bgface_to_lcell), face_to_bgface)) f = (p)->fill(Int8(UNSET),num_faces(p,cD)) - ctype_to_lface_to_ftype = map( f, get_reffes(cell_trian) ) - face_to_ftype = get_cell_type(face_trian) - cell_to_ctype = get_cell_type(cell_trian) + ctype_to_lface_to_ftype = map( f, get_reffes(cell_grid) ) + face_to_ftype = get_cell_type(face_grid) + cell_to_ctype = get_cell_type(cell_grid) _fill_ctype_to_lface_to_ftype!( ctype_to_lface_to_ftype, @@ -85,29 +83,26 @@ end """ """ -struct BoundaryTriangulation{Dc,Dp,Gf,Gc,G} <: Triangulation{Dc,Dp} - face_trian::Gf - cell_trian::Gc - glue::G +struct BoundaryTriangulation{Dc,Dp,A,B} <: Triangulation{Dc,Dp} + trian::A + glue::B function BoundaryTriangulation( - face_trian::Triangulation, - cell_trian::Triangulation, + trian::BodyFittedTriangulation, glue::FaceToCellGlue) - #@assert TriangulationStyle(cell_trian) == BackgroundTriangulation() - @assert num_point_dims(face_trian) == num_point_dims(cell_trian) - #@assert num_cell_dims(face_trian) == num_cell_dims(cell_trian) - 1 - - Dc = num_cell_dims(face_trian) - Dp = num_point_dims(face_trian) - Gf = typeof(face_trian) - Gc = typeof(cell_trian) - G = typeof(glue) - new{Dc,Dp,Gf,Gc,G}(face_trian, cell_trian, glue) + Dc = num_cell_dims(trian) + Dp = num_point_dims(trian) + A = typeof(trian) + B = typeof(glue) + new{Dc,Dp,A,B}(trian,glue) end end +function Boundary(args...;kwargs...) + BoundaryTriangulation(args...;kwargs...) +end + # Constructors """ @@ -123,12 +118,12 @@ function BoundaryTriangulation( topo = get_grid_topology(model) bgface_grid = Grid(ReferenceFE{D-1},model) - face_trian = RestrictedTriangulation(bgface_grid,face_to_bgface) - #cell_trian = Grid(ReferenceFE{D},model) - cell_trian = Triangulation(model) - glue = FaceToCellGlue(topo,cell_trian,face_trian,face_to_bgface,bgface_to_lcell) + face_grid = view(bgface_grid,face_to_bgface) + cell_grid = get_grid(model) + glue = FaceToCellGlue(topo,cell_grid,face_grid,face_to_bgface,bgface_to_lcell) + trian = BodyFittedTriangulation(model,face_grid,face_to_bgface) - BoundaryTriangulation(face_trian,cell_trian,glue) + BoundaryTriangulation(trian,glue) end function BoundaryTriangulation( @@ -179,79 +174,44 @@ function BoundaryTriangulation(model::DiscreteModel;tags=nothing) BoundaryTriangulation(model,labeling,tags=tags) end -# Triangulation API - -# Delegating to the underlying face Triangulation - -get_cell_coordinates(trian::BoundaryTriangulation) = get_cell_coordinates(trian.face_trian) - -get_reffes(trian::BoundaryTriangulation) = get_reffes(trian.face_trian) - -get_cell_type(trian::BoundaryTriangulation) = get_cell_type(trian.face_trian) - -get_node_coordinates(trian::BoundaryTriangulation) = get_node_coordinates(trian.face_trian) - -get_cell_node_ids(trian::BoundaryTriangulation) = get_cell_node_ids(trian.face_trian) - -get_cell_map(trian::BoundaryTriangulation) = get_cell_map(trian.face_trian) - -# Genuine methods - -TriangulationStyle(::Type{<:BoundaryTriangulation}) = SubTriangulation() - -get_background_triangulation(trian::BoundaryTriangulation) = trian.cell_trian - -get_cell_to_bgcell(trian::BoundaryTriangulation) = trian.glue.face_to_cell - -function get_cell_to_bgcell( - trian_in::BoundaryTriangulation, - trian_out::BoundaryTriangulation) - - if have_compatible_domains(trian_out,get_background_triangulation(trian_in)) - return get_cell_to_bgcell(trian_in) - end - - @check have_compatible_domains( - get_background_triangulation(trian_in), - get_background_triangulation(trian_out)) - - face_in_to_bgface = trian_in.glue.face_to_bgface - face_out_to_bgface = trian_out.glue.face_to_bgface - - nbgfaces = length(trian_in.glue.bgface_to_lcell) - bgface_to_face_out = zeros(Int32,nbgfaces) - bgface_to_face_out[face_out_to_bgface] .= 1:length(face_out_to_bgface) - face_in_to_face_out = bgface_to_face_out[face_in_to_bgface] - @check all( face_in_to_face_out .!= 0) "the first triangulation is not a subset of the second" - face_in_to_face_out +function BoundaryTriangulation(rtrian::Triangulation,args...;kwargs...) + rmodel = get_active_model(rtrian) + dtrian = BoundaryTriangulation(rmodel,args...;kwargs...) + CompositeTriangulation(rtrian,dtrian) end -function is_included( - trian_in::BoundaryTriangulation, - trian_out::BoundaryTriangulation) +# API - if have_compatible_domains(trian_out,get_background_triangulation(trian_in)) - return true - end +get_background_model(t::BoundaryTriangulation) = get_background_model(t.trian) +get_grid(t::BoundaryTriangulation) = get_grid(t.trian) +get_glue(t::BoundaryTriangulation{D},::Val{D}) where D = get_glue(t.trian,Val(D)) - @check have_compatible_domains( - get_background_triangulation(trian_in), - get_background_triangulation(trian_out)) +function get_glue(trian::BoundaryTriangulation,::Val{Dp}) where Dp + model = get_background_model(trian) + Dm = num_cell_dims(model) + get_glue(trian,Val(Dp),Val(Dm)) +end - face_in_to_bgface = trian_in.glue.face_to_bgface - face_out_to_bgface = trian_out.glue.face_to_bgface +function get_glue(trian::BoundaryTriangulation,::Val{Dp},::Val{Dm}) where {Dp,Dm} + nothing +end - nbgfaces = length(trian_in.glue.bgface_to_lcell) - bgface_to_face_out = zeros(Int32,nbgfaces) - bgface_to_face_out[face_out_to_bgface] .= 1:length(face_out_to_bgface) - face_in_to_face_out = bgface_to_face_out[face_in_to_bgface] - all( face_in_to_face_out .!= 0) +function get_glue(trian::BoundaryTriangulation,::Val{D},::Val{D}) where D + tface_to_mface = trian.glue.face_to_cell + face_to_q_vertex_coords = _compute_face_to_q_vertex_coords(trian) + f(p) = get_shapefuns(LagrangianRefFE(Float64,get_polytope(p),1)) + ftype_to_shapefuns = map( f, get_reffes(trian) ) + face_to_shapefuns = expand_cell_data(ftype_to_shapefuns,trian.glue.face_to_ftype) + face_s_q = lazy_map(linear_combination,face_to_q_vertex_coords,face_to_shapefuns) + tface_to_mface_map = face_s_q + mface_to_tface = nothing + FaceToFaceGlue(tface_to_mface,tface_to_mface_map,mface_to_tface) end function get_facet_normal(trian::BoundaryTriangulation) glue = trian.glue - cell_trian = trian.cell_trian + cell_grid = get_grid(get_background_model(trian.trian)) ## Reference normal function f(r) @@ -262,18 +222,20 @@ function get_facet_normal(trian::BoundaryTriangulation) lface_pindex_to_n = [ fill(lface_to_n[lface],length(lface_to_pindex_to_perm[lface])) for lface in 1:nlfaces ] lface_pindex_to_n end - ctype_lface_pindex_to_nref = map(f, get_reffes(cell_trian)) + ctype_lface_pindex_to_nref = map(f, get_reffes(cell_grid)) face_to_nref = FaceCompressedVector(ctype_lface_pindex_to_nref,glue) face_s_nref = lazy_map(constant_field,face_to_nref) # Inverse of the Jacobian transpose - cell_q_x = get_cell_map(cell_trian) + cell_q_x = get_cell_map(cell_grid) cell_q_Jt = lazy_map(∇,cell_q_x) cell_q_invJt = lazy_map(Operation(pinvJt),cell_q_Jt) face_q_invJt = lazy_map(Reindex(cell_q_invJt),glue.face_to_cell) # Change of domain - face_s_q = get_cell_ref_map(trian) + D = num_cell_dims(cell_grid) + glue = get_glue(trian,Val(D)) + face_s_q = glue.tface_to_mface_map face_s_invJt = lazy_map(∘,face_q_invJt,face_s_q) face_s_n = lazy_map(Broadcasting(Operation(push_normal)),face_s_invJt,face_s_nref) Fields.MemoArray(face_s_n) @@ -289,32 +251,10 @@ end end end -function get_cell_ref_map(trian::BoundaryTriangulation) - face_to_q_vertex_coords = _compute_face_to_q_vertex_coords(trian) - f(p) = get_shapefuns(LagrangianRefFE(Float64,get_polytope(p),1)) - ftype_to_shapefuns = map( f, get_reffes(trian) ) - face_to_shapefuns = expand_cell_data(ftype_to_shapefuns,trian.glue.face_to_ftype) - face_s_q = lazy_map(linear_combination,face_to_q_vertex_coords,face_to_shapefuns) -end - -function get_cell_ref_map( - trian_in::BoundaryTriangulation, - trian_out::BoundaryTriangulation) - - if have_compatible_domains(trian_out,get_background_triangulation(trian_in)) - return get_cell_ref_map(trian_in) - end - - @check have_compatible_domains( - get_background_triangulation(trian_in), - get_background_triangulation(trian_out)) - - Fill(GenericField(identity),num_cells(trian_in)) -end - function _compute_face_to_q_vertex_coords(trian::BoundaryTriangulation) d = num_cell_dims(trian) - polytopes = map(get_polytope, get_reffes(trian.cell_trian)) + cell_grid = get_grid(get_background_model(trian.trian)) + polytopes = map(get_polytope, get_reffes(cell_grid)) cell_to_ctype = trian.glue.cell_to_ctype ctype_to_lvertex_to_qcoords = map(get_vertex_coordinates, polytopes) ctype_to_lface_to_lvertices = map((p)->get_faces(p,d,0), polytopes) @@ -491,27 +431,3 @@ function lazy_map(k::typeof(evaluate),::Type{T},a::Fill,b::FaceCompressedVector, FaceCompressedVector(ctype_lface_pindex_to_r,b.glue) end -#function lazy_map(k::typeof(evaluate),::Type{T},a::CompressedArray,b::FaceCompressedVector) where T -# if a.ptrs == lazy_map(Reindex(b.glue.cell_to_ctype),b.glue.face_to_cell) -# -# ctype_lface_pindex_to_r = Vector{Vector{Vector{T}}}(undef,length(b.ctype_lface_pindex_to_value)) -# for (ctype, lface_pindex_to_value) in enumerate(b.ctype_lface_pindex_to_value) -# lface_pindex_to_r = Vector{Vector{T}}(undef,length(lface_pindex_to_value)) -# for (lface, pindex_to_value) in enumerate(lface_pindex_to_value) -# pindex_to_r = Vector{T}(undef,length(pindex_to_value)) -# ftype = b.glue.ctype_to_lface_to_ftype[ctype][lface] -# if ftype != UNSET -# for (pindex, value) in enumerate(pindex_to_value) -# pindex_to_r[pindex] = evaluate(a.values[ftype],value) -# end -# end -# lface_pindex_to_r[lface] = pindex_to_r -# end -# ctype_lface_pindex_to_r[ctype] = lface_pindex_to_r -# end -# FaceCompressedVector(ctype_lface_pindex_to_r,b.glue) -# -# else -# @notimplemented -# end -#end diff --git a/src/Geometry/CompressedCellArrays.jl b/src/Geometry/CompressedCellArrays.jl index 7bc3b0aa5..00762fdd6 100644 --- a/src/Geometry/CompressedCellArrays.jl +++ b/src/Geometry/CompressedCellArrays.jl @@ -1,164 +1,158 @@ +function move_contributions( + scell_to_val::AbstractArray, strian::Triangulation) -function compress_ids(cell_to_bgcell::AbstractVector{<:Integer}) - nccells = 0 - c = -1 - for bgcell in cell_to_bgcell - if c != bgcell - nccells += 1 - c = bgcell - end - end - ccell_to_first_cell = zeros(Int32,nccells+1) - ccell = 0 - c = -1 - for (cell,bgcell) in enumerate(cell_to_bgcell) - if c != bgcell - ccell += 1 - c = bgcell - ccell_to_first_cell[ccell] = cell - end - end - ccell_to_first_cell[end] = length(cell_to_bgcell)+1 - ccell_to_first_cell + scell_to_val, strian end -function compress_ids(cell_ids,cell_to_bgcell::AbstractVector{<:Integer}) - ccell_to_first_cell = compress_ids(cell_to_bgcell) - nccells = length(ccell_to_first_cell)-1 - ccell_to_cell = view(ccell_to_first_cell,1:nccells) - ccell_ids = view(cell_ids,ccell_to_cell) - ccell_ids +function move_contributions( + scell_to_val::AbstractArray, strian::Triangulation, ttrian::Triangulation) + + D = num_cell_dims(ttrian) + sglue = get_glue(strian,Val(D)) + tglue = get_glue(ttrian,Val(D)) + move_contributions(scell_to_val,sglue,tglue) end -function compress_contributions( - cell_to_mat, - cell_to_bgcell::AbstractVector{<:Integer}, - ccell_to_first_cell::AbstractVector{<:Integer}=compress_ids(cell_to_bgcell)) +function move_contributions( + scell_to_val::AbstractArray, sglue::FaceToFaceGlue, tglue::FaceToFaceGlue) + move_contributions(scell_to_val,sglue,tglue,sglue.mface_to_tface) +end + +function move_contributions( + scell_to_val::AbstractArray, + sglue::FaceToFaceGlue, + tglue::FaceToFaceGlue, + mcell_to_scell::AbstractArray) - nccells = length(ccell_to_first_cell)-1 - ccell_to_cell = view(ccell_to_first_cell,1:nccells) - ccell_to_mat = CompressedCellArray(cell_to_mat,ccell_to_first_cell) - ccell_to_mat + mcell_to_val = extend(scell_to_val,mcell_to_scell) + tcell_to_mcell = tglue.tface_to_mface + tcell_to_val = lazy_map(Reindex(mcell_to_val),tcell_to_mcell) end -struct CompressedCellArray{T,A,B} <: AbstractVector{T} - cell_to_array::A - ccell_to_first_cell::B - function CompressedCellArray(cell_to_array::A, ccell_to_first_cell::B) where {A,B} - T = eltype(cell_to_array) - new{T,A,B}(cell_to_array,ccell_to_first_cell) +function move_contributions( + scell_to_val::AbstractArray, + sglue::FaceToFaceGlue, + tglue::FaceToFaceGlue, + mcell_to_scell::Nothing) + + scell_to_mcell = sglue.tface_to_mface + mcell_to_tcell = tglue.mface_to_tface + ntcells = length(tglue.tface_to_mface) + tcell_to_scells_ptr = zeros(Int32,ntcells+1) + for mcell in scell_to_mcell + tcell = mcell_to_tcell[mcell] + tcell_to_scells_ptr[1+tcell] += Int32(1) + end + length_to_ptrs!(tcell_to_scells_ptr) + ndata = tcell_to_scells_ptr[end]-1 + tcell_to_scells_data = zeros(Int32,ndata) + for (scell,mcell) in enumerate(scell_to_mcell) + tcell = mcell_to_tcell[mcell] + p = tcell_to_scells_ptr[tcell] + tcell_to_scells_data[p] = scell + tcell_to_scells_ptr[tcell] += Int32(1) end + rewind_ptrs!(tcell_to_scells_ptr) + tcell_to_scells = Table(tcell_to_scells_data,tcell_to_scells_ptr) + k = CombineContributionsMap(scell_to_val) + tcell_to_val = lazy_map(k,tcell_to_scells) end -Base.size(a::CompressedCellArray) = (length(a.ccell_to_first_cell)-1,) -Base.IndexStyle(::Type{<:CompressedCellArray}) = IndexLinear() +struct CombineContributionsMap{A} <: Map + scell_to_val::A +end -function Base.getindex(a::CompressedCellArray,ccell::Integer) - cell_first = a.ccell_to_first_cell[ccell] - cell_last = a.ccell_to_first_cell[ccell+1]-1 - array = a.cell_to_array[cell_first] - cell_range = (cell_first+1):cell_last - _compress!(array,a.cell_to_array,cell_range) +function return_cache(k::CombineContributionsMap{<:AbstractArray{<:Number}},scells) + z = zero(testitem(k.scell_to_val)) + z, array_cache(k.scell_to_val) end -@inline function _compress!(array,cell_to_array,cell_range) - r = copy(array) - for cell in cell_range - carray = cell_to_array[cell] - _addto!(r,carray) +function evaluate!(cache,k::CombineContributionsMap{<:AbstractArray{<:Number}},scells) + z,c = cache + val = zero(z) + for scell in scells + val += getindex!(c,k.scell_to_val,scell) + end + val +end + +function return_cache(k::CombineContributionsMap,scells) + array = testitem(k.scell_to_val) + c12 = _cache_compress(array) + c = array_cache(k.scell_to_val) + c12, c +end + +function evaluate!(cache,k::CombineContributionsMap,scells) + c12,c = cache + c1,c2 = c12 + if length(scells) == 0 + _setempty_compress!(c1) + val = _uncached_compress!(c1,c2) + else + val1 = getindex!(c,k.scell_to_val,scells[1]) + _setsize_compress!(c1,val1) + val = _uncached_compress!(c1,c2) + _copyto_compress!(val,val1) + for i in 2:length(scells) + vali = getindex!(c,k.scell_to_val,scells[i]) + _addto_compress!(val,vali) + end + val end - r + val +end + +function _cache_compress(array::AbstractArray) + c1 = CachedArray(copy(array)) + c1, nothing +end + +function _cache_compress(array::ArrayBlock) + c1 = CachedArray(deepcopy(array)) + c2 = return_cache(Fields.unwrap_cached_array,c1) + c1,c2 end -@inline function _compress!(matvec::Tuple,cell_to_matvec,cell_range) +function _cache_compress(matvec::Tuple) mat, vec = matvec - rm = copy(mat) - rv = copy(vec) - for cell in cell_range - cmat, cvec = cell_to_matvec[cell] - _addto!(rm,cmat) - _addto!(rv,cvec) - end - (rm,rv) + cmat,ca = _cache_compress(mat) + cvec,cb = _cache_compress(vec) + (cmat, cvec), (ca,cb) end -function _addto!(a,b) - @check size(a) == size(b) - for k in eachindex(a) - a[k] = a[k] + b[k] - end - a +function _setempty_compress!(a::CachedArray) + setsize!(a,0 .* size(a)) end -function _addto!(a::ArrayBlock,b::ArrayBlock) - @check size(a) == size(b) +function _setempty_compress!(a::ArrayBlock) for k in eachindex(a.array) - @check a.touched[k] == b.touched[k] if a.touched[k] - _addto!(a.array[k],b.array[k]) + _setempty_compress!(a.array[k]) end end - a end -function array_cache(a::CompressedCellArray) - array = testitem(a.cell_to_array) - c = _compress_cache(array) - ccache = array_cache(a.cell_to_array) - c,ccache +function _setempty_compress!(ab::Tuple) + a,b = ab + _setempty_compress!(a) + _setempty_compress!(b) end -function _compress_cache(array) - c1 = CachedArray(copy(array)) - c2 = return_cache(Fields.unwrap_cached_array,c1) - c1,c2 +function _uncached_compress!(a::CachedArray,c2) + a.array end -function _compress_cache(matvec::Tuple) - mat, vec = matvec - cmat = _compress_cache(mat) - cvec = _compress_cache(vec) - cmat, cvec -end - -function getindex!(cache,a::CompressedCellArray,ccell::Integer) - c, ccache = cache - cell_first = a.ccell_to_first_cell[ccell] - cell_last = a.ccell_to_first_cell[ccell+1]-1 - array = getindex!(ccache,a.cell_to_array,cell_first) - cell_range = (cell_first+1):cell_last - _compress!(c,array,ccache,a.cell_to_array,cell_range) -end - -@inline function _compress!(c,array,ccache,cell_to_array,cell_range) - c1,c2 = c - _setsize_compress!(c1,array) - r = evaluate!(c2,Fields.unwrap_cached_array,c1) - copyto!(r,array) - for cell in cell_range - carray = getindex!(ccache,cell_to_array,cell) - _addto!(r,carray) - end - r +function _uncached_compress!(c1::ArrayBlock,c2) + evaluate!(c2,Fields.unwrap_cached_array,c1) end -@inline function _compress!(c,matvec::Tuple,ccache,cell_to_matvec,cell_range) - cm, cv = c - cm1,cm2 = cm - cv1,cv2 = cv - mat, vec = matvec - _setsize_compress!(cm1,mat) - _setsize_compress!(cv1,vec) - rm = evaluate!(cm2,Fields.unwrap_cached_array,cm1) - rv = evaluate!(cv2,Fields.unwrap_cached_array,cv1) - copyto!(rm,mat) - copyto!(rv,vec) - for cell in cell_range - cmat, cvec = getindex!(ccache,cell_to_matvec,cell) - _addto!(rm,cmat) - _addto!(rv,cvec) - end - (rm, rv) +function _uncached_compress!(c1::Tuple,c2) + a1,b1 = c1 + a2,b2 = c2 + a = _uncached_compress!(a1,a2) + b = _uncached_compress!(b1,b2) + (a,b) end function _setsize_compress!(a::CachedArray,b::AbstractArray) @@ -175,4 +169,62 @@ function _setsize_compress!(a::ArrayBlock,b::ArrayBlock) end end +function _setsize_compress!(a::Tuple,b::Tuple) + a1,a2 = a + b1,b2 = b + _setsize_compress!(a1,b1) + _setsize_compress!(a2,b2) +end + +function _copyto_compress!(a::AbstractArray,b::AbstractArray) + @check size(a) == size(b) + for k in eachindex(a) + a[k] = b[k] + end + a +end + +function _copyto_compress!(a::ArrayBlock,b::ArrayBlock) + @check size(a) == size(b) + for k in eachindex(a.array) + @check a.touched[k] == b.touched[k] + if a.touched[k] + _copyto_compress!(a.array[k],b.array[k]) + end + end + a +end + +function _copyto_compress!(a::Tuple,b::Tuple) + a1,a2 = a + b1,b2 = b + _copyto_compress!(a1,b1) + _copyto_compress!(a2,b2) +end + +function _addto_compress!(a::AbstractArray,b::AbstractArray) + @check size(a) == size(b) + for k in eachindex(a) + a[k] = a[k] + b[k] + end + a +end + +function _addto_compress!(a::ArrayBlock,b::ArrayBlock) + @check size(a) == size(b) + for k in eachindex(a.array) + @check a.touched[k] == b.touched[k] + if a.touched[k] + _addto_compress!(a.array[k],b.array[k]) + end + end + a +end + +function _addto_compress!(a::Tuple,b::Tuple) + a1,a2 = a + b1,b2 = b + _addto_compress!(a1,b1) + _addto_compress!(a2,b2) +end diff --git a/src/Geometry/DiscreteModelPortions.jl b/src/Geometry/DiscreteModelPortions.jl index 1220a49d3..4b226858e 100644 --- a/src/Geometry/DiscreteModelPortions.jl +++ b/src/Geometry/DiscreteModelPortions.jl @@ -41,6 +41,16 @@ function DiscreteModelPortion(model::DiscreteModel, cell_to_is_in::AbstractVecto DiscreteModelPortion(model,cell_to_parent_cell) end +function DiscreteModelPortion(model::DiscreteModel,grid_p::GridPortion) + topo = get_grid_topology(model) + labels = get_face_labeling(model) + cell_to_parent_cell = grid_p.cell_to_parent_cell + topo_p, d_to_dface_to_parent_dface = _grid_topology_portion(topo,cell_to_parent_cell) + labels_p = _setup_labels_p(labels,d_to_dface_to_parent_dface) + model_p = DiscreteModel(grid_p,topo_p,labels_p) + DiscreteModelPortion(model_p,model,d_to_dface_to_parent_dface) +end + function _grid_topology_portion(topo,cell_to_parent_cell) D = num_cell_dims(topo) diff --git a/src/Geometry/DiscreteModels.jl b/src/Geometry/DiscreteModels.jl index 8614e9e31..af1933971 100644 --- a/src/Geometry/DiscreteModels.jl +++ b/src/Geometry/DiscreteModels.jl @@ -71,12 +71,6 @@ get_cell_type(g::DiscreteModel) = get_cell_type(get_grid(g)) get_reffes(g::DiscreteModel) = get_reffes(get_grid(g)) -get_background_triangulation(g::DiscreteModel) = get_background_triangulation(get_grid(g)) - -get_cell_to_bgcell(g::DiscreteModel) = get_cell_to_bgcell(get_grid(g)) - -get_cell_ref_map(g::DiscreteModel) = get_cell_ref_map(get_grid(g)) - # Default API """ @@ -378,29 +372,6 @@ function Grid(::Type{ReferenceFE{d}},model::DiscreteModel{d}) where d get_grid(model) end -""" - Triangulation(::Type{ReferenceFE{d}},model::DiscreteModel) where d - Triangulation(model::DiscreteModel) -""" -function Triangulation(::Type{ReferenceFE{d}},model::DiscreteModel) where d - Grid(ReferenceFE{d},model) -end - -function Triangulation(model::DiscreteModel;tags=nothing) - if tags == nothing - get_triangulation(model) - else - Triangulation(model,get_face_labeling(model),tags=tags) - end -end - -""" - get_triangulation(model::DiscreteModel) -""" -function get_triangulation(model::DiscreteModel) - get_grid(model) -end - """ simplexify(model::DiscreteModel) """ @@ -487,3 +458,4 @@ end function GridTopology(::Type{<:Polytope{D}},model::DiscreteModel) where D GridTopology(Polytope{D},get_grid_topology(model)) end + diff --git a/src/Geometry/Geometry.jl b/src/Geometry/Geometry.jl index b776ad6ae..c99b0e049 100644 --- a/src/Geometry/Geometry.jl +++ b/src/Geometry/Geometry.jl @@ -102,9 +102,6 @@ export compress_ids export UnstructuredGridTopology export Triangulation -export TriangulationStyle -export BackgroundTriangulation -export SubTriangulation export get_reffes export get_cell_coordinates export get_cell_ref_coordinates @@ -112,11 +109,12 @@ export get_cell_reffe export get_cell_shapefuns export get_facet_normal export test_triangulation -export get_cell_to_bgcell export get_cell_map -export get_background_triangulation -export get_cell_ref_map -export have_compatible_domains + +export get_background_model +export get_active_model +export get_grid +export get_glue export Grid export get_cell_node_ids @@ -164,9 +162,15 @@ export UnstructuredDiscreteModel export CartesianDiscreteModel export BoundaryDiscreteModel +export GenericTriangulation export BoundaryTriangulation export DiscreteModelPortion +export Interior +export Boundary +export Skeleton +export Interface + export SkeletonPair export SkeletonTriangulation export InterfaceTriangulation @@ -180,7 +184,13 @@ export AppendedTriangulation export GridMock -include("Triangulations.jl") +export extend +export pos_neg_data +export is_change_possible +export best_target +export FaceToFaceGlue +export BodyFittedTriangulation +export move_contributions include("Grids.jl") @@ -206,22 +216,18 @@ include("UnstructuredDiscreteModels.jl") include("CartesianDiscreteModels.jl") -include("RestrictedTriangulations.jl") - -include("BoundaryTriangulations.jl") - -include("SkeletonTriangulations.jl") - include("GridPortions.jl") include("DiscreteModelPortions.jl") -include("RestrictedDiscreteModels.jl") +include("Triangulations.jl") + +include("BoundaryTriangulations.jl") + +include("SkeletonTriangulations.jl") include("AppendedTriangulations.jl") include("CompressedCellArrays.jl") -include("BoundaryDiscreteModels.jl") - end # module diff --git a/src/Geometry/GridPortions.jl b/src/Geometry/GridPortions.jl index 967aa5c64..95f5ef1fc 100644 --- a/src/Geometry/GridPortions.jl +++ b/src/Geometry/GridPortions.jl @@ -1,27 +1,27 @@ """ struct GridPortion{Dc,Dp,G} <: Grid{Dc,Dp} - parent_grid::G + parent::G cell_to_parent_cell::Vector{Int32} node_to_parent_node::Vector{Int32} end """ struct GridPortion{Dc,Dp,G} <: Grid{Dc,Dp} - parent_grid::G + parent::G cell_to_parent_cell::Vector{Int32} node_to_parent_node::Vector{Int32} cell_to_nodes::Table{Int32,Vector{Int32},Vector{Int32}} @doc """ - GridPortion(parent_grid::Grid{Dc,Dp},cell_to_parent_cell::Vector{Int32}) where {Dc,Dp} + GridPortion(parent::Grid{Dc,Dp},cell_to_parent_cell::Vector{Int32}) where {Dc,Dp} """ - function GridPortion(parent_grid::Grid,cell_to_parent_cell::AbstractVector{<:Integer}) + function GridPortion(parent::Grid,cell_to_parent_cell::AbstractVector{<:Integer}) - Dc = num_cell_dims(parent_grid) - Dp = num_point_dims(parent_grid) + Dc = num_cell_dims(parent) + Dp = num_point_dims(parent) - parent_cell_to_parent_nodes = get_cell_node_ids(parent_grid) - nparent_nodes = num_nodes(parent_grid) - parent_node_to_coords = get_node_coordinates(parent_grid) + parent_cell_to_parent_nodes = get_cell_node_ids(parent) + nparent_nodes = num_nodes(parent) + parent_node_to_coords = get_node_coordinates(parent) node_to_parent_node, parent_node_to_node = _find_active_nodes( parent_cell_to_parent_nodes,cell_to_parent_cell,nparent_nodes) @@ -29,18 +29,18 @@ struct GridPortion{Dc,Dp,G} <: Grid{Dc,Dp} cell_to_nodes = _renumber_cell_nodes( parent_cell_to_parent_nodes,parent_node_to_node,cell_to_parent_cell) - new{Dc,Dp,typeof(parent_grid)}(parent_grid,cell_to_parent_cell,node_to_parent_node,cell_to_nodes) + new{Dc,Dp,typeof(parent)}(parent,cell_to_parent_cell,node_to_parent_node,cell_to_nodes) end end -function GridPortion(parent_grid::Grid,parent_cell_to_mask::AbstractArray{Bool}) +function GridPortion(parent::Grid,parent_cell_to_mask::AbstractArray{Bool}) cell_to_parent_cell = findall(collect1d(parent_cell_to_mask)) - GridPortion(parent_grid,cell_to_parent_cell) + GridPortion(parent,cell_to_parent_cell) end -function GridPortion(parent_grid::Grid,parent_cell_to_mask::AbstractVector{Bool}) +function GridPortion(parent::Grid,parent_cell_to_mask::AbstractVector{Bool}) cell_to_parent_cell = findall(parent_cell_to_mask) - GridPortion(parent_grid,cell_to_parent_cell) + GridPortion(parent,cell_to_parent_cell) end function OrientationStyle(::Type{GridPortion{Dc,Dp,G}}) where {Dc,Dp,G} @@ -52,7 +52,7 @@ function RegularityStyle(::Type{GridPortion{Dc,Dp,G}}) where {Dc,Dp,G} end function get_node_coordinates(grid::GridPortion) - parent_node_to_coords = get_node_coordinates(grid.parent_grid) + parent_node_to_coords = get_node_coordinates(grid.parent) lazy_map(Reindex(parent_node_to_coords),grid.node_to_parent_node) end @@ -61,11 +61,33 @@ function get_cell_node_ids(grid::GridPortion) end function get_reffes(grid::GridPortion) - get_reffes(grid.parent_grid) + get_reffes(grid.parent) end function get_cell_type(grid::GridPortion) - lazy_map(Reindex(get_cell_type(grid.parent_grid)),grid.cell_to_parent_cell) + lazy_map(Reindex(get_cell_type(grid.parent)),grid.cell_to_parent_cell) +end + +function get_facet_normal(grid::GridPortion) + lazy_map(Reindex(get_facet_normal(grid.parent)),grid.cell_to_parent_cell) +end + +# The following are not strictly needed, sine there is a default implementation for them. +# In any case, we delegate just in case the underlying grid defines more performant versions +function get_cell_coordinates(grid::GridPortion) + lazy_map(Reindex(get_cell_coordinates(grid.parent)),grid.cell_to_parent_cell) +end +function get_cell_ref_coordinates(grid::GridPortion) + lazy_map(Reindex(get_cell_ref_coordinates(grid.parent)),grid.cell_to_parent_cell) +end +function get_cell_shapefuns(grid::GridPortion) + lazy_map(Reindex(get_cell_shapefuns(grid.parent)),grid.cell_to_parent_cell) +end +function get_cell_map(grid::GridPortion) + lazy_map(Reindex(get_cell_map(grid.parent)),grid.cell_to_parent_cell) +end +function get_cell_reffe(grid::GridPortion) + lazy_map(Reindex(get_cell_reffe(grid.parent)),grid.cell_to_parent_cell) end # Helpers @@ -107,3 +129,58 @@ function _renumber_cell_nodes(oldcell_to_oldnodes,oldnode_to_node,cell_to_oldcel end Table(cell_to_nodes_data,cell_to_nodes_ptrs) end + +# In contrast to GridPortion, this one only renumbers cells (not nodes) +# and its creation does not allocate memory proportional to number of cells +struct GridView{Dc,Dp,A,B} <: Grid{Dc,Dp} + parent::A + cell_to_parent_cell::B + function GridView(parent::Grid,cell_to_parent_cell::AbstractArray) + Dc = num_cell_dims(parent) + Dp = num_point_dims(parent) + A = typeof(parent) + B = typeof(cell_to_parent_cell) + new{Dc,Dp,A,B}(parent,cell_to_parent_cell) + end +end + +Base.view(a::Grid,b::AbstractArray) = GridView(a,b) + +function GridView(parent::Grid,parent_cell_to_mask::AbstractArray{Bool}) + cell_to_parent_cell = findall(collect1d(parent_cell_to_mask)) + GridView(parent,cell_to_parent_cell) +end + +function GridView(parent::Grid,parent_cell_to_mask::AbstractVector{Bool}) + cell_to_parent_cell = findall(parent_cell_to_mask) + GridView(parent,cell_to_parent_cell) +end + +function OrientationStyle(::Type{GridView{Dc,Dp,G}}) where {Dc,Dp,G} + OrientationStyle(G) +end + +function RegularityStyle(::Type{GridView{Dc,Dp,G}}) where {Dc,Dp,G} + RegularityStyle(G) +end + +function get_node_coordinates(grid::GridView) + get_node_coordinates(grid.parent) +end + +function get_cell_node_ids(grid::GridView) + lazy_map(Reindex(get_cell_node_ids(grid.parent)),grid.cell_to_parent_cell) +end + +function get_reffes(grid::GridView) + get_reffes(grid.parent) +end + +function get_cell_type(grid::GridView) + lazy_map(Reindex(get_cell_type(grid.parent)),grid.cell_to_parent_cell) +end + +function get_facet_normal(grid::GridView) + lazy_map(Reindex(get_facet_normal(grid.parent)),grid.cell_to_parent_cell) +end + diff --git a/src/Geometry/GridTopologies.jl b/src/Geometry/GridTopologies.jl index bc7a241cd..87f6305db 100644 --- a/src/Geometry/GridTopologies.jl +++ b/src/Geometry/GridTopologies.jl @@ -373,7 +373,6 @@ function compute_reffaces(g::GridTopology) (collect(vcat(d_to_refdfaces...)), vcat(d_to_dface_to_ftype...), d_to_offset) end - """ get_isboundary_face(g::GridTopology) """ diff --git a/src/Geometry/Grids.jl b/src/Geometry/Grids.jl index dcc598dbc..d62a5fd47 100644 --- a/src/Geometry/Grids.jl +++ b/src/Geometry/Grids.jl @@ -1,19 +1,16 @@ """ - abstract type Grid{Dc,Dp} <: Triangulation{Dc,Dp} + abstract type Grid{Dc,Dp} -Abstract type that represents conforming triangulations, whose cell-wise -nodal coordinates are defined with a vector of nodal coordinates, plus -a cell-wise vector of node ids. +Abstract type that represents mesh of a domain of parametric dimension `Dc` and +physical dimension `Dp`. -The interface of `Grid` is defined by overloading the -methods in `Triangulation` plus the following ones: +The interface of `Grid` is defined by overloading: - [`get_node_coordinates(trian::Grid)`](@ref) - [`get_cell_node_ids(trian::Grid)`](@ref) - -From these two methods a default implementation of [`get_cell_coordinates(trian::Triangulation)`](@ref) -is available. +- [`get_reffes(trian::Grid)`](@ref) +- [`get_cell_type(trian::Grid)`](@ref) The `Grid` interface has the following traits @@ -25,7 +22,7 @@ The interface of `Grid` is tested with - [`test_grid`](@ref) """ -abstract type Grid{Dc,Dp} <: Triangulation{Dc,Dp} end +abstract type Grid{Dc,Dp} <: GridapType end # Traits @@ -71,11 +68,50 @@ function get_cell_node_ids(trian::Grid) @abstractmethod end +""" + get_reffes(trian::Grid) -> Vector{LagrangianRefFE} +""" +function get_reffes(trian::Grid) + @abstractmethod +end + +""" + get_cell_type(trian::Grid) -> AbstractVector{<:Integer} +""" +function get_cell_type(trian::Grid) + @abstractmethod +end + +""" + get_facet_normal(trian::Grid) +""" +function get_facet_normal(trian::Grid) + Dp = num_point_dims(trian) + Dc = num_cell_dims(trian) + if Dp == Dc + 1 + @abstractmethod + else + @unreachable "get_facet_normal does not make sense for this grid" + end +end + """ test_grid(trian::Grid) """ -function test_grid(trian::Grid) - test_triangulation(trian) +function test_grid(trian::Grid{Dc,Dp}) where {Dc,Dp} + @test num_cell_dims(trian) == Dc + @test num_point_dims(trian) == Dp + @test num_cell_dims(typeof(trian)) == Dc + @test num_point_dims(typeof(trian)) == Dp + cell_coords = get_cell_coordinates(trian) + @test isa(cell_coords,AbstractArray{<:AbstractVector{<:Point}}) + reffes = get_reffes(trian) + @test isa(reffes,AbstractVector{<:LagrangianRefFE{Dc}}) + cell_types = get_cell_type(trian) + @test isa(cell_types,AbstractArray{<:Integer}) + ncells = num_cells(trian) + @test ncells == length(cell_coords) + @test ncells == length(cell_types) nodes_coords = get_node_coordinates(trian) @test isa(nodes_coords,AbstractArray{<:Point}) cell_node_ids = get_cell_node_ids(trian) @@ -89,7 +125,89 @@ function test_grid(trian::Grid) @test is_regular(trian) == (RegularityStyle(trian) == Regular()) end -# Methods from triangulation +# Some API + +""" + num_cells(trian::Grid) -> Int +""" +num_cells(trian::Grid) = length(get_cell_type(trian)) + +""" + num_nodes(trian::Grid) -> Int +""" +num_nodes(trian::Grid) = length(get_node_coordinates(trian)) + +""" + num_cell_dims(::Grid) -> Int + num_cell_dims(::Type{<:Grid}) -> Int +""" +num_cell_dims(::Grid{Dc,Dp}) where {Dc,Dp} = Dc +num_cell_dims(::Type{<:Grid{Dc,Dp}}) where {Dc,Dp} = Dc + +""" + num_point_dims(::Grid) -> Int + num_point_dims(::Type{<:Grid}) -> Int +""" +num_point_dims(::Grid{Dc,Dp}) where {Dc,Dp} = Dp +num_point_dims(::Type{<:Grid{Dc,Dp}}) where {Dc,Dp} = Dp + +""" + num_dims(::Grid) -> Int + num_dims(::Type{<:Grid}) -> Int + +Equivalent to `num_cell_dims`. +""" +num_dims(g::Grid{Dc}) where Dc = Dc +num_dims(::Type{<:Grid{Dc}}) where Dc = Dc + +""" + is_first_order(trian::Grid) -> Bool +""" +function is_first_order(trian::Grid) + reffes = get_reffes(trian) + all(map(is_first_order,reffes)) +end + +""" + get_cell_reffe(trian::Grid) -> Vector{<:LagrangianRefFE} + +It is not desirable to iterate over the resulting array +for large number of cells if the underlying reference FEs +are of different Julia type. +""" +function get_cell_reffe(trian::Grid) + type_to_reffe = get_reffes(trian) + cell_to_type = get_cell_type(trian) + expand_cell_data(type_to_reffe,cell_to_type) +end + +""" +""" +function get_cell_ref_coordinates(trian::Grid) + type_to_reffe = get_reffes(trian) + type_to_coords = map(get_node_coordinates,type_to_reffe) + cell_to_type = get_cell_type(trian) + expand_cell_data(type_to_coords,cell_to_type) +end + +""" + get_cell_shapefuns(trian::Grid) -> Vector{<:Field} +""" +function get_cell_shapefuns(trian::Grid) + type_to_reffes = get_reffes(trian) + cell_to_type = get_cell_type(trian) + type_to_shapefuns = map(get_shapefuns, type_to_reffes) + expand_cell_data(type_to_shapefuns,cell_to_type) +end + +""" + get_cell_map(trian::Grid) -> Vector{<:Field} +""" +function get_cell_map(trian::Grid) + cell_to_coords = get_cell_coordinates(trian) + cell_to_shapefuns = get_cell_shapefuns(trian) + lazy_map(linear_combination,cell_to_coords,cell_to_shapefuns) +end function get_cell_coordinates(trian::Grid) node_to_coords = get_node_coordinates(trian) @@ -97,7 +215,12 @@ function get_cell_coordinates(trian::Grid) lazy_map(Broadcasting(Reindex(node_to_coords)),cell_to_nodes) end -# Some API +function Quadrature(trian::Grid,args...;kwargs...) + cell_ctype = get_cell_type(trian) + ctype_polytope = map(get_polytope,get_reffes(trian)) + ctype_quad = map(p->Quadrature(p,args...;kwargs...),ctype_polytope) + cell_quad = expand_cell_data(ctype_quad,cell_ctype) +end """ is_oriented(::Type{<:Grid}) -> Bool diff --git a/src/Geometry/RestrictedDiscreteModels.jl b/src/Geometry/RestrictedDiscreteModels.jl deleted file mode 100644 index 174859bea..000000000 --- a/src/Geometry/RestrictedDiscreteModels.jl +++ /dev/null @@ -1,100 +0,0 @@ -""" -""" -function DiscreteModel(parent_model::DiscreteModel,cell_to_parent_cell::AbstractVector{<:Integer}) - RestrictedDiscreteModel(parent_model,cell_to_parent_cell) -end - -function DiscreteModel(parent_model::DiscreteModel,parent_cell_to_mask::AbstractArray{Bool}) - RestrictedDiscreteModel(parent_model,parent_cell_to_mask) -end - -function DiscreteModel(parent_model::DiscreteModel,labels::FaceLabeling;tags) - parent_cell_to_mask = get_face_mask(labels,tags,num_cell_dims(parent_model)) - DiscreteModel(parent_model,parent_cell_to_mask) -end - -function DiscreteModel(parent_model::DiscreteModel;tags) - labels = get_face_labeling(parent_model) - DiscreteModel(parent_model,labels,tags=tags) -end - -""" -""" -struct RestrictedDiscreteModel{Dc,Dp} <: DiscreteModel{Dc,Dc} - model::DiscreteModelPortion{Dc,Dp} -end - -function RestrictedDiscreteModel(parent_model::DiscreteModel, cell_to_parent_cell::AbstractVector{<:Integer}) - _model = DiscreteModelPortion(parent_model,cell_to_parent_cell) - RestrictedDiscreteModel(_model) -end - -function RestrictedDiscreteModel(parent_model::DiscreteModel, parent_cell_to_mask::AbstractArray{Bool}) - _model = DiscreteModelPortion(parent_model,parent_cell_to_mask) - RestrictedDiscreteModel(_model) -end - -get_grid(model::RestrictedDiscreteModel) = get_grid(model.model) - -get_grid_topology(model::RestrictedDiscreteModel) = get_grid_topology(model.model) - -get_face_labeling(model::RestrictedDiscreteModel) = get_face_labeling(model.model) - -get_face_to_parent_face(model::RestrictedDiscreteModel,d::Integer) = get_face_to_parent_face(model.model,d) - -get_cell_to_parent_cell(model::RestrictedDiscreteModel) = get_cell_to_parent_cell(model.model) - -get_parent_model(model::RestrictedDiscreteModel) = get_parent_model(model.model) - -function Triangulation(model::RestrictedDiscreteModel) - parent_trian = Triangulation(get_parent_model(model)) - cell_to_parent_cell = get_cell_to_parent_cell(model) - RestrictedTriangulation(parent_trian,cell_to_parent_cell) -end - -function get_triangulation(model::RestrictedDiscreteModel) - Triangulation(model) -end - -function Triangulation(::Type{ReferenceFE{d}},model::RestrictedDiscreteModel) where d - @notimplemented -end - -function Triangulation(model::RestrictedDiscreteModel,cell_to_parent_cell::AbstractVector{<:Integer}) - @notimplemented -end - -function Triangulation(model::RestrictedDiscreteModel,cell_to_mask::AbstractArray{Bool}) - @notimplemented -end - -function BoundaryTriangulation( - model::RestrictedDiscreteModel, - face_to_bgface::AbstractVector{<:Integer}, - bgface_to_lcell::AbstractVector{<:Integer}) - - parent_model = get_parent_model(model) - bgface_to_parent_face = get_face_to_parent_face(model,num_cell_dims(model)-1) - face_to_parent_face = lazy_map(Reindex(bgface_to_parent_face),face_to_bgface) - parent_face_to_lcell = fill(Int8(1),num_facets(parent_model)) - parent_face_to_lcell[bgface_to_parent_face] .= bgface_to_lcell - - BoundaryTriangulation(parent_model,face_to_parent_face,parent_face_to_lcell) -end - -function BoundaryTriangulation( - model::RestrictedDiscreteModel, - bgface_to_mask::AbstractVector{Bool}, - bgface_to_lcell::AbstractVector{<:Integer}) - - face_to_bgface = findall(bgface_to_mask) - BoundaryTriangulation(model,face_to_bgface,bgface_to_lcell) -end - -function InterfaceTriangulation(model_in::RestrictedDiscreteModel,model_out::RestrictedDiscreteModel) - cells_in = get_cell_to_parent_cell(model_in) - cells_out = get_cell_to_parent_cell(model_out) - model = get_parent_model(model_in) - InterfaceTriangulation(model,cells_in,cells_out) -end - diff --git a/src/Geometry/RestrictedTriangulations.jl b/src/Geometry/RestrictedTriangulations.jl deleted file mode 100644 index 2de58d1b4..000000000 --- a/src/Geometry/RestrictedTriangulations.jl +++ /dev/null @@ -1,119 +0,0 @@ - -""" -""" -struct RestrictedTriangulation{Dc,Dp,G,A} <: Triangulation{Dc,Dp} - parent_trian::G - cell_to_parent_cell::A - @doc """ - """ - function RestrictedTriangulation( - parent_trian::Triangulation, - cell_to_parent_cell::AbstractVector{<:Integer}) - - Dc = num_cell_dims(parent_trian) - Dp = num_point_dims(parent_trian) - G = typeof(parent_trian) - A = typeof(cell_to_parent_cell) - new{Dc,Dp,G,A}(parent_trian,cell_to_parent_cell) - end -end - -# Constructors - -function RestrictedTriangulation( - parent_trian::Triangulation, - parent_cell_to_mask::AbstractArray{Bool}) - - cell_to_parent_cell = findall(collect1d(parent_cell_to_mask)) - RestrictedTriangulation(parent_trian,cell_to_parent_cell) -end - -function RestrictedTriangulation( - parent_trian::Triangulation, - parent_cell_to_mask::AbstractVector{Bool}) - - cell_to_parent_cell = findall(parent_cell_to_mask) - RestrictedTriangulation(parent_trian,cell_to_parent_cell) -end - -function Triangulation( - parent_trian::Triangulation, - cell_to_parent_cell::AbstractVector{<:Integer}) - - RestrictedTriangulation(parent_trian,cell_to_parent_cell) -end - -function Triangulation( - parent_trian::Triangulation, - parent_cell_to_mask::AbstractArray{Bool}) - - RestrictedTriangulation(parent_trian,parent_cell_to_mask) -end - -function Triangulation( - parent_model::DiscreteModel, - cell_to_parent_cell::AbstractVector{<:Integer}) - - parent_trian = Triangulation(parent_model) - RestrictedTriangulation(parent_trian,cell_to_parent_cell) -end - -function Triangulation( - parent_model::DiscreteModel, - parent_cell_to_mask::AbstractArray{Bool}) - - parent_trian = Triangulation(parent_model) - RestrictedTriangulation(parent_trian,parent_cell_to_mask) -end - -function Triangulation(parent_model::DiscreteModel, labels::FaceLabeling; tags) - parent_trian = Triangulation(parent_model) - parent_cell_to_mask = get_face_mask(labels,tags,num_cell_dims(parent_model)) - RestrictedTriangulation(parent_trian,parent_cell_to_mask) -end - -# Triangulation API - - -TriangulationStyle(::Type{<:RestrictedTriangulation}) = SubTriangulation() - -get_background_triangulation(trian::RestrictedTriangulation) = get_background_triangulation(trian.parent_trian) - -get_node_coordinates(trian::RestrictedTriangulation) = get_node_coordinates(trian.parent_trian) - -get_reffes(trian::RestrictedTriangulation) = get_reffes(trian.parent_trian) - -function get_cell_coordinates(trian::RestrictedTriangulation) - parent_cell_data = get_cell_coordinates(trian.parent_trian) - lazy_map(Reindex(parent_cell_data),trian.cell_to_parent_cell) -end - -function get_cell_type(trian::RestrictedTriangulation) - parent_cell_data = get_cell_type(trian.parent_trian) - lazy_map(Reindex(parent_cell_data),trian.cell_to_parent_cell) -end - -function get_cell_node_ids(trian::RestrictedTriangulation) - parent_cell_data = get_cell_node_ids(trian.parent_trian) - lazy_map(Reindex(parent_cell_data),trian.cell_to_parent_cell) -end - -function get_cell_map(trian::RestrictedTriangulation) - parent_cell_data = get_cell_map(trian.parent_trian) - lazy_map(Reindex(parent_cell_data),trian.cell_to_parent_cell) -end - -function get_cell_to_bgcell(trian::RestrictedTriangulation) - parent_cell_data = get_cell_to_bgcell(trian.parent_trian) - lazy_map(Reindex(parent_cell_data),trian.cell_to_parent_cell) -end - -function get_facet_normal(trian::RestrictedTriangulation) - parent_cell_data = get_facet_normal(trian.parent_trian) - lazy_map(Reindex(parent_cell_data),trian.cell_to_parent_cell) -end - -function get_cell_ref_map(trian::RestrictedTriangulation) - parent_cell_data = get_cell_ref_map(trian.parent_trian) - lazy_map(Reindex(parent_cell_data),trian.cell_to_parent_cell) -end diff --git a/src/Geometry/SkeletonTriangulations.jl b/src/Geometry/SkeletonTriangulations.jl index 36250650e..a17221013 100644 --- a/src/Geometry/SkeletonTriangulations.jl +++ b/src/Geometry/SkeletonTriangulations.jl @@ -1,3 +1,27 @@ +""" + struct SkeletonPair{L,R} <: GridapType + plus::L + minus::R + end +""" +struct SkeletonPair{L,R} <: GridapType + plus::L + minus::R +end + +function Base.getproperty(x::SkeletonPair, sym::Symbol) + if sym == :⁺ + x.plus + elseif sym == :⁻ + x.minus + else + getfield(x, sym) + end +end + +function Base.propertynames(x::SkeletonPair, private::Bool=false) + (fieldnames(typeof(x))...,:⁺,:⁻) +end """ struct SkeletonTriangulation{Dc,Dp,B} <: Triangulation{Dc,Dp} @@ -16,6 +40,10 @@ struct SkeletonTriangulation{Dc,Dp,B} <: Triangulation{Dc,Dp} end end +function Skeleton(args...;kwargs...) + SkeletonTriangulation(args...;kwargs...) +end + function Base.getproperty(x::SkeletonTriangulation, sym::Symbol) if sym == :⁺ x.plus @@ -30,9 +58,54 @@ function Base.propertynames(x::SkeletonTriangulation, private::Bool=false) (fieldnames(typeof(x))...,:⁺,:⁻) end -#have_compatible_domains(a::SkeletonTriangulation,b::Triangulation) = a.plus===b || a.minus===b -#have_compatible_domains(a::Triangulation,b::SkeletonTriangulation) = have_compatible_domains(b,a) -#have_compatible_domains(a::SkeletonTriangulation,b::SkeletonTriangulation) = a===b +# Triangulation interface + +get_background_model(t::SkeletonTriangulation) = get_background_model(t.plus) +get_grid(t::SkeletonTriangulation) = get_grid(t.plus) +get_glue(t::SkeletonTriangulation{D},::Val{D}) where D = get_glue(t.plus,Val(D)) + +function get_glue(trian::SkeletonTriangulation,::Val{Dp}) where Dp + model = get_background_model(trian) + Dm = num_cell_dims(model) + get_glue(trian,Val(Dp),Val(Dm)) +end + +function get_glue(trian::SkeletonTriangulation,::Val{Dp},::Val{Dm}) where {Dp,Dm} + nothing +end + +function get_glue(trian::SkeletonTriangulation,::Val{D},::Val{D}) where D + plus = get_glue(trian.plus,Val(D)) + minus = get_glue(trian.minus,Val(D)) + SkeletonPair(plus,minus) +end + +function is_change_possible(sglue::FaceToFaceGlue,tglue::SkeletonPair) + is_change_possible(sglue,tglue.plus) && is_change_possible(sglue,tglue.minus) +end + +function get_facet_normal(trian::SkeletonTriangulation) + plus = get_facet_normal(trian.plus) + minus = get_facet_normal(trian.minus) + SkeletonPair(plus,minus) +end + +# Related with CompositeTriangulation +function _compose_glues(rglue::FaceToFaceGlue,dglue::SkeletonPair) + plus = _compose_glues(rglue,dglue.plus) + minus = _compose_glues(rglue,dglue.minus) + SkeletonPair(plus,minus) +end + +function Base.view(glue::SkeletonPair{<:FaceToFaceGlue},ids::AbstractArray) + SkeletonPair(view(glue.plus,ids),view(glue.minus,ids)) +end + +function restrict(a::SkeletonPair,b::AbstractArray) + SkeletonPair(restrict(a.plus,b),restrict(a.minus,b)) +end + +# Constructors """ SkeletonTriangulation(model::DiscreteModel,face_to_mask::Vector{Bool}) @@ -53,6 +126,12 @@ function SkeletonTriangulation(model::DiscreteModel) SkeletonTriangulation(model,face_to_mask) end +function SkeletonTriangulation(rtrian::Triangulation,args...;kwargs...) + rmodel = get_active_model(rtrian) + dtrian = SkeletonTriangulation(rmodel,args...;kwargs...) + CompositeTriangulation(rtrian,dtrian) +end + function SkeletonTriangulation( model::DiscreteModel, reffe::ReferenceFE, @@ -146,6 +225,10 @@ function InterfaceTriangulation(model::DiscreteModel,cell_to_is_in::Vector{Bool} InterfaceTriangulation(model,cell_to_inout) end +function Interface(args...;kwargs...) + InterfaceTriangulation(args...;kwargs...) +end + function InterfaceTriangulation(model::DiscreteModel,cells_in,cells_out) cell_to_inout = fill(Int8(OUT),num_cells(model)) cell_to_inout[cells_in] .= IN @@ -153,6 +236,19 @@ function InterfaceTriangulation(model::DiscreteModel,cells_in,cells_out) InterfaceTriangulation(model,cell_to_inout) end +function InterfaceTriangulation(trian_in::Triangulation,trian_out::Triangulation) + D = num_cell_dims(trian_in) + @assert D == num_cell_dims(trian_out) + glue_in = get_glue(trian_in,Val(D)) + glue_out = get_glue(trian_out,Val(D)) + cells_in = glue_in.tface_to_mface + cells_out = glue_out.tface_to_mface + model = get_background_model(trian_in) + @check model === get_background_model(trian_out) + @notimplementedif D != num_cell_dims(model) "Not implemented, but it should be easy to implement." + InterfaceTriangulation(model,cells_in,cells_out) +end + function InterfaceTriangulation(model::DiscreteModel,cell_to_inout::AbstractVector{<:Integer}) D = num_cell_dims(model) @@ -164,13 +260,14 @@ function InterfaceTriangulation(model::DiscreteModel,cell_to_inout::AbstractVect ifacet_to_facet, facet_to_lcell_left, facet_to_lcell_right = _find_interface_facets( cell_to_inout, facet_to_cells) - ifacet_trian = RestrictedTriangulation(facet_grid,ifacet_to_facet) + ifacet_grid = view(facet_grid,ifacet_to_facet) - glue_left = FaceToCellGlue(topo,cell_grid,ifacet_trian,ifacet_to_facet,facet_to_lcell_left) - glue_right = FaceToCellGlue(topo,cell_grid,ifacet_trian,ifacet_to_facet,facet_to_lcell_right) + glue_left = FaceToCellGlue(topo,cell_grid,ifacet_grid,ifacet_to_facet,facet_to_lcell_left) + glue_right = FaceToCellGlue(topo,cell_grid,ifacet_grid,ifacet_to_facet,facet_to_lcell_right) - plus = BoundaryTriangulation(ifacet_trian,cell_grid,glue_left) - minus = BoundaryTriangulation(ifacet_trian,cell_grid,glue_right) + trian = BodyFittedTriangulation(model,ifacet_grid,ifacet_to_facet) + plus = BoundaryTriangulation(trian,glue_left) + minus = BoundaryTriangulation(trian,glue_right) SkeletonTriangulation(plus,minus) end @@ -224,59 +321,3 @@ function _find_interface_facets( cell_to_inout, facet_to_cells::Table) ifacet_to_facet, facet_to_lcell_left, facet_to_lcell_right end -# Triangulation interface - -function get_cell_coordinates(trian::SkeletonTriangulation) - get_cell_coordinates(trian.plus) -end - -function get_node_coordinates(trian::SkeletonTriangulation) - get_node_coordinates(trian.plus) -end - -function get_cell_node_ids(trian::SkeletonTriangulation) - get_cell_node_ids(trian.plus) -end - -function get_reffes(trian::SkeletonTriangulation) - get_reffes(trian.plus) -end - -function get_cell_type(trian::SkeletonTriangulation) - get_cell_type(trian.plus) -end - -function get_cell_map(trian::SkeletonTriangulation) - get_cell_map(trian.plus) -end - -function get_facet_normal(trian::SkeletonTriangulation) - plus = get_facet_normal(trian.plus) - minus = get_facet_normal(trian.minus) - SkeletonPair(plus,minus) -end - -TriangulationStyle(::Type{<:SkeletonTriangulation}) = SubTriangulation() - -function get_background_triangulation(trian::SkeletonTriangulation) - get_background_triangulation(trian.plus) -end - -function get_cell_to_bgcell(trian::SkeletonTriangulation) - plus = get_cell_to_bgcell(trian.plus) - minus = get_cell_to_bgcell(trian.minus) - SkeletonPair(plus,minus) -end - -function get_cell_ref_map(trian::SkeletonTriangulation) - plus = get_cell_ref_map(trian.plus) - minus = get_cell_ref_map(trian.minus) - SkeletonPair(plus,minus) -end - -function RestrictedTriangulation( - oldtrian::SkeletonTriangulation,cell_to_oldcell::AbstractVector{<:Integer}) - plus = RestrictedTriangulation(oldtrian.plus,cell_to_oldcell) - minus = RestrictedTriangulation(oldtrian.minus,cell_to_oldcell) - SkeletonTriangulation(plus,minus) -end diff --git a/src/Geometry/Triangulations.jl b/src/Geometry/Triangulations.jl index 6dda9f36b..8db29320b 100644 --- a/src/Geometry/Triangulations.jl +++ b/src/Geometry/Triangulations.jl @@ -1,400 +1,480 @@ - """ - abstract type Triangulation{Dc,Dp} - -Abstract type representing an arbitrary tiling, tessellation, -or triangulation of a domain of parametric dimension `Dc` and -physical dimension `Dp`. - -We define a triangulation from two basic ingredients: - -- the cell-wise nodal coordinates of the cells in the triangulation, plus -- an interpolation of this cell-wise coordinates into the cells interior. - -Note that this type represents general triangulations (not necessarily conforming), -which is the minimum geometrical information needed to perform cell-wise numerical integration. - -The `Triangulation` interface is defined by overloading these methods: - -- [`get_cell_coordinates(trian::Triangulation)`](@ref) -- [`get_reffes(trian::Triangulation)`](@ref) -- [`get_cell_type(trian::Triangulation)`](@ref) - -Optional interface: - -For triangulations living in a space of co-dimension 1, the following method can be defined: - -- [`get_facet_normal(trian::Triangulation)`] + abstract type Triangulation{Dt,Dp} -In some cases, concrete implementations want to override the default implementation of the following methods: +A discredited physical domain associated with a `DiscreteModel{Dm,Dp}`. -- [`restrict(f::AbstractArray, trian::Triangulation)`] -- [`get_cell_to_bgcell(f::AbstractArray, trian::Triangulation)`] +`Dt` and `Dm` can be different. The (mandatory) `Triangulation` interface can be tested with - [`test_triangulation`](@ref) - - """ -abstract type Triangulation{Dc,Dp} <: GridapType end +abstract type Triangulation{Dc,Dp} <: Grid{Dc,Dp} end -""" - get_cell_coordinates(trian::Triangulation) -> AbstractArray{Vector{<:Point{Dp}}} -""" -function get_cell_coordinates(trian::Triangulation) +function get_background_model(t::Triangulation) @abstractmethod end -""" - get_reffes(trian::Triangulation) -> Vector{LagrangianRefFE} -""" -function get_reffes(trian::Triangulation) +function get_grid(t::Triangulation) @abstractmethod end -""" - get_cell_type(trian::Triangulation) -> AbstractVector{<:Integer} -""" -function get_cell_type(trian::Triangulation) - @abstractmethod +# See possible types of glue below +function get_glue(t::Triangulation,::Val{d}) where d + nothing end """ - get_facet_normal(trian::Triangulation) + test_triangulation(trian::Triangulation) """ -function get_facet_normal(trian::Triangulation) - Dp = num_point_dims(trian) - Dc = num_cell_dims(trian) - if Dp == Dc + 1 - @abstractmethod - else - @unreachable "get_facet_normal does not make sense for this triangulation" +function test_triangulation(trian::Triangulation{Dc,Dp}) where {Dc,Dp} + test_grid(trian) + model = get_background_model(trian) + @assert isa(model,DiscreteModel) + grid = get_grid(trian) + test_grid(grid) +end + +# Grid interface +get_node_coordinates(trian::Triangulation) = get_node_coordinates(get_grid(trian)) +get_cell_node_ids(trian::Triangulation) = get_cell_node_ids(get_grid(trian)) +get_reffes(trian::Triangulation) = get_reffes(get_grid(trian)) +get_cell_type(trian::Triangulation) = get_cell_type(get_grid(trian)) +get_facet_normal(trian::Triangulation) = get_facet_normal(get_grid(trian)) + +# The following are not strictly needed, sine there is a default implementation for them. +# In any case, we delegate just in case the underlying grid defines more performant versions +get_cell_coordinates(trian::Triangulation) = get_cell_coordinates(get_grid(trian)) +get_cell_ref_coordinates(trian::Triangulation) = get_cell_ref_coordinates(get_grid(trian)) +get_cell_shapefuns(trian::Triangulation) = get_cell_shapefuns(get_grid(trian)) +get_cell_map(trian::Triangulation) = get_cell_map(get_grid(trian)) +get_cell_reffe(trian::Triangulation) = get_cell_reffe(get_grid(trian)) +is_first_order(trian::Triangulation) = is_first_order(get_grid(trian)) + +# This is the most used glue, but others are possible, see e.g. SkeletonGlue. +struct FaceToFaceGlue{A,B,C} + tface_to_mface::A + tface_to_mface_map::B + mface_to_tface::C +end + +function is_change_possible(strian::Triangulation,ttrian::Triangulation) + if strian === ttrian + return true end + @check get_background_model(strian) === get_background_model(ttrian) "Triangulations do not point to the same background discrete model!" + D = num_cell_dims(strian) + sglue = get_glue(strian,Val(D)) + tglue = get_glue(ttrian,Val(D)) + is_change_possible(sglue,tglue) end -""" -If the reference (resp. physical) space is the same for both triangulaitons. -""" -have_compatible_domains(a::Triangulation,b::Triangulation) = a===b +function is_change_possible(strian,ttrian) + false +end -# Trait that signals if the triangulation is a sub-mesh of a background triangulation +function is_change_possible(sglue::FaceToFaceGlue,tglue::FaceToFaceGlue) + sglue.mface_to_tface != nothing +end -abstract type TriangulationStyle end -struct BackgroundTriangulation <: TriangulationStyle end -struct SubTriangulation <: TriangulationStyle end +function best_target(trian1::Triangulation,trian2::Triangulation) + @check is_change_possible(trian1,trian2) + @check is_change_possible(trian2,trian1) + D1 = num_cell_dims(trian1) + D2 = num_cell_dims(trian2) + glue1 = get_glue(trian1,Val(D2)) + glue2 = get_glue(trian2,Val(D1)) + best_target(trian1,trian2,glue1,glue2) +end -TriangulationStyle(::Type{<:Triangulation}) = BackgroundTriangulation() -TriangulationStyle(::T) where T<:Triangulation = TriangulationStyle(T) +function best_target( + trian1::Triangulation,trian2::Triangulation,glue1::FaceToFaceGlue,glue2::FaceToFaceGlue) + # Return the background + model = get_background_model(trian1) + D = num_cell_dims(trian1) + @assert num_cell_dims(trian2) == D + Triangulation(ReferenceFE{D},model) +end -# Default methods needed to be overloaded by Triangulations that are integration sub-meshes +function get_active_model(t::Triangulation) + compute_active_model(t) +end -""" -Returns the background triangulation. -""" -get_background_triangulation(trian::Triangulation) = - get_background_triangulation(trian,TriangulationStyle(trian)) -get_background_triangulation(trian::Triangulation,::BackgroundTriangulation) = trian -get_background_triangulation(trian::Triangulation,::SubTriangulation) = @abstractmethod - -#""" -# reindex(a::AbstractArray, trian::Triangulation) -#""" -#function reindex(a::AbstractArray,trian::Triangulation) -# reindex(a,get_cell_to_bgcell(trian)) -#end +function compute_active_model(t::Triangulation) + D = num_cell_dims(t) + glue = get_glue(t,Val(D)) + @assert glue.mface_to_tface !== nothing + bgmodel = get_background_model(t) + model = DiscreteModel(Polytope{D},bgmodel) + _restrict_model(model,get_grid(t),glue.tface_to_mface) +end -""" - get_cell_to_bgcell(trian::Triangulation) +function _restrict_model(model,grid::Grid,tface_to_mface) + _restrict_model(model,tface_to_mface) +end -Map from the indices in the sub-triangulation to the indices in the background triangulation -""" -get_cell_to_bgcell(trian::Triangulation) = get_cell_to_bgcell(trian,TriangulationStyle(trian)) -get_cell_to_bgcell(trian::Triangulation,::BackgroundTriangulation) = IdentityVector(num_cells(trian)) -get_cell_to_bgcell(trian::Triangulation,::SubTriangulation) = @abstractmethod -function get_cell_to_bgcell(trian::Triangulation,bgtrian::Triangulation) - if have_compatible_domains(get_background_triangulation(trian),bgtrian) - return get_cell_to_bgcell(trian) - else - @notimplemented +function _restrict_model(model,grid::GridPortion,tface_to_mface) + @check grid.cell_to_parent_cell == tface_to_mface + DiscreteModelPortion(model,grid) +end + +function _restrict_model(model,tface_to_mface) + DiscreteModelPortion(model,tface_to_mface) +end + +function _restrict_model(model,tface_to_mface::IdentityVector) + model +end + +# This is the most basic Triangulation +# It represents a physical domain built using the faces of a DiscreteModel +struct BodyFittedTriangulation{Dt,Dp,A,B,C} <: Triangulation{Dt,Dp} + model::A + grid::B + tface_to_mface::C + function BodyFittedTriangulation(model::DiscreteModel,grid::Grid,tface_to_mface) + Dp = num_point_dims(model) + @assert Dp == num_point_dims(grid) + Dt = num_cell_dims(grid) + A = typeof(model) + B = typeof(grid) + C = typeof(tface_to_mface) + new{Dt,Dp,A,B,C}(model,grid,tface_to_mface) end end -function is_included(trian::Triangulation,bgtrian::Triangulation) - if have_compatible_domains(get_background_triangulation(trian),bgtrian) - true +get_background_model(trian::BodyFittedTriangulation) = trian.model +get_grid(trian::BodyFittedTriangulation) = trian.grid + +function get_glue(trian::BodyFittedTriangulation{Dt},::Val{Dt}) where Dt + tface_to_mface = trian.tface_to_mface + tface_to_mface_map = Fill(GenericField(identity),num_cells(trian)) + if isa(tface_to_mface,IdentityVector) && num_faces(trian.model,Dt) == num_cells(trian) + mface_to_tface = tface_to_mface else - false + nmfaces = num_faces(trian.model,Dt) + mface_to_tface = PosNegPartition(tface_to_mface,Int32(nmfaces)) end + FaceToFaceGlue(tface_to_mface,tface_to_mface_map,mface_to_tface) end -#""" -# restrict(f::AbstractArray, trian::Triangulation) -#""" -#function restrict(f::AbstractArray,trian::Triangulation) -# f +#function get_glue(trian::BodyFittedTriangulation{Dt},::Val{Dm}) where {Dt,Dm} +# @notimplemented #end -""" -Return the cell-wise map that goes from the reference space of the sub-triangulation to -the reference space of the background triangulation -""" -get_cell_ref_map(trian::Triangulation) = get_cell_ref_map(trian,TriangulationStyle(trian)) -get_cell_ref_map(trian::Triangulation,::BackgroundTriangulation) = Fill(GenericField(identity),num_cells(trian)) -get_cell_ref_map(trian::Triangulation,::SubTriangulation) = @abstractmethod -function get_cell_ref_map(trian::Triangulation,bgtrian::Triangulation) - if have_compatible_domains(get_background_triangulation(trian),bgtrian) - return get_cell_ref_map(trian) +function Base.view(t::BodyFittedTriangulation,ids::AbstractArray) + model = t.model + grid = view(t.grid,ids) + tface_to_mface = lazy_map(Reindex(t.tface_to_mface),ids) + BodyFittedTriangulation(model,grid,tface_to_mface) +end + +get_triangulation(model) = Triangulation(model) + +function Triangulation( + ::Type{ReferenceFE{d}},model::DiscreteModel,filter::AbstractArray) where d + mgrid = Grid(ReferenceFE{d},model) + # Grid portion is OK here since this is usually used to + # define a FE space + tgrid = GridPortion(mgrid,filter) + tface_to_mface = tgrid.cell_to_parent_cell + BodyFittedTriangulation(model,tgrid,tface_to_mface) +end + +function Triangulation(model::DiscreteModel,filter::AbstractArray) + d = num_cell_dims(model) + Triangulation(ReferenceFE{d},model,filter) +end + +function Triangulation( + ::Type{ReferenceFE{d}}, + model::DiscreteModel, + labels::FaceLabeling;tags=nothing) where d + + if tags === nothing + grid = Grid(ReferenceFE{d},model) + tface_to_mface = IdentityVector(num_cells(grid)) + BodyFittedTriangulation(model,grid,tface_to_mface) else - @notimplemented + mface_to_mask = get_face_mask(labels,tags,d) + Triangulation(ReferenceFE{d},model,mface_to_mask) end end -#""" -#Given an array aligned with the cells in the background triangulation, return another array -#aligned with the cells of the sub-triangulation. Do nothing if `trian` is already a -#background triangulation. -#""" -#change_cell_index(a::AbstractArray,trian::Triangulation) = change_cell_index(a,trian,TriangulationStyle(trian)) -#function change_cell_index(a::AbstractArray,trian::Triangulation,::BackgroundTriangulation) -# @assert length(a) == num_cells(trian) -# a -#end -#function change_cell_index(a::AbstractArray,trian::Triangulation,::SubTriangulation) -# bgtrian = get_background_triangulation(trian) -# @assert length(a) == num_cells(bgtrian) -# lazy_map(Reindex(a),get_cell_to_bgcell(trian)) -#end -# -#""" -#Given an array (of arrays) of Field objects that is aligned with the sub-triangulation but -#the domain space of those fields corresponds to the reference space of the background triangulation, -#return another array (of arrays) of Field objects with domain in the sub-triangulation. -#Do nothing if `trian` is already a background triangulation. -#Note that one typically needs to call `change_cell_index` before calling `change_cell_domain`. -#""" -#change_cell_domain(a::AbstractArray,trian::Triangulation) = change_cell_domain(a,trian,TriangulationStyle(trian)) -#function change_cell_domain(a::AbstractArray,trian::Triangulation,::BackgroundTriangulation) -# @assert length(a) == num_cells(trian) -# a -#end -#function change_cell_domain(a::AbstractArray,trian::Triangulation,::SubTriangulation) -# @assert length(a) == num_cells(trian) -# cell_ref_map = get_cell_ref_map(trian) -# lazy_map(Broadcasting(∘),a,cell_map) + +function Triangulation( + ::Type{ReferenceFE{d}},model::DiscreteModel;kwargs...) where d + labels = get_face_labeling(model) + Triangulation(ReferenceFE{d},model,labels;kwargs...) +end + +function Triangulation(model::DiscreteModel;kwargs...) + d = num_cell_dims(model) + labels = get_face_labeling(model) + Triangulation(ReferenceFE{d},model,labels;kwargs...) +end + +function Triangulation(trian::Triangulation,args...;kwargs...) + amodel = get_active_model(trian) + dtrian = Triangulation(amodel,args...;kwargs...) + CompositeTriangulation(trian,dtrian) +end + +function Triangulation(trian::Triangulation,x::AbstractArray{<:Integer}) + view(trian,x) +end + +function Triangulation(trian::Triangulation,x::AbstractArray{<:Bool}) + y = findall(collect1d(x)) + view(trian,y) +end + +function Interior(args...;kwargs...) + Triangulation(args...;kwargs...) +end + +# This is the low-level functionality to move from one Triangulation to another + +function restrict(a::AbstractArray,b::AbstractArray) + lazy_map(Reindex(a),b) +end + +function extend(tface_to_val,mface_to_tface) + @notimplemented +end + +function extend(tface_to_val,mface_to_tface::IdentityVector) + tface_to_val +end + +function extend(tface_to_val,mface_to_tface::PosNegPartition) + ipos_to_val, ineg_to_val = pos_neg_data(tface_to_val,mface_to_tface) + i_to_iposneg = mface_to_tface + lazy_map(PosNegReindex(ipos_to_val,ineg_to_val),i_to_iposneg) +end + +function extend(a::LazyArray{<:Fill{typeof(transpose)}},b::PosNegPartition) + c = a.args[1] + d = extend(c,b) + lazy_map(transpose,d) +end + +function extend(a::LazyArray{<:Fill{typeof(linear_combination)}},b::PosNegPartition) + d1 = extend(a.args[1],b) + d2 = extend(a.args[2],b) + lazy_map(linear_combination,d1,d2) +end + +#function extend(a::LazyArray{<:Fill},b::PosNegPartition) +# k = a.maps.value +# args = map(i->extend(i,b),a.args) +# lazy_map(k,args...) #end -""" - struct SkeletonPair{L,R} <: GridapType - plus::L - minus::R - end -""" -struct SkeletonPair{L,R} <: GridapType - plus::L - minus::R +function pos_neg_data( + ipos_to_val::AbstractArray{<:Number},i_to_iposneg::PosNegPartition) + nineg = length(i_to_iposneg.ineg_to_i) + ineg_to_val = Fill(zero(eltype(ipos_to_val)),nineg) + ipos_to_val, ineg_to_val end -function Base.getproperty(x::SkeletonPair, sym::Symbol) - if sym == :⁺ - x.plus - elseif sym == :⁻ - x.minus - else - getfield(x, sym) - end +function pos_neg_data( + ipos_to_val::AbstractArray{<:AbstractArray{<:Number}},i_to_iposneg::PosNegPartition) + nineg = length(i_to_iposneg.ineg_to_i) + val = testitem(ipos_to_val) + zs = 0 .* size(val) + void = similar(val,eltype(val),zs) + ineg_to_val = Fill(void,nineg) + ipos_to_val, ineg_to_val end -function Base.propertynames(x::SkeletonPair, private::Bool=false) - (fieldnames(typeof(x))...,:⁺,:⁻) +function pos_neg_data( + ipos_to_val::AbstractArray{<:Field},i_to_iposneg::PosNegPartition) + nineg = length(i_to_iposneg.ineg_to_i) + ipos_to_v = lazy_map(VoidFieldMap(false),ipos_to_val) + ineg_to_v = Fill(VoidField(testitem(ipos_to_val),true),nineg) + ipos_to_v, ineg_to_v end -""" - test_triangulation(trian::Triangulation) -""" -function test_triangulation(trian::Triangulation{Dc,Dp}) where {Dc,Dp} - @test num_cell_dims(trian) == Dc - @test num_point_dims(trian) == Dp - @test num_cell_dims(typeof(trian)) == Dc - @test num_point_dims(typeof(trian)) == Dp - cell_coords = get_cell_coordinates(trian) - @test isa(cell_coords,AbstractArray{<:AbstractVector{<:Point}}) - reffes = get_reffes(trian) - @test isa(reffes,AbstractVector{<:LagrangianRefFE{Dc}}) - cell_types = get_cell_type(trian) - @test isa(cell_types,AbstractArray{<:Integer}) - ncells = num_cells(trian) - @test ncells == length(cell_coords) - @test ncells == length(cell_types) - @test isa(TriangulationStyle(trian),TriangulationStyle) - bgtrian = get_background_triangulation(trian) - @test isa(bgtrian,Triangulation) - cell_id = get_cell_to_bgcell(trian) - @test isa(cell_id,AbstractArray) || isa(cell_id,SkeletonPair) - cell_ref_map = get_cell_ref_map(trian) - @test isa(cell_ref_map,AbstractArray) || isa(cell_ref_map,SkeletonPair) -end - -# Some API +function pos_neg_data( + ipos_to_val::AbstractArray{<:AbstractArray{<:Field}},i_to_iposneg::PosNegPartition) + _pos_neg_data_basis(ipos_to_val,i_to_iposneg) +end -""" - num_cells(trian::Triangulation) -> Int -""" -num_cells(trian::Triangulation) = length(get_cell_type(trian)) +function pos_neg_data( + ipos_to_val::AbstractArray{<:AbstractArray{<:Dof}},i_to_iposneg::PosNegPartition) + _pos_neg_data_basis(ipos_to_val,i_to_iposneg) +end -""" - num_nodes(trian::Triangulation) -> Int -""" -num_nodes(trian::Triangulation) = length(get_node_coordinates(trian)) +function _pos_neg_data_basis(ipos_to_val,i_to_iposneg) + nineg = length(i_to_iposneg.ineg_to_i) + ipos_to_v = lazy_map(VoidBasisMap(false),ipos_to_val) + ineg_to_v = Fill(VoidBasis(testitem(ipos_to_val),true),nineg) + ipos_to_v, ineg_to_v +end -""" - num_cell_dims(::Triangulation) -> Int - num_cell_dims(::Type{<:Triangulation}) -> Int -""" -num_cell_dims(::Triangulation{Dc,Dp}) where {Dc,Dp} = Dc -num_cell_dims(::Type{<:Triangulation{Dc,Dp}}) where {Dc,Dp} = Dc +function pos_neg_data( + ipos_to_val::AbstractArray{<:ArrayBlock},i_to_iposneg::PosNegPartition) + nineg = length(i_to_iposneg.ineg_to_i) + val = testitem(ipos_to_val) + void = _similar_empty(val) + ineg_to_val = Fill(void,nineg) + ipos_to_val, ineg_to_val +end -""" - num_point_dims(::Triangulation) -> Int - num_point_dims(::Type{<:Triangulation}) -> Int -""" -num_point_dims(::Triangulation{Dc,Dp}) where {Dc,Dp} = Dp -num_point_dims(::Type{<:Triangulation{Dc,Dp}}) where {Dc,Dp} = Dp +function pos_neg_data( + ipos_to_val::AbstractArray{<:Tuple{<:Any,<:Any}},i_to_iposneg::PosNegPartition) + nineg = length(i_to_iposneg.ineg_to_i) + val = testitem(ipos_to_val) + void = _similar_empty(val) + ineg_to_val = Fill(void,nineg) + ipos_to_val, ineg_to_val +end -""" - num_dims(::Triangulation) -> Int - num_dims(::Type{<:Triangulation}) -> Int +function _similar_empty(val::AbstractArray) + zs = 0 .* size(val) + void = similar(val,eltype(val),zs) +end -Equivalent to `num_cell_dims`. -""" -num_dims(g::Triangulation{Dc}) where Dc = Dc -num_dims(::Type{<:Triangulation{Dc}}) where Dc = Dc +function _similar_empty(val::ArrayBlock) + a = deepcopy(val) + for i in eachindex(a) + if a.touched[i] + a.array[i] = _similar_empty(a.array[i]) + end + end + a +end -""" - is_first_order(trian::Triangulation) -> Bool -""" -function is_first_order(trian::Triangulation) - reffes = get_reffes(trian) - all(map(is_first_order,reffes)) +function _similar_empty(val::Tuple) + a, b = val + a1 = _similar_empty(a) + b1 = _similar_empty(b) + (a1,b1) end -""" - get_cell_reffe(trian::Triangulation) -> Vector{<:LagrangianRefFE} -It is not desirable to iterate over the resulting array -for large number of cells if the underlying reference FEs -are of different Julia type. -""" -function get_cell_reffe(trian::Triangulation) - type_to_reffe = get_reffes(trian) - cell_to_type = get_cell_type(trian) - expand_cell_data(type_to_reffe,cell_to_type) +# "Compose" triangulations + +struct CompositeTriangulation{Dc,Dp,A,B} <: Triangulation{Dc,Dp} + rtrian::A + dtrian::B + function CompositeTriangulation( + rtrian::Triangulation, dtrian::Triangulation) + @assert num_point_dims(rtrian) == num_point_dims(dtrian) + Dp = num_point_dims(rtrian) + Dc = num_cell_dims(dtrian) + #@assert get_active_model(rtrian) === get_background_model(dtrian) + A = typeof(rtrian) + B = typeof(dtrian) + new{Dc,Dp,A,B}(rtrian,dtrian) + end end -""" -""" -function get_cell_ref_coordinates(trian::Triangulation) - type_to_reffe = get_reffes(trian) - type_to_coords = map(get_node_coordinates,type_to_reffe) - cell_to_type = get_cell_type(trian) - expand_cell_data(type_to_coords,cell_to_type) +get_background_model(t::CompositeTriangulation) = get_background_model(t.rtrian) +get_active_model(t::CompositeTriangulation) = get_active_model(t.dtrian) +get_grid(t::CompositeTriangulation) = get_grid(t.dtrian) +get_facet_normal(t::CompositeTriangulation) = get_facet_normal(t.dtrian) +function get_glue(t::CompositeTriangulation,::Val{D}) where D + Dr = num_cell_dims(t.rtrian) + rglue = get_glue(t.rtrian,Val(D)) + dglue = get_glue(t.dtrian,Val(Dr)) + _compose_glues(rglue,dglue) end -""" - get_cell_shapefuns(trian::Triangulation) -> Vector{<:Field} -""" -function get_cell_shapefuns(trian::Triangulation) - type_to_reffes = get_reffes(trian) - cell_to_type = get_cell_type(trian) - type_to_shapefuns = map(get_shapefuns, type_to_reffes) - expand_cell_data(type_to_shapefuns,cell_to_type) +function _compose_glues(rglue,dglue) + nothing end -""" - get_cell_map(trian::Triangulation) -> Vector{<:Field} -""" -function get_cell_map(trian::Triangulation) - cell_to_coords = get_cell_coordinates(trian) - cell_to_shapefuns = get_cell_shapefuns(trian) - lazy_map(linear_combination,cell_to_coords,cell_to_shapefuns) +function _compose_glues(rglue::FaceToFaceGlue,dglue::FaceToFaceGlue) + rface_to_mface = rglue.tface_to_mface + dface_to_rface = dglue.tface_to_mface + dface_to_mface = collect(lazy_map(Reindex(rface_to_mface),dface_to_rface)) + rface_to_mface_map = rglue.tface_to_mface_map + dface_to_rface_map = dglue.tface_to_mface_map + dface_to_mface_map1 = lazy_map(Reindex(rface_to_mface_map),dface_to_rface) + dface_to_mface_map = lazy_map(∘,dface_to_mface_map1,dface_to_rface_map) + mface_to_dface = nothing + FaceToFaceGlue(dface_to_mface,dface_to_mface_map,mface_to_dface) end -function get_node_coordinates(trian::Triangulation) - @notimplemented +struct GenericTriangulation{Dc,Dp,A,B,C} <: Triangulation{Dc,Dp} + grid::A + model::B + glue::C + function GenericTriangulation( + grid::Grid, + model=nothing, + glue=ntuple(i->nothing,num_cell_dims(grid)+1)) + Dc = num_cell_dims(grid) + Dp = num_point_dims(grid) + A = typeof(grid) + B = typeof(model) + C = typeof(glue) + new{Dc,Dp,A,B,C}(grid,model,glue) + end end -function get_cell_node_ids(trian::Triangulation) - @notimplemented +get_grid(a::GenericTriangulation) = a.grid +get_glue(a::GenericTriangulation,::Val{D}) where D = a.glue[D+1] +function get_background_model(a::GenericTriangulation) + @notimplementedif a.model === nothing "This triangulation object cannot be used to define a FE Space" + a.model end -function compress_contributions(cell_mat,trian::Triangulation) - cell_mat +struct TriangulationView{Dc,Dp,A,B} <: Triangulation{Dc,Dp} + parent::A + cell_to_parent_cell::B + function TriangulationView(parent::Triangulation,cell_to_parent_cell::AbstractArray) + Dc = num_cell_dims(parent) + Dp = num_point_dims(parent) + A = typeof(parent) + B = typeof(cell_to_parent_cell) + new{Dc,Dp,A,B}(parent,cell_to_parent_cell) + end end -function compress_ids(cell_ids,trian::Triangulation) - cell_ids +Base.view(a::Triangulation,b::AbstractArray) = TriangulationView(a,b) + +function TriangulationView(parent::Triangulation,parent_cell_to_mask::AbstractArray{Bool}) + cell_to_parent_cell = findall(collect1d(parent_cell_to_mask)) + TriangulationView(parent,cell_to_parent_cell) end -function Quadrature(trian::Triangulation,args...;kwargs...) - cell_ctype = get_cell_type(trian) - ctype_polytope = map(get_polytope,get_reffes(trian)) - ctype_quad = map(p->Quadrature(p,args...;kwargs...),ctype_polytope) - cell_quad = expand_cell_data(ctype_quad,cell_ctype) +function TriangulationView(parent::Triangulation,parent_cell_to_mask::AbstractVector{Bool}) + cell_to_parent_cell = findall(parent_cell_to_mask) + TriangulationView(parent,cell_to_parent_cell) end -#""" -#""" -#function CellField(object,trian::Triangulation) -# cm = get_cell_map(trian) -# convert_to_cell_field(object,cm) -#end -# - -# Helpers for Triangulation - -#""" -# restrict(cf::CellField,trian::Triangulation) -#""" -#function restrict(cf::CellField,trian::Triangulation) -# _cf = to_ref_space(cf) -# a = get_array(_cf) -# r = restrict(a,trian) -# axs = reindex(get_cell_axes(cf),trian) -# _restrict_cell_field(r,axs,MetaSizeStyle(cf),trian) -#end -# -#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.plus -# ra = r.minus -# l = GenericCellField(la,cm,Val(true),axs.plus,msize_style) -# r = GenericCellField(ra,cm,Val(true),axs.minus,msize_style) -# merge_cell_fields_at_skeleton(l,r) -#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 -# -#""" -# 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 +function get_background_model(trian::TriangulationView) + get_background_model(trian.parent) +end + +function get_grid(trian::TriangulationView) + view(get_grid(trian.parent),trian.cell_to_parent_cell) +end + +function get_glue(t::TriangulationView,::Val{d}) where d + parent = get_glue(t.parent,Val(d)) + view(parent,t.cell_to_parent_cell) +end + +function Base.view(glue::FaceToFaceGlue,ids::AbstractArray) + tface_to_mface = lazy_map(Reindex(glue.tface_to_mface),ids) + tface_to_mface_map = lazy_map(Reindex(glue.tface_to_mface_map),ids) + if glue.mface_to_tface === nothing + mface_to_tface = nothing + else + nmfaces = length(glue.mface_to_tface) + mface_to_tface = PosNegPartition(glue.tface_to_mface,Int32(nmfaces)) + end + FaceToFaceGlue(tface_to_mface,tface_to_mface_map,mface_to_tface) +end + +function get_facet_normal(trian::TriangulationView) + n = get_facet_normal(trian.parent) + restrict(n,trian.cell_to_parent_cell) +end + +function get_cell_map(trian::TriangulationView) + lazy_map(Reindex(get_cell_map(trian.parent)),trian.cell_to_parent_cell) +end diff --git a/src/Geometry/UnstructuredGrids.jl b/src/Geometry/UnstructuredGrids.jl index a985f8d4f..80d3f14a0 100644 --- a/src/Geometry/UnstructuredGrids.jl +++ b/src/Geometry/UnstructuredGrids.jl @@ -7,12 +7,13 @@ cell_types::Vector{Int8} end """ -struct UnstructuredGrid{Dc,Dp,Tp,O} <: Grid{Dc,Dp} +struct UnstructuredGrid{Dc,Dp,Tp,O,Tn} <: Grid{Dc,Dp} node_coordinates::Vector{Point{Dp,Tp}} cell_node_ids::Table{Int32,Vector{Int32},Vector{Int32}} reffes::Vector{LagrangianRefFE{Dc}} cell_types::Vector{Int8} orientation_style::O + facet_normal::Tn cell_map @doc """ function UnstructuredGrid( @@ -30,16 +31,19 @@ struct UnstructuredGrid{Dc,Dp,Tp,O} <: Grid{Dc,Dp} cell_node_ids::Table{Ti}, reffes::Vector{<:LagrangianRefFE{Dc}}, cell_types::Vector, - orientation_style::OrientationStyle=NonOriented()) where {Dc,Dp,Tp,Ti} + orientation_style::OrientationStyle=NonOriented(), + facet_normal=nothing) where {Dc,Dp,Tp,Ti} cell_map = _compute_cell_map(node_coordinates,cell_node_ids,reffes,cell_types) B = typeof(orientation_style) - new{Dc,Dp,Tp,B}( + Tn = typeof(facet_normal) + new{Dc,Dp,Tp,B,Tn}( node_coordinates, cell_node_ids, reffes, cell_types, orientation_style, + facet_normal, cell_map) end end @@ -84,7 +88,7 @@ function UnstructuredGrid(grid::UnstructuredGrid) end OrientationStyle( - ::Type{UnstructuredGrid{Dc,Dp,Tp,B}}) where {Dc,Dp,Tp,B} = B() + ::Type{<:UnstructuredGrid{Dc,Dp,Tp,B}}) where {Dc,Dp,Tp,B} = B() get_reffes(g::UnstructuredGrid) = g.reffes @@ -96,6 +100,11 @@ get_cell_node_ids(g::UnstructuredGrid) = g.cell_node_ids get_cell_map(g::UnstructuredGrid) = g.cell_map +function get_facet_normal(g::UnstructuredGrid) + @assert g.facet_normal != nothing "This Grid does not have information about normals." + g.facet_normal +end + # From ReferenceFE """ diff --git a/src/MultiField/MultiField.jl b/src/MultiField/MultiField.jl index fd80bbf68..0f3983b12 100644 --- a/src/MultiField/MultiField.jl +++ b/src/MultiField/MultiField.jl @@ -17,6 +17,8 @@ using Gridap.Fields using Gridap.FESpaces: FEBasis, TestBasis, TrialBasis, get_cell_dof_values using Gridap.FESpaces: SingleFieldFEBasis, TestBasis, TrialBasis +using Gridap.CellData: CellFieldAt +import Gridap.Fields: gradient, DIV, ∇∇ using FillArrays using SparseArrays diff --git a/src/MultiField/MultiFieldCellFields.jl b/src/MultiField/MultiFieldCellFields.jl index db41c07b3..ba9ce113b 100644 --- a/src/MultiField/MultiFieldCellFields.jl +++ b/src/MultiField/MultiFieldCellFields.jl @@ -1,6 +1,5 @@ struct MultiFieldCellField{DS<:DomainStyle} <: CellField single_fields::Vector{<:CellField} - trian::Triangulation domain_style::DS function MultiFieldCellField(single_fields::Vector{<:CellField}) @@ -14,10 +13,7 @@ struct MultiFieldCellField{DS<:DomainStyle} <: CellField domain_style = PhysicalDomain() end - trian = get_triangulation(f1) - #@check all(map(i-> get_triangulation(i) === trian,single_fields)) - - new{typeof(domain_style)}(single_fields,trian,domain_style) + new{typeof(domain_style)}(single_fields,domain_style) end end @@ -32,7 +28,12 @@ function CellData.get_data(f::MultiFieldCellField) @notimplemented s end -CellData.get_triangulation(f::MultiFieldCellField) = f.trian +function CellData.get_triangulation(f::MultiFieldCellField) + s1 = first(f.single_fields) + trian = get_triangulation(s1) + @check all(map(i->trian===get_triangulation(i),f.single_fields)) + trian +end CellData.DomainStyle(::Type{MultiFieldCellField{DS}}) where DS = DS() num_fields(a::MultiFieldCellField) = length(a.single_fields) Base.getindex(a::MultiFieldCellField,i::Integer) = a.single_fields[i] diff --git a/src/MultiField/MultiFieldFEFunctions.jl b/src/MultiField/MultiFieldFEFunctions.jl index f92b7dc88..49bd67e28 100644 --- a/src/MultiField/MultiFieldFEFunctions.jl +++ b/src/MultiField/MultiFieldFEFunctions.jl @@ -41,24 +41,24 @@ function FESpaces.get_cell_dof_values(f::MultiFieldFEFunction) """ trians = map(get_triangulation,f.fe_space.spaces) trian = first(trians) - @check all(map(t->have_compatible_domains(t,trian),trians)) msg + @check all(map(t->is_change_possible(t,trian),trians)) msg get_cell_dof_values(f,trian) end function FESpaces.get_cell_dof_values(f::MultiFieldFEFunction,trian::Triangulation) uhs = f.single_fe_functions - blockmask = [ _can_be_restricted_to(get_triangulation(uh),trian) for uh in uhs ] + blockmask = [ is_change_possible(get_triangulation(uh),trian) for uh in uhs ] active_block_ids = findall(blockmask) active_block_data = Any[ get_cell_dof_values(uhs[i],trian) for i in active_block_ids ] nblocks = length(uhs) lazy_map(BlockMap(nblocks,active_block_ids),active_block_data...) end -function FESpaces.get_cell_dof_values(f::MultiFieldFEFunction,trian::SkeletonTriangulation) - cell_values_plus = get_cell_dof_values(f,trian.plus) - cell_values_minus = get_cell_dof_values(f,trian.minus) - lazy_map(BlockMap(2,[1,2]),cell_values_plus,cell_values_minus) -end +#function FESpaces.get_cell_dof_values(f::MultiFieldFEFunction,trian::SkeletonTriangulation) +# cell_values_plus = get_cell_dof_values(f,trian.plus) +# cell_values_minus = get_cell_dof_values(f,trian.minus) +# lazy_map(BlockMap(2,[1,2]),cell_values_plus,cell_values_minus) +#end """ num_fields(m::MultiFieldFEFunction) diff --git a/src/MultiField/MultiFieldFESpaces.jl b/src/MultiField/MultiFieldFESpaces.jl index 1e542191c..32a157082 100644 --- a/src/MultiField/MultiFieldFESpaces.jl +++ b/src/MultiField/MultiFieldFESpaces.jl @@ -1,14 +1,3 @@ -function _can_be_restricted_to(trian_i,trian) - if have_compatible_domains(trian_i,trian) || - have_compatible_domains(trian_i,get_background_triangulation(trian)) || - have_compatible_domains(trian_i,get_background_triangulation(get_background_triangulation(trian))) || - Geometry.is_included(trian,trian_i) - true - else - false - end -end - abstract type MultiFieldStyle end struct ConsecutiveMultiFieldStyle <: MultiFieldStyle end @@ -99,17 +88,100 @@ FESpaces.get_vector_type(f::MultiFieldFESpace) = f.vector_type FESpaces.ConstraintStyle(::Type{MultiFieldFESpace{S,B,V}}) where {S,B,V} = B() +struct MultiFieldFEBasisComponent{B} <: FEBasis + cell_basis::AbstractArray + single_field::B + fieldid::Int + nfields::Int + function MultiFieldFEBasisComponent( + single_field::SingleFieldFEBasis,fieldid::Integer,nfields::Integer) + function block_dofs(cell_bs,::TestBasis,fieldid,nfields) + cell_basis = lazy_map(BlockMap(nfields,fieldid),cell_bs) + end + function block_dofs(cell_bs,::TrialBasis,fieldid,nfields) + cell_basis = lazy_map(BlockMap((1,nfields),fieldid),cell_bs) + end + B = typeof(single_field) + cell_bs = get_data(single_field) + bsty = BasisStyle(single_field) + cell_basis = block_dofs(cell_bs,bsty,fieldid,nfields) + new{B}(cell_basis,single_field,fieldid,nfields) + end +end + +CellData.get_data(f::MultiFieldFEBasisComponent) = f.cell_basis +CellData.get_triangulation(f::MultiFieldFEBasisComponent) = get_triangulation(f.single_field) +FESpaces.BasisStyle(::Type{<:MultiFieldFEBasisComponent{B}}) where B = BasisStyle(B) +CellData.DomainStyle(::Type{<:MultiFieldFEBasisComponent{B}}) where B = DomainStyle(B) +function FESpaces.CellData.similar_cell_field( + f::MultiFieldFEBasisComponent,cell_data,trian,ds::DomainStyle) + @notimplemented +end +function FESpaces.similar_fe_basis( + f::MultiFieldFEBasisComponent,cell_data,trian,bs::BasisStyle,ds::DomainStyle) + @notimplemented +end + +for fun in (:gradient,:DIV,:∇∇) + @eval begin + function $fun(f::MultiFieldFEBasisComponent) + g = $fun(f.single_field) + MultiFieldFEBasisComponent(g,f.fieldid,f.nfields) + end + end +end + +function CellData.change_domain( + a::MultiFieldFEBasisComponent, + tdomain::DomainStyle) + sf = change_domain(a.single_field,tdomain) + MultiFieldFEBasisComponent(sf,a.fieldid,a.nfields) +end + +function CellData.change_domain( + a::MultiFieldFEBasisComponent, + ttrian::Triangulation, + tdomain::DomainStyle) + sf = change_domain(a.single_field,ttrian,tdomain) + MultiFieldFEBasisComponent(sf,a.fieldid,a.nfields) +end + +function MultiFieldFEBasisComponent( + single_field::CellFieldAt{S,<:SingleFieldFEBasis}, + fieldid::Integer, + nfields::Integer) where S + + sf = single_field.parent + mf = MultiFieldFEBasisComponent(sf,fieldid,nfields) + CellFieldAt{S}(mf) +end + +function CellData.change_domain( + a::CellFieldAt{S,<:MultiFieldFEBasisComponent}, + tdomain::DomainStyle) where S + mf = a.parent + sfin = CellFieldAt{S}(mf.single_field) + sfout = change_domain(sfin,tdomain) + MultiFieldFEBasisComponent(sfout,mf.fieldid,mf.nfields) +end + +function CellData.change_domain( + a::CellFieldAt{S,<:MultiFieldFEBasisComponent}, + ttrian::Triangulation, + tdomain::DomainStyle) where S + mf = a.parent + sfin = CellFieldAt{S}(mf.single_field) + sfout = change_domain(sfin,ttrian,tdomain) + MultiFieldFEBasisComponent(sfout,mf.fieldid,mf.nfields) +end + function FESpaces.get_fe_basis(f::MultiFieldFESpace) nfields = length(f.spaces) - all_febases = SingleFieldFEBasis[] + all_febases = MultiFieldFEBasisComponent[] for field_i in 1:nfields dv_i = get_fe_basis(f.spaces[field_i]) - cell_basis = lazy_map(BlockMap(nfields,field_i),get_data(dv_i)) - trian = get_triangulation(dv_i) - bs = BasisStyle(dv_i) - @assert bs == TestBasis() - ds = DomainStyle(dv_i) - dv_i_b = SingleFieldFEBasis(cell_basis,trian,bs,ds) + @assert BasisStyle(dv_i) == TestBasis() + dv_i_b = MultiFieldFEBasisComponent(dv_i,field_i,nfields) push!(all_febases,dv_i_b) end MultiFieldCellField(all_febases) @@ -117,15 +189,11 @@ end function FESpaces.get_trial_fe_basis(f::MultiFieldFESpace) nfields = length(f.spaces) - all_febases = SingleFieldFEBasis[] + all_febases = MultiFieldFEBasisComponent[] for field_i in 1:nfields du_i = get_trial_fe_basis(f.spaces[field_i]) - cell_basis = lazy_map(BlockMap((1,nfields),field_i),get_data(du_i)) - trian = get_triangulation(du_i) - bs = BasisStyle(du_i) - @assert bs == TrialBasis() - ds = DomainStyle(du_i) - du_i_b = SingleFieldFEBasis(cell_basis,trian,bs,ds) + @assert BasisStyle(du_i) == TrialBasis() + du_i_b = MultiFieldFEBasisComponent(du_i,field_i,nfields) push!(all_febases,du_i_b) end MultiFieldCellField(all_febases) @@ -198,14 +266,14 @@ function FESpaces.get_cell_isconstrained(f::MultiFieldFESpace) """ trians = map(get_triangulation,f.spaces) trian = first(trians) - @check all(map(t->have_compatible_domains(t,trian),trians)) msg + @check all(map(t->t===trian,trians)) msg get_cell_isconstrained(f,trian) end function FESpaces.get_cell_isconstrained(f::MultiFieldFESpace,trian::Triangulation) data = map(f.spaces) do space trian_i = get_triangulation(space) - if _can_be_restricted_to(trian_i,trian) + if is_change_possible(trian_i,trian) get_cell_isconstrained(space,trian) else Fill(false,num_cells(trian)) @@ -214,11 +282,11 @@ function FESpaces.get_cell_isconstrained(f::MultiFieldFESpace,trian::Triangulati lazy_map( (args...) -> +(args...)>0, data...) end -function FESpaces.get_cell_isconstrained(f::MultiFieldFESpace,trian::SkeletonTriangulation) - plus = get_cell_isconstrained(f,trian.plus) - minus = get_cell_isconstrained(f,trian.minus) - lazy_map((l,r)-> l||r,plus,minus) -end +#function FESpaces.get_cell_isconstrained(f::MultiFieldFESpace,trian::SkeletonTriangulation) +# plus = get_cell_isconstrained(f,trian.plus) +# minus = get_cell_isconstrained(f,trian.minus) +# lazy_map((l,r)-> l||r,plus,minus) +#end function FESpaces.get_cell_is_dirichlet(f::MultiFieldFESpace) msg = """\n @@ -229,14 +297,14 @@ function FESpaces.get_cell_is_dirichlet(f::MultiFieldFESpace) """ trians = map(get_triangulation,f.spaces) trian = first(trians) - @check all(map(t->have_compatible_domains(t,trian),trians)) msg + @check all(map(t->t===trian,trians)) msg get_cell_is_dirichlet(f,trian) end function FESpaces.get_cell_is_dirichlet(f::MultiFieldFESpace,trian::Triangulation) data = map(f.spaces) do space trian_i = get_triangulation(space) - if _can_be_restricted_to(trian_i,trian) + if is_change_possible(trian_i,trian) get_cell_is_dirichlet(space,trian) else Fill(false,num_cells(trian)) @@ -245,11 +313,11 @@ function FESpaces.get_cell_is_dirichlet(f::MultiFieldFESpace,trian::Triangulatio lazy_map( (args...) -> +(args...)>0, data...) end -function FESpaces.get_cell_is_dirichlet(f::MultiFieldFESpace,trian::SkeletonTriangulation) - plus = get_cell_is_dirichlet(f,trian.plus) - minus = get_cell_is_dirichlet(f,trian.minus) - lazy_map((l,r)-> l||r,plus,minus) -end +#function FESpaces.get_cell_is_dirichlet(f::MultiFieldFESpace,trian::SkeletonTriangulation) +# plus = get_cell_is_dirichlet(f,trian.plus) +# minus = get_cell_is_dirichlet(f,trian.minus) +# lazy_map((l,r)-> l||r,plus,minus) +#end function FESpaces.get_cell_constraints(f::MultiFieldFESpace) msg = """\n @@ -260,13 +328,13 @@ function FESpaces.get_cell_constraints(f::MultiFieldFESpace) """ trians = map(get_triangulation,f.spaces) trian = first(trians) - @check all(map(t->have_compatible_domains(t,trian),trians)) msg + @check all(map(t->t===trian,trians)) msg get_cell_constraints(f,trian) end function FESpaces.get_cell_constraints(f::MultiFieldFESpace,trian::Triangulation) nfields = length(f.spaces) - blockmask = [ _can_be_restricted_to(get_triangulation(Vi),trian) for Vi in f.spaces ] + blockmask = [ is_change_possible(get_triangulation(Vi),trian) for Vi in f.spaces ] active_block_ids = findall(blockmask) active_block_data = Any[ get_cell_constraints(f.spaces[i],trian) for i in active_block_ids ] blockshape = (nfields,nfields) @@ -274,11 +342,11 @@ function FESpaces.get_cell_constraints(f::MultiFieldFESpace,trian::Triangulation lazy_map(BlockMap(blockshape,blockindices),active_block_data...) end -function FESpaces.get_cell_constraints(f::MultiFieldFESpace,trian::SkeletonTriangulation) - cell_values_plus = get_cell_constraints(f,trian.plus) - cell_values_minus = get_cell_constraints(f,trian.minus) - lazy_map(BlockMap((2,2),[(1,1),(2,2)]),cell_values_plus,cell_values_minus) -end +#function FESpaces.get_cell_constraints(f::MultiFieldFESpace,trian::SkeletonTriangulation) +# cell_values_plus = get_cell_constraints(f,trian.plus) +# cell_values_minus = get_cell_constraints(f,trian.minus) +# lazy_map(BlockMap((2,2),[(1,1),(2,2)]),cell_values_plus,cell_values_minus) +#end function FESpaces.get_cell_dof_ids(f::MultiFieldFESpace) msg = """\n @@ -289,7 +357,7 @@ function FESpaces.get_cell_dof_ids(f::MultiFieldFESpace) """ trians = map(get_triangulation,f.spaces) trian = first(trians) - @check all(map(t->have_compatible_domains(t,trian),trians)) msg + @check all(map(t->t===trian,trians)) msg get_cell_dof_ids(f,trian) end @@ -297,11 +365,11 @@ function FESpaces.get_cell_dof_ids(f::MultiFieldFESpace,trian::Triangulation) get_cell_dof_ids(f,trian,MultiFieldStyle(f)) end -function FESpaces.get_cell_dof_ids(f::MultiFieldFESpace,trian::SkeletonTriangulation) - cell_values_plus = get_cell_dof_ids(f,trian.plus) - cell_values_minus = get_cell_dof_ids(f,trian.minus) - lazy_map(BlockMap(2,[1,2]),cell_values_plus,cell_values_minus) -end +#function FESpaces.get_cell_dof_ids(f::MultiFieldFESpace,trian::SkeletonTriangulation) +# cell_values_plus = get_cell_dof_ids(f,trian.plus) +# cell_values_minus = get_cell_dof_ids(f,trian.minus) +# lazy_map(BlockMap(2,[1,2]),cell_values_plus,cell_values_minus) +#end function FESpaces.get_cell_dof_ids(f::MultiFieldFESpace,::Triangulation,::MultiFieldStyle) @notimplemented @@ -310,7 +378,7 @@ end function FESpaces.get_cell_dof_ids(f::MultiFieldFESpace,trian::Triangulation,::ConsecutiveMultiFieldStyle) offsets = compute_field_offsets(f) nfields = length(f.spaces) - blockmask = [ _can_be_restricted_to(get_triangulation(Vi),trian) for Vi in f.spaces ] + blockmask = [ is_change_possible(get_triangulation(Vi),trian) for Vi in f.spaces ] active_block_ids = findall(blockmask) active_block_data = Any[] for i in active_block_ids @@ -335,6 +403,35 @@ function _sum_if_first_positive(a,b) end end +function Arrays.return_value(k::Broadcasting{typeof(_sum_if_first_positive)},dofs::VectorBlock,o) + evaluate(k,dofs,o) +end + +function Arrays.return_cache(k::Broadcasting{typeof(_sum_if_first_positive)},dofs::VectorBlock,o) + i = first(findall(dofs.touched)) + dofsi = dofs.array[i] + ci = return_cache(k,dofsi,o) + odofsi = evaluate!(ci,k,dofsi,o) + array = Vector{typeof(odofsi)}(undef,length(dofs.array)) + c = Vector{typeof(ci)}(undef,length(dofs.array)) + for i in 1:length(dofs.array) + if dofs.touched[i] + c[i] = return_cache(k,dofs.array[i],o) + end + end + ArrayBlock(array,dofs.touched), c +end + +function Arrays.evaluate!(cache,k::Broadcasting{typeof(_sum_if_first_positive)},dofs::VectorBlock,o) + r,c = cache + for i in 1:length(dofs.array) + if dofs.touched[i] + r[i] = evaluate!(c[i],k,dofs.array[i],o) + end + end + r +end + # API for multi field case """ @@ -377,6 +474,10 @@ even in the case that the given cell field does not fulfill them) """ function FESpaces.interpolate(objects, fe::MultiFieldFESpace) free_values = zero_free_values(fe) + interpolate!(objects,free_values,fe) +end + +function FESpaces.interpolate!(objects,free_values::AbstractVector,fe::MultiFieldFESpace) blocks = SingleFieldFEFunction[] for (field, (U,object)) in enumerate(zip(fe.spaces,objects)) free_values_i = restrict_to_field(fe,free_values,field) diff --git a/src/Visualization/VisualizationData.jl b/src/Visualization/VisualizationData.jl index 660251d81..539e6386c 100644 --- a/src/Visualization/VisualizationData.jl +++ b/src/Visualization/VisualizationData.jl @@ -19,6 +19,10 @@ end # Visualizing Triangulation, cellfields, etc. +function visualization_data(grid::Grid, filebase::AbstractString;celldata=Dict(),nodaldata=Dict()) + (VisualizationData(grid,filebase;celldata=celldata,nodaldata=nodaldata),) +end + function visualization_data( trian::Triangulation, filebase::AbstractString; order=-1, nsubcells=-1, celldata=Dict(), cellfields=Dict()) @@ -30,7 +34,7 @@ function visualization_data( # Use cells of given order as visualization cells f = (reffe) -> UnstructuredGrid(LagrangianRefFE(Float64,get_polytope(reffe),order)) elseif order == -1 && nsubcells != -1 - # Use use linear sub-cells with nsubcells per direction + # Use linear sub-cells with nsubcells per direction f = (reffe) -> UnstructuredGrid(compute_reference_grid(reffe,nsubcells)) else @unreachable "order and nsubcells kw-arguments can not be given at the same time" diff --git a/src/Visualization/Vtk.jl b/src/Visualization/Vtk.jl index 3f5969116..c719f601e 100644 --- a/src/Visualization/Vtk.jl +++ b/src/Visualization/Vtk.jl @@ -1,4 +1,10 @@ + +## TODO this needs to be deleted +# once WriteVTK provides the pvtk_grid function +include("pvtk_grid.jl") + + """ """ function writevtk(args...;kwargs...) @@ -64,6 +70,23 @@ function create_vtk_file( return vtkfile end +function create_pvtk_file( + trian::Grid, filebase; pvtkargs, celldata=Dict(), nodaldata=Dict()) + + points = _vtkpoints(trian) + cells = _vtkcells(trian) + vtkfile = TMP.pvtk_grid(filebase, points, cells,pvtkargs=pvtkargs, compress=false) + + for (k,v) in celldata + vtkfile[k,VTKCellData()] = _prepare_data(v) + end + for (k,v) in nodaldata + vtkfile[k,VTKPointData()] = _prepare_data(v) + end + + return vtkfile +end + function _vtkpoints(trian) D = num_point_dims(trian) x = get_node_coordinates(trian) diff --git a/src/Visualization/pvtk_grid.jl b/src/Visualization/pvtk_grid.jl new file mode 100644 index 000000000..c06b8b7e4 --- /dev/null +++ b/src/Visualization/pvtk_grid.jl @@ -0,0 +1,334 @@ +module TMP + +using WriteVTK +using WriteVTK: VTKFile, VTKDataType, AbstractVTKDataset, XMLDocument +using WriteVTK: XMLElement, DatasetFile, AbstractFieldData, VTKUnstructuredGrid +using WriteVTK: create_root, xml_name, set_attribute, IS_LITTLE_ENDIAN +using WriteVTK: new_child, file_extension, add_extension, root +using WriteVTK: attribute, find_element, child_elements, datatype_str +using WriteVTK: save_file +import WriteVTK: vtk_save + +struct ParallelDatasetFile <: VTKFile + pvtkargs::Dict + xdoc::XMLDocument + dataset::DatasetFile + path::AbstractString + function ParallelDatasetFile( + pvtkargs::Dict, + xdoc::XMLDocument, + dataset::DatasetFile, + path::AbstractString) + new(pvtkargs,xdoc,dataset,path) + end +end + +function _default_pvtkargs(pvtkargs) + mandatory = [:part,:nparts] + optional = [:ismain,:ghost_level] + allkeys = vcat(mandatory,optional) + + d = Dict{Symbol,Any}(pvtkargs) + for k in keys(d) + if !(k in allkeys) + throw(ArgumentError("$k is not a valid key in pvtkargs.")) + end + end + for k in mandatory + if !(haskey(d,k)) + throw(ArgumentError("$k is a mandatory key in pvtkargs.")) + end + end + if ! haskey(d,:ismain) + d[:ismain] = (d[:part] == 1) + end + if ! haskey(d,:ghost_level) + d[:ghost_level] = 0 + end + d +end + +function vtk_save(vtk::ParallelDatasetFile) + if isopen(vtk) + _pvtk_grid_body(vtk) + if vtk.pvtkargs[:ismain] + save_file(vtk.xdoc, vtk.path) + end + vtk_save(vtk.dataset) + close(vtk) + end + return [vtk.path] :: Vector{String} +end + +function new_pdata_array(xParent, + type::Type{<:VTKDataType}, + name::AbstractString, + Nc=nothing) + xDA = new_child(xParent, "PDataArray") + set_attribute(xDA, "type", datatype_str(type)) + set_attribute(xDA, "Name", name) + if Nc != nothing + set_attribute(xDA, "NumberOfComponents", Nc) + end +end + +function get_extension(filename::AbstractString) + path, ext = splitext(filename) + ext +end + +function get_path(filename::AbstractString) + path, ext = splitext(filename) + path +end + +function parallel_file_extension(g::AbstractVTKDataset) + ext=file_extension(g) + replace(ext,"."=>".p") +end + +function parallel_xml_name(g::AbstractVTKDataset) + "P"*xml_name(g) +end + +function parallel_xml_write_header(pvtx::XMLDocument,dtype::AbstractVTKDataset) + xroot = create_root(pvtx, "VTKFile") + set_attribute(xroot, "type", parallel_xml_name(dtype)) + set_attribute(xroot, "version", "1.0") + if IS_LITTLE_ENDIAN + set_attribute(xroot, "byte_order", "LittleEndian") + else + set_attribute(xroot, "byte_order", "BigEndian") + end + xroot +end + +function add_pieces!(grid_xml_node, + prefix::AbstractString, + extension::AbstractString, + num_pieces::Int) + for i=1:num_pieces + piece=new_child(grid_xml_node,"Piece") + fn = _serial_filename(i,num_pieces,prefix,extension) + set_attribute(piece,"Source",fn) + end + grid_xml_node +end + +function add_ppoints!(grid_xml_node; + type::Type{<:VTKDataType}=Float64) + ppoints=new_child(grid_xml_node,"PPoints") + new_pdata_array(ppoints,type,"Points",3) +end + +function add_ppoint_data!(pdataset::ParallelDatasetFile, + name::AbstractString; + type::Type{<:VTKDataType}=Float64, + Nc::Integer=1) + xroot=root(pdataset.xdoc) + dtype = xml_name_to_VTK_Dataset(pdataset.dataset.grid_type) + grid_xml_node=find_element(xroot,parallel_xml_name(dtype)) + @assert grid_xml_node != nothing + grid_xml_node_ppoint=find_element(grid_xml_node,"PPointData") + if (grid_xml_node_ppoint==nothing) + grid_xml_node_ppoint=new_child(grid_xml_node,"PPointData") + end + new_pdata_array(grid_xml_node_ppoint,type,name,Nc) +end + +function add_pcell_data!(pdataset::ParallelDatasetFile, + name::AbstractString; + type::Type{<:VTKDataType}=Float64, + Nc=nothing) + xroot=root(pdataset.xdoc) + dtype = xml_name_to_VTK_Dataset(pdataset.dataset.grid_type) + grid_xml_node=find_element(xroot,parallel_xml_name(dtype)) + @assert grid_xml_node != nothing + grid_xml_node_pcell=find_element(grid_xml_node,"PCellData") + if (grid_xml_node_pcell==nothing) + grid_xml_node_pcell=new_child(grid_xml_node,"PCellData") + end + new_pdata_array(grid_xml_node_pcell,type,name,Nc) +end + +function Base.setindex!(pvtk::ParallelDatasetFile, + data, + name::AbstractString, + loc::AbstractFieldData) + pvtk.dataset[name,loc]=data +end + +function Base.setindex!(vtk::ParallelDatasetFile, data, name::AbstractString) + vtk.dataset[name]=data +end + +function get_dataset_extension(dataset::DatasetFile) + path, ext = splitext(dataset.path) + @assert ext != "" + ext +end + +function get_dataset_path(dataset::DatasetFile) + path, ext = splitext(dataset.path) + @assert ext != "" + path +end + +function xml_name_to_VTK_Dataset(xml_name::AbstractString) + if (xml_name=="ImageData") + VTKImageData() + elseif (xml_name=="RectilinearGrid") + VTKRectilinearGrid() + elseif (xml_name=="PolyData") + VTKPolyData() + elseif (xml_name=="StructuredGrid") + VTKStructuredGrid() + elseif (xml_name=="UnstructuredGrid") + VTKUnstructuredGrid() + else + @assert false + end +end + +function num_children(element) + length(collect(child_elements(element))) +end + +function get_child_attribute(element,child,attr) + children=collect(child_elements(element)) + attribute(children[child],attr) +end + +function get_dataset_xml_type(dataset::DatasetFile) + r=root(dataset.xdoc) + attribute(r,"type") +end + +function get_dataset_xml_grid_element(dataset::DatasetFile, + element::AbstractString) + r=root(dataset.xdoc) + uns=find_element(r,get_dataset_xml_type(dataset)) + piece=find_element(uns,"Piece") + find_element(piece,element) +end + + +const string_to_VTKDataType = Dict("Int8"=>Int8, + "UInt8"=>UInt8, + "Int16"=>Int16, + "UInt16"=>UInt16, + "Int32"=>Int32, + "UInt32"=>UInt32, + "Int64"=>Int64, + "UInt64"=>UInt64, + "Float32"=>Float32, + "Float64"=>Float64, + "String"=>String) + +""" + pvtk_grid(args...;pvtkargs,kwargs...) + +Return a handler representing a parallel vtk file, which can be +eventually written to file with `vtk_save`. + +Positional and keyword arguments in `args` and `kwargs` +are passed to `vtk_grid` verbatim (except file names that are augmented with the +corresponding part id). + +The extra keyword argument `pvtkargs` contains +extra options (as a `Dict{Symbol,Any}` or a `Vector{Pair{Symbol,Any}}`) +that only apply for parallel vtk file formats. + +Mandatory keys in `pvtkargs` are: + +- `:part` current (1-based) part id +- `:nparts` total number of parts + +Default key/value pairs in `pvtkargs` are +- `:ismain=>part==1` True if the current part id `part` is the main (the only one that will write the .pvtk file). +- `:ghost_level=>0` Ghost level. +""" +function pvtk_grid(filename::AbstractString,args...;pvtkargs,kwargs...) + _pvtkargs = _default_pvtkargs(pvtkargs) + part = _pvtkargs[:part] + nparts = _pvtkargs[:nparts] + bname = basename(filename) + path = mkpath(filename) + prefix = joinpath(path,bname) + extension = "" + fn = _serial_filename(part,nparts,prefix,extension) + vtk = vtk_grid(fn,args...;kwargs...) + _pvtk_grid_header(_pvtkargs,vtk,path) +end + +function _serial_filename(part,nparts,prefix,extension) + p = lpad(part,ceil(Int,log10(nparts)),'0') + fn = prefix*"_$p"*extension +end + +function _pvtk_grid_header( + pvtkargs::Dict, + dataset::DatasetFile, + filename::AbstractString) + + pvtx = XMLDocument() + dtype = xml_name_to_VTK_Dataset(dataset.grid_type) + xroot = parallel_xml_write_header(pvtx,dtype) + + # Generate parallel grid node + grid_xml_node=new_child(xroot,"P"*dataset.grid_type) + set_attribute(grid_xml_node, "GhostLevel", string(pvtkargs[:ghost_level])) + + prefix=joinpath(filename,basename(filename)) + extension=file_extension(dtype) + add_pieces!(grid_xml_node,prefix,extension,pvtkargs[:nparts]) + + pextension = parallel_file_extension(dtype) + pfilename = add_extension(filename,pextension) + pdataset=ParallelDatasetFile(pvtkargs,pvtx,dataset,pfilename) + + # Generate PPoints + points=get_dataset_xml_grid_element(dataset,"Points") + type=get_child_attribute(points,1,"type") + add_ppoints!(grid_xml_node,type=string_to_VTKDataType[type]) + + pdataset + end + +function _pvtk_grid_body(pdataset::ParallelDatasetFile) + dataset=pdataset.dataset + # Generate PPointData + pointdata=get_dataset_xml_grid_element(dataset,"PointData") + if pointdata != nothing + if (num_children(pointdata)>0) + for child=1:num_children(pointdata) + name=get_child_attribute(pointdata,child,"Name") + type=get_child_attribute(pointdata,child,"type") + Nc=get_child_attribute(pointdata,child,"NumberOfComponents") + add_ppoint_data!(pdataset, + name; + type=string_to_VTKDataType[type], + Nc=parse(Int64,Nc)) + end + end + end + + # Generate PCellData + celldata=get_dataset_xml_grid_element(dataset,"CellData") + if celldata!=nothing + if (num_children(celldata)>0) + for child=1:num_children(celldata) + name=get_child_attribute(celldata,child,"Name") + type=get_child_attribute(celldata,child,"type") + Nc=get_child_attribute(celldata,child,"NumberOfComponents") + add_pcell_data!(pdataset, + name; + type=string_to_VTKDataType[type], + Nc=(Nc==nothing ? nothing : parse(Int64,Nc))) + end + end + end + pdataset + end + +end #module diff --git a/test/AlgebraTests/AlgebraInterfacesTests.jl b/test/AlgebraTests/AlgebraInterfacesTests.jl index 629b34db7..2ebb4c9da 100644 --- a/test/AlgebraTests/AlgebraInterfacesTests.jl +++ b/test/AlgebraTests/AlgebraInterfacesTests.jl @@ -1,6 +1,7 @@ module AlgebraInterfacesTests using Gridap.Algebra +using LinearAlgebra using Test a = allocate_vector(Vector{Int},10) @@ -19,7 +20,7 @@ b = allocate_in_range(Vector{Int},a) b = allocate_in_domain(Vector{Int},a) @test length(b) == 6 -fill_entries!(b,4) +fill!(b,4) @test all( b .== 4 ) a = rand(6) @@ -44,7 +45,7 @@ a .-= b a = rand(6) c = copy(a) -scale_entries!(a,10) +rmul!(a,10) @test all( a .== 10*c) a = rand(4,6) @@ -139,7 +140,7 @@ for A in (SparseMatrixCSC{Float64,Int},SparseMatrixCSC{Float64,Int32}) add_entry!(c,nothing,1,1) add_entry!(c,nothing,3,1) add_entry!(c,3.0,4,9) - + a = nz_counter(builder,(rows,cols)) add_entries!(a,[1.0 -1.0; -1.0 1.0],[1,-1],[-1,1]) add_entries!(a,nothing,[1,1],[1,-1]) @@ -188,7 +189,7 @@ for A in (SparseMatrixCSC{Float64,Int},SparseMatrixCSC{Float64,Int32}) add_entry!(c,nothing,1,1) add_entry!(c,nothing,3,1) add_entry!(c,3.0,4,9) - + a = nz_counter(builder,(rows,cols)) add_entries!(a,[1.0 -1.0; -1.0 1.0],[1,-1],[-1,1]) add_entries!(a,nothing,[1,1],[1,-1]) @@ -256,7 +257,7 @@ for A in (SparseMatrixCSR{1,Float64,Int},SparseMatrixCSR{0,Float64,Int32}) add_entry!(c,nothing,1,1) add_entry!(c,nothing,1,3) add_entry!(c,3.0,9,4) - + a = nz_counter(builder,(rows,cols)) add_entries!(a,[1.0 -1.0; -1.0 1.0],[1,-1],[-1,1]) add_entries!(a,nothing,[1,1],[1,-1]) @@ -305,7 +306,7 @@ for A in (SparseMatrixCSR{0,Float64,Int},SparseMatrixCSR{1,Float64,Int32}) add_entry!(c,nothing,1,1) add_entry!(c,nothing,3,1) add_entry!(c,3.0,9,4) - + a = nz_counter(builder,(rows,cols)) add_entries!(a,[1.0 -1.0; -1.0 1.0],[1,-1],[-1,1]) add_entries!(a,nothing,[1,1],[1,-1]) @@ -362,7 +363,7 @@ for A in ( add_entry!(c,3.0,2,2) add_entry!(c,3.0,2,6) add_entry!(c,3.0,6,2) - + a = nz_counter(builder,(rows,cols)) add_entries!(a,[1.0 -1.0; -1.0 1.0],[1,-1],[-1,1]) add_entries!(a,nothing,[1,1],[1,-1]) diff --git a/test/AlgebraTests/SparseMatrixCSCTests.jl b/test/AlgebraTests/SparseMatrixCSCTests.jl index a44beff11..f52364107 100644 --- a/test/AlgebraTests/SparseMatrixCSCTests.jl +++ b/test/AlgebraTests/SparseMatrixCSCTests.jl @@ -56,7 +56,7 @@ for T in (Int32,Int,Float32,Float64) add_entry!(+,CSC,1,maxrows,maxcols) @test getindex(CSC,maxrows,maxcols) == vold+1 - fill_entries!(CSC,0) + LinearAlgebra.fillstored!(CSC,0) @test all(x->x==0, nonzeros(CSC)) end diff --git a/test/AlgebraTests/SparseMatrixCSRTests.jl b/test/AlgebraTests/SparseMatrixCSRTests.jl index e7d7649c8..7aa2a15c5 100644 --- a/test/AlgebraTests/SparseMatrixCSRTests.jl +++ b/test/AlgebraTests/SparseMatrixCSRTests.jl @@ -59,7 +59,7 @@ for Ti in int_types add_entry!(+,CSR,1,maxrows,maxcols) @test getindex(CSR,maxrows,maxcols) == vold+1 - fill_entries!(CSR,0) + LinearAlgebra.fillstored!(CSR,0) @test all(x->x==0, nonzeros(CSR)) end diff --git a/test/AlgebraTests/SymSparseMatrixCSRTests.jl b/test/AlgebraTests/SymSparseMatrixCSRTests.jl index b384206c7..de2e42c55 100644 --- a/test/AlgebraTests/SymSparseMatrixCSRTests.jl +++ b/test/AlgebraTests/SymSparseMatrixCSRTests.jl @@ -57,7 +57,7 @@ for Ti in int_types add_entry!(+,SYMCSR,1,maxrows,maxcols) @test getindex(SYMCSR,maxrows,maxcols) == vold+1 - fill_entries!(SYMCSR,0) + LinearAlgebra.fillstored!(SYMCSR,0) @test all(x->x==0, nonzeros(SYMCSR)) end diff --git a/test/ArraysTests/AppendedArraysTests.jl b/test/ArraysTests/AppendedArraysTests.jl index 026e1e092..b018cc17b 100644 --- a/test/ArraysTests/AppendedArraysTests.jl +++ b/test/ArraysTests/AppendedArraysTests.jl @@ -83,5 +83,12 @@ c2 = CompressedArray([3.0],fill(1,5)) d = lazy_map(evaluate,c1,c2) test_array(d,[3,3,3,-3,-3]) +r1 = [1,2,3,4] +r2 = [5,6] +r = lazy_append(r1,r2) +v = rand(6) +w = lazy_map(Reindex(v),r) +@test isa(w,AppendedArray) +@test w == v[r] end # module diff --git a/test/ArraysTests/PosNegReindexTests.jl b/test/ArraysTests/PosNegReindexTests.jl index c71375104..9c5c65acb 100644 --- a/test/ArraysTests/PosNegReindexTests.jl +++ b/test/ArraysTests/PosNegReindexTests.jl @@ -5,6 +5,10 @@ using Gridap using Gridap.Arrays using Gridap.TensorValues +i_to_iposneg = PosNegPartition(Int32[],Int32(10)) +@test length(i_to_iposneg.ipos_to_i) == 0 +@test length(i_to_iposneg.ineg_to_i) == 10 + for indices in ([1,3,-1,2,-2], PosNegPartition([1,4,2],5)) values_pos = Float64[40,30,10] diff --git a/test/CellDataTests/CellDofsTests.jl b/test/CellDataTests/CellDofsTests.jl index 86d10f86e..5a7951d85 100644 --- a/test/CellDataTests/CellDofsTests.jl +++ b/test/CellDataTests/CellDofsTests.jl @@ -33,8 +33,8 @@ x = get_cell_points(s) vx = v(x) test_array(vx,r) -acell_to_cell = [1,3,5,3] -atrian = Triangulation(trian,acell_to_cell) +acell_to_cell = [1,3,5,2] +atrian = Triangulation(model,acell_to_cell) s_a = change_domain(s,atrian,DomainStyle(s)) v_a = change_domain(v,atrian,DomainStyle(v)) diff --git a/test/CellDataTests/CellFieldsTests.jl b/test/CellDataTests/CellFieldsTests.jl index 0f4f8c925..351c5b43c 100644 --- a/test/CellDataTests/CellFieldsTests.jl +++ b/test/CellDataTests/CellFieldsTests.jl @@ -1,7 +1,6 @@ module CellFieldsTests using Test -using BlockArrays using FillArrays using Gridap.Arrays using Gridap.TensorValues @@ -9,9 +8,8 @@ using Gridap.Fields using Gridap.ReferenceFEs using Gridap.Geometry using Gridap.CellData -using Gridap.FESpaces +#using Gridap.FESpaces using Random -using StaticArrays domain = (0,1,0,1) cells = (3,3) @@ -21,7 +19,13 @@ trian = Triangulation(model) trian_N =BoundaryTriangulation(model) trian_D =BoundaryTriangulation(model,tags="tag_8") trian_S =SkeletonTriangulation(model) -trian_0 =Triangulation(trian_D,Int[]) +trian_0 =Triangulation(model,Int32[]) + +trian_sv = view(trian_S,[1,5,4,2]) +nv = get_normal_vector(trian_sv) +@test isa(nv,SkeletonPair) +@test isa(nv.plus,CellField) +@test isa(nv.minus,CellField) ϕ = GenericCellField(get_cell_map(trian),trian,ReferenceDomain()) ϕinv = GenericCellField(lazy_map(inverse_map,get_cell_map(trian)),trian,PhysicalDomain()) @@ -62,6 +66,11 @@ test_array(fx_0,collect(fx_0)) n_S = get_normal_vector(trian_S) x_S = get_cell_points(trian_S) +ts = get_triangulation(∇(f)) +tt = get_triangulation(n_S.plus) + +@test is_change_possible(ts,tt) == true + nf_S = n_S⋅∇(f) jnf_S = jump(n_S⋅∇(f)) @@ -194,250 +203,4 @@ h_N = (2*f_N+g)⋅g hx_N = h_N(x_N) test_array(hx_N,collect(hx_N)) -# Test function evaluation - -# Set reproducible random number seed -Random.seed!(0) -@testset "evaluating functions" for D in 1:3 - xmin = 0 - xmax = 1 - domain = repeat([xmin, xmax], D) - ncells = 3 - partition = repeat([ncells], D) - base_model = CartesianDiscreteModel(domain, partition) - order = 2 - reffe = ReferenceFE(lagrangian, Float64, order) - - for M ∈ [:hypercubes, :simplices] - model = (M == :hypercubes) ? base_model : simplexify(base_model) - - V = FESpace(model, reffe) - - coeff0 = rand(Float64) - coeffs = rand(SVector{D,Float64}) - f(x) = coeffs ⋅ SVector(Tuple(x)) + coeff0 - # TODO: use this mechanism instead to project - # Francesc Verdugo @fverdugo 13:11 - # a(u,v) = ∫( u*v )dΩ - # l(v) = a(f,v) - # Solve a fe problem with this weak form - # See also tutorial 10, "Isotropic damage model", section "L2 - # projection", function "project" - fh = interpolate_everywhere(f, V) - fhcache = return_cache(fh, VectorValue(zeros(D)...)) - - # Test Random points - xs = [VectorValue(rand(D)...) for i in 1:10] - for x in xs - x = VectorValue(rand(D)...) - fx = f(x) - fhx = evaluate!(fhcache, fh, x) - @test fhx ≈ fx - end - fhxs = fh(xs) - @test fhxs ≈ f.(xs) - - nv = num_vertices(model) # Number of vertices - nf = num_faces(model,D-1) # Number of faces - trian = Triangulation(model) - topo = GridTopology(model) - - pts = get_vertex_coordinates(topo) # Vertex coordinates - face_nodes = get_face_nodes(model, D-1) # face-to-node numbering - face_coords = lazy_map(Broadcasting(Reindex(pts)), face_nodes) # Get LazyArray of coordinates of face - - # Test a random vertex from the triangulation - pt = pts[rand(1:nv)] - fhpt = evaluate!(fhcache, fh, pt) - @test fhpt .≈ f(pt) - - # Test a random point lying on the face of the polytope - face_coord = face_coords[rand(1:nf)] - λ = rand(length(face_coord)); - λ = (D > 1) ? λ./sum(λ) : λ - pt = face_coord ⋅ λ # Point on the face - fhpt = evaluate!(fhcache, fh, pt) - @test fhpt .≈ f(pt) - - # Test with CellPoint - # Build cell_to_fxs manually - cache1,cache2 = fhcache - ncells = num_cells(model) - x_to_cell(x) = CellData._point_to_cell!(cache1, x) - point_to_cell = map(x_to_cell, xs) - cell_to_points, point_to_lpoint = make_inverse_table(point_to_cell, ncells) - cell_to_xs = lazy_map(Broadcasting(Reindex(xs)), cell_to_points) - cell_to_f = get_array(fh) - cell_to_fxs = lazy_map(evaluate, cell_to_f, cell_to_xs) - - # Now build CellPoint with xs instead of building cell_to_xs - cell_point_xs = compute_cell_points_from_vector_of_points(xs, trian, PhysicalDomain()) - cell_point_fxs = evaluate(fh, cell_point_xs) - @test cell_point_fxs ≈ cell_to_fxs - - end -end - -p = QUAD -D = num_dims(QUAD) -et = Float64 -source_model = CartesianDiscreteModel((0,1,0,1),(2,2)) - -@testset "Test interpolation Lagrangian" begin - # Lagrangian space -> Lagrangian space - f(x) = x[1] + x[2] - reffe = LagrangianRefFE(et, p, 1) - V₁ = FESpace(source_model, reffe, conformity=:H1) - fh = interpolate_everywhere(f, V₁) - # Target Lagrangian Space - reffe = LagrangianRefFE(et, p, 2) - model = CartesianDiscreteModel((0,1,0,1),(4,4)) - V₂ = FESpace(model, reffe, conformity=:H1) - - ifh = Interpolable(fh) - try - interpolate_everywhere(fh, V₂) - catch - gh = interpolate_everywhere(ifh, V₂) - pts = [VectorValue(rand(2)) for i=1:10] - for pt in pts - @test gh(pt) ≈ fh(pt) - end - end - - # VectorValued Lagrangian - fᵥ(x) = VectorValue([x[1], x[1]+x[2]]) - reffe = ReferenceFE(lagrangian, VectorValue{2,et}, 1) - V₁ = FESpace(source_model, reffe, conformity=:H1) - fh = interpolate_everywhere(fᵥ, V₁) - # Target - reffe = ReferenceFE(lagrangian, VectorValue{2,et}, 2) - V₂ = FESpace(model, reffe, conformity=:H1) - - ifh = Interpolable(fh); - gh = interpolate_everywhere(ifh, V₂) - pts = [VectorValue(rand(2)) for i=1:10] - for pt in pts - @test gh(pt) ≈ fh(pt) - end -end - -@testset "Test interpolation RT" begin - # RT Space -> RT Space - f(x) = VectorValue([x[1], x[2]]) - reffe = RaviartThomasRefFE(et, p, 0) - V₁ = FESpace(source_model, reffe, conformity=:HDiv) - fh = interpolate_everywhere(f, V₁); - # Target RT Space - reffe = RaviartThomasRefFE(et, p, 1) - model = CartesianDiscreteModel((0,1,0,1),(40,40)) - V₂ = FESpace(model, reffe, conformity=:HDiv) - - ifh = Interpolable(fh) - gh = interpolate_everywhere(ifh, V₂) - pts = [VectorValue(rand(2)) for i=1:10] - for pt in pts - @test gh(pt) ≈ fh(pt) - end -end - - -#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) -# -#zfr = reindex(zf,[1,4,3]) -#@test length(zfr) == 3 -#@test length(get_array(zfr)) == 3 -#@test length(get_cell_map(zfr)) == 3 -#@test length(get_cell_axes(zfr)) == 3 -# -## 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.plus,xl) -#afR_x = evaluate(afS.minus,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 index e96fab4c0..af54be951 100644 --- a/test/CellDataTests/CellQuadraturesTests.jl +++ b/test/CellDataTests/CellQuadraturesTests.jl @@ -62,7 +62,7 @@ s = ∫( x->1 )*quad_N @test ∑(s) ≈ 6 cell_measure = get_cell_measure(trian) -cell_measure_N = get_cell_measure(trian_N) +cell_measure_N = get_cell_measure(trian_N,trian) @test length(cell_measure) == num_cells(model) @test length(cell_measure_N) == num_cells(model) @test sum(cell_measure) ≈ 1 diff --git a/test/FESpacesTests/AppendedTriangulationsTests.jl b/test/FESpacesTests/AppendedTriangulationsTests.jl index 6931f4345..4c5885d36 100644 --- a/test/FESpacesTests/AppendedTriangulationsTests.jl +++ b/test/FESpacesTests/AppendedTriangulationsTests.jl @@ -20,10 +20,8 @@ nin = ceil(Int,2*ncells/3) cell_to_mask = fill(false,ncells) cell_to_mask[1:nin] .= true -grid = get_grid(model) - -Ω_in = RestrictedTriangulation(grid,cell_to_mask) -Ω_out = RestrictedTriangulation(grid,.! cell_to_mask) +Ω_in = Triangulation(model,cell_to_mask) +Ω_out = Triangulation(model,.! cell_to_mask) Ω = lazy_append(Ω_out,Ω_in) test_triangulation(Ω) diff --git a/test/FESpacesTests/AssemblersTests.jl b/test/FESpacesTests/AssemblersTests.jl index 1e2bee7f8..e5dd9c30a 100644 --- a/test/FESpacesTests/AssemblersTests.jl +++ b/test/FESpacesTests/AssemblersTests.jl @@ -140,4 +140,35 @@ A,b = assemble_matrix_and_vector(assem,data) x = A\b @test x ≈ b + +mutable struct MyArrayCounter + count + MyArrayCounter()=new(0) +end +function Algebra.LoopStyle(::Type{<:MyArrayCounter}) + Loop() +end + +function Algebra.add_entry!(c::Function,a::MyArrayCounter,v,i,j) + a.count=a.count+1 +end +function Algebra.add_entry!(c::Function,a::MyArrayCounter,v,i) + a.count=a.count+1 +end +function Algebra.add_entries!(c::Function,a::MyArrayCounter,v,i,j) + a.count=a.count+length(i) +end +function Algebra.add_entries!(c::Function,a::MyArrayCounter,v,i) + a.count=a.count+length(i) +end + +mac=MyArrayCounter() +vec_contribs = ∫(1*dv)*dΩ +data = collect_cell_vector(V,vec_contribs) +symbolic_loop_vector!(mac,assem,data) +@test mac.count == num_cells(Ω)*4 + + + + end # module diff --git a/test/FESpacesTests/CLagrangianFESpacesTests.jl b/test/FESpacesTests/CLagrangianFESpacesTests.jl index 5041e1cb6..2f3d274c5 100644 --- a/test/FESpacesTests/CLagrangianFESpacesTests.jl +++ b/test/FESpacesTests/CLagrangianFESpacesTests.jl @@ -10,14 +10,15 @@ using Gridap.CellData domain = (0,1,0,1) partition = (2,2) -grid = CartesianGrid(domain,partition) +model = CartesianDiscreteModel(domain,partition) +grid = Triangulation(model) x = collect1d(get_node_coordinates(grid)) V = CLagrangianFESpace(Float64,grid) -matvecdata = ([],[],[]) -matdata = ([],[],[]) -vecdata = ([],[]) -test_single_field_fe_space(V,matvecdata,matdata,vecdata) +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) +test_single_field_fe_space(V,cellmatvec,cellmat,cellvec,grid) @test get_cell_dof_ids(V) == collect1d(get_cell_node_ids(grid)) @test V.metadata.free_dof_to_node == collect(1:num_nodes(grid)) @@ -31,7 +32,10 @@ ux = u.(x) @test uhx ≈ ux V = CLagrangianFESpace(VectorValue{2,Float64},grid) -test_single_field_fe_space(V,matvecdata,matdata,vecdata) +cellmat = [rand(8,8) for cell in 1:num_cells(model)] +cellvec = [rand(8) for cell in 1:num_cells(model)] +cellmatvec = pair_arrays(cellmat,cellvec) +test_single_field_fe_space(V,cellmatvec,cellmat,cellvec,grid) @test get_cell_dof_ids(V) == [[1,3,7,9,2,4,8,10], [3,5,9,11,4,6,10,12], [7,9,13,15,8,10,14,16], [9,11,15,17,10,12,16,18]] @test V.metadata.free_dof_to_node == [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9] @@ -45,7 +49,7 @@ ux = u.(x) @test uhx ≈ collect1d(reinterpret(ux)) model = CartesianDiscreteModel(domain,partition) -grid = get_grid(model) +grid = Triangulation(model) labels = get_face_labeling(model) tags = [1,2,4,5,8] node_to_tag = get_face_tag_index(labels,tags,0) diff --git a/test/FESpacesTests/CellFieldsTests.jl b/test/FESpacesTests/CellFieldsTests.jl new file mode 100644 index 000000000..97038eb13 --- /dev/null +++ b/test/FESpacesTests/CellFieldsTests.jl @@ -0,0 +1,165 @@ +module CellFieldsTests2 + +using Test +using BlockArrays +using FillArrays +using Gridap.Arrays +using Gridap.TensorValues +using Gridap.Fields +using Gridap.ReferenceFEs +using Gridap.Geometry +using Gridap.CellData +using Gridap.FESpaces +using Random +using StaticArrays + +# Test function evaluation + +# Set reproducible random number seed +Random.seed!(0) +@testset "evaluating functions" for D in 1:3 + xmin = 0 + xmax = 1 + domain = repeat([xmin, xmax], D) + ncells = 3 + partition = repeat([ncells], D) + base_model = CartesianDiscreteModel(domain, partition) + order = 2 + reffe = ReferenceFE(lagrangian, Float64, order) + + for M ∈ [:hypercubes, :simplices] + model = (M == :hypercubes) ? base_model : simplexify(base_model) + + V = FESpace(model, reffe) + + coeff0 = rand(Float64) + coeffs = rand(SVector{D,Float64}) + f(x) = coeffs ⋅ SVector(Tuple(x)) + coeff0 + # TODO: use this mechanism instead to project + # Francesc Verdugo @fverdugo 13:11 + # a(u,v) = ∫( u*v )dΩ + # l(v) = a(f,v) + # Solve a fe problem with this weak form + # See also tutorial 10, "Isotropic damage model", section "L2 + # projection", function "project" + fh = interpolate_everywhere(f, V) + fhcache = return_cache(fh, VectorValue(zeros(D)...)) + + # Test Random points + xs = [VectorValue(rand(D)...) for i in 1:10] + for x in xs + x = VectorValue(rand(D)...) + fx = f(x) + fhx = evaluate!(fhcache, fh, x) + @test fhx ≈ fx + end + fhxs = fh(xs) + @test fhxs ≈ f.(xs) + + nv = num_vertices(model) # Number of vertices + nf = num_faces(model,D-1) # Number of faces + trian = Triangulation(model) + topo = GridTopology(model) + + pts = get_vertex_coordinates(topo) # Vertex coordinates + face_nodes = get_face_nodes(model, D-1) # face-to-node numbering + face_coords = lazy_map(Broadcasting(Reindex(pts)), face_nodes) # Get LazyArray of coordinates of face + + # Test a random vertex from the triangulation + pt = pts[rand(1:nv)] + fhpt = evaluate!(fhcache, fh, pt) + @test fhpt .≈ f(pt) + + # Test a random point lying on the face of the polytope + face_coord = face_coords[rand(1:nf)] + λ = rand(length(face_coord)); + λ = (D > 1) ? λ./sum(λ) : λ + pt = face_coord ⋅ λ # Point on the face + fhpt = evaluate!(fhcache, fh, pt) + @test fhpt .≈ f(pt) + + # Test with CellPoint + # Build cell_to_fxs manually + cache1,cache2 = fhcache + ncells = num_cells(model) + x_to_cell(x) = CellData._point_to_cell!(cache1, x) + point_to_cell = map(x_to_cell, xs) + cell_to_points, point_to_lpoint = make_inverse_table(point_to_cell, ncells) + cell_to_xs = lazy_map(Broadcasting(Reindex(xs)), cell_to_points) + cell_to_f = get_array(fh) + cell_to_fxs = lazy_map(evaluate, cell_to_f, cell_to_xs) + + # Now build CellPoint with xs instead of building cell_to_xs + cell_point_xs = compute_cell_points_from_vector_of_points(xs, trian, PhysicalDomain()) + cell_point_fxs = evaluate(fh, cell_point_xs) + @test cell_point_fxs ≈ cell_to_fxs + + end +end + +p = QUAD +D = num_dims(QUAD) +et = Float64 +source_model = CartesianDiscreteModel((0,1,0,1),(2,2)) + +@testset "Test interpolation Lagrangian" begin + # Lagrangian space -> Lagrangian space + f(x) = x[1] + x[2] + reffe = LagrangianRefFE(et, p, 1) + V₁ = FESpace(source_model, reffe, conformity=:H1) + fh = interpolate_everywhere(f, V₁) + # Target Lagrangian Space + reffe = LagrangianRefFE(et, p, 2) + model = CartesianDiscreteModel((0,1,0,1),(4,4)) + V₂ = FESpace(model, reffe, conformity=:H1) + + ifh = Interpolable(fh) + try + interpolate_everywhere(fh, V₂) + catch + gh = interpolate_everywhere(ifh, V₂) + pts = [VectorValue(rand(2)) for i=1:10] + for pt in pts + @test gh(pt) ≈ fh(pt) + end + end + + # VectorValued Lagrangian + fᵥ(x) = VectorValue([x[1], x[1]+x[2]]) + reffe = ReferenceFE(lagrangian, VectorValue{2,et}, 1) + V₁ = FESpace(source_model, reffe, conformity=:H1) + fh = interpolate_everywhere(fᵥ, V₁) + # Target + reffe = ReferenceFE(lagrangian, VectorValue{2,et}, 2) + V₂ = FESpace(model, reffe, conformity=:H1) + + ifh = Interpolable(fh); + gh = interpolate_everywhere(ifh, V₂) + pts = [VectorValue(rand(2)) for i=1:10] + for pt in pts + @test gh(pt) ≈ fh(pt) + end +end + +@testset "Test interpolation RT" begin + # RT Space -> RT Space + f(x) = VectorValue([x[1], x[2]]) + reffe = RaviartThomasRefFE(et, p, 0) + V₁ = FESpace(source_model, reffe, conformity=:HDiv) + fh = interpolate_everywhere(f, V₁); + # Target RT Space + reffe = RaviartThomasRefFE(et, p, 1) + model = CartesianDiscreteModel((0,1,0,1),(40,40)) + V₂ = FESpace(model, reffe, conformity=:HDiv) + + ifh = Interpolable(fh) + gh = interpolate_everywhere(ifh, V₂) + pts = [VectorValue(rand(2)) for i=1:10] + for pt in pts + @test gh(pt) ≈ fh(pt) + end +end + + +end # module + diff --git a/test/FESpacesTests/ConformingFESpacesTests.jl b/test/FESpacesTests/ConformingFESpacesTests.jl index e9d60297d..0af561288 100644 --- a/test/FESpacesTests/ConformingFESpacesTests.jl +++ b/test/FESpacesTests/ConformingFESpacesTests.jl @@ -83,12 +83,15 @@ V = FESpace(model,reffe,dirichlet_tags=dirichlet_tags) test_single_field_fe_space(V) -matvecdata = ([],[],[]) -matdata = ([],[],[]) -vecdata = ([],[]) -test_single_field_fe_space(V,matvecdata,matdata,vecdata) +matvecdata = [] +matdata = [] +vecdata = [] +test_single_field_fe_space(V,matvecdata,matdata,vecdata,trian) V = FESpace(model,reffe,dirichlet_tags=dirichlet_tags,dirichlet_masks=dirichlet_components) test_single_field_fe_space(V) +V = FESpace(trian,reffe,dirichlet_tags=dirichlet_tags,dirichlet_masks=dirichlet_components) +test_single_field_fe_space(V) + end # module diff --git a/test/FESpacesTests/DirichletFESpacesTests.jl b/test/FESpacesTests/DirichletFESpacesTests.jl index c9ce09be3..ffaea4a06 100644 --- a/test/FESpacesTests/DirichletFESpacesTests.jl +++ b/test/FESpacesTests/DirichletFESpacesTests.jl @@ -1,6 +1,7 @@ module DirichletFESpacesTests using Test +using Gridap.Arrays using Gridap.Algebra using Gridap.Geometry using Gridap.FESpaces @@ -13,6 +14,7 @@ domain = (0,1,0,1) order = 1 dirichlet_tags = [1,3,4,6,7] model = CartesianDiscreteModel(domain, mesh) +Ω = Triangulation(model) labels = get_face_labeling(model) add_tag_from_tags!(labels,"dirichlet",dirichlet_tags) @@ -20,15 +22,15 @@ reffe = ReferenceFE(lagrangian,Float64,order) Vf = TestFESpace( model,reffe; conformity=:H1, labels=labels, dirichlet_tags="dirichlet") Vd = DirichletFESpace(Vf) -matvecdata = ([],[],[]) -matdata = ([],[],[]) -vecdata = ([],[]) -test_single_field_fe_space(Vd,matvecdata,matdata,vecdata) +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) +test_single_field_fe_space(Vd,cellmatvec,cellmat,cellvec,Ω) Uf = TrialFESpace(Vf,1) Ud = TrialFESpace(Vd) -test_single_field_fe_space(Ud,matvecdata,matdata,vecdata) +test_single_field_fe_space(Ud,cellmatvec,cellmat,cellvec,Ω) trian = Triangulation(model) degree = 2*order diff --git a/test/FESpacesTests/DivConformingFESpacesTests.jl b/test/FESpacesTests/DivConformingFESpacesTests.jl index f99b5a47b..b8c0dc8c9 100644 --- a/test/FESpacesTests/DivConformingFESpacesTests.jl +++ b/test/FESpacesTests/DivConformingFESpacesTests.jl @@ -123,11 +123,11 @@ domain = (0,1,0,1,0,1) cells = (2,2,2) model = CartesianDiscreteModel(domain,cells) -# Restrict model to cube surface (using new BoundaryDiscreteModel) +# Restrict model to cube surface labels = get_face_labeling(model) bgface_to_mask = get_face_mask(labels,"boundary",2) Γface_to_bgface = findall(bgface_to_mask) -Dc2Dp3model = BoundaryDiscreteModel(Polytope{2},model,Γface_to_bgface) +Dc2Dp3model = DiscreteModelPortion(DiscreteModel(Polytope{2},model),Γface_to_bgface) order = 0 degree = 1 diff --git a/test/FESpacesTests/ExtendedFESpacesTests.jl b/test/FESpacesTests/ExtendedFESpacesTests.jl index 3475e1097..235fd9d7f 100644 --- a/test/FESpacesTests/ExtendedFESpacesTests.jl +++ b/test/FESpacesTests/ExtendedFESpacesTests.jl @@ -16,7 +16,7 @@ domain = (0,1,0,1) .- 1 order = 1 model = CartesianDiscreteModel(domain, mesh) -trian = Triangulation(model) +Ω = Triangulation(model) const R = 0.7 @@ -27,28 +27,24 @@ function is_in(coords) d < 0 end -oldcell_to_coods = get_cell_coordinates(trian) +oldcell_to_coods = get_cell_coordinates(Ω) oldcell_to_is_in = collect1d(lazy_map(is_in,oldcell_to_coods)) -model_in = DiscreteModel(model,oldcell_to_is_in) -@test isa(model_in,RestrictedDiscreteModel) +Ω_in = Triangulation(model,oldcell_to_is_in) +@test isa(Ω_in,BodyFittedTriangulation) -@test trian === get_triangulation(get_parent_model(model_in)) +@test model === get_background_model(Ω_in) -V = TestFESpace(model_in,ReferenceFE(lagrangian,Float64,order),conformity=:H1) -@test isa(V,FESpaces.ExtendedFESpace) +V = TestFESpace(Ω_in,ReferenceFE(lagrangian,Float64,order),conformity=:H1) test_single_field_fe_space(V) U = TrialFESpace(V) test_single_field_fe_space(U) oldcell_to_is_out = lazy_map(!,oldcell_to_is_in) -model_out = DiscreteModel(model,oldcell_to_is_out) +Ω_out = Triangulation(model,oldcell_to_is_out) -Ω = Triangulation(model) -Ω_in = Triangulation(model_in) -Ω_out = Triangulation(model_out) -Γ = InterfaceTriangulation(model_in,model_out) +Γ = InterfaceTriangulation(Ω_in,Ω_out) degree = 2 dΩ = Measure(Ω,degree) @@ -141,18 +137,16 @@ l(v) = op = AffineFEOperator(a,l,U,V) -V = TestFESpace(model_in,ReferenceFE(lagrangian,Float64,2),conformity=:H1) -@test isa(V,FESpaces.ExtendedFESpace) +V = TestFESpace(Ω_in,ReferenceFE(lagrangian,Float64,2),conformity=:H1) -V = TestFESpace(model_in,ReferenceFE(lagrangian,Float64,2),conformity=:H1,constraint=:zeromean) +V = TestFESpace(Ω_in,ReferenceFE(lagrangian,Float64,2),conformity=:H1,constraint=:zeromean) uh = FEFunction(V,rand(num_free_dofs(V))) @test sum(∫(uh)*dΩ_in) + 1 ≈ 1 -V = TestFESpace(model,ReferenceFE(lagrangian,Float64,2),conformity=:H1) -@test !isa(V,FESpaces.ExtendedFESpace) +V = TestFESpace(Ω,ReferenceFE(lagrangian,Float64,2),conformity=:H1) -V_in = TestFESpace(model_in,ReferenceFE(lagrangian,Float64,2),conformity=:H1) -V = TestFESpace(model,ReferenceFE(lagrangian,Float64,2),conformity=:H1) +V_in = TestFESpace(Ω_in,ReferenceFE(lagrangian,Float64,2),conformity=:H1) +V = TestFESpace(Ω,ReferenceFE(lagrangian,Float64,2),conformity=:H1) vh_in = interpolate(V_in) do x x[1] @@ -161,7 +155,7 @@ 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]) +#writevtk(Ω,"Ω",cellfields=["vh"=>vh,"vh_in"=>vh_in]) end # module diff --git a/test/FESpacesTests/FESolversTests.jl b/test/FESpacesTests/FESolversTests.jl index 694592677..4c7a60591 100644 --- a/test/FESpacesTests/FESolversTests.jl +++ b/test/FESpacesTests/FESolversTests.jl @@ -30,12 +30,11 @@ u = get_trial_fe_basis(U) cellmat = integrate(∇(v)⊙∇(u),quad) cellvec = integrate(v⊙f,quad) -cellids = collect(1:num_cells(trian)) -rows = get_cell_dof_ids(V,cellids) -cols = get_cell_dof_ids(U,cellids) -cellmat_c = attach_constraints_cols(U,cellmat,cellids) -cellmat_rc = attach_constraints_rows(V,cellmat_c,cellids) -cellvec_r = attach_constraints_rows(V,cellvec,cellids) +rows = get_cell_dof_ids(V,trian) +cols = get_cell_dof_ids(U,trian) +cellmat_c = attach_constraints_cols(U,cellmat,trian) +cellmat_rc = attach_constraints_rows(V,cellmat_c,trian) +cellvec_r = attach_constraints_rows(V,cellvec,trian) assem = SparseMatrixAssembler(U,V) matdata = ([cellmat_rc],[rows],[cols]) diff --git a/test/FESpacesTests/FESpaceFactoriesTests.jl b/test/FESpacesTests/FESpaceFactoriesTests.jl index 68e923656..759cafe9a 100644 --- a/test/FESpacesTests/FESpaceFactoriesTests.jl +++ b/test/FESpacesTests/FESpaceFactoriesTests.jl @@ -8,7 +8,6 @@ using Gridap.TensorValues using Gridap.ReferenceFEs using Gridap.FESpaces using Gridap.CellData -using Gridap.FESpaces: ExtendedFESpace domain = (0,1,0,1) partition = (10,10) @@ -92,57 +91,73 @@ end Ω = Triangulation(model) cell_coords = get_cell_coordinates(Ω) cell_mask = lazy_map(is_in,cell_coords) -model_in = DiscreteModel(model,cell_mask) +Ω_in = Triangulation(model,cell_mask) # From a single reffe -V = FESpace(model_in,QUAD4) -@test isa(V,ExtendedFESpace) +V = FESpace(Ω_in,QUAD4) +@test isa(V,UnconstrainedFESpace) -V = FESpace(model_in,QUAD4,conformity=:L2) -@test isa(V,ExtendedFESpace) +V = FESpace(Ω_in,QUAD4,conformity=:L2) +@test isa(V,UnconstrainedFESpace) -V = FESpace(model_in,QUAD4,conformity=:L2,constraint=:zeromean) +V = FESpace(Ω_in,QUAD4,conformity=:L2,constraint=:zeromean) @test isa(V,ZeroMeanFESpace) # From parameter list describing the reffe reffe = ReferenceFE(lagrangian,Float64,order) -V = FESpace(model_in,reffe) -@test isa(V,ExtendedFESpace) +V = FESpace(Ω_in,reffe) +@test isa(V,UnconstrainedFESpace) -V = FESpace(model_in,reffe,conformity=:L2) -@test isa(V,ExtendedFESpace) +V = FESpace(Ω_in,reffe,conformity=:L2) +@test isa(V,UnconstrainedFESpace) -V = FESpace(model_in,reffe,conformity=:L2,constraint=:zeromean) +V = FESpace(Ω_in,reffe,conformity=:L2,constraint=:zeromean) @test isa(V,ZeroMeanFESpace) # From a cell-wise vector of reffes +model_in = get_active_model(Ω_in) cell_reffe = ReferenceFE(model_in,lagrangian,Float64,order) -V = FESpace(model_in,cell_reffe) -@test isa(V,ExtendedFESpace) +V = FESpace(model_in,cell_reffe,trian=Ω_in) +@test isa(V,UnconstrainedFESpace) +@test Ω_in === get_triangulation(V) -V = FESpace(model_in,cell_reffe,conformity=:L2) -@test isa(V,ExtendedFESpace) +V = FESpace(model_in,cell_reffe,trian=Ω_in,conformity=:L2) +@test isa(V,UnconstrainedFESpace) +@test Ω_in === get_triangulation(V) -V = FESpace(model_in,cell_reffe,conformity=:L2,constraint=:zeromean) +V = FESpace(model_in,cell_reffe,trian=Ω_in,conformity=:L2,constraint=:zeromean) @test isa(V,ZeroMeanFESpace) +@test Ω_in === get_triangulation(V) # From a CellFE cell_fe = FiniteElements(PhysicalDomain(),model_in,lagrangian,Float64,order) -V = FESpace(model_in,cell_fe) -@test isa(V,ExtendedFESpace) +V = FESpace(model_in,cell_fe,trian=Ω_in) +@test isa(V,UnconstrainedFESpace) +@test Ω_in === get_triangulation(V) cell_fe = FiniteElements(PhysicalDomain(),model_in,lagrangian,Float64,order,conformity=:L2) -V = FESpace(model_in,cell_fe) -@test isa(V,ExtendedFESpace) +V = FESpace(model_in,cell_fe,trian=Ω_in) +@test isa(V,UnconstrainedFESpace) +@test Ω_in === get_triangulation(V) -V = FESpace(model_in,cell_fe,constraint=:zeromean) +V = FESpace(model_in,cell_fe,trian=Ω_in,constraint=:zeromean) @test isa(V,ZeroMeanFESpace) +@test Ω_in === get_triangulation(V) + +Γ = Boundary(model) +reffe = ReferenceFE(lagrangian,Float64,1) +V = FESpace(Γ,reffe) +@test get_triangulation(V) === Γ +V = FESpace(Γ,reffe,conformity=:H1) +@test get_triangulation(V) === Γ +V = FESpace(Γ,reffe,conformity=:L2) +@test get_triangulation(V) === Γ end # module diff --git a/test/FESpacesTests/FESpacesInterfacesTests.jl b/test/FESpacesTests/FESpacesInterfacesTests.jl index dfbe78b1a..80e801e6f 100644 --- a/test/FESpacesTests/FESpacesInterfacesTests.jl +++ b/test/FESpacesTests/FESpacesInterfacesTests.jl @@ -28,6 +28,8 @@ test_fe_function(vh) dv = get_fe_basis(V) du = get_trial_fe_basis(V) +Ω = Triangulation(model) +∂Ω = BoundaryTriangulation(model) trian_Γ = SkeletonTriangulation(model) x_Γ = get_cell_points(trian_Γ) @@ -36,14 +38,12 @@ x_Γ = get_cell_points(trian_Γ) @test isa(∇(dv).plus(x_Γ)[1],ArrayBlock) @test isa(∇(du).minus(x_Γ)[1],ArrayBlock) -cellids = [1,3,5,2] -cell_vals = get_cell_dof_values(vh,cellids) +glue = get_glue(∂Ω,Val(num_cell_dims(model))) +cellids = glue.tface_to_mface +cell_vals = get_cell_dof_values(vh,∂Ω) @test cell_vals == get_cell_dof_values(vh)[cellids] -cellidsL = cellids -cellidsR = [2,4,3,1] -cellidsS = SkeletonPair(cellidsL,cellidsR) -cell_vals = get_cell_dof_values(vh,cellidsS) +cell_vals = get_cell_dof_values(vh,trian_Γ) @test isa(cell_vals[1],ArrayBlock) zh = zero(V) @@ -51,42 +51,36 @@ zh = zero(V) @test has_constraints(V) == false cellids = [1,3,5,2] -@test get_cell_dof_ids(V,cellids) == [[-1, 1, 4, 5], [2, 3, 6, 7], [5, 6, 9, 10], [1, 2, 5, 6]] +Ω1 = Triangulation(model,cellids) +@test get_cell_dof_ids(V,Ω1) == [[-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_dof_ids(V,cellidsS)[1],ArrayBlock) -@test get_cell_dof_ids(V,cellidsS)[1][1] == [-1, 1, 4, 5] -@test get_cell_dof_ids(V,cellidsS)[1][2] == [1, 2, 5, 6] +@test isa(get_cell_dof_ids(V,trian_Γ)[1],ArrayBlock) +@test get_cell_dof_ids(V,trian_Γ)[1][1] == [-1, 1, 4, 5] +@test get_cell_dof_ids(V,trian_Γ)[1][2] == [4, 5, 8, 9] 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) +cell_constr = get_cell_constraints(V,Ω1) @test cell_constr == [Matrix(I,4,4) for cell in 1:length(cellids)] -@test get_cell_isconstrained(V,cellids) == Fill(false,length(cellids)) +@test get_cell_isconstrained(V,Ω1) == Fill(false,length(cellids)) -cell_constr = get_cell_constraints(V,cellidsS) +cell_constr = get_cell_constraints(V,trian_Γ) @test isa(cell_constr[1],ArrayBlock) du = get_trial_fe_basis(V) du_data = get_data(du) @test size(du_data[1]) == (1,4) -@test get_cell_isconstrained(V,cellidsS) == Fill(false,length(cellids)) +@test get_cell_isconstrained(V,trian_Γ) == Fill(false,num_cells(trian_Γ)) 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 = IdentityVector(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) + +@test cellmat === attach_constraints_rows(V,cellmat,Ω) +@test cellmat === attach_constraints_cols(V,cellmat,Ω) +test_fe_space(V,cellmatvec,cellmat,cellvec,Ω) end # module diff --git a/test/FESpacesTests/FESpacesWithLinearConstraintsTests.jl b/test/FESpacesTests/FESpacesWithLinearConstraintsTests.jl index 528bf7691..662e5f72b 100644 --- a/test/FESpacesTests/FESpacesWithLinearConstraintsTests.jl +++ b/test/FESpacesTests/FESpacesWithLinearConstraintsTests.jl @@ -18,6 +18,13 @@ labels = get_face_labeling(model) add_tag_from_tags!(labels,"dirichlet",[1,2,5]) add_tag_from_tags!(labels,"neumann",[6,7,8]) +Ω = Triangulation(model) +Γ = BoundaryTriangulation(model,tags="neumann") +Λ = SkeletonTriangulation(model) +dΩ = Measure(Ω,2) +dΓ = Measure(Γ,2) +dΛ = Measure(Λ,2) + V = FESpace( model,ReferenceFE(lagrangian,Float64,1), conformity=:H1, dirichlet_tags="dirichlet") test_single_field_fe_space(V) @@ -39,8 +46,7 @@ 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],ArrayBlock) +@test isa(get_cell_constraints(Vc,Λ)[1],ArrayBlock) @test Vc.n_fdofs == 6 @test Vc.n_fmdofs == 4 @@ -54,12 +60,6 @@ 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, v(x) = sin(4*x[1]+0.4)*cos(5*x[2]+0.7) vch = interpolate(v,Vc) -Ω = Triangulation(model) -Γ = BoundaryTriangulation(model,tags="neumann") -Λ = SkeletonTriangulation(model) -dΩ = Measure(Ω,2) -dΓ = Measure(Γ,2) -dΛ = Measure(Λ,2) #using Gridap.Visualization #writevtk(Ω,"trian",nsubcells=10,cellfields=["vh"=>vh,"vch"=>vch]) diff --git a/test/FESpacesTests/SingleFieldFESpacesTests.jl b/test/FESpacesTests/SingleFieldFESpacesTests.jl index 570f67b85..e0f3b63fc 100644 --- a/test/FESpacesTests/SingleFieldFESpacesTests.jl +++ b/test/FESpacesTests/SingleFieldFESpacesTests.jl @@ -11,15 +11,16 @@ using Gridap.FESpaces domain =(0,1,0,1,0,1) partition = (3,3,3) model = CartesianDiscreteModel(domain,partition) +Ω = Triangulation(model) order = 2 reffe = ReferenceFE(lagrangian,Float64,order) V0 = FESpace(model,reffe,dirichlet_tags=["tag_24","tag_25"]) -matvecdata = ([],[],[]) -matdata = ([],[],[]) -vecdata = ([],[]) -test_single_field_fe_space(V0,matvecdata,matdata,vecdata) +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) +test_single_field_fe_space(V0,cellmatvec,cellmat,cellvec,Ω) f(x) = sin(4*pi*(x[1]-x[2]^2))+1 @@ -51,7 +52,6 @@ f_real(x) = real(f(x)) f_imag(x) = imag(f(x)) f_conj(x) = conj(f(x)) -Ω = Triangulation(model) dΩ = Measure(Ω,2) tol = 1e-9 diff --git a/test/FESpacesTests/SparseMatrixAssemblersTests.jl b/test/FESpacesTests/SparseMatrixAssemblersTests.jl index b0a6cc49d..cef4dcfe6 100644 --- a/test/FESpacesTests/SparseMatrixAssemblersTests.jl +++ b/test/FESpacesTests/SparseMatrixAssemblersTests.jl @@ -33,45 +33,42 @@ quad = CellQuadrature(trian,degree) btrian = BoundaryTriangulation(model) bquad = CellQuadrature(btrian,degree) -b0trian = Triangulation(btrian,Int[]) +b0trian = Triangulation(model,Int[]) b0quad = CellQuadrature(b0trian,degree) cellmat = integrate(∇(v)⊙∇(u),quad) cellvec = integrate(v⊙b,quad) cellmatvec = pair_arrays(cellmat,cellvec) -cellids = collect(1:num_cells(trian)) -rows = get_cell_dof_ids(V,cellids) -cols = get_cell_dof_ids(U,cellids) -cellmat_c = attach_constraints_cols(U,cellmat,cellids) -cellmat_rc = attach_constraints_rows(V,cellmat_c,cellids) -cellvec_r = attach_constraints_rows(V,cellvec,cellids) -cellmatvec_c = attach_constraints_cols(U,cellmatvec,cellids) -cellmatvec_rc = attach_constraints_rows(V,cellmatvec_c,cellids) +rows = get_cell_dof_ids(V,trian) +cols = get_cell_dof_ids(U,trian) +cellmat_c = attach_constraints_cols(U,cellmat,trian) +cellmat_rc = attach_constraints_rows(V,cellmat_c,trian) +cellvec_r = attach_constraints_rows(V,cellvec,trian) +cellmatvec_c = attach_constraints_cols(U,cellmatvec,trian) +cellmatvec_rc = attach_constraints_rows(V,cellmatvec_c,trian) bcellmat = integrate(v*u,bquad) bcellvec = integrate(v*3,bquad) bcellmatvec = pair_arrays(bcellmat,bcellvec) -bcellids = btrian.glue.face_to_cell -brows = get_cell_dof_ids(V,bcellids) -bcols = get_cell_dof_ids(U,bcellids) -bcellmat_c = attach_constraints_cols(U,bcellmat,bcellids) -bcellmat_rc = attach_constraints_rows(V,bcellmat_c,bcellids) -bcellvec_r = attach_constraints_rows(V,bcellvec,bcellids) -bcellmatvec_c = attach_constraints_cols(U,bcellmatvec,bcellids) -bcellmatvec_rc = attach_constraints_rows(V,bcellmatvec_c,bcellids) +brows = get_cell_dof_ids(V,btrian) +bcols = get_cell_dof_ids(U,btrian) +bcellmat_c = attach_constraints_cols(U,bcellmat,btrian) +bcellmat_rc = attach_constraints_rows(V,bcellmat_c,btrian) +bcellvec_r = attach_constraints_rows(V,bcellvec,btrian) +bcellmatvec_c = attach_constraints_cols(U,bcellmatvec,btrian) +bcellmatvec_rc = attach_constraints_rows(V,bcellmatvec_c,btrian) b0cellmat = integrate(v*u,b0quad) b0cellvec = integrate(v*3,b0quad) b0cellmatvec = pair_arrays(b0cellmat,b0cellvec) -b0cellids = get_cell_to_bgcell(b0trian) -b0rows = get_cell_dof_ids(V,b0cellids) -b0cols = get_cell_dof_ids(U,b0cellids) -@test length(b0cellids) == 0 -b0cellmat_c = attach_constraints_cols(U,b0cellmat,b0cellids) -b0cellmat_rc = attach_constraints_rows(V,b0cellmat_c,b0cellids) -b0cellvec_r = attach_constraints_rows(V,b0cellvec,b0cellids) -b0cellmatvec_c = attach_constraints_cols(U,b0cellmatvec,b0cellids) -b0cellmatvec_rc = attach_constraints_rows(V,b0cellmatvec_c,b0cellids) +b0rows = get_cell_dof_ids(V,b0trian) +b0cols = get_cell_dof_ids(U,b0trian) +@test length(b0rows) == 0 +b0cellmat_c = attach_constraints_cols(U,b0cellmat,b0trian) +b0cellmat_rc = attach_constraints_rows(V,b0cellmat_c,b0trian) +b0cellvec_r = attach_constraints_rows(V,b0cellvec,b0trian) +b0cellmatvec_c = attach_constraints_cols(U,b0cellmatvec,b0trian) +b0cellmatvec_rc = attach_constraints_rows(V,b0cellmatvec_c,b0trian) term_to_cellmat = [cellmat_rc, bcellmat_rc, b0cellmat_rc] term_to_cellvec = [cellvec, bcellvec, b0cellvec] @@ -169,11 +166,10 @@ scellmat = integrate(jump(v)*u.⁻,squad) scellvec = integrate(mean(v*3),squad) @test isa(scellvec[1],ArrayBlock) scellmatvec = pair_arrays(scellmat,scellvec) -scellids = get_cell_to_bgcell(strian) -srows = get_cell_dof_ids(V,scellids) -scols = get_cell_dof_ids(U,scellids) +srows = get_cell_dof_ids(V,strian) +scols = get_cell_dof_ids(U,strian) zh = zero(V) -scellvals = get_cell_dof_values(zh,scellids) +scellvals = get_cell_dof_values(zh,strian) scellmatvec = attach_dirichlet(scellmatvec,scellvals) matvecdata = ([scellmatvec],[srows],[scols]) diff --git a/test/FESpacesTests/TrialFESpacesTests.jl b/test/FESpacesTests/TrialFESpacesTests.jl index bccadaa73..3941a1d55 100644 --- a/test/FESpacesTests/TrialFESpacesTests.jl +++ b/test/FESpacesTests/TrialFESpacesTests.jl @@ -12,6 +12,7 @@ using Gridap.CellData domain =(0,1,0,1,0,1) partition = (3,3,3) model = CartesianDiscreteModel(domain,partition) +Ω = Triangulation(model) order = 2 reffe = ReferenceFE(lagrangian,Float64,order) @@ -28,10 +29,10 @@ ud = compute_dirichlet_values_for_tags!(v,copy(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) +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) +test_single_field_fe_space(U,cellmatvec,cellmat,cellvec,Ω) @test get_dirichlet_dof_values(U) == [4.0, 3.0, 3.0, 3.0, 3.0, 3.0] TrialFESpace!(U,[1,2]) @@ -56,13 +57,11 @@ el2 = sqrt(sum(integrate(inner(e,e),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_dof_values(uh,cellidsS) +Λ = SkeletonTriangulation(model) +cell_vals = get_cell_dof_values(uh,Λ) @test isa(cell_vals[1],ArrayBlock) -cell_dofs = get_cell_dof_ids(U,cellidsS) +cell_dofs = get_cell_dof_ids(U,Λ) @test isa(cell_dofs[1],ArrayBlock) U0 = HomogeneousTrialFESpace(U) diff --git a/test/FESpacesTests/ZeroMeanFESpacesTests.jl b/test/FESpacesTests/ZeroMeanFESpacesTests.jl index 601ebb47e..ed78ea91e 100644 --- a/test/FESpacesTests/ZeroMeanFESpacesTests.jl +++ b/test/FESpacesTests/ZeroMeanFESpacesTests.jl @@ -1,6 +1,7 @@ module ZeroMeanFESpacesTests using Test +using Gridap.Arrays using Gridap.Geometry using Gridap.Fields using Gridap.FESpaces @@ -21,13 +22,13 @@ _V = FESpace(model,ReferenceFE(lagrangian,Float64,order);conformity=:L2) V = ZeroMeanFESpace(_V,dΩ) -matvecdata = ([],[],[]) -matdata = ([],[],[]) -vecdata = ([],[]) -test_single_field_fe_space(V,matvecdata,matdata,vecdata) +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) +test_single_field_fe_space(V,cellmatvec,cellmat,cellvec,trian) U = TrialFESpace(V) -test_single_field_fe_space(U,matvecdata,matdata,vecdata) +test_single_field_fe_space(U,cellmatvec,cellmat,cellvec,trian) @test isa(U,ZeroMeanFESpace) fun(x) = sin(4*pi*(x[1]+x[2]^2)) + 3 diff --git a/test/FESpacesTests/runtests_1.jl b/test/FESpacesTests/runtests_1.jl index 97c2fd1e0..b764632ce 100644 --- a/test/FESpacesTests/runtests_1.jl +++ b/test/FESpacesTests/runtests_1.jl @@ -28,4 +28,6 @@ using Test @testset "CurlConformingFESpaces" begin include("CurlConformingFESpacesTests.jl") end +@testset "CellFields" begin include("CellFieldsTests.jl") end + end # module diff --git a/test/FieldsTests/DensifyInnerMostBlockLevelMapsTests.jl b/test/FieldsTests/DensifyInnerMostBlockLevelMapsTests.jl new file mode 100644 index 000000000..c1bdd8f68 --- /dev/null +++ b/test/FieldsTests/DensifyInnerMostBlockLevelMapsTests.jl @@ -0,0 +1,83 @@ +module DensifyInnerMostBlockLevelMapsTests + using Test + using Gridap + using Gridap.Fields + using Gridap.Arrays + + m=DensifyInnerMostBlockLevelMap() + + # VectorBlock{Vector} test + y=Vector{Vector{Float64}}(undef,3) + touched=Vector{Bool}(undef,3) + touched .= true + x=rand(3) + y[1]=x + y[2]=x.+1 + y[3]=x.+2 + by=ArrayBlock(y,touched) + cache=return_cache(m,by) + @test vcat(y...)==evaluate!(cache,m,by) + + # MatrixBlock{Vector} test + x=rand(3) + y=Array{Vector{Float64},2}(undef,(1,4)) + y[1,1]=x + y[1,3]=x.+2 + y[1,4]=x.+3 + touched = Array{Bool,2}(undef,(1,4)) + touched .= true + touched[1,2]=false + by=ArrayBlock(y,touched) + cache=return_cache(m,by) + @test hcat(y[1,1],zeros(3),y[1,3],y[1,4]) == evaluate!(cache,m,by) + + # VectorBlock{Matrix} test + x=rand(1,3) + y=Array{Matrix{Float64}}(undef,(4,)) + y[1]=x + y[2]=x.+1 + y[3]=x.+2 + y[4]=x.+3 + touched = Array{Bool,1}(undef,(4,)) + touched .= true + by=ArrayBlock(y,touched) + cache=return_cache(m,by) + @test vcat(y...)==evaluate!(cache,m,by) + + # MatrixBlock{Matrix} test + x1=rand(2,3) + x2=rand(3,3) + x3=rand(4,3) + y=Array{Matrix{Float64}}(undef,(3,3)) + y[1,1]=x + y[2,1]=x2 + y[3,1]=x3 + y[1,2]=x.+3 + y[1,3]=x.+5 + touched = Array{Bool,2}(undef,(3,3)) + touched .= true + touched[2:3,2:3].=false + by=ArrayBlock(y,touched) + cache=return_cache(m,ArrayBlock(y,touched)) + @test vcat(hcat(y[1,1:3]...), + hcat(y[2,1],zeros(3,3),zeros(3,3)), + hcat(y[3,1],zeros(4,3),zeros(4,3)))==evaluate!(cache,m,by) + + # Nested blocking test + touched_parent = Array{Bool,2}(undef,(3,3)) + touched_parent .= false + touched_parent[2,3] = true + y_parent = Array{ArrayBlock{Matrix{Float64}},2}(undef,(3,3)) + y_parent[2,3] = by + parent = ArrayBlock(y_parent,touched_parent) + cache=return_cache(m,parent) + + result_touched = Array{Bool,2}(undef,(3,3)) + result_array = Array{Matrix{Float64}}(undef,(3,3)) + result_touched .= touched_parent + result_array[2,3] = vcat(hcat(y[1,1:3]...), + hcat(y[2,1],zeros(3,3),zeros(3,3)), + hcat(y[3,1],zeros(4,3),zeros(4,3))) + + @test result_array[2,3] == evaluate!(cache,m,parent).array[2,3] +end diff --git a/test/FieldsTests/FieldInterfacesTests.jl b/test/FieldsTests/FieldInterfacesTests.jl index aa0da78a1..21cfd99f4 100644 --- a/test/FieldsTests/FieldInterfacesTests.jl +++ b/test/FieldsTests/FieldInterfacesTests.jl @@ -53,7 +53,6 @@ test_field(f,z,f.(z),grad=∇(f).(z),gradgrad=∇∇(f).(z)) #c = return_cache(∇∇f,x) #@btime evaluate!($c,$∇∇f,$x) - # integration fun(x) = 3*x[1] @@ -360,6 +359,21 @@ test_field(f,z,f.(z),grad=∇(f).(z)) #c = return_cache(∇f,x) #@btime evaluate!($c,$∇f,$x) - +vfun(x) = 2*x[1]+x[2] +v = GenericField(vfun) +vt = VoidFieldMap(true)(v) +vf = VoidFieldMap(false)(v) +test_field(vt,p,zero(v(p))) +test_field(vf,p,v(p)) +test_field(vt,p,zero(v(p)),grad=zero(∇(v)(p))) +test_field(vf,p,v(p),grad=∇(v)(p)) +test_field(vt,p,zero(v(p)),grad=zero(∇(v)(p)),gradgrad=zero(∇∇(v)(p))) +test_field(vf,p,v(p),grad=∇(v)(p),gradgrad=∇∇(v)(p)) +test_field(vt,x,zero.(v(x))) +test_field(vf,x,v(x)) +test_field(vt,x,zero.(v(x)),grad=zero.(∇(v)(x))) +test_field(vf,x,v(x),grad=∇(v)(x)) +test_field(vt,x,zero.(v(x)),grad=zero.(∇(v)(x)),gradgrad=zero.(∇∇(v)(x))) +test_field(vf,x,v(x),grad=∇(v)(x),gradgrad=∇∇(v)(x)) end # module diff --git a/test/FieldsTests/runtests.jl b/test/FieldsTests/runtests.jl index 51378f23d..fac93c402 100644 --- a/test/FieldsTests/runtests.jl +++ b/test/FieldsTests/runtests.jl @@ -20,4 +20,6 @@ using Test @testset "InverseFields" begin include("InverseFieldsTests.jl") end +@testset "DensifyInnerMostBlockLevelMapsTests" begin include("DensifyInnerMostBlockLevelMapsTests.jl") end + end diff --git a/test/GeometryTests/AppendedTriangulationsTests.jl b/test/GeometryTests/AppendedTriangulationsTests.jl index 2d49b5fce..f50f0a2cc 100644 --- a/test/GeometryTests/AppendedTriangulationsTests.jl +++ b/test/GeometryTests/AppendedTriangulationsTests.jl @@ -18,10 +18,10 @@ cell_to_mask[1:nin] .= true grid = get_grid(model) -trian_in = RestrictedTriangulation(grid,cell_to_mask) +trian_in = Triangulation(model,cell_to_mask) test_triangulation(trian_in) -trian_out = RestrictedTriangulation(grid,.! cell_to_mask) +trian_out = Triangulation(model,.! cell_to_mask) test_triangulation(trian_out) trian = lazy_append(trian_out,trian_in) @@ -33,15 +33,29 @@ test_triangulation(trian) @test isa(get_cell_map(trian),AppendedArray) -@test isa(get_cell_ref_map(trian),AppendedArray) - @test !isa(get_cell_reffe(trian),AppendedArray) @test isa(get_cell_shapefuns(trian),AppendedArray) @test isa(get_cell_type(trian),AppendedArray) -@test isa(get_cell_to_bgcell(trian),AppendedArray) +glue = get_glue(trian,Val(2)) +@test isa(glue.tface_to_mface,AppendedArray) +@test isa(glue.tface_to_mface_map,AppendedArray) + +btrian1 = Boundary(model,tags=5) +btrian2 = Boundary(model,tags=2) +btrian = lazy_append(btrian1,btrian2) +test_triangulation(btrian) +@test get_facet_normal(btrian) !== nothing + +cell1_to_mat = [ones(3,3) for i in 1:num_cells(btrian1)] +cell2_to_mat = [ones(3,3) for i in 1:num_cells(btrian2)] +cell_to_mat = lazy_append(cell1_to_mat,cell2_to_mat) +tcell_to_mat, ttrian = move_contributions(cell_to_mat,btrian) +@test tcell_to_mat == cell_to_mat +tcell_to_mat, ttrian = move_contributions(collect(cell_to_mat),btrian) +@test tcell_to_mat == cell_to_mat #order = 1 #quad = CellQuadrature(trian,2*order) diff --git a/test/GeometryTests/BoundaryDiscreteModelsTests.jl b/test/GeometryTests/BoundaryDiscreteModelsTests.jl deleted file mode 100644 index 36761fc5f..000000000 --- a/test/GeometryTests/BoundaryDiscreteModelsTests.jl +++ /dev/null @@ -1,75 +0,0 @@ -module BoundaryDiscreteModelsTests - -using Test -using Gridap.Geometry -using Gridap.ReferenceFEs -using Gridap.FESpaces -using Gridap.CellData -using Gridap.Arrays -using Gridap.TensorValues - -domain = (0,1,0,1,0,1) -cells = (3,3,3) -bgmodel = CartesianDiscreteModel(domain,cells) - -labels = get_face_labeling(bgmodel) -bgface_to_mask = get_face_mask(labels,[22,23],2) - -model = BoundaryDiscreteModel(Polytope{2},bgmodel,bgface_to_mask) - -trian = Triangulation(model) -btrian = BoundaryTriangulation(model) -strian = SkeletonTriangulation(model) - -@test get_background_triangulation(trian) === Triangulation(bgmodel) -@test get_background_triangulation(btrian) === trian -@test get_background_triangulation(strian) === trian -@test get_background_triangulation(Triangulation(model.model)) === Triangulation(model.model) - -reffe = ReferenceFE(lagrangian,Float64,1) -V = FESpace(model,reffe) -bgV = FESpace(bgmodel,reffe) - -vh = FEFunction(V,rand(num_free_dofs(V))) -bgvh = FEFunction(bgV,rand(num_free_dofs(bgV))) - -@test get_triangulation(vh) === Triangulation(model) -@test get_background_triangulation(get_triangulation(vh)) === Triangulation(bgmodel) -@test get_background_triangulation(get_triangulation(vh)) === get_triangulation(bgvh) - -Ω = Triangulation(bgmodel) -Γ = trian -∂Γ = btrian -sΓ = strian - -dΩ = Measure(Ω,3) -dΓ = Measure(Γ,3) -d∂Γ = Measure(∂Γ,3) -dsΓ = Measure(sΓ,3) - -n_Γ = get_normal_vector(Γ) -n_∂Γ = get_normal_vector(∂Γ) - -@test ∑(∫(1)dΓ) ≈ 2.0 -@test ∑(∫(1)d∂Γ) ≈ 6.0 -@test ∑(∫(1)dsΓ) ≈ 9.0 - -@test ∑(∫(n_Γ⋅VectorValue(1.0,0.0,0.0))dΓ) ≈ 0.0 -@test ∑(∫(n_Γ⋅VectorValue(0.0,1.0,0.0))dΓ) ≈ -1.0 -@test ∑(∫(n_Γ⋅VectorValue(0.0,0.0,1.0))dΓ) ≈ 1.0 -@test ∑(∫(n_Γ⋅VectorValue(0.0,0.0,1.0))d∂Γ) ≈ 3.0 -@test ∑(∫(n_∂Γ⋅VectorValue(0.0,0.0,1.0))d∂Γ) ≈ -1.0 - -domain = (-1,1,-1,1,-1,1) -cells = (1,1,1) -bgmodel = CartesianDiscreteModel(domain,cells) -model = BoundaryDiscreteModel(Polytope{2},bgmodel,Int32[3,4,5,6,1,2]) -topo = get_grid_topology(model) -cell_vertices = get_faces(topo,2,0) -@test cell_vertices[5] == [1,2,3,4] -@test cell_vertices[6] == [5,6,7,8] -@test cell_vertices[1] == [1,2,5,6] -@test cell_vertices[2] == [3,4,7,8] -@test cell_vertices[3] == [1,3,5,7] -@test cell_vertices[4] == [2,4,6,8] -end diff --git a/test/GeometryTests/BoundaryTriangulationsTests.jl b/test/GeometryTests/BoundaryTriangulationsTests.jl index 815daef99..f8a3f4b64 100644 --- a/test/GeometryTests/BoundaryTriangulationsTests.jl +++ b/test/GeometryTests/BoundaryTriangulationsTests.jl @@ -14,9 +14,13 @@ model = simplexify(CartesianDiscreteModel(domain,partition)) btrian = BoundaryTriangulation(model,tags=[7,8]) test_triangulation(btrian) -@test get_background_triangulation(btrian) === get_triangulation(model) +@test get_background_model(btrian) === model +glue = get_glue(btrian,Val(1)) +@test glue.tface_to_mface === btrian.glue.face_to_bgface +glue = get_glue(btrian,Val(2)) +@test glue.tface_to_mface === btrian.glue.face_to_cell -face_s_q = get_cell_ref_map(btrian) +face_s_q = glue.tface_to_mface_map s1 = Point(0.0) s2 = Point(0.5) @@ -26,11 +30,12 @@ face_to_s = Fill(s,length(face_s_q)) face_to_q = lazy_map(evaluate,face_s_q,face_to_s) @test isa(face_to_q,Geometry.FaceCompressedVector) -cell_shapefuns = get_cell_shapefuns(btrian.cell_trian) +cell_grid = get_grid(get_background_model(btrian)) +cell_shapefuns = get_cell_shapefuns(cell_grid) cell_grad_shapefuns = lazy_map(Broadcasting(∇),cell_shapefuns) -face_shapefuns = lazy_map(Reindex(cell_shapefuns),get_cell_to_bgcell(btrian)) -face_grad_shapefuns = lazy_map(Reindex(cell_grad_shapefuns),get_cell_to_bgcell(btrian)) +face_shapefuns = lazy_map(Reindex(cell_shapefuns),glue.tface_to_mface) +face_grad_shapefuns = lazy_map(Reindex(cell_grad_shapefuns),glue.tface_to_mface) face_shapefuns_q = lazy_map(evaluate,face_shapefuns,face_to_q) test_array(face_shapefuns_q,collect(face_shapefuns_q)) @@ -50,14 +55,30 @@ test_array(face_to_nvec_s,collect(face_to_nvec_s)) #print_op_tree(face_grad_shapefuns_q) #print_op_tree(face_to_nvec_s) +Ω = Triangulation(model) +Γ = btrian +∂Γ = BoundaryTriangulation(Γ) +test_triangulation(∂Γ) +@test ∂Γ.rtrian === Γ +@test isa(∂Γ.dtrian,BoundaryTriangulation) +glue = get_glue(∂Γ,Val(2)) +glue = get_glue(∂Γ,Val(1)) +@test is_change_possible(Ω,∂Γ) +@test is_change_possible(Γ,∂Γ) + domain = (0,4,0,4) partition = (2,2) model = CartesianDiscreteModel(domain,partition) btrian = BoundaryTriangulation(model) test_triangulation(btrian) +@test get_background_model(btrian) === model +glue = get_glue(btrian,Val(1)) +@test glue.tface_to_mface === btrian.glue.face_to_bgface +glue = get_glue(btrian,Val(2)) +@test glue.tface_to_mface === btrian.glue.face_to_cell -face_s_q = get_cell_ref_map(btrian) +face_s_q = glue.tface_to_mface_map s1 = Point(0.0) s2 = Point(0.5) @@ -67,11 +88,12 @@ face_to_s = Fill(s,length(face_s_q)) face_to_q = lazy_map(evaluate,face_s_q,face_to_s) @test isa(face_to_q,Geometry.FaceCompressedVector) -cell_shapefuns = get_cell_shapefuns(btrian.cell_trian) +cell_grid = get_grid(get_background_model(btrian)) +cell_shapefuns = get_cell_shapefuns(cell_grid) cell_grad_shapefuns = lazy_map(Broadcasting(∇),cell_shapefuns) -face_shapefuns = lazy_map(Reindex(cell_shapefuns),get_cell_to_bgcell(btrian)) -face_grad_shapefuns = lazy_map(Reindex(cell_grad_shapefuns),get_cell_to_bgcell(btrian)) +face_shapefuns = lazy_map(Reindex(cell_shapefuns),glue.tface_to_mface) +face_grad_shapefuns = lazy_map(Reindex(cell_grad_shapefuns),glue.tface_to_mface) face_shapefuns_q = lazy_map(evaluate,face_shapefuns,face_to_q) test_array(face_shapefuns_q,collect(face_shapefuns_q)) @@ -92,7 +114,7 @@ test_array(face_to_nvec_s,collect(face_to_nvec_s)) s = CompressedArray([Point{1,Float64}[(0.25,),(0.75,)]],get_cell_type(btrian)) -s2q = get_cell_ref_map(btrian) +s2q = glue.tface_to_mface_map q = lazy_map(evaluate,s2q,s) r = Vector{Point{2,Float64}}[ @@ -102,8 +124,8 @@ r = Vector{Point{2,Float64}}[ [(0.25,1.0),(0.75,1.0)],[(1.0,0.25),(1.0,0.75)]] test_array(q,r) -q2x = get_cell_map(btrian.cell_trian) -s2x = lazy_map(∘,lazy_map(Reindex(q2x),get_cell_to_bgcell(btrian)),s2q) +q2x = get_cell_map(cell_grid) +s2x = lazy_map(∘,lazy_map(Reindex(q2x),glue.tface_to_mface),s2q) x = lazy_map(evaluate,s2x,s) r = Vector{Point{2,Float64}}[ @@ -125,13 +147,12 @@ test_array(nvec_s,r) cellids = collect(1:num_cells(model)) -face_to_cellid = lazy_map(Reindex(cellids),get_cell_to_bgcell(btrian)) -@test face_to_cellid == get_cell_to_bgcell(btrian) +face_to_cellid = lazy_map(Reindex(cellids),glue.tface_to_mface) +@test face_to_cellid == glue.tface_to_mface -trian = get_background_triangulation(btrian) -q2x = get_cell_map(trian) -s2q = get_cell_ref_map(btrian) -s2x = lazy_map(∘,lazy_map(Reindex(q2x),get_cell_to_bgcell(btrian)),s2q) +q2x = get_cell_map(cell_grid) +s2q = glue.tface_to_mface_map +s2x = lazy_map(∘,lazy_map(Reindex(q2x),glue.tface_to_mface),s2q) s = CompressedArray([Point{1,Float64}[(0.25,),(0.75,)]],get_cell_type(btrian)) x = lazy_map(evaluate,s2x,s) @@ -162,15 +183,18 @@ nvec_x = lazy_map(evaluate,nvec,s) s2x = get_cell_map(btrian) x = lazy_map(evaluate,s2x,s) -oldbtrian = BoundaryTriangulation(model) -bface_to_oldbface = collect(1:4) -btrian = RestrictedTriangulation(oldbtrian,bface_to_oldbface) -test_triangulation(btrian) - -nb = get_facet_normal(btrian) -@test length(nb) == num_cells(btrian) - btrian = BoundaryTriangulation(model,tags=["tag_6","tag_7"]) test_triangulation(btrian) +ids = [1,3,4] +vtrian = view(btrian,ids) +test_triangulation(vtrian) +@test num_cells(vtrian) == 3 +bglue = get_glue(btrian,Val(1)) +vglue = get_glue(vtrian,Val(1)) +@test vglue.tface_to_mface == bglue.tface_to_mface[ids] +bglue = get_glue(btrian,Val(2)) +vglue = get_glue(vtrian,Val(2)) +@test vglue.tface_to_mface == bglue.tface_to_mface[ids] + end # module diff --git a/test/GeometryTests/CompressedCellArraysTests.jl b/test/GeometryTests/CompressedCellArraysTests.jl index ee86c27f4..298a46b4d 100644 --- a/test/GeometryTests/CompressedCellArraysTests.jl +++ b/test/GeometryTests/CompressedCellArraysTests.jl @@ -11,95 +11,76 @@ domain= (0,1,0,1) cells = (3,3) model = CartesianDiscreteModel(domain,cells) -Γ = BoundaryTriangulation(model) - -cell_mat = [ones(3,3) for cell in 1:num_cells(Γ)] -cell_vec = [ones(3) for cell in 1:num_cells(Γ)] -cell_matvec = pair_arrays(cell_mat,cell_vec) - -cell_to_bgcell = get_cell_to_bgcell(Γ) -ccell_to_first_cell = compress_ids(cell_to_bgcell) -@test ccell_to_first_cell == [1, 3, 4, 6, 7, 8, 10, 11, 13] - -ccell_to_mat= compress_contributions(cell_mat,cell_to_bgcell,ccell_to_first_cell) -@test length(ccell_to_mat) == 8 -@test ccell_to_mat[1] == 2*ones(3,3) -@test ccell_to_mat[1] == 2*ones(3,3) -@test ccell_to_mat[2] == ones(3,3) -@test ccell_to_mat[3] == 2*ones(3,3) -@test ccell_to_mat[3] == 2*ones(3,3) -test_array(ccell_to_mat,collect(ccell_to_mat)) - -cache = array_cache(ccell_to_mat) -@test getindex!(cache,ccell_to_mat,1) == 2*ones(3,3) -@test getindex!(cache,ccell_to_mat,1) == 2*ones(3,3) -@test getindex!(cache,ccell_to_mat,2) == ones(3,3) - -ccell_to_vec = compress_contributions(cell_vec,cell_to_bgcell,ccell_to_first_cell) -@test ccell_to_vec[1] == 2*ones(3) -@test ccell_to_vec[1] == 2*ones(3) -@test ccell_to_vec[2] == ones(3) -@test ccell_to_vec[3] == 2*ones(3) -@test ccell_to_vec[3] == 2*ones(3) -test_array(ccell_to_vec,collect(ccell_to_vec)) - -cache = array_cache(ccell_to_vec) -@test getindex!(cache,ccell_to_vec,1) == 2*ones(3) -@test getindex!(cache,ccell_to_vec,1) == 2*ones(3) -@test getindex!(cache,ccell_to_vec,2) == ones(3) - -ccell_to_matvec = compress_contributions(cell_matvec,cell_to_bgcell,ccell_to_first_cell) -@test ccell_to_matvec[1] == (2*ones(3,3), 2*ones(3)) -@test ccell_to_matvec[1] == (2*ones(3,3), 2*ones(3)) -@test ccell_to_matvec[2] == (ones(3,3) , ones(3) ) -@test ccell_to_matvec[3] == (2*ones(3,3), 2*ones(3)) -@test ccell_to_matvec[3] == (2*ones(3,3), 2*ones(3)) -test_array(ccell_to_matvec,collect(ccell_to_matvec)) - -cache = array_cache(ccell_to_matvec) -@test getindex!(cache,ccell_to_matvec,1) == (2*ones(3,3), 2*ones(3)) -@test getindex!(cache,ccell_to_matvec,1) == (2*ones(3,3), 2*ones(3)) -@test getindex!(cache,ccell_to_matvec,2) == (ones(3,3) , ones(3) ) - -# now for blocks - -mat = ArrayBlock(Matrix{Matrix{Float64}}(undef,2,2),[true false; true true]) -mat[1,1] = ones(3,3) -mat[2,1] = ones(4,3) -mat[2,2] = ones(4,4) - -vec = ArrayBlock(Vector{Vector{Float64}}(undef,2),[false, true]) -vec[2] = ones(4) - -cell_mat = [copy(mat) for cell in 1:num_cells(Γ)] -cell_vec = [copy(vec) for cell in 1:num_cells(Γ)] -cell_matvec = pair_arrays(cell_mat,cell_vec) -ccell_to_mat= compress_contributions(cell_mat,cell_to_bgcell,ccell_to_first_cell) -ccell_to_vec= compress_contributions(cell_vec,cell_to_bgcell,ccell_to_first_cell) -ccell_to_matvec= compress_contributions(cell_matvec,cell_to_bgcell,ccell_to_first_cell) -test_array(ccell_to_mat,collect(ccell_to_mat)) -test_array(ccell_to_vec,collect(ccell_to_vec)) -test_array(ccell_to_matvec,collect(ccell_to_matvec)) - -# now for blocks of blocks - -mat11 = copy(mat) -mat = ArrayBlock(Matrix{MatrixBlock{Matrix{Float64}}}(undef,2,2),[true false; false false]) -mat[1,1] = mat11 - -vec2 = copy(vec) -vec = ArrayBlock(Vector{VectorBlock{Vector{Float64}}}(undef,2),[false, true]) -vec[2] = vec2 - -cell_mat = [copy(mat) for cell in 1:num_cells(Γ)] -cell_vec = [copy(vec) for cell in 1:num_cells(Γ)] -cell_matvec = pair_arrays(cell_mat,cell_vec) -ccell_to_mat= compress_contributions(cell_mat,cell_to_bgcell,ccell_to_first_cell) -ccell_to_vec= compress_contributions(cell_vec,cell_to_bgcell,ccell_to_first_cell) -ccell_to_matvec= compress_contributions(cell_matvec,cell_to_bgcell,ccell_to_first_cell) -test_array(ccell_to_mat,collect(ccell_to_mat)) -test_array(ccell_to_vec,collect(ccell_to_vec)) -test_array(ccell_to_matvec,collect(ccell_to_matvec)) - +Ω = Triangulation(model) +cell_xs = get_cell_coordinates(Ω) +cell_mask = lazy_map(cell_xs) do xs + R = 0.7 + n = length(xs) + x = (1/n)*sum(xs) + d = x[1]^2 + x[2]^2 - R^2 + d < 0 +end +Ω1 = Triangulation(model,cell_mask) +Γ = Boundary(model) + +tcell_num = [ 1 for cell in 1:num_cells(Γ)] +tcell_mat = [ones(3,3) for cell in 1:num_cells(Γ)] +tcell_vec = [ones(3) for cell in 1:num_cells(Γ)] +tcell_matvec = pair_arrays(tcell_mat,tcell_vec) +tcell_block = lazy_map(BlockMap(2,2),tcell_mat) + +mcell_num = move_contributions(tcell_num,Γ,Ω) +@test length(mcell_num) == num_cells(Ω) +@test sum(mcell_num) == sum(tcell_num) + +mcell_mat = move_contributions(tcell_mat,Γ,Ω) +@test length(mcell_mat) == num_cells(Ω) +@test sum(mcell_mat[length.(mcell_mat) .!= 0]) == sum(tcell_mat) + +mcell_vec = move_contributions(tcell_vec,Γ,Ω) +@test length(mcell_vec) == num_cells(Ω) +@test sum(mcell_vec[length.(mcell_vec) .!= 0]) == sum(tcell_vec) + +mcell_matvec = move_contributions(tcell_matvec,Γ,Ω) +@test length(mcell_matvec) == num_cells(Ω) +mcell_mat,mcell_vec = unpair_arrays(mcell_matvec) +@test sum(mcell_mat[length.(mcell_mat) .!= 0]) == sum(tcell_mat) +@test sum(mcell_vec[length.(mcell_vec) .!= 0]) == sum(tcell_vec) + +mcell_block = move_contributions(tcell_block,Γ,Ω) +@test length(mcell_block) == num_cells(Ω) +mcell_mat = lazy_map(b->b.array[2],mcell_block) +@test length(mcell_mat) == num_cells(Ω) +@test sum(mcell_mat[length.(mcell_mat) .!= 0]) == sum(tcell_mat) + +tcell_num = [ 1 for cell in 1:num_cells(Ω1)] +tcell_mat = [ones(3,3) for cell in 1:num_cells(Ω1)] +tcell_vec = [ones(3) for cell in 1:num_cells(Ω1)] +tcell_matvec = pair_arrays(tcell_mat,tcell_vec) +tcell_block = lazy_map(BlockMap(2,2),tcell_mat) + +mcell_num = move_contributions(tcell_num,Ω1,Ω) +@test length(mcell_num) == num_cells(Ω) +@test sum(mcell_num) == sum(tcell_num) + +mcell_mat = move_contributions(tcell_mat,Ω1,Ω) +@test length(mcell_mat) == num_cells(Ω) +@test sum(mcell_mat[length.(mcell_mat) .!= 0]) == sum(tcell_mat) + +mcell_vec = move_contributions(tcell_vec,Ω1,Ω) +@test length(mcell_vec) == num_cells(Ω) +@test sum(mcell_vec[length.(mcell_vec) .!= 0]) == sum(tcell_vec) + +mcell_matvec = move_contributions(tcell_matvec,Ω1,Ω) +@test length(mcell_matvec) == num_cells(Ω) +mcell_mat,mcell_vec = unpair_arrays(mcell_matvec) +@test sum(mcell_mat[length.(mcell_mat) .!= 0]) == sum(tcell_mat) +@test sum(mcell_vec[length.(mcell_vec) .!= 0]) == sum(tcell_vec) + +mcell_block = move_contributions(tcell_block,Ω1,Ω) +@test length(mcell_block) == num_cells(Ω) +mcell_mat = lazy_map(b->b.array[2],mcell_block) +@test length(mcell_mat) == num_cells(Ω) +@test sum(mcell_mat[length.(mcell_mat) .!= 0]) == sum(tcell_mat) end # module diff --git a/test/GeometryTests/DiscreteModelPortionsTests.jl b/test/GeometryTests/DiscreteModelPortionsTests.jl index 5ff4a7cc5..aea19a11d 100644 --- a/test/GeometryTests/DiscreteModelPortionsTests.jl +++ b/test/GeometryTests/DiscreteModelPortionsTests.jl @@ -8,6 +8,7 @@ using Test domain = (0,2,0,2,0,2) partition = (10,10,10) oldmodel = CartesianDiscreteModel(domain,partition) +Ω = Triangulation(oldmodel) const R = 0.7 diff --git a/test/GeometryTests/DiscreteModelsTests.jl b/test/GeometryTests/DiscreteModelsTests.jl index 9d0d93620..b6e932eb5 100644 --- a/test/GeometryTests/DiscreteModelsTests.jl +++ b/test/GeometryTests/DiscreteModelsTests.jl @@ -73,16 +73,6 @@ test_grid(grid2) @test num_dims(grid1) == 1 @test num_dims(grid2) == 2 -grid0 = Triangulation(ReferenceFE{0},model) -grid1 = Triangulation(ReferenceFE{1},model) -grid2 = Triangulation(ReferenceFE{2},model) -test_triangulation(grid0) -test_triangulation(grid1) -test_triangulation(grid2) -@test num_dims(grid0) == 0 -@test num_dims(grid1) == 1 -@test num_dims(grid2) == 2 - model = DiscreteModelMock() dict = to_dict(model) model2 = from_dict(DiscreteModel,dict) diff --git a/test/GeometryTests/GridPortionsTests.jl b/test/GeometryTests/GridPortionsTests.jl index b2e7d059c..cec0b3fbd 100644 --- a/test/GeometryTests/GridPortionsTests.jl +++ b/test/GeometryTests/GridPortionsTests.jl @@ -3,7 +3,7 @@ module GridPortionsTests using Gridap.Arrays using Gridap.ReferenceFEs using Gridap.Geometry - +using Test domain = (-1,1,-1,1) partition = (10,10) @@ -33,6 +33,16 @@ labels = FaceLabeling(topo) model = DiscreteModel(grid,topo,labels) test_discrete_model(model) +grid = view(oldgrid,oldcell_to_mask) +@test isa(grid,Geometry.GridView) +test_grid(grid) +@test num_cells(grid) == count(oldcell_to_mask) + +grid = view(oldgrid,findall(collect1d(oldcell_to_mask))) +@test isa(grid,Geometry.GridView) +test_grid(grid) +@test num_cells(grid) == count(oldcell_to_mask) + #using Gridap.Visualization #writevtk(model,"model") diff --git a/test/GeometryTests/RestrictedDiscreteModelsTests.jl b/test/GeometryTests/RestrictedDiscreteModelsTests.jl deleted file mode 100644 index 36d9059de..000000000 --- a/test/GeometryTests/RestrictedDiscreteModelsTests.jl +++ /dev/null @@ -1,96 +0,0 @@ -module RestrictedDiscreteModelsTests - -using Gridap.Arrays -using Gridap.ReferenceFEs -using Gridap.Geometry -using Test - -domain = (0,2,0,2,0,2) -partition = (10,10,10) -oldmodel = CartesianDiscreteModel(domain,partition) - -const R = 0.7 - -function is_in(coords) - n = length(coords) - x = (1/n)*sum(coords) - d = x[1]^2 + x[2]^2 - R^2 - d < 0 -end - -oldgrid = get_grid(oldmodel) -oldcell_to_coods = get_cell_coordinates(oldgrid) -cell_to_mask = lazy_map(is_in,oldcell_to_coods) -cell_to_oldcell = findall(collect1d(cell_to_mask)) - -labels = get_face_labeling(oldmodel) - -ne = num_entities(labels) -fluid_entity = ne+1 -solid_entity = ne+2 -cell_to_entity = get_cell_entity(labels) -cell_to_entity .= fluid_entity -cell_to_entity[cell_to_oldcell] .= solid_entity -add_tag!(labels,"fluid",[fluid_entity]) -add_tag!(labels,"solid",[solid_entity]) - -model = RestrictedDiscreteModel(oldmodel,cell_to_oldcell) -test_discrete_model(model) - -trian = get_triangulation(model) -@test isa(trian,RestrictedTriangulation) - -trian = Triangulation(model) -@test isa(trian,RestrictedTriangulation) - -model = DiscreteModel(oldmodel,cell_to_oldcell) -test_discrete_model(model) -@test isa(model,RestrictedDiscreteModel) - -model = DiscreteModel(oldmodel,cell_to_mask) -test_discrete_model(model) -@test isa(model,RestrictedDiscreteModel) - -model_fluid = DiscreteModel(oldmodel,tags="fluid") -test_discrete_model(model_fluid) -@test isa(model_fluid,RestrictedDiscreteModel) - -model_solid = DiscreteModel(oldmodel,tags="solid") -test_discrete_model(model_solid) -@test isa(model_solid,RestrictedDiscreteModel) - -itrian = InterfaceTriangulation(model_fluid,model_solid) - -#using Gridap.Visualization -#writevtk(itrian,"itrian",nsubcells=3,cellfields=["normal"=>get_normal_vector(itrian)]) - -# -#writevtk(model,"model") -#writevtk(trian,"trian") - -oldtrian = Triangulation(oldmodel) -trian_s = SkeletonTriangulation(model) -trian_b = BoundaryTriangulation(model) - -@test get_background_triangulation(trian_s) === oldtrian -@test get_background_triangulation(trian_b) === oldtrian -@test get_background_triangulation(itrian) === oldtrian - -#meas_K_b = cell_measure(trian_b,oldtrian) -#meas_K_sl = cell_measure(trian_s.plus,oldtrian) -#meas_K_sr = cell_measure(trian_s.minus,oldtrian) -# -#oldcell_to_cell = zeros(Int,num_cells(oldmodel)) -#oldcell_to_cell[cell_to_oldcell] .= 1:length(cell_to_oldcell) -# -#@test all( oldcell_to_cell[findall(meas_K_b .!= 0)] .!= 0 ) -#@test all( oldcell_to_cell[findall(meas_K_sl .!= 0)] .!= 0 ) -#@test all( oldcell_to_cell[findall(meas_K_sr .!= 0)] .!= 0 ) - -#using Gridap.Visualization -#writevtk(trian_b,"trian_b") -#writevtk(trian_s,"trian_s") -#writevtk(trian,"trian") -#writevtk(oldtrian,"oldtrian",celldata=["meas_K_b"=>meas_K_b,"meas_K_sl"=>meas_K_sl,"meas_K_sr"=>meas_K_sr]) - -end # module diff --git a/test/GeometryTests/RestrictedTriangulationsTests.jl b/test/GeometryTests/RestrictedTriangulationsTests.jl deleted file mode 100644 index 8400b417b..000000000 --- a/test/GeometryTests/RestrictedTriangulationsTests.jl +++ /dev/null @@ -1,46 +0,0 @@ -module RestrictedTriangulationsTests - -using Gridap.Arrays -using Gridap.ReferenceFEs -using Gridap.Geometry -using Test - -domain = (-1,1,-1,1) -partition = (10,10) -oldmodel = CartesianDiscreteModel(domain,partition) -oldtrian = get_triangulation(oldmodel) - -cell_to_oldcell = collect(1:34) -trian = RestrictedTriangulation(oldtrian,cell_to_oldcell) -test_triangulation(trian) - -cell_to_oldcell = [2,9,7] -trian_portion = RestrictedTriangulation(oldtrian,cell_to_oldcell) -trian_portion_portion = RestrictedTriangulation(trian_portion,[3,1]) -test_triangulation(trian_portion_portion) -@test get_cell_to_bgcell(trian_portion_portion)==[7,2] - -const R = 0.7 - -function is_in(coords) - n = length(coords) - x = (1/n)*sum(coords) - d = x[1]^2 + x[2]^2 - R^2 - d < 0 -end - -oldcell_to_coods = get_cell_coordinates(oldtrian) -oldcell_to_mask = lazy_map(is_in,oldcell_to_coods) -trian = RestrictedTriangulation(oldtrian,oldcell_to_mask) -trian = Triangulation(oldmodel,oldcell_to_mask) -trian = Triangulation(oldtrian,oldcell_to_mask) -trian = Triangulation(oldmodel,tags="interior") -trian = Triangulation(oldmodel,get_face_labeling(oldmodel),tags="interior") - -#using Gridap.Visualization -#writevtk(oldtrian,"oldtrian") -#writevtk(btrian,"btrian",cellfields=["normal"=>nb],celldata=["oldcell"=>get_cell_to_bgcell(btrian)]) -#writevtk(strian,"strian",cellfields=["normal"=>ns], -# celldata=["oldcell_left"=>get_cell_to_bgcell(strian).plus,"oldcell_right"=>get_cell_to_bgcell(strian).minus]) - -end # module diff --git a/test/GeometryTests/SkeletonTriangulationsTests.jl b/test/GeometryTests/SkeletonTriangulationsTests.jl index fc4869896..7446e8a44 100644 --- a/test/GeometryTests/SkeletonTriangulationsTests.jl +++ b/test/GeometryTests/SkeletonTriangulationsTests.jl @@ -13,17 +13,12 @@ model = DiscreteModelMock() strian = SkeletonTriangulation(model) test_triangulation(strian) -@test get_background_triangulation(strian) === get_triangulation(model) - -#function polar(q) -# r, t, z = q -# x = r*cos(t) -# y = r*sin(t) -# Point(x,y,z) -#end -#domain = (1,2,0,pi,0,0.5) -#partition = (10,30,4) -#model = CartesianDiscreteModel(domain,partition,polar) +@test get_background_model(strian) === model +glue = get_glue(strian,Val(1)) +@test glue.tface_to_mface === strian.plus.glue.face_to_bgface +glue = get_glue(strian,Val(2)) +@test glue.plus.tface_to_mface === strian.plus.glue.face_to_cell +@test glue.minus.tface_to_mface === strian.minus.glue.face_to_cell domain = (0,1,0,1,0,1) partition = (3,3,3) @@ -31,42 +26,38 @@ model = CartesianDiscreteModel(domain,partition) strian = SkeletonTriangulation(model) test_triangulation(strian) -@test get_background_triangulation(strian) === get_triangulation(model) - -#s = CompressedArray([Point{2,Float64}[(0.25,0.25),(0.75,0.75)]],get_cell_type(strian)) -# -#s2x = get_cell_map(strian) -#x = laevaluate(s2x,s) -# -#nvec = get_normal_vector(strian) -#nx = evaluate(nvec,s) -#collect(nx) -# -#fun(x) = sin(pi*x[1])*cos(pi*x[2]) -# -#q2x = get_cell_map(trian) -# -#funq = compose(fun,q2x) -# -#fun_gamma = restrict(funq,strian) -# -#@test isa(fun_gamma, SkeletonPair) -# -#cellids = collect(1:num_cells(trian)) -# -#cellids_gamma = reindex(cellids,strian) -#@test isa(fun_gamma, SkeletonPair) -#@test cellids_gamma.plus == get_face_to_cell(strian.plus) -#@test cellids_gamma.minus == get_face_to_cell(strian.minus) -# -#ids = get_cell_to_bgcell(strian) -#@test isa(ids,SkeletonPair) -# -##using Gridap.Visualization -## -##writevtk(trian,"trian") -##writevtk(strian,"strian") -##writevtk(x,"x",nodaldata=["nvec" => nx]) +@test get_background_model(strian) === model +glue = get_glue(strian,Val(2)) +@test glue.tface_to_mface === strian.plus.glue.face_to_bgface +glue = get_glue(strian,Val(3)) +@test glue.plus.tface_to_mface === strian.plus.glue.face_to_cell +@test glue.minus.tface_to_mface === strian.minus.glue.face_to_cell + +ids = [1,3,4] +vtrian = view(strian,ids) +test_triangulation(vtrian) +@test num_cells(vtrian) == 3 +sglue = get_glue(strian,Val(2)) +vglue = get_glue(vtrian,Val(2)) +@test vglue.tface_to_mface == sglue.tface_to_mface[ids] +sglue = get_glue(strian,Val(3)) +vglue = get_glue(vtrian,Val(3)) +@test vglue.plus.tface_to_mface == sglue.plus.tface_to_mface[ids] +@test vglue.minus.tface_to_mface == sglue.minus.tface_to_mface[ids] +vn = get_facet_normal(vtrian) +@test isa(vn,SkeletonPair) +@test isa(vn.plus,AbstractArray) +@test isa(vn.minus,AbstractArray) + +Ω = Triangulation(model) +Γ = BoundaryTriangulation(model) +Λ = SkeletonTriangulation(Γ) +@test Λ.rtrian === Γ +@test isa(Λ.dtrian,SkeletonTriangulation) +glue = get_glue(Λ,Val(3)) +glue = get_glue(Λ,Val(2)) +@test is_change_possible(Ω,Λ) +@test is_change_possible(Γ,Λ) model = DiscreteModelMock() @@ -104,6 +95,9 @@ itrian = InterfaceTriangulation(model,cell_to_inout) itrian = InterfaceTriangulation(model,1:13,14:34) @test num_cells(itrian) == 11 +Ω_in = Triangulation(model,findall(i->i==IN,cell_to_inout)) +Ω_out = Triangulation(model,findall(i->i==OUT,cell_to_inout)) +itrian = InterfaceTriangulation(Ω_in,Ω_out) #ltrian = get_left_boundary(itrian) #rtrian = get_right_boundary(itrian) @@ -132,11 +126,4 @@ partition = (3,3,3) oldmodel = CartesianDiscreteModel(domain,partition) oldstrian = SkeletonTriangulation(oldmodel) -sface_to_oldsface = collect(1:10) -strian = RestrictedTriangulation(oldstrian,sface_to_oldsface) -test_triangulation(strian) -@test isa(strian,SkeletonTriangulation) - - - end # module diff --git a/test/GeometryTests/TriangulationsTests.jl b/test/GeometryTests/TriangulationsTests.jl index 85a827eef..344eec6d6 100644 --- a/test/GeometryTests/TriangulationsTests.jl +++ b/test/GeometryTests/TriangulationsTests.jl @@ -1,88 +1,126 @@ module TriangulationsTests -using Test -using FillArrays -using LinearAlgebra: norm - using Gridap.Geometry 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 -import Gridap.Geometry: get_cell_coordinates - -struct MockTriangulation <: Triangulation{2,2} end - -function get_cell_coordinates(::MockTriangulation) - c1 = Point{2,Float64}[(0,0), (2,0), (0,2)] - c2 = Point{2,Float64}[(2,0), (2,2), (1,1)] - c3 = Point{2,Float64}[(2,2), (0,2), (1,1)] - [c1,c2,c3] -end - -function get_cell_type(::MockTriangulation) - ncells = 3 - Fill(Int8(1),ncells) -end +using Test +using FillArrays -function get_reffes(::MockTriangulation) - [TRI3,] +domain = (-1,1,-1,1) +cells = (10,10) +model = CartesianDiscreteModel(domain,cells) +Ω = Triangulation(model) +test_triangulation(Ω) + +@test model === get_background_model(Ω) +@test model === get_active_model(Ω) +@test get_grid(Ω) === get_grid(model) +glue = get_glue(Ω,Val(2)) +@test isa(glue.tface_to_mface,IdentityVector) +@test isa(glue.mface_to_tface,IdentityVector) +glue.mface_to_tface === glue.tface_to_mface +@test isa(glue.tface_to_mface_map,Fill) + +glue_0 = get_glue(Ω,Val(0)) +glue_1 = get_glue(Ω,Val(1)) +glue_2 = get_glue(Ω,Val(2)) + +Θ = GenericTriangulation( + get_grid(Ω), + get_background_model(Ω), + (glue_0,glue_1,glue_2)) +test_triangulation(Θ) +@test get_glue(Θ,Val(0)) === glue_0 +@test get_glue(Θ,Val(1)) === glue_1 +@test get_glue(Θ,Val(2)) === glue_2 + +Θ = GenericTriangulation( + get_grid(Ω), + get_background_model(Ω)) +test_triangulation(Θ) + +Θ = GenericTriangulation(get_grid(Ω)) +@test isa(Θ,Triangulation) + +Γ = Triangulation(ReferenceFE{1},model) +@test model === get_background_model(Γ) +glue = get_glue(Γ,Val(1)) +@test isa(glue.tface_to_mface,IdentityVector) +@test isa(glue.mface_to_tface,IdentityVector) +glue.mface_to_tface === glue.tface_to_mface +@test isa(glue.tface_to_mface_map,Fill) + +cell_xs = get_cell_coordinates(Ω) +cell_mask = lazy_map(cell_xs) do xs + R = 0.7 + n = length(xs) + x = (1/n)*sum(xs) + d = x[1]^2 + x[2]^2 - R^2 + d < 0 end -trian = MockTriangulation() -test_triangulation(trian) - -a = lazy_map(x->norm(x[1]-x[2]),get_cell_coordinates(trian)) -test_array(a,collect(a)) - -cell_map = get_cell_map(trian) -cell_J = lazy_map(∇,cell_map) - -ncells = num_cells(trian) -@test ncells == 3 - -qi = Point(0.5,0.5) -np = 4 -qe = fill(qi,np) -q = Fill(qe,ncells) - -xi1 = Point(1.0, 1.0) -xi2 = Point(1.5, 1.5) -xi3 = Point(0.5, 1.5) -x1 = fill(xi1,np) -x2 = fill(xi2,np) -x3 = fill(xi3,np) -x = [x1,x2,x3] - -ji1 = TensorValue(2.0, 0.0, 0.0, 2.0) -ji2 = TensorValue(0.0, -1.0, 2.0, 1.0) -ji3 = TensorValue(-2.0, -1.0, 0.0, -1.0) -j1 = fill(ji1,np) -j2 = fill(ji2,np) -j3 = fill(ji3,np) -j = [j1,j2,j3] - -@test all(lazy_map(test_map,x,cell_map,q)) -@test all(lazy_map(test_map,j,cell_J,q)) -test_array(lazy_map(evaluate,cell_map,q),x) -test_array(lazy_map(evaluate,cell_J,q),j) - -@test is_first_order(trian) == true - -#cf1 = CellField(3,trian) -#cf2 = CellField(identity,trian) - -#x = get_physical_coordinate(trian) - -@test get_cell_to_bgcell(trian) == collect(1:num_cells(trian)) -r = rand(num_cells(trian)) -@test r === lazy_map(Reindex(r),get_cell_to_bgcell(trian)) - -#using Gridap.Visualization -#writevtk(trian,"trian",cellfields=["cf1"=>cf1,"cf2"=>cf2,"x"=>x, "gradx"=>∇(x)]) +Ω1 = Triangulation(model,cell_mask) +@test model === get_background_model(Ω1) +@test model !== get_active_model(Ω1) +glue = get_glue(Ω1,Val(2)) +@test glue.tface_to_mface == findall(collect1d(cell_mask)) +@test isa(glue.tface_to_mface_map,Fill) +@test model === get_background_model(Ω) +@test isa(glue.mface_to_tface,PosNegPartition) +@test glue.mface_to_tface[glue.tface_to_mface] == 1:length(glue.tface_to_mface) + +tface_to_val = [ rand(3,4) for i in 1:num_cells(Ω1) ] +mface_to_val = extend(tface_to_val,glue.mface_to_tface) +@test mface_to_val[glue.tface_to_mface] == tface_to_val + +cell_mcell = findall(collect1d(cell_mask)) +Ω1 = Triangulation(model,cell_mcell) +glue = get_glue(Ω1,Val(2)) +@test glue.tface_to_mface == cell_mcell +@test isa(glue.tface_to_mface_map,Fill) +@test model === get_background_model(Ω) +@test isa(glue.mface_to_tface,PosNegPartition) +@test glue.mface_to_tface[glue.tface_to_mface] == 1:length(glue.tface_to_mface) + +Ω1 = view(Ω,cell_mcell) +glue = get_glue(Ω1,Val(2)) +@test glue.tface_to_mface == cell_mcell +@test isa(glue.tface_to_mface_map,Fill) +@test model === get_background_model(Ω) +@test isa(glue.mface_to_tface,PosNegPartition) +@test glue.mface_to_tface[glue.tface_to_mface] == 1:length(glue.tface_to_mface) + +labels = get_face_labeling(model) +entity = num_entities(labels)+1 +labels.d_to_dface_to_entity[end][cell_mcell] .= entity +add_tag!(labels,"Ω1",[entity]) +Ω1 = Triangulation(model,tags="Ω1") +glue = get_glue(Ω1,Val(2)) +@test glue.tface_to_mface == cell_mcell +@test isa(glue.tface_to_mface_map,Fill) +@test model === get_background_model(Ω) +@test isa(glue.mface_to_tface,PosNegPartition) +@test glue.mface_to_tface[glue.tface_to_mface] == 1:length(glue.tface_to_mface) + +glue = get_glue(Ω,Val(2)) +tface_to_data = rand(num_cells(Ω)) +mface_to_data = extend(tface_to_data,glue.mface_to_tface) +@test tface_to_data === mface_to_data + +glue = get_glue(Ω1,Val(2)) +tface_to_data = rand(num_cells(Ω1)) +mface_to_data = extend(tface_to_data,glue.mface_to_tface) +@test mface_to_data[glue.tface_to_mface] == tface_to_data +tface_to_data = get_cell_shapefuns(Ω1) +mface_to_data = extend(tface_to_data,glue.mface_to_tface) +@test mface_to_data[glue.tface_to_mface] == tface_to_data + +@test is_change_possible(Ω,Ω1) +@test is_change_possible(Ω1,Ω) + +Ω2 = best_target(Ω1,Ω) +glue = get_glue(Ω2,Val(2)) +@test isa(glue.tface_to_mface,IdentityVector) +@test isa(glue.mface_to_tface,IdentityVector) end # module diff --git a/test/GeometryTests/UnstructuredGridsTests.jl b/test/GeometryTests/UnstructuredGridsTests.jl index 3ec2769e0..11a94a99d 100644 --- a/test/GeometryTests/UnstructuredGridsTests.jl +++ b/test/GeometryTests/UnstructuredGridsTests.jl @@ -6,6 +6,7 @@ using Gridap.Geometry using Gridap.Fields using Gridap.ReferenceFEs using Gridap.Io +using Gridap.TensorValues # Unstructured grid from raw data @@ -15,6 +16,12 @@ node_coordinates = get_node_coordinates(trian) cell_node_ids = get_cell_node_ids(trian) reffes = get_reffes(trian) cell_types = get_cell_type(trian) +facet_normal = fill(VectorValue(0,1),num_cells(trian)) #dummy value + +grid = UnstructuredGrid(node_coordinates,cell_node_ids,reffes,cell_types,Oriented(),facet_normal) +test_grid(grid) +@test is_oriented(grid) == true +@test get_facet_normal(grid) === facet_normal grid = UnstructuredGrid(node_coordinates,cell_node_ids,reffes,cell_types,Oriented()) test_grid(grid) diff --git a/test/GeometryTests/runtests.jl b/test/GeometryTests/runtests.jl index e6b64ad77..6ee18e4d9 100644 --- a/test/GeometryTests/runtests.jl +++ b/test/GeometryTests/runtests.jl @@ -2,8 +2,6 @@ module GeometryTests using Test -@testset "Triangulations" begin include("TriangulationsTests.jl") end - @testset "Grids" begin include("GridsTests.jl") end @testset "UnstructuredGrids" begin include("UnstructuredGridsTests.jl") end @@ -24,33 +22,18 @@ using Test @testset "PeriodicBC" begin include("PeriodicBCTests.jl") end -@testset "RestrictedTriangulations" begin include("RestrictedTriangulationsTests.jl") end - -@testset "BoundaryTriangulations" begin include("BoundaryTriangulationsTests.jl") end - -@testset "SkeletonTriangulations" begin include("SkeletonTriangulationsTests.jl") end - @testset "GridPortions" begin include("GridPortionsTests.jl") end @testset "DiscreteModelPortions" begin include("DiscreteModelPortionsTests.jl") end -@testset "RestrictedDiscreteModels" begin include("RestrictedDiscreteModelsTests.jl") end +@testset "Triangulations" begin include("TriangulationsTests.jl") end + +@testset "BoundaryTriangulations" begin include("BoundaryTriangulationsTests.jl") end + +@testset "SkeletonTriangulations" begin include("SkeletonTriangulationsTests.jl") end @testset "AppendedTriangulations" begin include("AppendedTriangulationsTests.jl") end @testset "CompressedCellArrays" begin include("CompressedCellArraysTests.jl") end -@testset "BoundaryDiscreteModels" begin include("BoundaryDiscreteModelsTests.jl") end - -# -#@testset "CellFields" begin include("CellFieldsTests.jl") end -# -#@testset "QPointCellFields" begin include("QPointCellFieldsTests.jl") end -# -# -#@testset "SkeletonPairs" begin include("SkeletonPairsTests.jl") end -# -#@testset "CellQuadratures" begin include("CellQuadraturesTests.jl") end -# - end # module diff --git a/test/GridapTests/PoissonLagrangeMultiplierTests.jl b/test/GridapTests/PoissonLagrangeMultiplierTests.jl index e5811fc30..df703c9c5 100644 --- a/test/GridapTests/PoissonLagrangeMultiplierTests.jl +++ b/test/GridapTests/PoissonLagrangeMultiplierTests.jl @@ -14,33 +14,35 @@ domain = (0,1,0,1) partition = (3,3) model = CartesianDiscreteModel(domain,partition) -labels = get_face_labeling(model) -bgface_to_mask = get_face_mask(labels,"boundary",1) -Γface_to_bgface = findall(bgface_to_mask) -model_Γ = BoundaryDiscreteModel(Polytope{1},model,Γface_to_bgface) +Ω = Interior(model) +Γ = Boundary(model) +Λ = Skeleton(Γ) -Γ = Triangulation(model_Γ) -Γface_coords = get_cell_coordinates(Γ) -Γface_mask = lazy_map(is_left,Γface_coords) +Γface_to_coords = get_cell_coordinates(Γ) +Γface_mask = lazy_map(is_left,Γface_to_coords) Γlface_Γface = findall(Γface_mask) Γrface_Γface = findall(!,Γface_mask) -Γl = BoundaryTriangulation(model,view(Γface_to_bgface,Γlface_Γface)) -Γr = BoundaryTriangulation(model,view(Γface_to_bgface,Γrface_Γface)) - -Λ = SkeletonTriangulation(model_Γ) +Γl = Triangulation(Γ,Γlface_Γface) +Γr = Triangulation(Γ,Γrface_Γface) order = 2 reffe_u = ReferenceFE(lagrangian,Float64,order) reffe_λ = ReferenceFE(lagrangian,Float64,order-1) -V = TestFESpace(model,reffe_u,conformity=:H1) -S = TestFESpace(model_Γ,reffe_λ,conformity=:L2) +V = TestFESpace(Ω,reffe_u,conformity=:H1) +S = TestFESpace(Γ,reffe_λ,conformity=:L2) U = TrialFESpace(V) L = TrialFESpace(S) Y = MultiFieldFESpace([V,S]) X = MultiFieldFESpace([U,L]) +#uh, λh = FEFunction(Y,rand(num_free_dofs(Y))) +#writevtk(Ω,"t_Ω",nsubcells=10,cellfields=["uh"=>uh]) +#writevtk(Γ,"t_Γ",nsubcells=10,cellfields=["uh"=>uh,"λh"=>λh]) +#writevtk(Λ,"t_Λ",cellfields=["uh"=>mean(uh),"λh"=>mean(λh)]) +#writevtk(Γr,"t_Γr",nsubcells=10,cellfields=["uh"=>uh,"λh"=>λh]) +#writevtk(Γl,"t_Γl",nsubcells=10,cellfields=["uh"=>uh,"λh"=>λh]) + degree = 2*order -Ω = Triangulation(model) dΩ = Measure(Ω,degree) dΓl = Measure(Γl,degree) dΓr = Measure(Γr,degree) diff --git a/test/GridapTests/PoissonTests.jl b/test/GridapTests/PoissonTests.jl index 99981b576..bea1fe375 100644 --- a/test/GridapTests/PoissonTests.jl +++ b/test/GridapTests/PoissonTests.jl @@ -69,7 +69,7 @@ for data in [ vector_data, scalar_data ] for domain_style in (ReferenceDomain(),PhysicalDomain()) cell_fe = FiniteElements(domain_style,model,lagrangian,T,order) - V = TestFESpace(model,cell_fe,dirichlet_tags="dirichlet",labels=labels) + V = TestFESpace(Ω,cell_fe,dirichlet_tags="dirichlet",labels=labels) U = TrialFESpace(V,u) uh = interpolate(u, U) diff --git a/test/GridapTests/SurfaceCouplingTests.jl b/test/GridapTests/SurfaceCouplingTests.jl index 8c999c51b..490f958fa 100644 --- a/test/GridapTests/SurfaceCouplingTests.jl +++ b/test/GridapTests/SurfaceCouplingTests.jl @@ -48,13 +48,11 @@ cell_to_coords = get_cell_coordinates(Ω) cell_to_is_solid = lazy_map(is_in,cell_to_coords) cell_to_is_fluid = lazy_map(!,cell_to_is_solid) -model_solid = DiscreteModel(model,cell_to_is_solid) -model_fluid = DiscreteModel(model,cell_to_is_fluid) +Ωs = Triangulation(model,cell_to_is_solid) +Ωf = Triangulation(model,cell_to_is_fluid) -Ωs = Triangulation(model_solid) -Ωf = Triangulation(model_fluid) Λ = BoundaryTriangulation(model,labels,tags="neumann") -Γ = InterfaceTriangulation(model_fluid,model_solid) +Γ = InterfaceTriangulation(Ωf,Ωs) n_Λ = get_normal_vector(Λ) n_Γ = get_normal_vector(Γ) @@ -73,8 +71,8 @@ dΓ = Measure(Γ,degree) reffe_u = ReferenceFE(lagrangian,VectorValue{2,Float64},order) reffe_p = ReferenceFE(lagrangian,Float64,order-1,space=:P) -V = TestFESpace(model,reffe_u,conformity=:H1,labels=labels,dirichlet_tags="dirichlet") -Q = TestFESpace(model_fluid,reffe_p,conformity=:L2) +V = TestFESpace(Ω,reffe_u,conformity=:H1,labels=labels,dirichlet_tags="dirichlet") +Q = TestFESpace(Ωf,reffe_p,conformity=:L2) U = TrialFESpace(V,u) P = Q @@ -107,8 +105,11 @@ uh, ph = solve(op) eu = u - uh ep = p - ph -#writevtk(Ω,"trian",cellfields=["uh"=>uh,"ph"=>ph,"eu"=>eu,"ep"=>ep]) -#writevtk(Ωf,"trian_fluid",cellfields=["uh"=>uh,"ph"=>ph,"eu"=>eu,"ep"=>ep]) +#writevtk(Ω,"trian_Ω",cellfields=["uh"=>uh,"ph"=>ph,"eu"=>eu,"ep"=>ep]) +#writevtk(Ωs,"trian_Ωs",cellfields=["uh"=>uh,"ph"=>ph,"eu"=>eu,"ep"=>ep]) +#writevtk(Γ,"trian_Γ",cellfields=["uh+"=>uh.⁺,"p"=>p,"n+"=>n_Γ.⁺]) +#writevtk(Λ,"trian_Λ",cellfields=["uh"=>uh,"ph"=>ph,"eu"=>eu,"ep"=>ep,"n"=>n_Λ]) +#writevtk(Ωf,"trian_Ωf",cellfields=["uh"=>uh,"ph"=>ph,"eu"=>eu,"ep"=>ep]) # Errors diff --git a/test/MultiFieldTests/MultiFieldFESpacesTests.jl b/test/MultiFieldTests/MultiFieldFESpacesTests.jl index 2770bfb40..74818364a 100644 --- a/test/MultiFieldTests/MultiFieldFESpacesTests.jl +++ b/test/MultiFieldTests/MultiFieldFESpacesTests.jl @@ -43,7 +43,6 @@ du, dp = dx cellmat = integrate(dv*du,quad) cellvec = integrate(dv*2,quad) -cellids = get_cell_to_bgcell(trian) cellmatvec = pair_arrays(cellmat,cellvec) @test isa(cellmat[end],ArrayBlock) @test cellmat[1][1,1] != nothing @@ -52,10 +51,6 @@ cellmatvec = pair_arrays(cellmat,cellvec) @test cellvec[1][1] != nothing @test cellvec[1][2] == nothing -matvecdata = (cellmatvec,cellids,cellids) -matdata = (cellmat,cellids,cellids) -vecdata = (cellvec,cellids) - free_values = rand(num_free_dofs(X)) xh = FEFunction(X,free_values) test_fe_function(xh) @@ -76,8 +71,8 @@ cell_dof_ids = get_cell_dof_ids(X,trian) cf = CellField(X,get_cell_dof_ids(X,trian)) @test isa(cf,MultiFieldCellField) -test_fe_space(X,matvecdata,matdata,vecdata) -test_fe_space(Y,matvecdata,matdata,vecdata) +test_fe_space(X,cellmatvec,cellmat,cellvec,trian) +test_fe_space(Y,cellmatvec,cellmat,cellvec,trian) #using Gridap.Visualization #writevtk(trian,"trian";nsubcells=30,cellfields=["uh" => uh, "ph"=> ph]) diff --git a/test/MultiFieldTests/MultiFieldSparseMatrixAssemblersTests.jl b/test/MultiFieldTests/MultiFieldSparseMatrixAssemblersTests.jl index bae0f1156..d9bcd0b8b 100644 --- a/test/MultiFieldTests/MultiFieldSparseMatrixAssemblersTests.jl +++ b/test/MultiFieldTests/MultiFieldSparseMatrixAssemblersTests.jl @@ -50,29 +50,27 @@ grad_dp = ∇(dp) cellmat = integrate(dv*du,quad) cellvec = integrate(dv*2,quad) -cellids = get_cell_to_bgcell(trian) cellmatvec = pair_arrays(cellmat,cellvec) -rows = get_cell_dof_ids(Y,cellids) -cols = get_cell_dof_ids(X,cellids) -cellmat_c = attach_constraints_cols(X,cellmat,cellids) -cellmat_rc = attach_constraints_rows(Y,cellmat_c,cellids) -cellvec_r = attach_constraints_rows(Y,cellvec,cellids) -cellmatvec_c = attach_constraints_cols(X,cellmatvec,cellids) -cellmatvec_rc = attach_constraints_rows(Y,cellmatvec_c,cellids) +rows = get_cell_dof_ids(Y,trian) +cols = get_cell_dof_ids(X,trian) +cellmat_c = attach_constraints_cols(X,cellmat,trian) +cellmat_rc = attach_constraints_rows(Y,cellmat_c,trian) +cellvec_r = attach_constraints_rows(Y,cellvec,trian) +cellmatvec_c = attach_constraints_cols(X,cellmatvec,trian) +cellmatvec_rc = attach_constraints_rows(Y,cellmatvec_c,trian) #cellmat_Γ = integrate( jump(dv)*dp.⁺ + mean(dq)*jump(dp), quad_Γ) cellmat_Γ = integrate( jump(dv)*mean(du) + jump(∇(dq))⋅jump(∇(dp)), quad_Γ) cellvec_Γ = integrate( jump(dv) + mean(dq),quad_Γ) cellmatvec_Γ = pair_arrays(cellmat_Γ,cellvec_Γ) -cellids_Γ = get_cell_to_bgcell(trian_Γ) -rows_Γ = get_cell_dof_ids(Y,cellids_Γ) -cols_Γ = get_cell_dof_ids(X,cellids_Γ) -cellmat_Γ_c = attach_constraints_cols(X,cellmat_Γ,cellids_Γ) -cellmat_Γ_rc = attach_constraints_rows(Y,cellmat_Γ_c,cellids_Γ) -cellvec_Γ_r = attach_constraints_rows(Y,cellvec_Γ,cellids_Γ) -cellmatvec_Γ_c = attach_constraints_cols(X,cellmatvec_Γ,cellids_Γ) -cellmatvec_Γ_rc = attach_constraints_rows(Y,cellmatvec_Γ_c,cellids_Γ) +rows_Γ = get_cell_dof_ids(Y,trian_Γ) +cols_Γ = get_cell_dof_ids(X,trian_Γ) +cellmat_Γ_c = attach_constraints_cols(X,cellmat_Γ,trian_Γ) +cellmat_Γ_rc = attach_constraints_rows(Y,cellmat_Γ_c,trian_Γ) +cellvec_Γ_r = attach_constraints_rows(Y,cellvec_Γ,trian_Γ) +cellmatvec_Γ_c = attach_constraints_cols(X,cellmatvec_Γ,trian_Γ) +cellmatvec_Γ_rc = attach_constraints_rows(Y,cellmatvec_Γ_c,trian_Γ) assem = SparseMatrixAssembler(SparseMatrixCSR{0,Float64,Int},X,Y) @@ -81,6 +79,11 @@ matdata = ([cellmat,cellmat_Γ],[rows,rows_Γ],[cols,cols_Γ]) vecdata = ([cellvec,cellvec_Γ],[rows,rows_Γ]) data = (matvecdata,matdata,vecdata) +#@show num_free_dofs(X) +#@show num_free_dofs(Y) +#display(cellmat_Γ[end][1,1]) +#display(rows_Γ[end][1]) + test_assembler(assem,matdata,vecdata,data) A = assemble_matrix(assem,matdata) diff --git a/test/VisualizationTests/VtkTests.jl b/test/VisualizationTests/VtkTests.jl index db35225e3..5740a3e8d 100644 --- a/test/VisualizationTests/VtkTests.jl +++ b/test/VisualizationTests/VtkTests.jl @@ -29,6 +29,13 @@ write_vtk_file( nodaldata=["nodeid"=>node_ids], celldata=["cellid"=>cell_ids,"centers"=>cell_center]) +pvtk = Visualization.create_pvtk_file( + trian,f, + pvtkargs = [:part=>1,:nparts=>1], + nodaldata=["nodeid"=>node_ids], + celldata=["cellid"=>cell_ids,"centers"=>cell_center]) +vtk_save(pvtk) + reffe = LagrangianRefFE(VectorValue{3,Float64},WEDGE,(3,3,4)) f = joinpath(d,"reffe") writevtk(reffe,f) @@ -60,12 +67,12 @@ model = DiscreteModelMock() writevtk(model,f,labels=get_face_labeling(model)) f = joinpath(d,"trian") -trian = GridMock() +trian = Triangulation(model) writevtk(trian,f,order=2) domain = (0,1,0,1) partition = (2,4) -trian = CartesianGrid(domain,partition) +trian = Triangulation(CartesianDiscreteModel(domain,partition)) writevtk(trian,f,nsubcells=5,celldata=["rnd"=>rand(num_cells(trian))]) @@ -92,10 +99,6 @@ f = joinpath(d,"x") writevtk(x,f,celldata=["cellid" => collect(1:num_cells(trian))], nodaldata = ["x" => x]) - -f = joinpath(d,"trian") -writevtk(trian,f) - # Write VTK_LAGRANGE_* FE elements writevtk(Grid(LagrangianRefFE(Float64,TRI,3)),joinpath(d,"tri_order3")) writevtk(Grid(LagrangianRefFE(Float64,TRI,4)),joinpath(d,"tri_order4")) @@ -106,6 +109,8 @@ writevtk(Grid(LagrangianRefFE(Float64,TET,3)),joinpath(d,"tet_order1")) writevtk(Grid(LagrangianRefFE(Float64,HEX,3)),joinpath(d,"hex_order1")) # Paraview collections +model = DiscreteModelMock() +trian = Triangulation(model) f = joinpath(d,"collection") paraview_collection(f) do pvd for i in 1:10