|
| 1 | +""" |
| 2 | +Given a Discrete Model and a reffe, builds a new grid in which the geometrical |
| 3 | +map is a `FEFunction`. This is useful when considering geometrical maps that are |
| 4 | +the result of a FE problem (mesh displacement). |
| 5 | +""" |
| 6 | +struct GridWithFEMap{Dc,Dp,A,B,C,D,E} <: Grid{Dc,Dp} |
| 7 | + grid::Grid{Dc,Dp} |
| 8 | + fe_sp::A |
| 9 | + scal_fe_sp::B |
| 10 | + fe_map::C |
| 11 | + node_coords::D |
| 12 | + reffes::E |
| 13 | +end |
| 14 | + |
| 15 | +function GridWithFEMap(model,order; kwargs...) |
| 16 | + orders = Fill(order,num_cells(model)) |
| 17 | + # _reffes = [reffe] |
| 18 | + # reffes = lazy_map(Reindex(_reffes),cell_type) |
| 19 | + GridWithFEMap(model,orders; kwargs...) |
| 20 | +end |
| 21 | + |
| 22 | +function GridWithFEMap(model,orders::AbstractArray; kwargs...) |
| 23 | + |
| 24 | + # Create a FESpace for the geometrical description |
| 25 | + # The FEFunction that describes the coordinate field |
| 26 | + # or displacement can be a interpolation or a solution |
| 27 | + # of a mesh displacement problem |
| 28 | + T = eltype(get_node_coordinates(model)) |
| 29 | + Ts = eltype(T) |
| 30 | + |
| 31 | + os = orders |
| 32 | + _ps = get_polytopes(model) |
| 33 | + ct = get_cell_type(model) |
| 34 | + ps = lazy_map(Reindex(_ps), ct) |
| 35 | + |
| 36 | + f(a,b) = LagrangianRefFE(T,a,b) |
| 37 | + reffes = lazy_map(f,ps,os) |
| 38 | + Vₕ = FESpace(model,reffes;conformity=:H1,kwargs...) |
| 39 | + |
| 40 | + fs(a,b) = LagrangianRefFE(Ts,a,b) |
| 41 | + s_reffes = lazy_map(f,ps,os) |
| 42 | + Vₕ_scal = FESpace(model,s_reffes;conformity=:H1) |
| 43 | + |
| 44 | + grid = get_grid(model) |
| 45 | + geo_map = get_cell_map(grid) |
| 46 | + |
| 47 | + cell_ctype = get_cell_type(grid) |
| 48 | + c_reffes = get_reffes(grid) |
| 49 | + |
| 50 | + # Create a fe_map using the cell_map that can be evaluated at the |
| 51 | + # vertices of the fe space (nodal type) |
| 52 | + # This returns a FEFunction initialised with the coordinates |
| 53 | + # But this is to build the FEFunction that will be inserted, it is |
| 54 | + # an advanced constructor, not needed at this stage |
| 55 | + |
| 56 | + c_dofs = get_fe_dof_basis(Vₕ) |
| 57 | + dof_basis = get_data(c_dofs) |
| 58 | + c_nodes = lazy_map(get_nodes,get_data(c_dofs)) |
| 59 | + |
| 60 | + xh = zero(Vₕ) |
| 61 | + c_dofv = lazy_map(evaluate,dof_basis,geo_map) |
| 62 | + |
| 63 | + Uₕ = TrialFESpace(Vₕ) |
| 64 | + |
| 65 | + fv = get_free_dof_values(xh) |
| 66 | + dv = get_dirichlet_dof_values(get_fe_space(xh)) |
| 67 | + gather_free_and_dirichlet_values!(fv,dv,Uₕ,c_dofv) |
| 68 | + |
| 69 | + c_xh = lazy_map(evaluate,get_data(xh),c_nodes) |
| 70 | + c_scal_ids = get_cell_dof_ids(Vₕ_scal) |
| 71 | + |
| 72 | + |
| 73 | + nodes_coords = Vector{eltype(eltype(c_xh))}(undef,num_free_dofs(Vₕ_scal)) |
| 74 | + Geometry._cell_vector_to_dof_vector!(nodes_coords,c_scal_ids,c_xh) |
| 75 | + |
| 76 | + GridWithFEMap(grid, Vₕ, Vₕ_scal, xh, nodes_coords, reffes) |
| 77 | +end |
| 78 | + |
| 79 | +function _compute_node_coordinates(grid,xh) |
| 80 | + c_dofs = get_fe_dof_basis(grid.fe_sp) |
| 81 | + c_nodes = lazy_map(get_nodes,get_data(c_dofs)) |
| 82 | + |
| 83 | + c_xh = lazy_map(evaluate,get_data(xh),c_nodes) |
| 84 | + c_scal_ids = get_cell_dof_ids(grid.scal_fe_sp) |
| 85 | + |
| 86 | + nodes_coords = grid.node_coords |
| 87 | + Geometry._cell_vector_to_dof_vector!(nodes_coords,c_scal_ids,c_xh) |
| 88 | + |
| 89 | + return nothing |
| 90 | + |
| 91 | +end |
| 92 | + |
| 93 | +function add_mesh_displacement!(grid::GridWithFEMap,dh::FEFunction) |
| 94 | + |
| 95 | + Xh = grid.fe_map |
| 96 | + |
| 97 | + Xh_fv = get_free_dof_values(Xh) |
| 98 | + Xh_dv = get_dirichlet_dof_values(get_fe_space(Xh)) |
| 99 | + |
| 100 | + Xh_fv .= Xh_fv .+ get_free_dof_values(dh) |
| 101 | + Xh_dv .= Xh_dv .+ get_dirichlet_dof_values(get_fe_space(dh)) |
| 102 | + |
| 103 | + _compute_node_coordinates(grid,Xh) |
| 104 | + |
| 105 | +end |
| 106 | + |
| 107 | +function update_coordinates!(grid::GridWithFEMap,dh::FEFunction) |
| 108 | + |
| 109 | + Xh = grid.fe_map |
| 110 | + |
| 111 | + Xh_fv = get_free_dof_values(Xh) |
| 112 | + Xh_dv = get_dirichlet_dof_values(get_fe_space(Xh)) |
| 113 | + |
| 114 | + Xh_fv .= get_free_dof_values(dh) |
| 115 | + Xh_dv .= get_dirichlet_dof_values(get_fe_space(dh)) |
| 116 | + |
| 117 | + _compute_node_coordinates(grid,Xh) |
| 118 | + |
| 119 | +end |
| 120 | + |
| 121 | +# Interface |
| 122 | +get_node_coordinates(grid::GridWithFEMap) = grid.node_coords |
| 123 | +get_cell_node_ids(grid::GridWithFEMap) = get_cell_dof_ids(grid.scal_fe_sp) |
| 124 | +get_reffes(grid::GridWithFEMap) = grid.reffes |
| 125 | +get_cell_type(grid::GridWithFEMap) = get_cell_type(grid.grid) |
| 126 | +OrientationStyle(grid::GridWithFEMap) = OrientationStyle(grid.grid) |
| 127 | +RegularityStyle(grid::GridWithFEMap) = RegularityStyle(grid.grid) |
| 128 | +# santiagobadia: To think (does it make sense here, I think it is for surface problems) |
| 129 | +get_facet_normal(grid::GridWithFEMap) = get_facet_normal(grid.grid) |
| 130 | + |
| 131 | + |
| 132 | +# struct DiscreteModelWithFEMap{Dc,Dp} <: DiscreteModel{Dc,Dp} |
| 133 | +# model::DiscreteModel{Dc,Dp} |
| 134 | +# mapped_grid::GridWithFEMap{Dc,Dp} |
| 135 | +# function DiscreteModelWithFEMap(model::DiscreteModel{Dc,Dp},phys_map) where {Dc,Dp} |
| 136 | +# mapped_grid = GridWithFEMap(get_grid(model),phys_map) |
| 137 | +# new{Dc,Dp}(model,mapped_grid) |
| 138 | +# end |
| 139 | +# end |
| 140 | + |
| 141 | +function DiscreteModelWithFEMap(model::DiscreteModel,order; kwargs...) |
| 142 | + mapped_grid = GridWithFEMap(model,order;kwargs...) |
| 143 | + MappedDiscreteModel(model,mapped_grid) |
| 144 | +end |
| 145 | + |
| 146 | +function DiscreteModelWithFEMap(model,orders::AbstractArray; kwargs...) |
| 147 | + mapped_grid = GridWithFEMap(model,orders;kwargs...) |
| 148 | + MappedDiscreteModel(model,mapped_grid) |
| 149 | +end |
0 commit comments