JuliaGeometry / MeshViz.jl

Makie.jl recipes for visualization of Meshes.jl

Home Page:https://github.com/JuliaGeometry/Meshes.jl

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.

@juliohm

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 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?

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:

image

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:

https://github.com/JuliaGeometry/Meshes.jl/blob/380fd6937de5427e9e60ab32d95fbc8cb0b34789/src/topologies/halfedge.jl#L124-L211

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))

image

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.

Same issue occurs with your other t3_mesh, if you view the first 1000 elements, they do not form a surface, so you can't use the HalfEdgeTopology to visualize the edges with showfacets=true:

image

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)

image

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.