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

Suggestion to change faces(::Quad) to edges(::Quad) #789

Closed
wants to merge 9 commits into from

Conversation

lijas
Copy link
Collaborator

@lijas lijas commented Aug 14, 2023

The main reasons for doing this is :

  • I think the code base becomes nicer, see e.g. the dofhandler, topology, InterpolationInfo. Basically we can remove most if dim== 2 etc. We can also remove the "hacks" we have for embedded elements (shells, beams). In other words we will have better integration of embedded elements.

Another indication that this might be the right change is that many other FE-related packages uses this definition, e.g Finics, Gmsh, defelements (also deal.ii i think)

The drawback is:

  • Changes to the api. FaceIndex will not be "dimension independent" anymore. For 2d-problems, one would need to use e.g. getedgeset() instead of getfaceset() (actually, this is not strictly necessary because the we can keep backwards compatibility by defining:
    getfacset(grid::Grid{2}, name::String) = grid.edgesets[name] .... however, it might be a bit strange that getfaceset returns an edgeset (for 2d-problems)).
    One possible way of keeping a "dimension independent" way of accessing boundary-sets (facesets/edgeset) is to introduce "facets", for example getfacetset, addfacetset, with the following meaning:
getfacetsets(grid::AbstractGrid{1}) = grid.vertexsets
getfacetsets(grid::AbstractGrid{2}) = grid.edgesets
getfacetsets(grid::AbstractGrid{3}) = grid.facesets

To be clear, this is only a suggestion. Please come with feedback :)

@termi-official
Copy link
Member

Thanks for the suggestion and working on this. A few comments on this.

Deal.ii uses faces for lines in 2D. MFEM for example does not have a consistent definition for this. I also asked a bit around and the response whether people would call the boundary of a 2D element an edge or face is actually pretty split.

Saying an edge is a topological 1D entity further raises the question whether the cell for a line element is also an edge, and e.g. how do we handle this edge case in the code.

Regarding the removal of the internal hacks I thought about having an dimension-independent layer in the Ferrite core, which is independent of the actual definition of face/edge/... .

@KnutAM
Copy link
Member

KnutAM commented Aug 14, 2023

Would be really nice if this could simplify the internals!

IMO any such change must be done without removing the possibility of straight-forward writing dimension-independent code. Would this also turn FaceValues into FacetValues?

@lijas
Copy link
Collaborator Author

lijas commented Aug 14, 2023

@termi-official
I can imagaine that there are many ways to implement it and there is no right ansewr!.

Saying an edge is a topological 1D entity further raises the question whether the cell for a line element is also an edge,

I think this is true, a line element would also be an edge, but what would be the problem with this? What edge-cases (pun intended? :P ) needs to be handled.

@KnutAM
I agree, it should still be possible to write dimension independent code. And I think introducing the definition of facet would make this possible.

Regarding FaceValues, I think it would be nice to introduce FacetValues which returns FaceValues for 3d-surfaces and EdgeValues for Lines.

@koehlerson
Copy link
Member

koehlerson commented Aug 14, 2023

#780 I have there a lot of dim==3 code branches because I often have to look at the full surrounding of a cell. Could this be beneficial in such cases?

@@ -70,9 +70,14 @@ mutable struct ExclusiveTopology <: AbstractTopology
edge_edge_neighbor::Matrix{EntityNeighborhood{EdgeIndex}}
# lazy constructed face topology
face_skeleton::Union{Vector{FaceIndex}, Nothing}
edge_skeleton::Union{Vector{EdgeIndex}, Nothing}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems only valid for 2D and should rather be facet_skeleton ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I dont think so. My idea is that you generate the edge_skeleton, face_skeleton etc the same for both a 2d and 3d grid (because topologicaly they are definied in the same way now), and then if you want to loop over the dim-1 entity, you would dispatch on the dim-parameter:

function facetskeleton(top::ExclusiveTopology, grid::Grid{2})
    return top.edge_skeleton
end
function facetskeleton(top::ExclusiveTopology, grid::Grid{3})
    return top.face_skeleton
end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'm wondering in general about the dispatch. If I'm not mistaken, then you define a facet as a dim-1 entity and you can store directly the facetskeleton without having the extra field in the struct

function facetskeleton(top::ExclusiveTopology, grid)
    return top.facetskeleton
end

Or is there some advantage of having both fields?

Copy link
Collaborator Author

@lijas lijas Aug 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what if you have a hex mesh? Then you might want to have both an edge_skeleton and a face_skeleton. Then you will have a extra field called facet_skeleton which is identical to face_skeleton?

I realise now though that the dispatch approach might not work for shells in 3d... the dispatch for facetskeleton(..., grid{3}) would return the face_skeleton, even though you probably would want egde_skeleton...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay! I think as of now, there is no construction of edge skeleton in 3D cases planned. Not sure if they are useful in some cases, but if we want to include them, then this makes sense

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following my comments below, I think this should be facetskeleton and ridgeskeleton, that would allow having the edge skeleton in 3d, but for the current cases only facetskeleton would be used.

@KnutAM
Copy link
Member

KnutAM commented Aug 14, 2023

Regarding FaceValues, I think it would be nice to introduce FacetValues which returns FaceValues for 3d-surfaces and EdgeValues for Lines.

I would have thought the other way around, that the actual type is FacetValues, because they are always codimension 1. If we have both facets/ridges and faces/edges internally, this should be possible to handle.

My main fear with those definitions (but they are what they are, so can't really change the name), is that I find facetset and faceset is too similar making it hard to read the code. Furthermore, while using the mathematically correct definitions is nice, could it be confusing for inexperienced users? Especially since it is being used in introductory FE courses. (Not necessarily saying such a change shouldn't be made - every time I think about this I'm changing my mind)

@lijas
Copy link
Collaborator Author

lijas commented Aug 15, 2023

@KnutAM Those are my concerns too.

Regarding FacetValues... I think you are right, we might need to introduce a new type FacetValues, because EdgeValues typically does not store any normals, which is still something you might want for a 2d problem even though the boundary is technically an edge.

@termi-official
Copy link
Member

I am fine with renaming the stuff, but we should be consistent to avoid further confusion. Hence, for consistency of the API we should also discuss the (re-)naming of:

FaceIndex -> FacetIndex
FaceValues -> FacetValues
EdgeIndex -> RidgeIndex
celldof_interior_indices -> volumedof_interior_indices

I think the confusion can be somewhat complied with by providing additional docs and an FAQ.

For me the bothering part when defining faces and edges by dimension (instead of by codimension) in the implementation is the implication on the data structures for the user-facing part. What exactly should FaceValues do for quadrilaterals? Facet or Cell with normal?

Copy link
Member

@fredrikekre fredrikekre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix the things we discussed.

revert some changes

revert som changes
@lijas
Copy link
Collaborator Author

lijas commented Apr 18, 2024

@termi-official and @KnutAM, can you make a review of this PR? I know you have thought about this problem, so I would like your input here. I think that I have convinced Fredrik and Kim that this is a good solution (although the breaking changes are of course not nice), but I imagine you have a different approach in mind . Note, there are still stuff to do in this PR, like deciding if we should rename FaceValues, docs, fixing tests.... But I think the point of the PR is clear.

To reiterate the main idea of this PR. We keep the names vertices, edges and faces (e.g in VertexIndex, EdgeIndex and FaceIndex), but we make the definitions of these entities consistent for all cells (and interpolations):

  • Vertex refers to points (nothing changes here)
  • edges always refers to lines between two vertices
  • faces are surfaces with normals
    (These are not formal definitions, but I think you get the point).

As an example, the sides of a Quadrilateral would no longer be called faces; they are now edges .

This change simplifies the code-base quite a lot at some places, especially in the dof-distribution, and solves most(all?) of the consistency issues we have

The major drawback is now that users can no longer call e.g. getfaceset(grid, "right") in 2d problems anymore (sdim=2), since the boundary of the domain is now an edgeset. To account for this, we also introduce the concept of facets, e.g. getfacetset, which changes meaning depening on the reference dim of the element:

 facets(c::AbstractCell{<:AbstractRefShape{1}}) = vertices(c)
 facets(c::AbstractCell{<:AbstractRefShape{2}}) = edges(c)
 facets(c::AbstractCell{<:AbstractRefShape{3}}) = faces(c)

Similar dispatches are used through out the code, e.g for dirichlet_facetdof_indices, facetdof_indices ...

@termi-official
Copy link
Member

Thanks for the work on solving the issue here!

@termi-official and @KnutAM, can you make a review of this PR? I know you have thought about this problem, so I would like your input here. I think that I have convinced Fredrik and Kim that this is a good solution, but I imagine you have a different approach in mind .

Sure I will take a look. I do not think that I have a different solution per-se, but I share similar concerns as Kim about the entry barrier to Ferrite with these changes (and I mean with all possible solutions, not specific to this PR).

To reiterate the main idea of this PR. We keep the names vertices, edges and faces (e.g in VertexIndex, EdgeIndex and FaceIndex), but we make the definitions of these entities consistent for all cells (and interpolations):

I already discussed this with Fredrik and want to bring this also up here: Now FaceIndex and EdgeIndex is a bit ambigous. Maybe we should introduce FacetIndex and RidgeIndex, because this is actually what these indices refer to on master.

* Vertex refers to points (nothing changes here)

I would rather reserve vertex for corners and nodes for points in general. I think this is a bit more consistent with our intent. We really need to clarify this in the docs, because I think this is already on master super confusing for users.

* edges always refers to lines between two vertices

I think we all can agree on this definition.

* faces are surfaces with normals
  (These are not formal definitions, but I think you get the point).

I would drop the normal part here, because defining what the normal (field) is can be troublesome. E.g. what is the normal of a face in 4D or 2D?

This change simplifies the code-base quite a lot at some places, especially in the dof-distribution, and solves most(all?) of the consistency issues we have
This would definitely solve the dof distribution consistency issue for the current set of interpolations, but not all.

The major drawback is now that users can no longer call e.g. getfaceset(grid, "right") in 2d problems anymore (sdim=2), since the boundary of the domain is now an edgeset. To account for this, we also introduce the concept of facets, e.g. getfacetset, which changes meaning depening on the reference dim of the element:

 facets(c::AbstractCell{<:AbstractRefShape{1}}) = vertices(c)
 facets(c::AbstractCell{<:AbstractRefShape{2}}) = edges(c)
 facets(c::AbstractCell{<:AbstractRefShape{3}}) = faces(c)

Similar dispatches are used through out the code, e.g for dirichlet_facetdof_indices, facetdof_indices ...

For me personally this is also fine. But we should reflect this somewhere in the docs very carefully and visible for beginners. No idea how tho.

@termi-official
Copy link
Member

Before I go for a full review, can you also update the remaining files in FEValues and interators.jl?

How should we proceed with the current boundary indices FaceIndex and EdgeIndex? And should the grid rather contain facets and rigdes or faces and edges?

Since we are at it

  • the function sortface for one and two vertices is now also off and should be removed
  • the doc strings in ConstraintHandler and many variable names are now off (refering to faces when operating on facets)
  • FacetQuadratureRule?

Copy link
Member

@KnutAM KnutAM left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for starting this huge effort @lijas!
Some initial comments/thoughts

My comments are based on my understanding that co-dimension is relative the spatial dimension (as opposed to the reference (element) dimension), so with my understanding, for RefLine embedded in 2d, the edge is the facet and the point is the ridge, but in a non-embedded case (1d), the edge is the cell and the point is the facet. Does this match your view?
Edit: Updated comments after I understood that we use the codim relative the topological/reference shape dimension.

I would have expected that for the grid we work with co-dimensional entities (basically as we were before, except we had the wrong names), i.e. we should just rename

FaceIndex -> FacetIndex
EdgeIndex -> RidgeIndex
VertexIndex -> PeakIndex

instead of changing depending on the sdim in the grid.

As @termi-official mentions, I think we should have FaceValues -> FacetValues and FaceQuadratureRule to FacetQuadratureRule. AFAIU, from the user perspective, one would for most cases only need to care about these names (cell, facet, ridge, peak).

Changing to using the dimensional entities (volume, face, edge, point) for interpolations, reference shapes, and dof distribution looks like it works great!

src/Grid/grid.jl Outdated
Comment on lines 571 to 573
@inline facets(c::AbstractCell{<:AbstractRefShape{1}}) = vertices(c)
@inline facets(c::AbstractCell{<:AbstractRefShape{2}}) = edges(c)
@inline facets(c::AbstractCell{<:AbstractRefShape{3}}) = faces(c)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is wrong, since facet refers to sdim - 1 and not rdim - 1?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, facet is rdim - 1

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I unresolved this, because I think we should add this information to the documentation to have a single source of truth for the definitions. @lijas

src/Grid/grid.jl Outdated Show resolved Hide resolved
Comment on lines +328 to +367
struct EdgeIterator{FC<:FaceCache}
fc::FC
set::Set{EdgeIndex}
end

function EdgeIterator(gridordh::Union{Grid,AbstractDofHandler},
set::Set{EdgeIndex}, flags::UpdateFlags=UpdateFlags())
if gridordh isa DofHandler
# Keep here to maintain same settings as for CellIterator
_check_same_celltype(get_grid(gridordh), set)
end
return EdgeIterator(FaceCache(gridordh, flags), set)
end

@inline _getcache(fi::EdgeIterator) = fi.fc
@inline _getset(fi::EdgeIterator) = fi.set

struct VertexIterator{FC<:FaceCache}
fc::FC
set::Set{VertexIndex}
end

function VertexIterator(gridordh::Union{Grid,AbstractDofHandler},
set::Set{VertexIndex}, flags::UpdateFlags=UpdateFlags())
if gridordh isa DofHandler
# Keep here to maintain same settings as for CellIterator
_check_same_celltype(get_grid(gridordh), set)
end
return VertexIterator(FaceCache(gridordh, flags), set)
end

@inline _getcache(fi::VertexIterator) = fi.fc
@inline _getset(fi::VertexIterator) = fi.set

FaceIterator(gridordh::Union{Grid,AbstractDofHandler}, set::Set{EdgeIndex}, flags::UpdateFlags=UpdateFlags()) =
EdgeIterator(gridordh, set, flags)

FaceIterator(gridordh::Union{Grid,AbstractDofHandler}, set::Set{VertexIndex}, flags::UpdateFlags=UpdateFlags()) =
VertexIterator(gridordh, set, flags)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cannot a FacetIterator replace the current FaceIterator?

@fredrikekre
Copy link
Member

My comments are based on my understanding that co-dimension is relative the spatial dimension (as opposed to the reference (element) dimension), so with my understanding, for RefLine embedded in 2d, the edge is the facet and the point is the ridge, but in a non-embedded case (1d), the edge is the cell and the point is the facet. Does this match your view?

Elias and I discussed this based on https://defelement.com/ciarlet.html#Cell+subentities where they explicitly define the names based on codimension of the reference element (topological dimension) and not the spatial dimension (which they refer to as geometric dimension).

So if we have 3 spatial dimension with hex and (embedded) quads we have 8 facets of the hex which are faces and we have 4 facets of the quad which are edges.

@KnutAM
Copy link
Member

KnutAM commented Apr 19, 2024

Elias and I discussed this based on https://defelement.com/ciarlet.html#Cell+subentities where they explicitly define the names based on codimension of the reference element (topological dimension) and not the spatial dimension (which they refer to as geometric dimension).

Thanks for correcting me (I have to rethink a bit:))
At least fenics use the same definition for a facet. (relative topological/reference dimension)

I guess the implication for the example in #899 then would be that the "face" of the beam would not be accessible for adding boundary conditions to (using facets), but the endpoints would be available. And when thinking of this now, that makes sense because in the non-embedded case a load on the "face" of the beam would actually be a body load!

# Ferrite grid: Beam attached to face
# 3 ____ 4  4
# |      |  |   
# |      |  | (Beam attached to face)    
# 1 ____ 2  2

I'll go through again and update my comments accordingly

src/Grid/grid.jl Outdated
Comment on lines 539 to 541
getfacetsets(grid::AbstractGrid{1}) = grid.vertexsets
getfacetsets(grid::AbstractGrid{2}) = grid.edgesets
getfacetsets(grid::AbstractGrid{3}) = grid.facesets
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since facet refers to rdim-1 this isn't always true then, right?
So it would be better to actually just store the peaksets, ridgesets, and facetsets directly?

@KnutAM
Copy link
Member

KnutAM commented Apr 19, 2024

Vertex refers to points (nothing changes here)

Shouldn't this be renamed to "point" following the table, and "vertex" refers to the zero-dimensional reference shape?
image

@koehlerson
Copy link
Member

koehlerson commented Apr 19, 2024

Vertex refers to points (nothing changes here)

Shouldn't this be renamed to "point" following the table, and "vertex" refers to the zero-dimensional reference shape? image

If we do vertex == nodes, then we need a new name for the current vertex which are all the corners of an element. The naming is already mixed up in the code base from time to time. So point would be good substitute for nodes

@KnutAM
Copy link
Member

KnutAM commented Apr 19, 2024

If we do vertex == nodes, then we need a new name for the current vertex which are all the corners of an element. The naming is already mixed up in the code base from time to time. So point would be good substitute for nodes

I don't think vertex == nodes becomes the result? For example, what is a node in the middle of an edge, to me a node is a different concept (but could be wrong), relating to the interpolation (either geometric or algebraic).

AFAIU point becomes the corners of an element, vertex the reference shape for 0-dimensional entities, and peak == point for 3d refshapes.

@koehlerson
Copy link
Member

koehlerson commented Apr 19, 2024

I just meant that we should keep the distinction between corners which are vertices currently and all 0 dimension entities of an element, which should be currently nodes in the code base.

AFAIU point becomes the corners of an element, vertex the reference shape for 0-dimensional entities, and peak == point for 3d refshapes.

https://defelement.com/elements/examples/quadrilateral-lagrange-gll-1.html

Here for instance, they refer still to the corners as vertices, which is fine for me. I was just unsure if the table also gathers the inner 0 dimension entities as vertices.

@KnutAM
Copy link
Member

KnutAM commented Apr 19, 2024

Interesting, so either I have further misunderstandings, or they are inconsistent 🤔 (But language-wise I'd switch vertex and point in the table)

@fredrikekre
Copy link
Member

I guess the implication for the example in #899 then would be that the "face" of the beam would not be accessible for adding boundary conditions to (using facets), but the endpoints would be available. And when thinking of this now, that makes sense because in the non-embedded case a load on the "face" of the beam would actually be a body load!

Yea, and thats why it make sense to use CellValues also for embedded elements and not FacetValue etc.

@fredrikekre
Copy link
Member

I mean that if it was relative the spatial dimension, then when integrating for example an embedded quad in 3d you would use a FacetValue and when integrating an embedded beam in 3d you would use RidgeValues.

@KnutAM
Copy link
Member

KnutAM commented Apr 19, 2024

Aha, yes - I agree that codim relative rdim/topological dimension makes more sense!

Just to put up the a summary of fenics' definitions based on their manual, I think the only difference from defelement is the vertex vs point, (currently I'm leaning towards the fenics definition as the more logical one).
(Feel free to edit this post with more names / links if I've missed something)

Co-dimensionally defined quantities

  • Cell: "A Cell is a MeshEntity of topological codimension 0."
  • Facet: "A Facet is a MeshEntity of topological codimension 1."
  • Ridge: Not defined
  • Peak: Not defined

Topologically dimensionally defined quantities

  • Vertex: "A Vertex is a MeshEntity of topological dimension 0."
  • Edge: "An Edge is a MeshEntity of topological dimension 1."
  • Face: "A Face is a MeshEntity of topological dimension 2."
  • Volume: Not defined

Other relevant names

  • Point: "A Point represents a point in $\mathbb{R}^3$ with coordinates x,y,z, or alternatively, a vector in $\mathbb{R}^3$, supporting standard operations like the norm, distances, scalar and vector products etc."
  • FacetCell: "This class represents a cell in a mesh incident to a facet on the boundary. It is useful in cases where one needs to iterate over a boundary mesh and access the corresponding cells in the original mesh."

@koehlerson
Copy link
Member

koehlerson commented Apr 19, 2024

Aha, yes - I agree that codim relative rdim/topological dimension makes more sense!

Just to put up the a summary of fenics' definitions based on their manual, I think the only difference from defelement is the vertex vs point, (currently I'm leaning towards the fenics definition as the more logical one). (Feel free to edit this post with more names / links if I've missed something)

Co-dimensionally defined quantities

* [Cell](https://fenicsproject.org/olddocs/dolfin/1.3.0/python/programmers-reference/cpp/mesh/Cell.html): "A Cell is a MeshEntity of topological codimension 0."

* [Facet](https://fenicsproject.org/olddocs/dolfin/1.3.0/python/programmers-reference/cpp/mesh/Facet.html#dolfin.cpp.mesh.Facet): "A Facet is a MeshEntity of topological codimension 1."

* Ridge: _Not defined_

* Peak: _Not defined_

Topologically dimensionally defined quantities

* [Vertex](https://fenicsproject.org/olddocs/dolfin/1.3.0/python/programmers-reference/cpp/mesh/Vertex.html): "A Vertex is a MeshEntity of topological dimension 0."

* [Edge](https://fenicsproject.org/olddocs/dolfin/1.3.0/python/programmers-reference/cpp/mesh/Edge.html): "An Edge is a MeshEntity of topological dimension 1."

* [Face](https://fenicsproject.org/olddocs/dolfin/1.3.0/python/programmers-reference/cpp/mesh/Face.html): "A Face is a MeshEntity of topological dimension 2."

* Volume: _Not defined_

Other relevant names

* [Point](https://fenicsproject.org/olddocs/dolfin/1.3.0/python/programmers-reference/cpp/mesh/Point.html): "A Point represents a point in R3 with coordinates x,y,z, or alternatively, a vector in R3, supporting standard operations like the norm, distances, scalar and vector products etc."

* [FacetCell](https://fenicsproject.org/olddocs/dolfin/1.3.0/python/programmers-reference/cpp/mesh/FacetCell.html): "This class represents a cell in a mesh incident to a facet on the boundary. It is useful in cases where one needs to iterate over a boundary mesh and access the corresponding cells in the original mesh."

In this definition of a vertex you set vertex == nodes or am I missing something? This is only valid for linear stuff. If we want to distinguish corner points from interior points

@KnutAM
Copy link
Member

KnutAM commented Apr 19, 2024

In this definition of a vertex you set vertex == nodes or am I missing something? This is only valid for linear stuff. If we want to distinguish corner points from interior points

That's not how I understand it (but these definitions are still confusing me a bit), when reading up on this I found this resource on the Ciarlet definition insightful, where the nodal values are defined as the support variables for the interpolation (https://finite-element.github.io/L2_fespaces.html). So as I understand, in general a node is not understood as a geometrical point at all (for example for the vector interpolations such as Nedelec where the nodal values are the integrated along an edge). However, in the case of e.g. Lagrange interpolations, all nodes coincide with the interpolated value at specific geometrical points. (This goes against my previous understanding of a node though, so I do see the risk confusion). When it comes to the geometrical nodes, since our interpolations are scalar we have the correspondance between a geometrical node and point (I guess in IGA this doesn't hold @lijas?). However, vertices are specific to the topology and refers specifically to the endpoints of intervals (i.e. the codim 1 of an interval/line). (But I agree that "MeshEntity of topological dimension 0" doesn't fully cover that)

@koehlerson
Copy link
Member

I'm just saying if we define something that includes all 0 dimension entities, there should be something for the corners, since they are very relevant for topological (geometry) constructions which was previously in the code base vertices. I think it's rather confusing going from vertices = corner to vertices = all 0 dimensional entities, but I don't mind how we name it in the future. I guess points refers to all 0 dimensional things, while vertices are just the corners, but I'm not sure and unfortunately I don't have access to the Ciarlet book. The website is not really clear on this subject for me

@KnutAM
Copy link
Member

KnutAM commented Apr 19, 2024

I guess points refers to all 0 dimensional things, while vertices are just the corners

This is my (current) understanding too.

@koehlerson
Copy link
Member

koehlerson commented Apr 19, 2024

I'm confused by the book. For triangles it seems that corners == vertices, but for quads all points == vertices (they are defined with a single index)

image
Fig 2.2.2

vs.
image
Fig 2.2.10

@KnutAM
Copy link
Member

KnutAM commented Apr 19, 2024

Yes, I don't get their numbering scheme either, e.g. why 3 indices are used for 3rd order cases (I would have assumed a_{ij} where i is edge number and j is the internal node number for edge i.)

image
Fig 2.2.4

But I think we can agree that

  • Vertex: End of line/interval segments (i.e. corners) (excludes internal points on edges/faces and in volumes)
  • Node: Support points for geometric interpolation? (Includes internal points on edges/faces and in volumes)

?

@termi-official
Copy link
Member

Maybe it is easier for everyone if we just rename the thing to "corner"? I think this is the most direct and unambiguous term.

Copy link

codecov bot commented Apr 19, 2024

Codecov Report

Attention: Patch coverage is 96.80851% with 9 lines in your changes are missing coverage. Please review.

Project coverage is 88.96%. Comparing base (f6a7d3d) to head (4bc6e68).
Report is 2 commits behind head on master.

❗ Current head 4bc6e68 differs from pull request most recent head b7b9607. Consider uploading reports for the commit b7b9607 to get more accurate results

Files Patch % Lines
src/Grid/grid.jl 92.53% 5 Missing ⚠️
src/Grid/topology.jl 94.44% 3 Missing ⚠️
src/interpolations.jl 98.21% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #789      +/-   ##
==========================================
- Coverage   93.30%   88.96%   -4.35%     
==========================================
  Files          36       36              
  Lines        5257     5382     +125     
==========================================
- Hits         4905     4788     -117     
- Misses        352      594     +242     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@KnutAM
Copy link
Member

KnutAM commented Apr 20, 2024

Maybe it is easier for everyone if we just rename the thing to "corner"? I think this is the most direct and unambiguous term.

Overall, from what I can read, vertices and corners are synonyms, but yet I wouldn't call the end-points of a line for corners, but rather vertices?

@fredrikekre
Copy link
Member

I suggest we use vertex then, and we can include a glossar in the docs with clarifications if needed.

@lijas
Copy link
Collaborator Author

lijas commented Apr 22, 2024

Knut pointed out that the dispatches

getfacetset(grid::AbstractGrid{1}) = grid.vertexsets
getfacetset(grid::AbstractGrid{2}) = grid.edgesets
getfacetset(grid::AbstractGrid{3}) = grid.facesets

are technically wrong, since facets is defined based on codimension of rdim, and the grid is parametrised with sdim. So my suggestion is to use the name getboundaryset instead, where "boundary" would be based on the co-dimension of sdim . What do you think?

I also think we can get away with not renaming FaceValues to FacetValues. My reasoning is:

  • You would never want to integrate on the faces in 2d. So there is not really any ambiguity what FaceValues refer to here.
  • In 3d, you would not use "FacetValues" to integrate along edges of e.g shell elements, since they do not have a defined normal direction (which facetvalues requires/stores). Instead, you would use something like "EdgeValues".

In this way, we would not need to introduce the concept of "facet" to the user, it would only be an internal thing.

@KnutAM
Copy link
Member

KnutAM commented Apr 22, 2024

getboundaryset instead, where "boundary" would be based on the co-dimension of sdim

In the following case, I would expect boundaryset to include the edges (4,3) and (3,6) as well as the vertex (3) if I want to integrate along the top boundary. These are all facets with co-dimension 1 wrt. rdim, so I think facetset makes more sense than introducing another dimension case.

# Ferrite grid: Embedded line element is nr 2
# 4 ____ 3  3 3 ____ 6
# |      |  | |      |
# | (1)  |  | |  (3) |
# 1 ____ 2  2 2 ____ 5

I would therefore argue that we should change the fields in Grid:

  • facesets: Change to to facetsets.
  • edgesets: I have never used them.
    Could become ridgesets, but since fenics don't seem to have it we could perhaps remove it? The only place I can find it used in the docs are for the shell example here, and that usage would be replaced by facetset after this PR.
  • vertexsets: I think keeping this makes sense. (e.g. apply Dirichlet at one location)
    I don't think peaksets are useful because they can only be used in 3d, and then coincides with vertexsets

You would never want to integrate on the faces in 2d. So there is not really any ambiguity what FaceValues refer to here.
In 3d, you would not use "FacetValues" to integrate along edges of e.g shell elements, since they do not have a defined normal direction (which facetvalues requires/stores). Instead, you would use something like "EdgeValues".

I think that while doing this change now, we should be fully consistent with the notation and avoid "exceptions", such as saying that FaceValues refers to facets which happens to coincide with faces in 3d, but are edges with defined normals in 2d, and vertices with defined normals in 1d.

shell elements, since they do not have a defined normal direction

In this case, I would expect that FacetValues stores the outwards pointing vector perpendicular to the edge tangent and the face normal, isn't this well-defined? An EdgeValues object would, on the other hand, only store the edge direction as the normal to an edge of a polyhedron is not defined.

I see that in this setting, it would also be relevant to know the edge tangent direction though, but this would be similar wrt. an embedded CellValues, which currently don't store the normal information.

I took a quick look at the code, and a change that could make sense is to include a direction-field in GeometryMapping (to be done in a separate PR, I don't think the current PR removes features that such a change would reenable). The direction field would change depending on the usage as something like

  • Standard, non-embedded CellValues: nothing
  • Standard, non-embdded FacetValues: Normal vector
  • 2D CellValues embedded in 3D: Normal vector
  • 1D CellValues embedded in 2D or 3D: Direction vector
  • 2D FacetValues embedded in 3D (e.g. shell): Edge direction vector and facet normal (perpendicular to edge direction and face normal)
  • 1D FacetValues embedded in 2D or 3D: Normal vector

@fredrikekre
Copy link
Member

In the following case, I would expect boundaryset to include the edges (4,3) and (3,6) as well as the vertex (3) if I want to integrate along the top boundary.

But surely you couldn't treat these three entities the same in the integration? You would in this case do something for the edges and something else for the vertex, right?

I think we should just not allow facetsets of different types. In this example you would instead have two facetsets for the top boundary, which would correspond how you treat them in the code anyway.

@KnutAM
Copy link
Member

KnutAM commented Apr 23, 2024

But surely you couldn't treat these three entities the same in the integration? ...

True, I would have different loops for these. But if I ask for the set on the boundary, I expect both to be included, and then I would split the set via intersection with the subdofhandlers. I think this is how it would currently be on the master, except there we would ask for the faceset instead of the facetset.

I think we should just not allow facetsets of different types

I don't see the problem for keeping this functionality when we rename FaceIndex to FacetIndex, this would all just be a FacetIndex(cellid, facetid).

@fredrikekre fredrikekre added this to the v1.0.0 milestone May 13, 2024
KnutAM added a commit that referenced this pull request May 23, 2024
Adressing changes in #692, #789, and #914
---------

Co-authored-by: Fredrik Ekre <ekrefredrik@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants