Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add compat for introduction of facets in Ferrite v1 #43

Merged
merged 6 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ 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.2.0]

Required breaking changes to support Ferrite v1 and later.
### Changed
- Keyword arg of `get_ferrite_grid`: `generate_facesets` -> `generate_facetsets`
- Function renamed: `create_faceset` -> `create_facetset`

## [0.1.8]

Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "FerriteMeshParser"
uuid = "0f8c756f-80dd-4a75-85c6-b0a5ab9d4620"
authors = ["Knut Andreas Meyer and contributors"]
version = "0.1.8"
version = "0.2.0"

[deps]
Ferrite = "c061ca5d-56c9-439f-9c0e-210fe06d3992"
Expand Down
2 changes: 1 addition & 1 deletion docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ get_ferrite_grid
```

```@docs
create_faceset
create_facetset
```
19 changes: 10 additions & 9 deletions docs/src/literate/compact_tension.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,18 @@ println([(key, length(set)) for (key, set) in Ferrite.getcellsets(grid)])

# As we see, in addition to the sets created in Abaqus, the cellsets also include a set
# for each abaqus element type (useful if you for example defined reduced integration
# in only part of the domain and want to have this in Ferrite). Finally, facesets are
# automatically created by default (can be turned off by `generate_facesets=false`
# in only part of the domain and want to have this in Ferrite). Finally, facetsets are
# automatically created by default (can be turned off by `generate_facetsets=false`
# argument) based on the nodesets:
println([(key, length(set)) for (key, set) in Ferrite.getfacesets(grid)])
# Clearly, the faceset `"CrackZone"` doesn't make much sense, but unless the mesh is
# very large it doesn't hurt. The facesets can be created manually from each nodeset
# by using the `create_faceset` function:
faceset = create_faceset(grid, getnodeset(grid,"Hole"));
# This can if desired be merged into the grid by
merge!(Ferrite.getfacesets(grid), Dict("HoleManual" => faceset))
println([(key, length(set)) for (key, set) in Ferrite.getfacesets(grid)])
# Clearly, the facetset `"CrackZone"` doesn't make much sense, but unless the mesh is
# very large it doesn't hurt. The facetsets can be created manually from each nodeset
# by using the `create_facetset` function:
facetset = create_facetset(grid, getnodeset(grid,"Hole"));
# This can, if desired, be merged into the grid by
# ```julia
# addfaceset!(grid, "HoleManual", facetset)
# ```

#
#md # ## [Plain Program](@id compact-tension-plain-program)
Expand Down
56 changes: 40 additions & 16 deletions src/FerriteMeshParser.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
module FerriteMeshParser
using Ferrite
using Ferrite:
Ferrite, Grid, Node, Vec,
getcells, getnodes, getcoordinates, getncells

# Convenience when debugging
const DEBUG_PARSE = false

Expand All @@ -23,6 +26,20 @@ struct InvalidFileContent <: Exception
end
Base.showerror(io::IO, e::InvalidFileContent) = println(io, e.msg)

@static if !isdefined(Ferrite, :SerendipityQuadraticHexahedron)
const SerendipityQuadraticHexahedron = Ferrite.Cell{3,20,6}
const SerendipityQuadraticQuadrilateral = Ferrite.Cell{2,8,4}
else
const SerendipityQuadraticHexahedron = Ferrite.SerendipityQuadraticHexahedron
const SerendipityQuadraticQuadrilateral = Ferrite.SerendipityQuadraticQuadrilateral
end

const FacetsDefined = isdefined(Ferrite, :FacetIndex) # Ferrite after v1.0 (Ferrite#914)

const FacetIndex = FacetsDefined ? Ferrite.FacetIndex : Ferrite.FaceIndex
const facets = FacetsDefined ? Ferrite.facets : Ferrite.faces
const addfacetset! = FacetsDefined ? Ferrite.addfacetset! : Ferrite.addfaceset!

include("rawmesh.jl")
include("elements.jl")
include("reading_utils.jl")
Expand All @@ -34,7 +51,7 @@ include("gridcreator.jl")
filename;
meshformat=AutomaticMeshFormat(),
user_elements=Dict{String,DataType}(),
generate_facesets=true
generate_facetsets=true
)

Create a `Ferrite.Grid` by reading in the file specified by `filename`.
Expand All @@ -44,45 +61,46 @@ Optional arguments:
is given in, normally automatically detected by the file extension
* `user_elements`: Used to add extra elements not supported,
might require a separate cell constructor.
* `generate_facesets`: Should facesets be automatically generated from all nodesets?
* `generate_facetsets`: Should facesets be automatically generated from all nodesets?

"""
function get_ferrite_grid(filename; meshformat=AutomaticMeshFormat(), user_elements::Dict{String,DataType}=Dict{String,DataType}(), generate_facesets::Bool=true)
function get_ferrite_grid(filename; meshformat=AutomaticMeshFormat(), user_elements::Dict{String, DataType}=Dict{String, DataType}(), generate_facetsets::Bool=true, generate_facesets=nothing)
generate_facesets !== nothing && error("The keyword generate_facesets is deprecated, use generate_facetsets instead")
detected_format = detect_mesh_format(filename, meshformat)
mesh = read_mesh(filename, detected_format)
checkmesh(mesh)
grid = create_grid(mesh, detected_format, user_elements)
generate_facesets && generate_facesets!(grid)
generate_facetsets && generate_facetsets!(grid)
return grid
end

"""
create_faceset(
create_facetset(
grid::Ferrite.AbstractGrid,
nodeset::Set{Int},
cellset::Union{UnitRange{Int},Set{Int}}=1:getncells(grid)
)

Find the faces in the grid for which all nodes are in `nodeset`. Return them as a `Set{FaceIndex}`.
Find the facets in the grid for which all nodes are in `nodeset`. Return them as a `Set{FacetIndex}`.
A `cellset` can be given to only look only for faces amongst those cells to speed up the computation.
Otherwise the search is over all cells.

This function is normally only required when calling `get_ferrite_grid` with `generate_facesets=false`.
The created `faceset` can be added to the grid as `addfaceset!(grid, "facesetkey", faceset)`
This function is normally only required when calling `get_ferrite_grid` with `generate_facetsets=false`.
The created `facetset` can be added to the grid as `addfacetset!(grid, "facetsetkey", facetset)`
"""
function create_faceset(grid::Ferrite.AbstractGrid, nodeset::AbstractSet{Int}, cellset=1:getncells(grid))
faceset = sizehint!(Set{FaceIndex}(), length(nodeset))
function create_facetset(grid::Ferrite.AbstractGrid, nodeset::AbstractSet{Int}, cellset=1:getncells(grid))
facetset = sizehint!(Set{FacetIndex}(), length(nodeset))
for (cellid, cell) in enumerate(getcells(grid))
cellid ∈ cellset || continue
if any(n-> n ∈ nodeset, cell.nodes)
for (faceid, face) in enumerate(Ferrite.faces(cell))
if all(n -> n ∈ nodeset, face)
push!(faceset, FaceIndex(cellid, faceid))
for (facetid, facet) in enumerate(facets(cell))
if all(n -> n ∈ nodeset, facet)
push!(facetset, FacetIndex(cellid, facetid))
end
end
end
end
return faceset
return facetset
end

detect_mesh_format(_, meshformat) = meshformat
Expand All @@ -94,6 +112,12 @@ function detect_mesh_format(filename, ::AutomaticMeshFormat)
end
end

export get_ferrite_grid, create_faceset
export get_ferrite_grid, create_facetset

# Deprecated
function create_faceset(args...)
error("create_faceset is no longer supported, use create_facetset instead")
end
export create_faceset

end
21 changes: 8 additions & 13 deletions src/elements.jl
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
@static if !isdefined(Ferrite, :SerendipityQuadraticHexahedron)
const SerendipityQuadraticHexahedron = Cell{3,20,6}
const SerendipityQuadraticQuadrilateral = Cell{2,8,4}
end

function get_element_type_dict(::AbaqusMeshFormat)

quad = (Quadrilateral, ("CPE4", "CPS4", "CPE4R", "CPS4R"))
quad = (Ferrite.Quadrilateral, ("CPE4", "CPS4", "CPE4R", "CPS4R"))
quad2 = (SerendipityQuadraticQuadrilateral, ("CPS8", "CPS8R", "CPE8", "CPE8R"))
tria = (Triangle, ("CPE3", "CPS3"))
tria2 = (QuadraticTriangle, ("CPE6", "CPS6", "CPE6M", "CPS6M"))
tetra = (Tetrahedron, ("C3D4",))
tetra2 = (QuadraticTetrahedron, ("C3D10",))
hexa = (Hexahedron, ("C3D8","C3D8R"))
tria = (Ferrite.Triangle, ("CPE3", "CPS3"))
tria2 = (Ferrite.QuadraticTriangle, ("CPE6", "CPS6", "CPE6M", "CPS6M"))
tetra = (Ferrite.Tetrahedron, ("C3D4",))
tetra2 = (Ferrite.QuadraticTetrahedron, ("C3D10",))
hexa = (Ferrite.Hexahedron, ("C3D8","C3D8R"))
hexa2 = (SerendipityQuadraticHexahedron, ("C3D20","C3D20R"))

dict = Dict{String,DataType}()
dict = Dict{String, DataType}()
for types in (quad, tria, quad2, tria2, tetra, tetra2, hexa, hexa2)
merge!(dict, Dict(code=>types[1] for code in types[2]))
merge!(dict, Dict(code => types[1] for code in types[2]))
end
return dict
end
Expand Down
20 changes: 11 additions & 9 deletions src/gridcreator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ function create_nodes(rawnodes::RawNodes, ::Val{dim}) where{dim}
return nodes
end

function create_cells(rawelementsdict::Dict{String,RawElements}, user_elements::Dict, format)
function create_cells(rawelementsdict::Dict{String, RawElements}, user_elements::Dict, format)
builtin_elements = get_element_type_dict(format)
num_elements = sum(getnumelements.(values(rawelementsdict)))
num_elements = sum(getnumelements, values(rawelementsdict))
cells_generic = Array{Ferrite.AbstractCell}(undef, num_elements)
for (key, rawelements) in rawelementsdict
if haskey(user_elements, key) # user_elements are prioritized over builtin
Expand All @@ -31,14 +31,14 @@ function create_cells(rawelementsdict::Dict{String,RawElements}, user_elements::
end
end
# Return a Union of cell types as this should be faster to use than a generic cell
cell_type = Union{(typeof.(unique(typeof,cells_generic))...)}
cells = convert(Array{cell_type}, cells_generic)
CellType = Union{(typeof.(unique(typeof, cells_generic))...)}
cells = convert(Array{CellType}, cells_generic)
return cells
end

function addcells!(cells, elementtype, rawelements::RawElements, format)
for (i, element_number) in enumerate(getnumbers(rawelements))
node_numbers = gettopology(rawelements)[:,i]
node_numbers = gettopology(rawelements)[:, i]
cells[element_number] = create_cell(elementtype, node_numbers, format)
end
end
Expand All @@ -56,13 +56,15 @@ end


"""
function generate_facesets!(grid::Ferrite.Grid)
function generate_facetsets!(grid::Ferrite.Grid)

Based on all nodesets in `grid`, generate facesets for those sets.
If there is a cellset in the grid with the same name as the nodeset,
only facets for cells in that cellset with be created.
"""
function generate_facesets!(grid::Ferrite.Grid)
function generate_facetsets!(grid::Ferrite.Grid)
for (key, set) in Ferrite.getnodesets(grid)
cellset = get(Ferrite.getcellsets(grid), key, 1:getncells(grid))
addfaceset!(grid, key, create_faceset(grid, set, cellset))
addfacetset!(grid, key, create_facetset(grid, set, cellset))
end
end
end
17 changes: 12 additions & 5 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ using Aqua

Aqua.test_all(FerriteMeshParser; ambiguities = false)
Aqua.test_ambiguities(FerriteMeshParser) # This excludes Core and Base, which gets many ambiguities with ForwardDiff

# Function to retrieve test fields
gettestfile(args...) = joinpath(@__DIR__, "test_files", args...)

Expand All @@ -22,6 +22,10 @@ if !isdefined(Main, :SerendipityQuadrilateral)
Ferrite.faces(c::SerendipityQuadrilateral) = ((c.nodes[1],c.nodes[2]), (c.nodes[2],c.nodes[3]), (c.nodes[3],c.nodes[4]), (c.nodes[4],c.nodes[1]))
end

if !isdefined(Ferrite, :getfacetset)
getfacetset(args...) = Ferrite.getfaceset(args...)
end

if isdefined(Ferrite, :FieldHandler)
create_cell_values(ip; order=1) = CellScalarValues(QuadratureRule{Ferrite.getdim(ip), Ferrite.getrefshape(ip)}(order), ip, ip)
else # v1.0
Expand Down Expand Up @@ -66,12 +70,12 @@ end
@test _getgridtype(grid_mixed) == Union{Triangle,Quadrilateral}
end

@testset "facesetgeneration" begin
@testset "facet set generation" begin
filename = gettestfile("compact_tension.inp")
grid = get_ferrite_grid(filename)
face_set = create_faceset(grid, getnodeset(grid, "Hole"))
@test getfaceset(grid, "Hole") == face_set
@test face_set == create_faceset(grid, getnodeset(grid, "Hole"), getcellset(grid, "Hole")) # Test that including cells doesn't change the created sets
face_set = create_facetset(grid, getnodeset(grid, "Hole"))
@test getfacetset(grid, "Hole") == face_set
@test face_set == create_facetset(grid, getnodeset(grid, "Hole"), getcellset(grid, "Hole")) # Test that including cells doesn't change the created sets
end

@testset "exceptions" begin
Expand All @@ -96,6 +100,9 @@ end
showerror(io, FerriteMeshParser.UnsupportedElementType(test_string))
@test contains(String(take!(io)), test_string)

grid = get_ferrite_grid(gettestfile("compact_tension.inp"))
nset = getnodeset(grid, "Hole")
@test_throws ErrorException("create_faceset is no longer supported, use create_facetset instead") create_faceset(grid, nset)
end

@testset "ordering" begin
Expand Down
Loading