21 template<
typename Scalar>
22 H1Space<Scalar>::H1Space() : Space<Scalar>()
26 template<
typename Scalar>
29 if (shapeset ==
nullptr)
35 this->precalculate_projection_matrix(2, this->proj_mat, this->chol_p);
42 throw Hermes::Exceptions::Exception(
"P_INIT must be >= 1 in an H1 space.");
50 template<
typename Scalar>
52 :
Space<Scalar>(mesh, shapeset, essential_bcs)
54 init(shapeset, p_init);
57 template<
typename Scalar>
58 H1Space<Scalar>::H1Space(MeshSharedPtr mesh,
int p_init, Shapeset* shapeset)
59 : Space<Scalar>(mesh, shapeset, nullptr)
61 init(shapeset, p_init);
64 template<
typename Scalar>
65 H1Space<Scalar>::~H1Space()
69 template<
typename Scalar>
72 this->set_shapeset(space->get_shapeset(),
true);
73 this->precalculate_projection_matrix(2, this->proj_mat, this->chol_p);
80 template<
typename Scalar>
83 if (!(shapeset->
get_id() < 10))
84 throw Hermes::Exceptions::Exception(
"Wrong shapeset type in H1Space<Scalar>::set_shapeset()");
88 if (this->own_shapeset)
89 delete this->shapeset;
91 this->shapeset = shapeset->clone();
95 this->shapeset = shapeset;
96 this->own_shapeset =
false;
100 template<
typename Scalar>
113 this->vertex_functions_count = 0;
114 for_all_active_elements(e, this->mesh)
116 int order = this->get_element_order(e->
id);
119 for (
unsigned char i = 0; i < e->get_nvert(); i++)
127 nd->dof = this->H2D_CONSTRAINED_DOF;
131 nd->dof = this->next_dof;
133 this->vertex_functions_count++;
142 template<
typename Scalar>
143 void H1Space<Scalar>::assign_edge_dofs()
147 this->edge_functions_count = 0;
148 for_all_active_elements(e, this->mesh)
150 int order = this->get_element_order(e->id);
153 for (
unsigned char i = 0; i < e->get_nvert(); i++)
156 typename Space<Scalar>::NodeData* nd = this->ndata + vn->id;
158 nd = this->ndata + en->id;
159 if (nd->dof == this->H2D_UNASSIGNED_DOF)
162 if (en->ref > 1 || en->bnd || this->mesh->peek_vertex_node(en->p1, en->p2) !=
nullptr)
164 int ndofs = this->get_edge_order_internal(en) - 1;
168 if (this->essential_bcs !=
nullptr)
169 if (this->essential_bcs->get_boundary_condition(this->mesh->boundary_markers_conversion.get_user_marker(e->en[i]->marker).marker) !=
nullptr)
170 nd->dof = this->H2D_CONSTRAINED_DOF;
173 nd->dof = this->next_dof;
174 this->next_dof += ndofs;
175 this->edge_functions_count += ndofs;
179 nd->dof = this->next_dof;
180 this->next_dof += ndofs;
181 this->edge_functions_count += ndofs;
185 nd->dof = this->next_dof;
186 this->next_dof += ndofs;
187 this->edge_functions_count += ndofs;
198 template<
typename Scalar>
199 void H1Space<Scalar>::assign_bubble_dofs()
203 this->bubble_functions_count = 0;
204 for_all_active_elements(e, this->mesh)
206 typename Space<Scalar>::ElementData* ed = &this->edata[e->id];
207 ed->bdof = this->next_dof;
208 ed->n = this->shapeset->get_num_bubbles(ed->order, e->get_mode());
209 this->next_dof += ed->n;
210 this->bubble_functions_count += ed->n;
214 template<
typename Scalar>
215 void H1Space<Scalar>::get_vertex_assembly_list(Element* e,
int iv, AsmList<Scalar>* al)
const
217 Node* vn = e->vn[iv];
218 typename Space<Scalar>::NodeData* nd = &this->ndata[vn->id];
219 int index = this->shapeset->get_vertex_index(iv, e->get_mode());
221 if (!vn->is_constrained_vertex())
223 al->add_triplet(index, nd->dof, (nd->dof >= 0) ? 1.0 : *(nd->vertex_bc_coef));
227 for (
int j = 0; j < nd->ncomponents; j++)
228 if (nd->baselist[j].coef != (Scalar)0)
230 al->add_triplet(index, nd->baselist[j].dof, nd->baselist[j].coef);
235 template<
typename Scalar>
236 void H1Space<Scalar>::get_boundary_assembly_list_internal(Element* e,
int surf_num, AsmList<Scalar>* al)
const
238 Node* en = e->en[surf_num];
239 typename Space<Scalar>::NodeData* nd = &this->ndata[en->id];
245 int ori = (e->vn[surf_num]->id < e->vn[e->next_vert(surf_num)]->id) ? 0 : 1;
246 for (
int j = 0, dof = nd->dof; j < nd->n; j++, dof++)
247 al->add_triplet(this->shapeset->get_edge_index(surf_num, ori, j + 2, e->get_mode()), dof, 1.0);
251 for (
int j = 0; j < nd->n; j++)
253 al->add_triplet(this->shapeset->get_edge_index(surf_num, 0, j + 2, e->get_mode()), -1, nd->edge_bc_proj[j + 2]);
260 int ori = part < 0 ? 1 : 0;
261 if (part < 0) part ^= ~0;
263 nd = &this->ndata[nd->base->id];
264 for (
int j = 0, dof = nd->dof; j < nd->n; j++, dof++)
265 al->add_triplet(this->shapeset->get_constrained_edge_index(surf_num, j + 2, ori, part, e->get_mode()), dof, 1.0);
269 template<
typename Scalar>
270 Scalar* H1Space<Scalar>::get_bc_projection(SurfPos* surf_pos,
int order, EssentialBoundaryCondition<Scalar> *bc)
273 Scalar* proj = malloc_with_check<H1Space<Scalar>, Scalar>(order + 1,
this);
275 if (bc->get_value_type() == BC_CONST)
277 proj[0] = proj[1] = bc->value_const;
279 else if (bc->get_value_type() == BC_FUNCTION)
281 surf_pos->t = surf_pos->lo;
284 Curve* curve =
nullptr;
285 CurvMap* cm = surf_pos->base->cm;
287 curve = cm->curves[surf_pos->surf_num];
289 CurvMap::nurbs_edge(surf_pos->base, curve, surf_pos->surf_num, 2.0*surf_pos->t - 1.0, x, y);
291 proj[0] = bc->value(x, y);
292 surf_pos->t = surf_pos->hi;
294 CurvMap::nurbs_edge(surf_pos->base, curve, surf_pos->surf_num, 2.0*surf_pos->t - 1.0, x, y);
296 proj[1] = bc->value(x, y);
302 Scalar* rhs = proj + 2;
303 int mo = quad1d.get_max_order();
304 double2* pt = quad1d.get_points(mo);
307 for (
int i = 0; i < order; i++)
310 int ii = this->shapeset->get_edge_index(0, 0, i + 2, surf_pos->base->get_mode());
311 for (
int j = 0; j < quad1d.get_num_points(mo); j++)
313 double t = (pt[j][0] + 1) * 0.5, s = 1.0 - t;
314 Scalar l = proj[0] * s + proj[1] * t;
315 surf_pos->t = surf_pos->lo * s + surf_pos->hi * t;
317 if (bc->get_value_type() == BC_CONST)
318 rhs[i] += pt[j][1] * this->shapeset->get_fn_value(ii, pt[j][0], -1.0, 0, surf_pos->base->get_mode()) * (bc->value_const - l);
320 else if (bc->get_value_type() == BC_FUNCTION)
324 Curve* curve =
nullptr;
325 CurvMap* cm = surf_pos->base->cm;
327 curve = cm->curves[surf_pos->surf_num];
329 CurvMap::nurbs_edge(surf_pos->base, curve, surf_pos->surf_num, 2.0*surf_pos->t - 1.0, x, y);
331 rhs[i] += pt[j][1] * this->shapeset->get_fn_value(ii, pt[j][0], -1.0, 0, surf_pos->base->get_mode()) * (bc->value(x, y) - l);
337 cholsl(this->proj_mat, order, this->chol_p, rhs, rhs);
343 template<
typename Scalar>
344 inline void H1Space<Scalar>::output_component(
typename Space<Scalar>::BaseComponent*& current,
typename Space<Scalar>::BaseComponent*& last,
typename Space<Scalar>::BaseComponent* min,
345 Node*& edge,
typename Space<Scalar>::BaseComponent*& edge_dofs)
348 if (last !=
nullptr && last->dof == min->dof)
350 last->coef += min->coef * 0.5;
355 if (edge !=
nullptr && this->ndata[edge->id].dof <= min->dof)
360 if (this->ndata[edge->id].dof != min->dof)
362 current += this->ndata[edge->id].n;
368 current->dof = min->dof;
369 current->coef = min->coef * 0.5;
373 template<
typename Scalar>
374 typename Space<Scalar>::BaseComponent* H1Space<Scalar>::merge_baselists(
typename Space<Scalar>::BaseComponent* l1,
int n1,
typename Space<Scalar>::BaseComponent* l2,
int n2,
375 Node* edge,
typename Space<Scalar>::BaseComponent*& edge_dofs,
int& ncomponents)
378 int max_result = n1 + n2;
380 max_result += this->ndata[edge->id].n;
382 typename Space<Scalar>::BaseComponent* result = malloc_with_check<typename Space<Scalar>::BaseComponent>(max_result);
383 typename Space<Scalar>::BaseComponent* current = result;
384 typename Space<Scalar>::BaseComponent* last =
nullptr;
388 while (i1 < n1 && i2 < n2)
390 if (l1[i1].dof < l2[i2].dof)
391 output_component(current, last, l1 + i1++, edge, edge_dofs);
393 output_component(current, last, l2 + i2++, edge, edge_dofs);
398 output_component(current, last, l1 + i1++, edge, edge_dofs);
400 output_component(current, last, l2 + i2++, edge, edge_dofs);
406 current += this->ndata[edge->id].n;
409 ncomponents = current - result;
410 if(ncomponents < max_result)
412 typename Space<Scalar>::BaseComponent* reallocated_result = (
typename Space<Scalar>::BaseComponent*) realloc(result, ncomponents *
sizeof(
typename Space<Scalar>::BaseComponent));
413 if(edge_dofs != NULL)
415 edge_dofs = reallocated_result + (edge_dofs - result);
417 return reallocated_result;
424 template<
typename Scalar>
425 void H1Space<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)
429 typename Space<Scalar>::EdgeInfo* ei[4] = { ei0, ei1, ei2, ei3 };
430 typename Space<Scalar>::NodeData* nd;
432 if (this->get_element_order(e->id) == 0)
return;
437 for (i = 0; i < e->get_nvert(); i++)
439 if (ei[i] !=
nullptr)
441 nd = &this->ndata[e->en[i]->id];
442 nd->base = ei[i]->node;
443 nd->part = ei[i]->part;
453 typename Space<Scalar>::EdgeInfo ei_data[4];
454 for (i = 0; i < e->get_nvert(); i++)
456 if (ei[i] ==
nullptr)
459 Node* mid_vn = this->get_mid_edge_vertex_node(e, i, j);
460 if (mid_vn !=
nullptr && mid_vn->is_constrained_vertex())
462 Node* mid_en = this->mesh->peek_edge_node(e->vn[i]->id, e->vn[j]->id);
463 if (mid_en !=
nullptr)
466 ei[i]->node = mid_en;
470 ei[i]->ori = (e->vn[i]->id < e->vn[j]->id) ? 0 : 1;
477 for (i = 0; i < e->get_nvert(); i++)
479 if (ei[i] ==
nullptr)
continue;
482 Node* mid_vn = this->get_mid_edge_vertex_node(e, i, j);
483 if (mid_vn ==
nullptr)
continue;
486 Node* vn[2] = { e->vn[i], e->vn[j] };
488 Node* en = ei[i]->node;
490 typename Space<Scalar>::BaseComponent *bl[2], dummy_bl[2];
492 int nc[2] = { 0, 0 };
495 for (k = 0; k < 2; k++)
497 nd = &this->ndata[vn[k]->id];
498 if (vn[k]->is_constrained_vertex())
500 bl[k] = nd->baselist;
501 nc[k] = nd->ncomponents;
505 dummy_bl[k].dof = nd->dof;
506 dummy_bl[k].coef = (nd->dof >= 0) ? 1.0 : (nd->vertex_bc_coef ? *nd->vertex_bc_coef : 0.);
507 bl[k] = &dummy_bl[k];
513 typename Space<Scalar>::BaseComponent* edge_dofs;
514 nd = &this->ndata[mid_vn->id];
515 nd->baselist = merge_baselists(bl[0], nc[0], bl[1], nc[1], en, edge_dofs, nd->ncomponents);
516 this->bc_data_base_components.push_back(nd->baselist);
519 double mid = (ei[i]->lo + ei[i]->hi) * 0.5;
520 nd = &this->ndata[en->id];
521 for (k = 0; k < nd->n; k++, edge_dofs++)
523 edge_dofs->dof = nd->dof + k;
524 edge_dofs->coef = this->shapeset->get_fn_value(this->shapeset->get_edge_index(0, ei[i]->ori, k + 2, e->get_mode()), mid, -1.0, 0, e->get_mode());
529 typename Space<Scalar>::EdgeInfo half_ei_data[4][2];
530 typename Space<Scalar>::EdgeInfo* half_ei[4][2];
531 for (i = 0; i < e->get_nvert(); i++)
535 half_ei[i][0] = half_ei[i][1] =
nullptr;
539 typename Space<Scalar>::EdgeInfo* h0 = half_ei[i][0] = half_ei_data[i];
540 typename Space<Scalar>::EdgeInfo* h1 = half_ei[i][1] = half_ei_data[i] + 1;
542 h0->node = h1->node = ei[i]->node;
543 h0->part = (ei[i]->part + 1) * 2;
544 h1->part = h0->part + 1;
545 h0->hi = h1->lo = (ei[i]->lo + ei[i]->hi) / 2;
548 h1->ori = h0->ori = ei[i]->ori;
553 if (e->is_triangle())
555 update_constrained_nodes(e->sons[0], half_ei[0][0],
nullptr, half_ei[2][1],
nullptr);
556 update_constrained_nodes(e->sons[1], half_ei[0][1], half_ei[1][0],
nullptr,
nullptr);
557 update_constrained_nodes(e->sons[2],
nullptr, half_ei[1][1], half_ei[2][0],
nullptr);
558 update_constrained_nodes(e->sons[3],
nullptr,
nullptr,
nullptr,
nullptr);
560 else if (e->sons[2] ==
nullptr)
562 update_constrained_nodes(e->sons[0], ei[0], half_ei[1][0],
nullptr, half_ei[3][1]);
563 update_constrained_nodes(e->sons[1],
nullptr, half_ei[1][1], ei[2], half_ei[3][0]);
565 else if (e->sons[0] ==
nullptr)
567 update_constrained_nodes(e->sons[2], half_ei[0][0],
nullptr, half_ei[2][1], ei[3]);
568 update_constrained_nodes(e->sons[3], half_ei[0][1], ei[1], half_ei[2][0],
nullptr);
572 update_constrained_nodes(e->sons[0], half_ei[0][0],
nullptr,
nullptr, half_ei[3][1]);
573 update_constrained_nodes(e->sons[1], half_ei[0][1], half_ei[1][0],
nullptr,
nullptr);
574 update_constrained_nodes(e->sons[2],
nullptr, half_ei[1][1], half_ei[2][0],
nullptr);
575 update_constrained_nodes(e->sons[3],
nullptr,
nullptr, half_ei[2][1], half_ei[3][0]);
580 template<
typename Scalar>
584 for_all_base_elements(e, this->mesh)
585 update_constrained_nodes(e,
nullptr,
nullptr,
nullptr,
nullptr);
H1ShapesetJacobi H1Shapeset
Experimental.
Stores one element of a mesh.
void init()
Common code for constructors.
Used to pass the instances of Space around.
Stores one node of a mesh.
virtual void copy(SpaceSharedPtr< Scalar > space, MeshSharedPtr new_mesh)
bool own_shapeset
true if default shapeset is created in the constructor, false if shapeset is supplied by user...
virtual unsigned char get_id() const =0
virtual void update_constraints()
Should be exactly the same as is the count of enum ShapesetType.
virtual int assign_dofs(int first_dof=0)
Builds basis functions and assigns DOF numbers to them.
bool is_constrained_vertex() const
Returns true if the (vertex) node is constrained.
Represents a finite element space over a domain.
MeshSharedPtr mesh
FE mesh.
virtual void set_shapeset(Shapeset *shapeset, bool clone=false)
Sets the shapeset.
void set_uniform_order_internal(int order, int marker)
virtual void copy(SpaceSharedPtr< Scalar > space, MeshSharedPtr new_mesh)
Copy from Space instance 'space'.
EssentialBCs< Scalar > * essential_bcs
Boundary conditions.
Node * vn[H2D_MAX_NUMBER_VERTICES]
vertex node pointers