-
Notifications
You must be signed in to change notification settings - Fork 92
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
p4est datastructures #780
base: master
Are you sure you want to change the base?
p4est datastructures #780
Conversation
…nd corner_neighbor need tests
…hanges. should be correct imho
…x corresponds to child_id
…corner and edge neighbor
There is a performance trap hiding here. Users might refine single elements one by one and if this triggers rebalancing the refinement can become quickly very expensive. Hence the users is responsible to call the balance function once he is done.
Yes, that is missing and necessary for any time-dependent problem. We add more features later (see follow-up PRs). This PR concentrates on the core implementation with documentation.
Here we run into the issue that Ferrite is "too low-level". The majority of error estimators need direct access to an evaluation of the energy or flux. So for now the only option is that the packages on top of Ferrite provide these. |
# Maps from entity to dofs | ||
# `vertexdict` keeps track of the visited vertices. The first dof added to vertex v is | ||
# stored in vertexdict[v]. | ||
vertexdicts::Vector{Vector{Int}} | ||
# `edgedict` keeps track of the visited edges, this will only be used for a 3D problem. | ||
# An edge is uniquely determined by two global vertices, with global direction going | ||
# from low to high vertex number. | ||
edgedicts::Vector{Dict{Tuple{Int,Int}, Int}} | ||
# `facedict` keeps track of the visited faces. We only need to store the first dof we | ||
# add to the face since currently more dofs per face isn't supported. In | ||
# 2D a face (i.e. a line) is uniquely determined by 2 vertices, and in 3D a face (i.e. a | ||
# surface) is uniquely determined by 3 vertices. | ||
facedicts::Vector{Dict{NTuple{3,Int}, Int}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reminder to me: Try to remove this again.
It fulfills the Ferrite.jl/src/Dofs/DofHandler.jl Line 522 in 3ae61fa
OctantBWG cells. Even the OctreeBWG won't know about its global ids, instead given o::OctantBWG in some tree::OctreeBWG part of forest::ForestBWG you can determine o 's global vertex ids. I think it's the same with distributed but just one layer removed and instead you can imagine to track the shared dofs somehow
Yeah for the algorithm or interface in general I need to discuss with @termi-official a bit. |
@fredrikekre what do you think in terms of minimal abstraction for gauss point data which eases state variable transfer and error estimation vs giving it up to the user to do this? |
OK, if the intention is that you should be able to call I guess we can at some point introduce a new function |
Side-note that I discovered when trying to understand the above: for cellid in cellids
refine!(grid, cellid)
end Perhaps the |
Because the first call generates new cell numbers or? |
Yes, as soon as the integer dispatch is called 4 (2D) or 8 (3D) new cells are inserted therefore shifting the cellids of the other cells |
I'd vote for structs that act as a flag whether or not after refinement should be balanced. That should be okay for all approaches. Balancing is not something super tightly connected to p4est. It's useful in cases where you don't want nested non-conformity constraints. I would rather go for |
That sounds good to me! |
No idea, but I guess there have to be some way to transfer things between the meshes, also the solution, right? A good start would probably be to have a cellmapping and then you can interpolate as you wish for quadrature data perhaps? |
…at makes actual sense
Yes the solution transfer is not so problematic since we have the knowledge about the fields, their underlying interpolation and the previous grid they lived on. However, what about the Gauss point data, e.g. internal variables. We need to transfer those as well in the long run. Further, we also need some interface for stress/flux computation since most error estimator do something with the stress/flux. If its just linear elastic, then it's simple you can just have a function somehow, but what about the case with internal variables? I think dealii also doesn't have a solution to it, since they only provide the kelly estimator for the poisson problem AFAIU https://www.dealii.org/current/doxygen/deal.II/classKellyErrorEstimator.html |
Yea at least for internal variables I don't think there is a good default solution so you would just have to provide the information for users to do it in a way that fits the problem at hand. |
xref Nonlinear Finite Elements (Ch 8.6.2) by Wriggers |
I tried to construct a mapping dictionary of the cell ids from a old grid/forest to the new one for 2D grid. function cell_id_map(forest_old::f, forest_new::f) where f
cell_id_old = 0
cell_id_new = 0
cellid_old2new_Dict = Dict()
for (ktree, tree) in enumerate(forest_old.cells)
kleaf_new = 1
for kleaf in 1:length(tree.leaves)
cell_id_old += 1
if forest_old.cells[ktree].leaves[kleaf].l == forest_new.cells[ktree].leaves[kleaf_new].l
# the element is not refine
cell_id_new += 1
cellid_old2new_Dict[cell_id_old] = [cell_id_new]
kleaf_new += 1
else
# refined
cellid_old2new_Dict[cell_id_old] = [cell_id_new+1, cell_id_new+2, cell_id_new+3, cell_id_new+4]
cell_id_new += 4
kleaf_new += 4
end
end
end
return cellid_old2new_Dict
end For each time of refinement, the old element may split or not change. Thus the values in the dictionary is a vector contain one or four elements. The implementation compares the old and new forest. Thus both of them should be stored. |
Cool thanks! That's a good starting point. You should consider making PRs 🚀 |
We have to think about how we can construct the mapping without having two instantiated |
Thanks @bplcn !
This is similar to what I had in mind. amr_map = initialize_amr_map(forest, instanced_grid)
refine!(forest, elements_to_refine, amr_map)
coarsen!(forest, elements_to_coarsen, amr_map)
balance!(forest, amp_map) where we can now query all refinement and coarsening information through |
This would have the same problem as #780 (comment)? Need to refine and coarsen in a single call instead? |
Indeed. This was just a sketch assuming that we have all indices properly determined a-priori. In general the loop body is a bit more involved
And now you can have different variations of We could also provide a function enum WatDo
Coarsen
Refine
Keep
end
elements_to_adapt = Vector{WatDo}(...)
adapt_mesh!(forest, elements_to_adapt, amr_map) |
Found 2 more issues in 3D with Maxi. Last commit has test coverage for them.
|
Failing analytical example:
|
to be discussed at FerriteCon 23, register now: https://ferrite-fem.github.io/FerriteCon/
TODO
OctantBWG
morton index encoded octant in 2 and 3DOctreeBWG
linear tree with homogeneousOctantBWG
leavesForestBWG
forest of homogeneousOctreeBWG
transform_face
transform_corner
transform_edge
[X-PR] p4est edge operations and consistent corner operation #902Ferrite.Grid
for unstructured meshesdocs/srcs/literate-tutorials/adaptivity.jl
docs/src/literate-tutorials/adaptivity.jl
with (almost?maybe?) working but slow ZZ error estimatordocs/src/literate-tutorials/heat-adaptivity.jl
docs/src/literate-tutorials/adaptivity.jl
to a proper tutorialFollowup PRs