17 #include "space_hdiv.h"
20 #include "shapeset/shapeset_hd_all.h"
21 #include "boundary_conditions/essential_boundary_conditions.h"
26 template<
typename Scalar>
27 HdivSpace<Scalar>::HdivSpace() : Space<Scalar>()
31 template<
typename Scalar>
32 HdivSpace<Scalar>::HdivSpace(MeshSharedPtr mesh, EssentialBCs<Scalar>* essential_bcs,
int p_init, Shapeset* shapeset)
33 : Space<Scalar>(mesh, shapeset, essential_bcs)
35 init(shapeset, p_init);
38 template<
typename Scalar>
39 HdivSpace<Scalar>::HdivSpace(MeshSharedPtr mesh,
int p_init, Shapeset* shapeset)
40 : Space<Scalar>(mesh, shapeset, nullptr)
42 init(shapeset, p_init);
45 template<
typename Scalar>
48 if (shapeset ==
nullptr)
51 this->own_shapeset =
true;
53 if (this->shapeset->
get_num_components() < 2)
throw Hermes::Exceptions::Exception(
"HdivSpace requires a vector shapeset.");
55 this->precalculate_projection_matrix(0, this->proj_mat, this->chol_p);
62 throw Hermes::Exceptions::Exception(
"P_INIT must be >= 0 in an Hdiv space.");
64 this->set_uniform_order_internal(p_init, HERMES_ANY_INT);
70 template<
typename Scalar>
75 template<
typename Scalar>
78 this->set_shapeset(space->get_shapeset(),
true);
80 this->precalculate_projection_matrix(0, this->proj_mat, this->chol_p);
85 template<
typename Scalar>
88 if (!(shapeset->
get_id() < 30 && shapeset->
get_id() > 19))
89 throw Hermes::Exceptions::Exception(
"Wrong shapeset type in HdivSpace<Scalar>::set_shapeset()");
93 if (this->own_shapeset)
94 delete this->shapeset;
96 this->shapeset = shapeset->clone();
100 this->shapeset = shapeset;
101 this->own_shapeset =
false;
105 template<
typename Scalar>
109 this->edge_functions_count = 0;
110 for_all_edge_nodes(en, this->mesh)
112 if (en->
ref > 1 || en->
bnd || this->mesh->peek_vertex_node(en->
p1, en->p2) !=
nullptr)
114 int ndofs = this->get_edge_order_internal(en) + 1;
115 this->ndata[en->
id].n = ndofs;
118 if (this->essential_bcs !=
nullptr)
119 if (this->essential_bcs->get_boundary_condition(this->mesh->boundary_markers_conversion.get_user_marker(en->
marker).marker) !=
nullptr)
120 this->ndata[en->
id].dof = this->H2D_CONSTRAINED_DOF;
123 this->ndata[en->
id].dof = this->next_dof;
124 this->next_dof += ndofs;
125 this->edge_functions_count += ndofs;
129 this->ndata[en->
id].dof = this->next_dof;
130 this->next_dof += ndofs;
131 this->edge_functions_count += ndofs;
135 this->ndata[en->
id].dof = this->next_dof;
136 this->next_dof += ndofs;
137 this->edge_functions_count += ndofs;
142 this->ndata[en->
id].n = -1;
147 template<
typename Scalar>
148 void HdivSpace<Scalar>::assign_bubble_dofs()
151 this->bubble_functions_count = 0;
152 for_all_active_elements(e, this->mesh)
154 typename Space<Scalar>::ElementData* ed = &this->edata[e->id];
155 ed->bdof = this->next_dof;
156 ed->n = this->shapeset->get_num_bubbles(ed->order, e->get_mode());
157 this->next_dof += ed->n;
158 this->bubble_functions_count += ed->n;
162 template<
typename Scalar>
163 void HdivSpace<Scalar>::get_boundary_assembly_list_internal(Element* e,
int surf_num, AsmList<Scalar>* al)
const
165 Node* en = e->en[surf_num];
166 typename Space<Scalar>::NodeData* nd = &this->ndata[en->id];
172 int ori = (e->vn[surf_num]->id < e->vn[e->next_vert(surf_num)]->id) ? 0 : 1;
173 for (
int j = 0, dof = nd->dof; j < nd->n; j++, dof++)
174 al->add_triplet(this->shapeset->get_edge_index(surf_num, ori, j, e->get_mode()), dof, 1.0);
178 for (
int j = 0; j < nd->n; j++)
179 al->add_triplet(this->shapeset->get_edge_index(surf_num, 0, j, e->get_mode()), -1, nd->edge_bc_proj[j]);
185 int ori = part < 0 ? 1 : 0;
186 if (part < 0) part ^= ~0;
189 nd = &this->ndata[nd->base->id];
190 for (
int j = 0, dof = nd->dof; j < nd->n; j++, dof++)
191 al->add_triplet(this->shapeset->get_constrained_edge_index(surf_num, j, ori, part, e->get_mode()), dof, 1.0);
195 template<
typename Scalar>
196 void HdivSpace<Scalar>::get_bubble_assembly_list(Element* e, AsmList<Scalar>* al)
const
198 typename Space<Scalar>::ElementData* ed = &this->edata[e->id];
201 short* indices = this->shapeset->get_bubble_indices(ed->order, e->get_mode());
202 for (
unsigned short i = 0, dof = ed->bdof; i < ed->n; i++, dof++)
203 al->add_triplet(*indices++, dof, 1.0);
208 template<
typename Scalar>
209 Scalar* HdivSpace<Scalar>::get_bc_projection(SurfPos* surf_pos,
int order, EssentialBoundaryCondition<Scalar> *bc)
212 Scalar* proj = malloc_with_check<HdivSpace<Scalar>, Scalar>(order + 1,
this);
216 int mo = quad1d.get_max_order();
217 double2* pt = quad1d.get_points(mo);
219 Node* vn1 = this->mesh->get_node(surf_pos->v1);
220 Node* vn2 = this->mesh->get_node(surf_pos->v2);
221 double el = sqrt(sqr(vn1->x - vn2->x) + sqr(vn1->y - vn2->y));
222 el *= 0.5 * (surf_pos->hi - surf_pos->lo);
225 for (
int i = 0; i <= order; i++)
228 int ii = this->shapeset->get_edge_index(0, 0, i, surf_pos->base->get_mode());
229 for (
int j = 0; j < quad1d.get_num_points(mo); j++)
231 double t = (pt[j][0] + 1) * 0.5, s = 1.0 - t;
232 surf_pos->t = surf_pos->lo * s + surf_pos->hi * t;
235 EssentialBoundaryCondition<Scalar> *bc = this->essential_bcs->get_boundary_condition(this->mesh->boundary_markers_conversion.get_user_marker(surf_pos->marker).marker);
237 if (bc->get_value_type() == BC_CONST)
239 rhs[i] += pt[j][1] * this->shapeset->get_fn_value(ii, pt[j][0], -1.0, 1, surf_pos->base->get_mode())
240 * bc->value_const * el;
243 else if (bc->get_value_type() == BC_FUNCTION)
247 Curve* curve = surf_pos->base->is_curved() ? surf_pos->base->cm->curves[surf_pos->surf_num] :
nullptr;
248 CurvMap::nurbs_edge(surf_pos->base, curve, surf_pos->surf_num, 2.0*surf_pos->t - 1.0, x, y);
250 rhs[i] += pt[j][1] * this->shapeset->get_fn_value(ii, pt[j][0], -1.0, 1, surf_pos->base->get_mode())
251 * bc->value(x, y) * el;
257 cholsl(this->proj_mat, order + 1, this->chol_p, rhs, rhs);
259 for (
int i = 0; i < order + 1; i++)
265 template<
typename Scalar>
266 void HdivSpace<Scalar>::update_constrained_nodes(Element* e,
typename Space<Scalar>::EdgeInfo* ei0,
typename Space<Scalar>::EdgeInfo* ei1,
typename Space<Scalar>::EdgeInfo* ei2,
typename Space<Scalar>::EdgeInfo* ei3)
269 typename Space<Scalar>::EdgeInfo* ei[4] = { ei0, ei1, ei2, ei3 };
270 typename Space<Scalar>::NodeData* nd;
275 for (
unsigned char i = 0; i < e->get_nvert(); i++)
277 if (ei[i] !=
nullptr)
279 nd = &this->ndata[e->en[i]->id];
280 nd->base = ei[i]->node;
281 nd->part = ei[i]->part;
282 if (ei[i]->ori) nd->part ^= ~0;
290 typename Space<Scalar>::EdgeInfo ei_data[4];
291 for (
unsigned char i = 0; i < e->get_nvert(); i++)
293 if (ei[i] ==
nullptr)
296 Node* mid_vn = this->get_mid_edge_vertex_node(e, i, j);
297 if (mid_vn !=
nullptr && mid_vn->is_constrained_vertex())
299 Node* mid_en = this->mesh->peek_edge_node(e->vn[i]->id, e->vn[j]->id);
300 if (mid_en !=
nullptr)
303 ei[i]->node = mid_en;
307 ei[i]->ori = (e->vn[i]->id < e->vn[j]->id) ? 0 : 1;
314 typename Space<Scalar>::EdgeInfo half_ei_data[4][2];
315 typename Space<Scalar>::EdgeInfo* half_ei[4][2];
316 for (
unsigned char i = 0; i < e->get_nvert(); i++)
318 if (ei[i] ==
nullptr)
320 half_ei[i][0] = half_ei[i][1] =
nullptr;
324 typename Space<Scalar>::EdgeInfo* h0 = half_ei[i][0] = half_ei_data[i];
325 typename Space<Scalar>::EdgeInfo* h1 = half_ei[i][1] = half_ei_data[i] + 1;
327 h0->node = h1->node = ei[i]->node;
328 h0->part = (ei[i]->part + 1) * 2;
329 h1->part = h0->part + 1;
330 h0->hi = h1->lo = (ei[i]->lo + ei[i]->hi) / 2;
333 h1->ori = h0->ori = ei[i]->ori;
338 if (e->is_triangle())
340 update_constrained_nodes(e->sons[0], half_ei[0][0],
nullptr, half_ei[2][1],
nullptr);
341 update_constrained_nodes(e->sons[1], half_ei[0][1], half_ei[1][0],
nullptr,
nullptr);
342 update_constrained_nodes(e->sons[2],
nullptr, half_ei[1][1], half_ei[2][0],
nullptr);
343 update_constrained_nodes(e->sons[3],
nullptr,
nullptr,
nullptr,
nullptr);
345 else if (e->sons[2] ==
nullptr)
347 update_constrained_nodes(e->sons[0], ei[0], half_ei[1][0],
nullptr, half_ei[3][1]);
348 update_constrained_nodes(e->sons[1],
nullptr, half_ei[1][1], ei[2], half_ei[3][0]);
350 else if (e->sons[0] ==
nullptr)
352 update_constrained_nodes(e->sons[2], half_ei[0][0],
nullptr, half_ei[2][1], ei[3]);
353 update_constrained_nodes(e->sons[3], half_ei[0][1], ei[1], half_ei[2][0],
nullptr);
357 update_constrained_nodes(e->sons[0], half_ei[0][0],
nullptr,
nullptr, half_ei[3][1]);
358 update_constrained_nodes(e->sons[1], half_ei[0][1], half_ei[1][0],
nullptr,
nullptr);
359 update_constrained_nodes(e->sons[2],
nullptr, half_ei[1][1], half_ei[2][0],
nullptr);
360 update_constrained_nodes(e->sons[3],
nullptr,
nullptr, half_ei[2][1], half_ei[3][0]);
365 template<
typename Scalar>
369 for_all_base_elements(e, this->mesh)
370 update_constrained_nodes(e,
nullptr,
nullptr,
nullptr,
nullptr);
Stores one element of a mesh.
HdivShapesetLegendre HdivShapeset
This is the default Hdiv shapeset typedef.
virtual void copy(SpaceSharedPtr< Scalar > space, MeshSharedPtr new_mesh)
Copy from Space instance 'space'.
void init()
Common code for constructors.
Used to pass the instances of Space around.
Common definitions for Hermes2D.
Stores one node of a mesh.
virtual void copy(SpaceSharedPtr< Scalar > space, MeshSharedPtr new_mesh)
virtual unsigned char get_id() const =0
Should be exactly the same as is the count of enum ShapesetType.
unsigned bnd
1 = boundary node; 0 = inner node
virtual void set_shapeset(Shapeset *shapeset, bool clone=false)
Sets the shapeset.
unsigned char get_num_components() const
Returns 2 if this is a vector shapeset, 1 otherwise.
unsigned ref
the number of elements using the node
virtual void update_constraints()