You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There is a lack of functions to get the volume of in Ferrite. Here I have given a solution. It needs to be checked by the developer and considered for merging. The following is the functions defined outside of module Ferrite. If put these to grid.jl, the prefix Ferrite. should be removed.
function Ferrite.getcoordinates(grid::Ferrite.AbstractGrid, nodes::NTuple{N,Int64}) where {N}
dim = Ferrite.getdim(grid)
T = Ferrite.get_coordinate_eltype(grid)
n = lastindex(nodes)
x = Vector{Vec{dim,T}}(undef, n)
@inbounds for i in 1:n
x[i] = Ferrite.getcoordinates(getnodes(grid, nodes[i]))
end
return x
end
## The following old function in Ferrite 0.3.14 is to get the coordinates of all nodes of a cell.
## function getcoordinates(grid::AbstractGrid, cell::CellIndex) = (grid, grid.cells[cell.idx[1]].nodes)
## get the coordinates of all vertices of cell
Ferrite.getcoordinates(grid::Ferrite.AbstractGrid, cell::CellIndex) = Ferrite.getcoordinates(grid, Ferrite.vertices(grid.cells[cell.idx[1]]))
Ferrite.getcoordinates(grid::Ferrite.AbstractGrid, face::FaceIndex) = getcoordinates(grid, Ferrite.faces(grid.cells[face[1]])[face[2]])
Ferrite.getcoordinates(grid::Ferrite.AbstractGrid, edge::EdgeIndex) = getcoordinates(grid, Ferrite.edges(grid.cells[edge[1]])[edge[2]])
Ferrite.getcoordinates(grid::Ferrite.AbstractGrid, vertex::VertexIndex) = getcoordinates(grid, (Ferrite.vertices(grid.cells[vertex[1]])[vertex[2]],))
# The `getvolume` function of a 3d / 2d / 1d cell is defined to get its volume / area / length, respectively.
# Specially, the volume of 3d planar cell Quadrilateral3D is zero, FaceIndex(x,1) should be used as the second parameter to get the area of Quadrilateral3D cell x.
# Similarly, the volume of Line3D and Line2D is zero, the correct parameter is EdgeIndex(x,1) and FaceIndex(x,1).
getvolume(grid::Ferrite.AbstractGrid{3}, cell::CellIndex) = _getvolume(Ferrite.getcoordinates(grid, cell))
getvolume(grid::Ferrite.AbstractGrid{3}, face::FaceIndex) = _getarea(Ferrite.getcoordinates(grid, face))
getvolume(grid::Ferrite.AbstractGrid{3}, edge::EdgeIndex) = _getlength(Ferrite.getcoordinates(grid, edge))
getvolume(grid::Ferrite.AbstractGrid{2}, cell::CellIndex) = _getarea(Ferrite.getcoordinates(grid, cell))
getvolume(grid::Ferrite.AbstractGrid{2}, face::FaceIndex) = _getlength(Ferrite.getcoordinates(grid, face))
getvolume(grid::Ferrite.AbstractGrid{1}, cell::CellIndex) = _getlength(Ferrite.getcoordinates(grid, cell))
#alias
getvolume(grid::Ferrite.AbstractGrid{3}, cell::Int) = getvolume(grid::Ferrite.AbstractGrid{3}, CellIndex(cell))
_getlength(coords::Vector{Vec{dim,T}}) where {dim,T} = norm(coords[1] - coords[2])
# Assuming that the faces of any 3D cell are planar.
# 2-order cell are calculated as 1-order cell (such as QuadraticTetrahedron -> Tetrahedron), ignoring the nodes in the edges.
# Assuming that the coordinate points enclose a convex area in counterclockwise order.
function _getarea(coords::Vector{Vec{dim,T}}) where {dim,T}
n = lastindex(coords)
n < 3 && return 0.0
vec_coords = [coords[i] - coords[1] for i in 2:n]
area = 0.0
for i in 1:n-2
area += norm(cross(vec_coords[i], vec_coords[i+1])) / 2
end
return area
end
function _getvolume(coords::Vector{Vec{dim,T}}) where {dim,T}
@inline volu_tet(coords) = dot(cross(coords[2] - coords[1], coords[3] - coords[1]), coords[4] - coords[1]) / 6
n = lastindex(coords)
n < 4 && return 0.0
volu = 0.0
if n == 4 # Tetrahedron
volu = volu_tet(coords)
elseif n == 8 # Hexahedron, divided into 5 Tetrahedron.
volu = volu_tet(coords[[2, 1, 6, 3]]) + volu_tet(coords[[7, 3, 6, 8]]) +
volu_tet(coords[[4, 1, 3, 8]]) + volu_tet(coords[[5, 1, 8, 6]]) +
volu_tet(coords[[6, 1, 8, 3]])
else
error("The volume of $(dim)D cell with $n vertices is not supported")
end
return volu
end
@termi-official The issue is lack of functions to get volume of a cell in Ferrite, which is important. Here I give a solution. Need developers to check and consider merging.
Hi and thanks for your suggestions.
Note that you can get the volume of a cell by using the CellValues, e.g.
using Ferrite
# General setup
grid =generate_grid(Quadrilateral, (2,3))
qr =QuadratureRule{RefQuadrilateral}(1)
ip =geometric_interpolation(getcelltype(grid))
cv =CellValues(qr, ip, ip)
# Get volume of cell nr 2
cellnr =2reinit!(cv, getcoordinates(grid, cellnr))
volume =sum(getdetJdV(cv, i) for i in1:getnquadpoints(cv))
# Or in this case, we only have one quadrature points, so the following works as well
volume2 =getdetJdV(cv, 1)
The possibility of getting coordinates for specific entities, such as faces, is a good idea. But in case of higher order cells (with nonlinear geometric interpolations), the above won't work. See some related discussion here #702.
There is a lack of functions to get the volume of in Ferrite. Here I have given a solution. It needs to be checked by the developer and considered for merging. The following is the functions defined outside of module
Ferrite
. If put these togrid.jl
, the prefixFerrite.
should be removed.The following is the test result:
The text was updated successfully, but these errors were encountered: