viz(mesh; showfacets=true) crashes on m1 Macbook with abnormal memory usage
acemby opened this issue · comments
I am trying to visualize a simple 3D mesh (this one: https://gmsh.info/doc/texinfo/gmsh.html#t3) using MeshViz and Meshes (great packages BTW.). viz
works without any problem when showfacets=false
, but when it's true
my laptop's swap usage goes up to 20+ GBs then Julia crashes.
The code I am using:
# Julia Version 1.8.2 (2022-09-29)
using Meshes, MeshViz
using FiniteMesh
using GLMakie
function toConnectivity(m::Matrix{<:Integer})
[connect(Tuple(v)) for v in eachslice(m; dims=1)]
end
function toConnectivity(x::Vector{<:Matrix{<:Integer}})
reduce(vcat, (toConnectivity(m) for m in x)
end
function toSimpleMesh(cells::Cells, points::Matrix{<:Real})
points = Meshes.Point.(collect(eachslice(points; dims = 1)))
connections = toConnectivity(cells.index)
Meshes.SimpleMesh(points, connections)
end
toSimpleMesh(path::String) = toSimpleMesh((read_mesh(path))...)
mesh = toSimpleMesh("t3.msh") # t3.msh file at https://www.dropbox.com/s/xzgvmcuzqn7n558/t3.msh?dl=0
viz(mesh; alpha=0.1) # This will pass
viz(mesh; alpha=0.1, showfacets=true) # Hang until OOM
Maybe this is related to #39 or #30?
I want to see clearly the lines of the mesh so I'd like to keep showfacets=true
, is there any workaround?
@acemby can you please confirm the eltype(mesh)? Do you have 3D elements like tetrahedra? The showfacets option only works with 2D polygons so far as it converts the topological data structure to a half-edge topology.
julia> eltype(mesh)
Ngon{N, 3, Float64, V} where {N, V<:AbstractVector{Meshes.Point3}}
Yes, it shouldn't be a problem. Can you please share a MWE to debug it further?
I am trying to visualize a simple 3D mesh (this one: https://gmsh.info/doc/texinfo/gmsh.html#t3) using MeshViz and Meshes (great packages BTW.).
viz
works without any problem whenshowfacets=false
, but when it'strue
my laptop's swap usage goes up to 20+ GBs then Julia crashes.The code I am using:
# Julia Version 1.8.2 (2022-09-29) using Meshes, MeshViz using FiniteMesh using GLMakie function toConnectivity(m::Matrix{<:Integer}) [connect(Tuple(v)) for v in eachslice(m; dims=1)] end function toConnectivity(x::Vector{<:Matrix{<:Integer}}) reduce(vcat, (toConnectivity(m) for m in x) end function toSimpleMesh(cells::Cells, points::Matrix{<:Real}) points = Meshes.Point.(collect(eachslice(points; dims = 1))) connections = toConnectivity(cells.index) Meshes.SimpleMesh(points, connections) end toSimpleMesh(path::String) = toSimpleMesh((read_mesh(path))...) mesh = toSimpleMesh("t3.msh") # t3.msh file at https://www.dropbox.com/s/xzgvmcuzqn7n558/t3.msh?dl=0 viz(mesh; alpha=0.1) # This will pass viz(mesh; alpha=0.1, showfacets=true) # Hang until OOMMaybe this is related to #39 or #30? I want to see clearly the lines of the mesh so I'd like to keep
showfacets=true
, is there any workaround?
You can just run the code mentioned above in REPL. I am using FiniteMesh to read the .msh file so you need to add it first.
I tried installing FiniteMesh but it depends on Python stuff, which I don't have installed. Do you think you can create a MWE without Python deps? You can simply store the list of vertices and list of connectivities in a text file, and write a simple read function to make things easier to reproduce.
How about this one?
using Meshes, MeshViz
using GLMakie
using JLD2
t3_mesh = load_object("t3_mesh") # https://www.dropbox.com/s/4flcgk32zx0rp06/t3_mesh?dl=0
viz(t3_mesh) # will pass
viz(t3_mesh; showfacets=true) # will crash the REPL
box_mesh = load_object("box_mesh") # https://www.dropbox.com/s/xdktkphckx853a2/box_mesh?dl=0
viz(box_mesh) # will pass
viz(box_mesh; showfacets=true) # will fail with the following error
ERROR: KeyError: key 1 not found
Stacktrace:
[1] getindex
@ ./dict.jl:498 [inlined]
[2] half4elem
@ ~/.julia/packages/Meshes/V9QOh/src/topologies/halfedge.jl:215 [inlined]
[3] element(t::HalfEdgeTopology, ind::Int64)
@ Meshes ~/.julia/packages/Meshes/V9QOh/src/topologies/halfedge.jl:262
[4] #92
@ ./none:0 [inlined]
[5] iterate
@ ./generator.jl:47 [inlined]
[6] collect(itr::Base.Generator{UnitRange{Int64}, Meshes.var"#92#93"{HalfEdgeTopology}})
@ Base ./array.jl:787
[7] convert(#unused#::Type{HalfEdgeTopology}, t::HalfEdgeTopology)
@ Meshes ~/.julia/packages/Meshes/V9QOh/src/topologies/halfedge.jl:279
[8] Boundary
@ ~/.julia/packages/Meshes/V9QOh/src/toporelations/boundary.jl:12 [inlined]
[9] (Boundary{1, 0})(topology::HalfEdgeTopology)
@ Meshes ~/.julia/packages/Meshes/V9QOh/src/toporelations/boundary.jl:21
[10] viz2D!(plot::Combined{MeshViz.viz, Tuple{SimpleMesh{3, Float64, Vector{Meshes.Point3}, SimpleTopology{Connectivity{Quadrangle{Dim, T} where {Dim, T}, 4}}}}}, mesh::SimpleMesh{3, Float64, Vector{Meshes.Point3}, SimpleTopology{Connectivity{Quadrangle{Dim, T} where {Dim, T}, 4}}})
@ MeshViz ~/.julia/packages/MeshViz/vjshU/src/simplemesh.jl:134
[11] plot!(plot::Combined{MeshViz.viz, Tuple{SimpleMesh{3, Float64, Vector{Meshes.Point3}, SimpleTopology{Connectivity{Quadrangle{Dim, T} where {Dim, T}, 4}}}}})
@ MeshViz ~/.julia/packages/MeshViz/vjshU/src/simplemesh.jl:0
[12] plot!(scene::Scene, P::Type{Combined{MeshViz.viz, Tuple{SimpleMesh{3, Float64, Vector{Meshes.Point3}, SimpleTopology{Connectivity{Quadrangle{Dim, T} where {Dim, T}, 4}}}}}}, attributes::Attributes, input::Tuple{Observable{SimpleMesh{3, Float64, Vector{Meshes.Point3}, SimpleTopology{Connectivity{Quadrangle{Dim, T} where {Dim, T}, 4}}}}}, args::Observable{Tuple{SimpleMesh{3, Float64, Vector{Meshes.Point3}, SimpleTopology{Connectivity{Quadrangle{Dim, T} where {Dim, T}, 4}}}}})
@ Makie ~/.julia/packages/Makie/Ppzqh/src/interfaces.jl:417
[13] plot!(scene::Scene, P::Type{Combined{MeshViz.viz}}, attributes::Attributes, args::SimpleMesh{3, Float64, Vector{Meshes.Point3}, SimpleTopology{Connectivity{Quadrangle{Dim, T} where {Dim, T}, 4}}}; kw_attributes::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
@ Makie ~/.julia/packages/Makie/Ppzqh/src/interfaces.jl:335
[14] plot!(scene::Scene, P::Type{Combined{MeshViz.viz}}, attributes::Attributes, args::SimpleMesh{3, Float64, Vector{Meshes.Point3}, SimpleTopology{Connectivity{Quadrangle{Dim, T} where {Dim, T}, 4}}})
@ Makie ~/.julia/packages/Makie/Ppzqh/src/interfaces.jl:302
[15] plot(P::Type{Combined{MeshViz.viz}}, args::SimpleMesh{3, Float64, Vector{Meshes.Point3}, SimpleTopology{Connectivity{Quadrangle{Dim, T} where {Dim, T}, 4}}}; axis::NamedTuple{(), Tuple{}}, figure::NamedTuple{(), Tuple{}}, kw_attributes::Base.Pairs{Symbol, Bool, Tuple{Symbol}, NamedTuple{(:showfacets,), Tuple{Bool}}})
@ Makie ~/.julia/packages/Makie/Ppzqh/src/figureplotting.jl:48
[16] #viz#1
@ ~/.julia/packages/MakieCore/rLlRw/src/recipes.jl:34 [inlined]
[17] top-level scope
@ ~/Dropbox/Projects/LearnFEM/test_mesh.jl:27
The first visualization already shows that the issue is probably related to incosistent orientation of the elements:
Some polygons are light and some other are dark because their orientation is not consistent. I will try to convert the topology to reproduce the crash. This orientation issue is really hard and annoying to fix.
@acemby I will be immersed in a workshop next week and won't be able to debug this issue in my workstation at home. Do you have experience with half-edge data structures? If you could run the VSCode debugger with your box_mesh, that would be super helpful:
@enter convert(HalfEdgeTopology, topology(box_mesh))
You can follow all the steps to see where our algorithm is hanging. You can read the algorithm here:
First, we sort the elements of the mesh with Meshes.adjsort
to make sure that they are traversed in adjacent-first order. You could use this information to plot the order and see if the sorting algorithm is failing somehow. After that, it loops over all elements and creates the half-edges. You can check the docstrings for additional references on this data structure.
I will try to take a look at it again after I am back from the workshop, but any additional information you can find may speed up the fix.
@juliohm Thank you for the help! Unfortunately I don't have much knowledge on half-edge data structures, neither the debugging stuff of Julia. But I will try to investigate this as much as I can.
@acemby I am back to my workstation. Tried to inspect the input meshes you provided. The box_mesh is certainly incorrect, if you simply plot the first 5 elements, you get someting like:
viz(view(box_mesh, 1:5))
Each quadrangle looks like a "butterfly" and they are displaced randomly in space, they do not form a surface, which is what HalfEdgeTopology supports.
I will investigate the other mesh now.
In summary, the showfacets=true
option currently converts the topology of the mesh to HalfEdgeTopology
for efficiently displaying edges. If you need to display edges in meshes that are not surfaces, you can collect all edges and plot them as a new mesh of edges instead. It will have repeated edges, but it is the best you can do currently:
viz(t3_mesh)
viz!(boundary.(t3_mesh), color=:red)
I will close the issue and mark it as invalid given that the inputs are invalid for the option showfacets. Maybe in the future we will have more flexibility with data structures that support non-surface meshes and will be able to use showfacets directly.