From c070140a00907efa1cbf8bb4931556d525b2e363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20K=C3=B6hler?= Date: Thu, 23 Mar 2023 13:50:39 +0100 Subject: [PATCH] MakiePlotter rewrite with ShaderAbstractions.Buffer (#69) * plots solutionplot for heat problem, need to filter the visible triangles by a buffer * use buffer * why is this slow * make solutionplot more readable and make a copy of physicalcoords for the Shader Buffer * fix ferriteviewer for newer Makie * remove unneccessary copy * make all examples work, remove unneccessary functions * fix clip plane * remove unneccessary copy * changelog entry * remove unneccessary visible function * eliminate remaining unneccessary allocs in transfer_solution * Apply suggestions from code review Co-authored-by: Dennis Ogiermann --------- Co-authored-by: Dennis Ogiermann --- CHANGELOG.md | 6 +++ Project.toml | 2 + src/FerriteViz.jl | 2 + src/makieplotting.jl | 115 +++++++++++++++++++++++++++++++------------ src/utils.jl | 106 ++++++++++++++++++++------------------- 5 files changed, 147 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa2cfdc..b72ce26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Modified - Removed unnecessary extra dispatches for three-dimensional case ([#56][github-56]). - function barrier for `transfer_solution` such that its closer to type groundedness ([#68][github-68]). + - `MakiePlotter` holds now `ShaderAbstractions.Buffer`s ([#69][github-69]) + - triangles are now stored in `Buffer`s with Observables + - triangle coords are now `Buffers`s with Observables +- replace overcomplicated ternary operators by `begin end` expressions ([#69][github-69]) +- remove unused functions ([#69][github-69]) ### Fixed - Renamed `Crincle` to `Crinkle` ([#56][github-56]). @@ -46,6 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [github-65]: https://github.com/Ferrite-FEM/FerriteViz.jl/pull/65 [github-63]: https://github.com/Ferrite-FEM/FerriteViz.jl/pull/63 [github-68]: https://github.com/Ferrite-FEM/FerriteViz.jl/pull/68 +[github-69]: https://github.com/Ferrite-FEM/FerriteViz.jl/pull/69 [Unreleased]: https://github.com/Ferrite-FEM/FerriteViz.jl/compare/v0.2.0...HEAD [0.2.0]: https://github.com/Ferrite-FEM/FerriteViz.jl/compare/v0.2.0...v0.1.4 diff --git a/Project.toml b/Project.toml index 33e9488..1800900 100644 --- a/Project.toml +++ b/Project.toml @@ -5,8 +5,10 @@ version = "0.2.0" [deps] Ferrite = "c061ca5d-56c9-439f-9c0e-210fe06d3992" +GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" +ShaderAbstractions = "65257c39-d410-5151-9873-9b3e5be5013e" Tensors = "48a634ad-e948-5137-8d70-aa71f2a747f4" [compat] diff --git a/src/FerriteViz.jl b/src/FerriteViz.jl index 4557cd6..3a35828 100644 --- a/src/FerriteViz.jl +++ b/src/FerriteViz.jl @@ -3,6 +3,8 @@ module FerriteViz using Makie using Tensors import Ferrite +import GeometryBasics +import ShaderAbstractions import LinearAlgebra abstract type AbstractPlotter end diff --git a/src/makieplotting.jl b/src/makieplotting.jl index 625cb5f..3378d7f 100644 --- a/src/makieplotting.jl +++ b/src/makieplotting.jl @@ -8,10 +8,6 @@ function update!(plotter::MakiePlotter, u::Vector) Makie.notify(plotter.u) end -function Makie.convert_arguments(P::Type{<:Makie.Mesh}, plotter::MakiePlotter) - return Makie.convert_arguments(P,plotter.physical_coords,visible(plotter)) -end - """ solutionplot(plotter::MakiePlotter; kwargs...) solutionplot(dh::AbstractDofHandler, u::Vector; kwargs...) @@ -45,13 +41,32 @@ end function Makie.plot!(SP::SolutionPlot{<:Tuple{<:MakiePlotter}}) plotter = SP[1][] - solution = @lift($(SP[:field])===:default ? reshape(transfer_solution(plotter,$(plotter.u); field_idx=1, process=$(SP[:process])), num_vertices(plotter)) : reshape(transfer_solution(plotter,$(plotter.u); field_idx=Ferrite.find_field(plotter.dh,$(SP[:field])), process=$(SP[:process])), num_vertices(plotter))) - u_matrix = @lift($(SP[:deformation_field])===:default ? zeros(0,3) : transfer_solution(plotter,$(plotter.u); field_idx=Ferrite.find_field(plotter.dh,$(SP[:deformation_field])), process=identity)) - coords = @lift($(SP[:deformation_field])===:default ? plotter.physical_coords : plotter.physical_coords .+ ($(SP[:deformation_scale]) .* $(u_matrix))) + solution = @lift begin + if $(SP[:field])===:default + reshape(transfer_solution(plotter,$(plotter.u); field_idx=1, process=$(SP[:process])), num_vertices(plotter)) + else + reshape(transfer_solution(plotter,$(plotter.u); field_idx=Ferrite.find_field(plotter.dh,$(SP[:field])), process=$(SP[:process])), num_vertices(plotter)) + end + end + u_matrix = @lift begin + if $(SP[:deformation_field])===:default + Ferrite.getdim(plotter.dh.grid) > 2 ? Point3f[Point3f(0,0,0)] : Point2f[Point2f(0,0)] + else + #TODO remove convert + convert(Vector{Point{Ferrite.getdim(plotter.dh.grid),Float32}},Makie.to_vertices(transfer_solution(plotter,$(plotter.u); field_idx=Ferrite.find_field(plotter.dh,$(SP[:deformation_field])), process=identity))) + end + end + @lift begin + if $(SP[:deformation_field])===:default + plotter.physical_coords_mesh[1:end] = plotter.physical_coords + else + plotter.physical_coords_mesh[1:end] = plotter.physical_coords .+ ($(SP[:deformation_scale]) .* $(u_matrix)) + end + end mins = @lift(minimum($solution)) maxs = @lift(maximum($solution)) SP[:colorrange] = @lift(isapprox($mins,$maxs) ? ($mins,1.01($maxs)) : ($mins,$maxs)) - return Makie.mesh!(SP, coords, visible(plotter), color=solution, shading=SP[:shading], scale_plot=SP[:scale_plot], colormap=SP[:colormap], transparent=SP[:transparent]) + return Makie.mesh!(SP, plotter.mesh, color=solution, shading=SP[:shading], scale_plot=SP[:scale_plot], colormap=SP[:colormap], transparent=SP[:transparent]) end """ @@ -86,13 +101,25 @@ end function Makie.plot!(CP::CellPlot{<:Tuple{<:MakiePlotter{dim},Vector}}) where dim plotter = CP[1][] qp_values = CP[2][] - u_matrix = @lift($(CP[:deformation_field])===:default ? zeros(0,3) : transfer_solution(plotter,$(plotter.u); field_idx=Ferrite.find_field(plotter.dh,$(CP[:deformation_field])), process=identity)) - coords = @lift($(CP[:deformation_field])===:default ? plotter.physical_coords : plotter.physical_coords .+ ($(CP[:deformation_scale]) .* $(u_matrix))) + u_matrix = @lift begin + if $(CP[:deformation_field])===:default + Point3f[Point3f(0,0,0)] + else + convert(Vector{Point{Ferrite.getdim(plotter.dh.grid),Float32}},Makie.to_vertices(transfer_solution(plotter,$(plotter.u); field_idx=Ferrite.find_field(plotter.dh,$(CP[:deformation_field])), process=identity))) + end + end + coords = @lift begin + if $(CP[:deformation_field])===:default + plotter.physical_coords_mesh[1:end] = plotter.physical_coords + else + plotter.physical_coords_mesh[1:end] = plotter.physical_coords .+ ($(CP[:deformation_scale]) .* $(u_matrix)) + end + end mins = minimum(qp_values) maxs = maximum(qp_values) CP[:colorrange] = @lift(isapprox($mins,$maxs) ? ($mins,1.01($maxs)) : ($mins,$maxs)) solution = @lift(reshape(transfer_scalar_celldata(plotter, qp_values; process=$(CP[:process])), num_vertices(plotter))) - return Makie.mesh!(CP, coords, visible(plotter), color=solution, shading=CP[:shading], scale_plot=CP[:scale_plot], colormap=CP[:colormap], transparent=CP[:transparent]) + return Makie.mesh!(CP, plotter.mesh, color=solution, shading=CP[:shading], scale_plot=CP[:scale_plot], colormap=CP[:colormap], transparent=CP[:transparent]) end """ @@ -145,17 +172,29 @@ function Makie.plot!(WF::Wireframe{<:Tuple{<:MakiePlotter{dim}}}) where dim # u_matrix = @lift($(WF[:deformation_field])===:default ? zeros(0,3) : transfer_solution(plotter; field_idx=Ferrite.find_field(plotter.dh,$(WF[:deformation_field])), process=identity)) # coords = @lift($(WF[:deformation_field])===:default ? plotter.physical_coords : plotter.physical_coords .+ ($(WF[:scale]) .* $(u_matrix))) #original representation - nodal_u_matrix = @lift($(WF[:deformation_field])===:default ? zeros(0,3) : dof_to_node(plotter.dh, $(WF[1][].u); field=Ferrite.find_field(plotter.dh,$(WF[:deformation_field])))) - gridnodes = @lift($(WF[:deformation_field])===:default ? plotter.gridnodes : plotter.gridnodes .+ ($(WF[:deformation_scale]) .* $(nodal_u_matrix))) + nodal_u_matrix = @lift begin + if $(WF[:deformation_field])===:default + Point3f[Point3f(0,0,0)] + else + convert(Vector{Point{Ferrite.getdim(plotter.dh.grid),Float32}},Makie.to_vertices(dof_to_node(plotter.dh, $(WF[1][].u); field=Ferrite.find_field(plotter.dh,$(WF[:deformation_field]))))) + end + end + gridnodes = @lift begin + if $(WF[:deformation_field])===:default + plotter.gridnodes + else + plotter.gridnodes .+ ($(WF[:deformation_scale]) .* $(nodal_u_matrix)) + end + end lines = @lift begin dim > 2 ? (lines = Point3f[]) : (lines = Point2f[]) for cell in Ferrite.getcells(plotter.dh.grid) boundaryentities = dim < 3 ? Ferrite.faces(cell) : Ferrite.edges(cell) - append!(lines, [$gridnodes[e,:] for boundary in boundaryentities for e in boundary]) + append!(lines, [$gridnodes[e] for boundary in boundaryentities for e in boundary]) end lines end - nodes = @lift($(WF[:plotnodes]) ? $(gridnodes) : zeros(Float32,0,3)) + nodes = @lift($(WF[:plotnodes]) ? $(gridnodes) : Point3f[Point3f(0,0,0)]) #plot cellsets cellsets = plotter.dh.grid.cellsets cellset_to_value = Dict{String,Int}() @@ -170,20 +209,32 @@ function Makie.plot!(WF::Wireframe{<:Tuple{<:MakiePlotter{dim}}}) where dim end end end - u_matrix = @lift($(WF[:deformation_field])===:default ? zeros(0,3) : transfer_solution(plotter,$(plotter.u); field_idx=Ferrite.find_field(plotter.dh,$(WF[:deformation_field])), process=identity)) - coords = @lift($(WF[:deformation_field])===:default ? plotter.physical_coords : plotter.physical_coords .+ ($(WF[:deformation_scale]) .* $(u_matrix))) + u_matrix = @lift begin + if $(WF[:deformation_field])===:default + Point3f[Point3f(0,0,0)] + else + Makie.to_vertices(transfer_solution(plotter,$(plotter.u); field_idx=Ferrite.find_field(plotter.dh,$(WF[:deformation_field])), process=identity)) + end + end + coords = @lift begin + if $(WF[:deformation_field])===:default + plotter.physical_coords_mesh[1:end] = plotter.physical_coords + else + plotter.physical_coords_mesh[1:end] = plotter.physical_coords .+ ($(WF[:deformation_scale]) .* $(u_matrix)) + end + end colorrange = isempty(cellset_to_value) ? (0,1) : (0,maximum(values(cellset_to_value))) cellset_u = reshape(transfer_scalar_celldata(plotter, cellset_u; process=identity), num_vertices(plotter)) - Makie.mesh!(WF, coords, visible(plotter), color=cellset_u, shading=false, scale_plot=false, colormap=:darktest, visible=WF[:cellsets]) + Makie.mesh!(WF, plotter.mesh, color=cellset_u, shading=false, scale_plot=false, colormap=:darktest, visible=WF[:cellsets]) #plot the nodes Makie.scatter!(WF,gridnodes,markersize=WF[:markersize], color=WF[:color], visible=WF[:visible]) #set up nodelabels nodelabels = @lift $(WF[:nodelabels]) ? ["$i" for i in 1:size($gridnodes,1)] : [""] - nodepositions = @lift $(WF[:nodelabels]) ? [dim < 3 ? Point2f(row) : Point3f(row) for row in eachrow($gridnodes)] : (dim < 3 ? [Point2f((0,0))] : [Point3f((0,0,0))]) + nodepositions = @lift $(WF[:nodelabels]) ? $gridnodes : (dim < 3 ? Point2f[Point2f((0,0))] : Point3f[Point3f((0,0,0))]) #set up celllabels celllabels = @lift $(WF[:celllabels]) ? ["$i" for i in 1:Ferrite.getncells(plotter.dh.grid)] : [""] cellpositions = @lift $(WF[:celllabels]) ? [midpoint(cell,$gridnodes) for cell in Ferrite.getcells(plotter.dh.grid)] : (dim < 3 ? [Point2f((0,0))] : [Point3f((0,0,0))]) - Makie.text!(WF,nodelabels, position=nodepositions, textsize=WF[:textsize], offset=WF[:offset],color=WF[:nodelabelcolor]) + Makie.text!(WF,nodepositions, text=nodelabels, fontsize=WF[:textsize], offset=WF[:offset],color=WF[:nodelabelcolor]) Makie.text!(WF,celllabels, position=cellpositions, textsize=WF[:textsize], color=WF[:celllabelcolor], align=(:center,:center)) #plot edges (3D) /faces (2D) of the mesh Makie.linesegments!(WF,lines,color=WF[:color], linewidth=WF[:strokewidth], visible=WF[:visible]) @@ -193,15 +244,16 @@ end function Makie.plot!(WF::Wireframe{<:Tuple{<:Ferrite.AbstractGrid{dim}}}) where dim grid = WF[1][] coords = [Ferrite.getcoordinates(node)[i] for node in Ferrite.getnodes(grid), i in 1:dim] + coords = Makie.to_vertices(coords) dim > 2 ? (lines = Point3f[]) : (lines = Point2f[]) for cell in Ferrite.getcells(grid) boundaryentities = dim < 3 ? Ferrite.faces(cell) : Ferrite.edges(cell) - append!(lines, [coords[e,:] for boundary in boundaryentities for e in boundary]) + append!(lines, [coords[e] for boundary in boundaryentities for e in boundary]) end - nodes = @lift($(WF[:plotnodes]) ? coords : zeros(Float32,0,3)) + nodes = @lift($(WF[:plotnodes]) ? coords : Point3f[Point3f(0,0,0)]) Makie.scatter!(WF,nodes,markersize=WF[:markersize], color=WF[:color]) nodelabels = @lift $(WF[:nodelabels]) ? ["$i" for i in 1:size(coords,1)] : [""] - nodepositions = @lift $(WF[:nodelabels]) ? [dim < 3 ? Point2f(row) : Point3f(row) for row in eachrow(coords)] : (dim < 3 ? [Point2f((0,0))] : [Point3f((0,0,0))]) + nodepositions = @lift $(WF[:nodelabels]) ? coords : (dim < 3 ? Point2f[Point2f((0,0))] : Point3f[Point3f((0,0,0))]) celllabels = @lift $(WF[:celllabels]) ? ["$i" for i in 1:Ferrite.getncells(grid)] : [""] cellpositions = @lift $(WF[:celllabels]) ? [midpoint(cell,coords) for cell in Ferrite.getcells(grid)] : (dim < 3 ? [Point2f((0,0))] : [Point3f((0,0,0))]) #cellsetsplot @@ -222,7 +274,7 @@ function Makie.plot!(WF::Wireframe{<:Tuple{<:Ferrite.AbstractGrid{dim}}}) where plotter = MakiePlotter(dh,cellset_u) cellset_u = reshape(transfer_scalar_celldata(plotter, cellset_u; process=identity), num_vertices(plotter)) colorrange = isempty(cellset_to_value) ? (0,1) : (0,maximum(values(cellset_to_value))) - Makie.mesh!(WF, plotter.physical_coords, visible(plotter), color=cellset_u, shading=false, scale_plot=false, colormap=:darktest, visible=WF[:cellsets]) + Makie.mesh!(WF, plotter.mesh, color=cellset_u, shading=false, scale_plot=false, colormap=:darktest, visible=WF[:cellsets]) Makie.text!(WF,nodelabels, position=nodepositions, textsize=WF[:textsize], offset=WF[:offset],color=WF[:nodelabelcolor]) Makie.text!(WF,celllabels, position=cellpositions, textsize=WF[:textsize], color=WF[:celllabelcolor], align=(:center,:center)) Makie.linesegments!(WF,lines,color=WF[:color], strokewidth=WF[:strokewidth]) @@ -256,8 +308,10 @@ function Makie.plot!(SF::Surface{<:Tuple{<:MakiePlotter{2}}}) plotter = SF[1][] field = @lift($(SF[:field])===:default ? 1 : Ferrite.find_field(plotter.dh,$(SF[:field]))) solution = @lift(reshape(transfer_solution(plotter, $(plotter.u); field_idx=$(field), process=$(SF[:process])), num_vertices(plotter))) - points = @lift([Point3f(coord[1], coord[2], $(solution)[idx]) for (idx, coord) in enumerate(eachrow(plotter.physical_coords))]) - return Makie.mesh!(SF,points, visible(plotter), color=solution, scale_plot=SF[:scale_plot], shading=SF[:shading], colormap=SF[:colormap]) + coords = @lift begin + Point3f[Point3f(coord[1], coord[2], $(solution)[idx]) for (idx, coord) in enumerate(plotter.physical_coords)] + end + return Makie.mesh!(SF, coords, plotter.vis_triangles, color=solution, scale_plot=SF[:scale_plot], shading=SF[:shading], colormap=SF[:colormap]) end """ @@ -294,17 +348,15 @@ function Makie.plot!(AR::Arrows{<:Tuple{<:MakiePlotter{dim}}}) where dim @assert Ferrite.getfielddim(plotter.dh,field[]) > 1 solution = @lift(transfer_solution(plotter, $(plotter.u); field_idx=$(field), process=identity)) if dim == 2 - ps = [Point2f(i) for i in eachrow(plotter.physical_coords)] ns = @lift([Vec2f(i) for i in eachrow($(solution))]) lengths = @lift($(AR[:color])===:default ? $(AR[:process]).($(ns)) : ones(length($(ns)))*$(AR[:color])) elseif dim == 3 - ps = [Point3f(i) for i in eachrow(plotter.physical_coords)] ns = @lift([Vec3f(i) for i in eachrow($(solution))]) lengths = @lift($(AR[:color])===:default ? $(AR[:process]).($(ns)) : ones(length($(ns)))*$(AR[:color])) else error("Arrows plots are only available in dim ≥ 2") end - Makie.arrows!(AR, ps, ns, arrowsize=AR[:arrowsize], colormap=AR[:colormap], color=lengths, lengthscale=AR[:lengthscale]) + Makie.arrows!(AR, plotter.physical_coords, ns, arrowsize=AR[:arrowsize], colormap=AR[:colormap], color=lengths, lengthscale=AR[:lengthscale]) end """ @@ -477,9 +529,8 @@ end function ferriteviewer(plotter::MakiePlotter, data::Vector{Vector{T}}) where T fig = ferriteviewer(plotter) - timeslider = labelslider!(fig, "timestep n:", 1:length(data); format = x->"$x", sliderkw = Dict(:snap=>false)) - fig[2,1] = timeslider.layout - @lift(FerriteViz.update!(plotter,data[$(timeslider.slider.value)])) + sg = SliderGrid(fig[2,1], (label="timestep n:", range=1:length(data), format = x->"$x")) + @lift(FerriteViz.update!(plotter,data[$(sg.sliders[1].value)])) display(fig) end diff --git a/src/utils.jl b/src/utils.jl index 6c69549..0511f53 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -13,16 +13,6 @@ function field_offset(dh::Ferrite.DofHandler, field_idx::Int) return offset end -function facedofs(cell, local_face_idx::Int, field_idx::Int) - celldofs_ = Ferrite.celldofs(cell) - offset_ = field_offset(cell.dh, field_idx) - fip = Ferrite.getfieldinterpolation(cell.dh, field_idx) - faces_ = Ferrite.faces(fip) - isempty(faces_) && return () # no face dofs :) - indices = faces_[local_face_idx] .+ offset_ - celldofs_[[indices...]] -end - Ferrite.vertices(cell::Ferrite.Cell{3,3,1}) = cell.nodes Ferrite.default_interpolation(::Type{Ferrite.Cell{3,3,1}}) = Ferrite.Lagrange{2,Ferrite.RefTetrahedron,1}() @@ -34,16 +24,19 @@ linear_face_cell(cell::Ferrite.Cell{3,N,6}, local_face_idx::Int) where N = Ferri # Obtain the face interpolation on regular geometries. getfaceip(ip::Ferrite.Interpolation{dim, shape, order}, local_face_idx::Int) where {dim, shape <: Union{Ferrite.RefTetrahedron, Ferrite.RefCube}, order} = Ferrite.getlowerdim(ip) -struct MakiePlotter{dim,DH<:Ferrite.AbstractDofHandler,T,TOP<:Union{Nothing,Ferrite.AbstractTopology}} <: AbstractPlotter +struct MakiePlotter{dim,DH<:Ferrite.AbstractDofHandler,T1,TOP<:Union{Nothing,Ferrite.AbstractTopology},T2,M,TRI} <: AbstractPlotter dh::DH - u::Makie.Observable{Vector{T}} # original solution on the original mesh (i.e. dh.mesh) + u::Makie.Observable{Vector{T1}} # original solution on the original mesh (i.e. dh.mesh) topology::TOP visible::Vector{Bool} #TODO change from per cell to per triangle - gridnodes::Matrix{T} # coordinates of grid nodes in matrix form - physical_coords::Matrix{T} # coordinates in physical space of a vertex - triangles::Matrix{Int} # each row carries a triple with the indices into the coords matrix defining the triangle + gridnodes::Vector{GeometryBasics.Point{dim,T2}} # coordinates of grid nodes in matrix form + physical_coords::Vector{GeometryBasics.Point{dim,T2}} #original coordinates in physical space of a vertex + physical_coords_mesh::ShaderAbstractions.Buffer{GeometryBasics.Point{dim,T2},Vector{GeometryBasics.Point{dim,T2}}} # coordinates in physical space of a vertex + all_triangles::Vector{TRI} + vis_triangles::ShaderAbstractions.Buffer{TRI,Vector{TRI}} triangle_cell_map::Vector{Int} - reference_coords::Matrix{T} # coordinates on the associated reference cell for the corresponding triangle vertex + reference_coords::Matrix{T1} # coordinates on the associated reference cell for the corresponding triangle vertex + mesh::M end """ @@ -76,9 +69,9 @@ function MakiePlotter(dh::Ferrite.AbstractDofHandler, u::Vector, topology::TOP) # Preallocate the matrices carrying the triangulation information triangles = Matrix{Int}(undef, num_triangles, 3) triangle_cell_map = Vector{Int}(undef, num_triangles) - physical_coords = Matrix{Float64}(undef, num_triangles*3, dim) - gridnodes = [node[i] for node in Ferrite.getcoordinates.(Ferrite.getnodes(dh.grid)), i in 1:dim] - reference_coords = Matrix{Float64}(undef, num_triangles*3, dim) # NOTE this should have the dimension of the actual reference element + physical_coords = Vector{GeometryBasics.Point{dim,Float32}}(undef, num_triangles*3) + gridnodes = [GeometryBasics.Point{dim,Float32}(node.data) for node in Ferrite.getcoordinates.(Ferrite.getnodes(dh.grid))] + reference_coords = Matrix{Float64}(undef, num_triangles*3,dim) # Decompose does the heavy lifting for us coord_offset = 1 @@ -88,14 +81,18 @@ function MakiePlotter(dh::Ferrite.AbstractDofHandler, u::Vector, topology::TOP) (coord_offset, triangle_offset) = decompose!(coord_offset, physical_coords, reference_coords, triangle_offset, triangles, dh.grid, cell) triangle_cell_map[triangle_offset_begin:(triangle_offset-1)] .= cell_id end - return MakiePlotter{dim,typeof(dh),eltype(u),typeof(topology)}(dh,Observable(u),topology,visible,gridnodes,physical_coords,triangles,triangle_cell_map,reference_coords); + all_triangles = Makie.to_triangles(triangles) + vis_triangles = copy(all_triangles) + n_visible = sum(visible[triangle_cell_map]) + n_notvisible = length(all_triangles) - n_visible + vis_triangles[ .! visible[triangle_cell_map]] .= (GeometryBasics.GLTriangleFace(1,1,1) for i in 1:n_notvisible) + vis_triangles = ShaderAbstractions.Buffer(Makie.Observable(vis_triangles)) + physical_coords_m = ShaderAbstractions.Buffer(Makie.Observable(copy(physical_coords))) + mesh = GeometryBasics.Mesh(physical_coords_m,vis_triangles) + return MakiePlotter{dim,typeof(dh),eltype(u),typeof(topology),Float32,typeof(mesh),eltype(vis_triangles)}(dh,Observable(u),topology,visible,gridnodes,physical_coords,physical_coords_m,all_triangles,vis_triangles,triangle_cell_map,reference_coords,mesh) end MakiePlotter(dh,u) = MakiePlotter(dh,u,Ferrite.getdim(dh.grid) > 2 ? Ferrite.ExclusiveTopology(dh.grid.cells) : nothing) -# triangle_to_cell -> visible -> triangle access -visible(plotter::MakiePlotter{3}) = @views plotter.triangles[plotter.visible[plotter.triangle_cell_map],:] -visible(plotter::MakiePlotter{2}) = plotter.triangles - """ Clip plane described by the normal and its distance to the coordinate origin. """ @@ -140,6 +137,9 @@ function crinkle_clip!(plotter::MakiePlotter{3,DH,T}, decision_fun::DF) where {D plotter.visible[cell_id] = false end end + plotter.vis_triangles[plotter.visible[plotter.triangle_cell_map]] = plotter.all_triangles[plotter.visible[plotter.triangle_cell_map]] + plotter.vis_triangles[ .! plotter.visible[plotter.triangle_cell_map]] = [GeometryBasics.GLTriangleFace(1,1,1) for i in 1:sum(.! plotter.visible[plotter.triangle_cell_map])] + nothing end """ @@ -149,7 +149,21 @@ Non-mutating version of `crinkle_clip!`. Note that chained calls to `crinkle_clip` won't work. """ function crinkle_clip(plotter::MakiePlotter{3,DH,T}, decision_fun) where {DH,T} - plotter_clipped = MakiePlotter{3,DH,T,typeof(plotter.topology)}(plotter.dh,plotter.u,plotter.topology,copy(plotter.visible),plotter.gridnodes,plotter.physical_coords,plotter.triangles,plotter.triangle_cell_map,plotter.reference_coords); + physical_coords_m = ShaderAbstractions.Buffer(Makie.Observable(copy(plotter.physical_coords_mesh))) + vis_triangles = ShaderAbstractions.Buffer(Makie.Observable(copy(plotter.vis_triangles))) + plotter_clipped = MakiePlotter{3,DH,T,typeof(plotter.topology),Float32,typeof(plotter.mesh),eltype(plotter.vis_triangles)}( + plotter.dh, + plotter.u, + plotter.topology, + plotter.visible, + plotter.gridnodes, + plotter.physical_coords, + physical_coords_m, + plotter.all_triangles, + vis_triangles, + plotter.triangle_cell_map, + plotter.reference_coords, + GeometryBasics.Mesh(physical_coords_m,vis_triangles)) crinkle_clip!(plotter_clipped,decision_fun) return plotter_clipped end @@ -159,17 +173,6 @@ Total number of vertices """ num_vertices(p::MakiePlotter) = size(p.physical_coords,1) -#Visualization is just fancy triangle plotting, every element needs to be translatable to a triangle *sadnoises* -to_triangle(cell::Ferrite.AbstractCell{2,N,3}) where N = [Ferrite.vertices(cell)[1:3]] -to_triangle(cell::Ferrite.AbstractCell{3,N,4}) where N = [Ferrite.vertices(cell)[[1,2,3]], Ferrite.vertices(cell)[[1,2,4]], Ferrite.vertices(cell)[[2,3,4]], Ferrite.vertices(cell)[[1,4,3]]] -to_triangle(cell::Ferrite.AbstractCell{2,N,4}) where N = [Ferrite.vertices(cell)[[1,2,3]], Ferrite.vertices(cell)[[3,4,1]]] -to_triangle(cell::Ferrite.AbstractCell{3,N,6}) where N = [Ferrite.vertices(cell)[[1,2,3]], Ferrite.vertices(cell)[[3,4,1]], - Ferrite.vertices(cell)[[1,5,6]], Ferrite.vertices(cell)[[6,2,1]], - Ferrite.vertices(cell)[[2,6,7]], Ferrite.vertices(cell)[[7,3,2]], - Ferrite.vertices(cell)[[3,7,8]], Ferrite.vertices(cell)[[8,4,3]], - Ferrite.vertices(cell)[[1,4,8]], Ferrite.vertices(cell)[[8,5,1]], - Ferrite.vertices(cell)[[5,8,7]], Ferrite.vertices(cell)[[7,6,5]]] - """ TODO this looks faulty...think harder. """ @@ -194,9 +197,9 @@ Decompose a triangle into a coordinates and a triangle index list to disconnect """ function decompose!(coord_offset, coord_matrix, ref_coord_matrix, triangle_offset, triangle_matrix, grid, cell::Union{Ferrite.AbstractCell{2,N,3}, Ferrite.AbstractCell{3,3,1}}) where {N} for (i,v) in enumerate(vertices(grid, cell)) - coord_matrix[coord_offset, :] = Ferrite.getcoordinates(v) - ref_coord_matrix[coord_offset, 1:2] = Ferrite.reference_coordinates(Ferrite.default_interpolation(typeof(cell)))[i] - triangle_matrix[triangle_offset, i] = coord_offset + coord_matrix[coord_offset] = GeometryBasics.Point(Ferrite.getcoordinates(v)...) + ref_coord_matrix[coord_offset,1:2] = Ferrite.reference_coordinates(Ferrite.default_interpolation(typeof(cell)))[i] + triangle_matrix[triangle_offset,i] = coord_offset coord_offset+=1 end triangle_offset+=1 @@ -220,15 +223,14 @@ and creates the decomposition 1-------2 where A=(1,2,5),B=(2,3,5),C=(3,4,5),D=(4,1,5) are the generated triangles in this order. """ -function decompose!(coord_offset, coord_matrix, ref_coord_matrix, triangle_offset, triangle_matrix, grid, cell::Union{Ferrite.AbstractCell{2,N,4}, Ferrite.AbstractCell{3,4,1}}) where {N} +function decompose!(coord_offset, coord_matrix::Vector{Point{space_dim,T}}, ref_coord_matrix, triangle_offset, triangle_matrix, grid, cell::Union{Ferrite.AbstractCell{2,N,4}, Ferrite.AbstractCell{3,4,1}}) where {N,space_dim,T} # A bit more complicated. The default diagonal decomposition into 2 triangles is missing a solution mode. # To resolve this we make a more expensive decomposition in 4 triangles which correctly displays the solution mode (in linear problems). coord_offset_initial = coord_offset vts = vertices(grid, cell) - space_dim = size(coord_matrix,2) # Compute coordinate of vertex 5 - center = [ntuple(x->0.0, space_dim)...] + center = zeros(space_dim) for v in vts center += Ferrite.getcoordinates(v) end @@ -245,18 +247,18 @@ function decompose!(coord_offset, coord_matrix, ref_coord_matrix, triangle_offse v2 = vts[i2] # current vertex - coord_matrix[coord_offset, :] = Ferrite.getcoordinates(v1) + coord_matrix[coord_offset] = GeometryBasics.Point(Ferrite.getcoordinates(v1)...) ref_coord_matrix[coord_offset, 1:2] = Ferrite.reference_coordinates(Ferrite.default_interpolation(typeof(cell)))[i] coord_offset+=1 # next vertex in chain - coord_matrix[coord_offset, :] = Ferrite.getcoordinates(v2) + coord_matrix[coord_offset] = GeometryBasics.Point(Ferrite.getcoordinates(v2)...) ref_coord_matrix[coord_offset, 1:2] = Ferrite.reference_coordinates(Ferrite.default_interpolation(typeof(cell)))[i2] coord_offset+=1 # center vertex (5) - coord_matrix[coord_offset, :] = center - ref_coord_matrix[coord_offset, 1:2] = [ntuple(x->0.0, 2)...] + coord_matrix[coord_offset] = GeometryBasics.Point(center...) + ref_coord_matrix[coord_offset, 1:2] .= ntuple(x->0.0, 2) coord_offset+=1 # collect indices @@ -292,10 +294,10 @@ x₃(x) = x[3] l2(x) = LinearAlgebra.norm(x,2) l1(x) = LinearAlgebra.norm(x,1) -midpoint(cell::Ferrite.AbstractCell{2,N,3}, points) where N = Point2f((1/3) * (points[cell.nodes[1],:] + points[cell.nodes[2],:] + points[cell.nodes[3],:])) -midpoint(cell::Ferrite.AbstractCell{2,N,4}, points) where N = Point2f(0.5 * (points[cell.nodes[1],:] + points[cell.nodes[3],:])) -midpoint(cell::Ferrite.AbstractCell{3,N,4}, points) where N = Point3f((1/4) * (points[cell.nodes[1],:] + points[cell.nodes[2],:] + points[cell.nodes[3],:] + points[cell.nodes[4],:])) -midpoint(cell::Ferrite.AbstractCell{3,N,6}, points) where N = Point3f(0.5 * (points[cell.nodes[1],:] + points[cell.nodes[7],:])) +midpoint(cell::Ferrite.AbstractCell{2,N,3}, points) where N = Point2f((1/3) * (points[cell.nodes[1]] + points[cell.nodes[2]] + points[cell.nodes[3]])) +midpoint(cell::Ferrite.AbstractCell{2,N,4}, points) where N = Point2f(0.5 * (points[cell.nodes[1]] + points[cell.nodes[3]])) +midpoint(cell::Ferrite.AbstractCell{3,N,4}, points) where N = Point3f((1/4) * (points[cell.nodes[1]] + points[cell.nodes[2]] + points[cell.nodes[3]] + points[cell.nodes[4]])) +midpoint(cell::Ferrite.AbstractCell{3,N,6}, points) where N = Point3f(0.5 * (points[cell.nodes[1]] + points[cell.nodes[7]])) """ postprocess(node_values::Vector{T}) -> T @@ -355,7 +357,7 @@ function _transfer_solution(ip_geo,ip_field,val_buffer,val,field_name,field_dim, data = fill(0.0, num_vertices(plotter),_processreturn) _local_coords = Ferrite.getcoordinates(grid,1) _local_celldofs = Ferrite.celldofs(dh,1) - _celldofs_field = reshape(_local_celldofs[local_dof_range], (field_dim, n_basefuncs)) + _celldofs_field = reshape(@view(_local_celldofs[local_dof_range]), (field_dim, n_basefuncs)) _local_ref_coords = Tensors.Vec{dim}(ref_coords[1,:]) for (isvisible,(cell_idx,cell_geo)) in zip(plotter.visible,enumerate(Ferrite.getcells(dh.grid))) @@ -378,7 +380,7 @@ function _transfer_solution(ip_geo,ip_field,val_buffer,val,field_name,field_dim, _local_ref_coords = Tensors.Vec{dim}(@view(ref_coords[current_vertex_index,:])) Ferrite.reinit!(pv, _local_coords, _local_ref_coords) for d in 1:field_dim - val_buffer[d] = Ferrite.function_value(pv, 1, @view(u[_celldofs_field[d,:]])) + val_buffer[d] = Ferrite.function_value(pv, 1, @views(u[_celldofs_field[d,:]])) end val = process(val_buffer) for d in 1:_processreturn