MAST
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
sub_elem_mesh_refinement.cpp
Go to the documentation of this file.
1 /*
2  * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit
3  * Copyright (C) 2013-2020 Manav Bhatia and MAST authors
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 
21 // MAST includes
25 
26 // libMesh includes
27 #include "libmesh/mesh_communication.h"
28 #include "libmesh/partitioner.h"
29 #include "libmesh/dof_map.h"
30 #include "libmesh/boundary_info.h"
31 
32 
34  libMesh::System& sys):
35 libMesh::System::Constraint (),
36 _initialized (false),
37 _strong_discontinuity (false),
38 _negative_level_set_subdomain_offset (0),
39 _inactive_subdomain_offset (0),
40 _level_set_boundary_id (0),
41 _mesh (mesh),
42 _system (sys),
43 _node_map (new MAST::SubElemNodeMap) {
44 
45 }
46 
47 
48 
50 
51  this->clear_mesh();
52  delete _node_map;
53 }
54 
55 
56 
57 bool
59  bool strong_discontinuity,
60  Real time,
61  unsigned int negative_level_set_subdomain_offset,
62  unsigned int inactive_subdomain_offset,
63  unsigned int level_set_boundary_id) {
64 
65  libmesh_assert(!_initialized);
66 
67  // currently only implemented for replicated mesh
68  libmesh_assert(_mesh.is_replicated());
69 
70  // if strong discontinuity is required then coincident nodes are
71  // created which will need unique_id support in libMesh
72  if (strong_discontinuity) {
73 #ifndef LIBMESH_ENABLE_UNIQUE_ID
74  libmesh_assert(false);
75 #endif
76  }
77 
79 
80  libMesh::MeshBase::element_iterator
81  e_it = _mesh.active_local_elements_begin(),
82  e_end = _mesh.active_local_elements_end();
83 
84  // for a replicated mesh all processors have to do the exct same operations
85  // to the mesh in the same order. Hence, we modify the iterators.
86  if (_mesh.is_replicated()) {
87 
88  e_it = _mesh.active_elements_begin(),
89  e_end = _mesh.active_elements_end();
90  }
91 
92  // first we need to identify all the elements that will be refined.
93  // Then we will iterate over all of them. Otherwise, the addition of
94  // new elemnts can invalidate the element iterators.
95  std::vector<libMesh::Elem*>
96  elems_to_partition;
97 
98  for ( ; e_it != e_end; e_it++) {
99 
100  libMesh::Elem* elem = *e_it;
101 
102  intersect.init(phi, *elem, time, _mesh.max_elem_id(), _mesh.max_node_id());
103 
104  if (intersect.if_intersection_through_elem() ||
105  ((intersect.get_intersection_mode() == MAST::COLINEAR_EDGE ||
106  intersect.get_intersection_mode() == MAST::THROUGH_NODE) &&
107  intersect.get_sub_elems_negative_phi().size() == 1) ||
108  intersect.if_elem_on_negative_phi())
109  elems_to_partition.push_back(elem);
110 
111  intersect.clear();
112  }
113 
114 
115  // now we process only the selected elements
116  bool
117  mesh_changed = false;
118 
119  for (unsigned int i=0; i<elems_to_partition.size(); i++) {
120 
121  libMesh::Elem* elem = elems_to_partition[i];
122 
123  intersect.init(phi, *elem, time, _mesh.max_elem_id(), _mesh.max_node_id());
124 
125  // if the intersection is through the element then
126  if (intersect.if_intersection_through_elem()) {
127 
128  _process_sub_elements(strong_discontinuity,
129  negative_level_set_subdomain_offset,
130  level_set_boundary_id,
131  *elem,
132  intersect,
133  true,
134  intersect.get_sub_elems_positive_phi());
135 
136  _process_sub_elements(strong_discontinuity,
137  negative_level_set_subdomain_offset,
138  level_set_boundary_id,
139  *elem,
140  intersect,
141  false,
142  intersect.get_sub_elems_negative_phi());
143 
144  // since the element has been partitioned, we set its subdomain
145  // id with an offset so that the assembly routines can choose to
146  // ignore them
147  _old_elems.push_back(std::make_pair(elem, elem->subdomain_id()));
148  elem->subdomain_id() += inactive_subdomain_offset;
149  mesh_changed = true;
150  }
151  else if ((intersect.get_intersection_mode() == MAST::COLINEAR_EDGE ||
152  intersect.get_intersection_mode() == MAST::THROUGH_NODE) &&
153  intersect.get_sub_elems_negative_phi().size() == 1) {
154 
155  if (strong_discontinuity) {
156  _process_negative_element(negative_level_set_subdomain_offset,
157  level_set_boundary_id,
158  *elem,
159  intersect);
160 
161  _old_elems.push_back(std::make_pair(elem, elem->subdomain_id()));
162  elem->subdomain_id() += inactive_subdomain_offset;
163  }
164  else {
165 
166  _old_elems.push_back(std::make_pair(elem, elem->subdomain_id()));
167  elem->subdomain_id() += negative_level_set_subdomain_offset;
168 
169  }
170  }
171  else if (intersect.if_elem_on_negative_phi()) {
172  // if the element has no positive region, then we set its
173  // subdomain id to that of negative level set offset
174 
175  _old_elems.push_back(std::make_pair(elem, elem->subdomain_id()));
176  elem->subdomain_id() += negative_level_set_subdomain_offset;
177  }
178 
179  intersect.clear();
180  }
181 
182  // If the mesh changed on any processor, it changed globally
183  _mesh.comm().max(mesh_changed);
184 
185  // And we may need to update DistributedMesh values reflecting the changes
186  if (mesh_changed)
187  _mesh.update_parallel_id_counts();
188 
189  if (mesh_changed && !_mesh.is_replicated())
190  {
191  libMesh::MeshCommunication().make_elems_parallel_consistent (_mesh);
192  libMesh::MeshCommunication().make_new_nodes_parallel_consistent (_mesh);
193 #ifdef DEBUG
194  _mesh.libmesh_assert_valid_parallel_ids();
195 #endif
196  }
197 
198  // If we're refining a Replicated_mesh, then we haven't yet assigned
199  // node processor ids. But if we're refining a partitioned
200  // Replicated_mesh, then we *need* to assign node processor ids.
201  if (mesh_changed && _mesh.is_replicated() &&
202  (_mesh.unpartitioned_elements_begin() ==
203  _mesh.unpartitioned_elements_end()))
204  libMesh::Partitioner::set_node_processor_ids(_mesh);
205 
206  if (mesh_changed)
207  _mesh.prepare_for_use(/*skip_renumber =*/ false);
208 
209  _strong_discontinuity = strong_discontinuity;
210  _negative_level_set_subdomain_offset = negative_level_set_subdomain_offset;
211  _inactive_subdomain_offset = inactive_subdomain_offset;
212  _level_set_boundary_id = level_set_boundary_id;
213  _initialized = true;
214 
215  return mesh_changed;
216 }
217 
218 
219 bool
221 
222  // clear the data structure
223  _hanging_node.clear();
224 
225  // modify the original element subdomain
226  for (unsigned int i=0; i<_old_elems.size(); i++)
227  _old_elems[i].first->subdomain_id() = _old_elems[i].second;
228  _old_elems.clear();
229 
230  // remove all the new nodes and elements from the mesh
231  for (unsigned int i=0; i<_new_elems.size(); i++) {
232 
233  // Remove this element from any neighbor
234  // lists that point to it.
235  _new_elems[i]->nullify_neighbors();
236 
237  // Remove any boundary information associated
238  // with this element
239  _mesh.get_boundary_info().remove(_new_elems[i]);
240 
241  _mesh.delete_elem(_new_elems[i]);
242  }
243 
244  for (unsigned int i=0; i<_new_nodes.size(); i++)
245  _mesh.delete_node(_new_nodes[i]);
246 
247 
248  bool
249  mesh_changed = false;
250 
251  if (_new_elems.size() || _new_nodes.size()) mesh_changed = true;
252 
253  _mesh.comm().max(mesh_changed);
254 
255  if (mesh_changed) {
256 
257  _mesh.update_parallel_id_counts();
258  _new_elems.clear();
259  _new_nodes.clear();
260  _node_map->clear();
261  _mesh.prepare_for_use();
262  }
263 
264  if (mesh_changed && !_mesh.is_serial()) {
265 
266  libMesh::MeshCommunication().make_nodes_parallel_consistent (_mesh);
267 
268 #ifdef DEBUG
269  MeshTools::libmesh_assert_valid_procids<Node>(_mesh);
270 #endif
271  }
272 
273  _negative_level_set_ids.clear();
274  _strong_discontinuity = false;
278  _initialized = false;
279 
280  return mesh_changed;
281 }
282 
283 
284 
285 void
287 
288  // we will constrain only if the mesh has been processed for the level set
289  // no constraint is to be added for weak discontinuity.
290  if (!_initialized || !_strong_discontinuity) return;
291 
292  // For strong discontinuity, iterate over all elements and constrain all
293  // dofs on them
294  libMesh::DofMap& dof_map = _system.get_dof_map();
295 
296  libMesh::MeshBase::const_element_iterator el =
297  _system.get_mesh().active_local_elements_begin();
298  const libMesh::MeshBase::const_element_iterator end_el =
299  _system.get_mesh().active_local_elements_end();
300 
301  const libMesh::dof_id_type
302  first_dof = dof_map.first_dof(_mesh.comm().rank()),
303  last_dof = dof_map.end_dof(_mesh.comm().rank());
304 
305  std::vector<libMesh::dof_id_type>
306  dof_indices;
307 
308  for ( ; el != end_el; ++el) {
309 
310  const libMesh::Elem* elem = *el;
311 
312  if (_negative_level_set_ids.count(elem->subdomain_id())) {
313 
314  dof_indices.clear();
315  dof_map.dof_indices(elem, dof_indices);
316 
317  // constrain all dofs if they have not already been constrained.
318  for (unsigned int i=0; i<dof_indices.size(); i++) {
319 
320  if ((dof_indices[i] >= first_dof || dof_indices[i] < last_dof) &&
321  !dof_map.is_constrained_dof(dof_indices[i])) {
322 
323  libMesh::DofConstraintRow c_row;
324  dof_map.add_constraint_row(dof_indices[i], c_row, true);
325  }
326  }
327  }
328  }
329 
330  // now add constriant for the nodes identified as hanging node
331  std::set<std::pair<const libMesh::Node*, std::pair<const libMesh::Node*, const libMesh::Node*>>>::iterator
332  n_it = _hanging_node.begin(),
333  n_end = _hanging_node.end();
334 
335  libMesh::Point
336  p;
337 
338  Real
339  d = 0.;
340 
341  unsigned int
342  dof_b_node1,
343  dof_b_node2,
344  dof_node;
345 
346  for ( ; n_it != n_end; n_it++) {
347 
348  const std::pair<const libMesh::Node*, std::pair<const libMesh::Node*, const libMesh::Node*>>
349  &v = *n_it;
350 
351  // obtain the fraction of the node from the bounding nodes
352  // distance of node from first
353  p = *v.first - *v.second.first;
354  d = p.norm();
355  // distance between the bounding nodes
356  p = *v.second.second - *v.second.first;
357  d /= p.norm();
358 
359 
360  // we iterate over the variables in the system
361  // and add a constraint for each node
362  for (unsigned int i=0; i<_system.n_vars(); i++) {
363 
364  // identify the dofs for the ith variable on each node
365  // first, the node for which the constraint will be added
366  dof_indices.clear();
367  dof_map.dof_indices(v.first, dof_indices, i);
368  libmesh_assert_equal_to(dof_indices.size(), 1);
369  dof_node = dof_indices[0];
370 
371  // next, the first bounding node
372  dof_indices.clear();
373  dof_map.dof_indices(v.second.first, dof_indices, i);
374  libmesh_assert_equal_to(dof_indices.size(), 1);
375  dof_b_node1 = dof_indices[0];
376 
377  // next, the second bounding node
378  dof_indices.clear();
379  dof_map.dof_indices(v.second.second, dof_indices, i);
380  libmesh_assert_equal_to(dof_indices.size(), 1);
381  dof_b_node2 = dof_indices[0];
382 
383  // now create and add the constraint
384  if ((dof_node >= first_dof || dof_node < last_dof) &&
385  !dof_map.is_constrained_dof(dof_node)) {
386 
387  // the constraint assumes linear variation of the value
388  // between the bounding nodes
389  // the constraint reads
390  // un = (1-d) ub1 + d ub2
391  // or, un - (1-d) ub1 - d ub2 = 0
392  libMesh::DofConstraintRow c_row;
393  c_row[dof_b_node1] = (1.-d);
394  c_row[dof_b_node2] = d;
395 
396  dof_map.add_constraint_row(dof_node, c_row, true);
397  }
398  }
399  }
400 }
401 
402 
403 
404 void
406  unsigned int negative_level_set_subdomain_offset,
407  unsigned level_set_boundary_id,
408  libMesh::Elem& e,
409  MAST::LevelSetIntersection& intersect,
410  bool positive_phi,
411  const std::vector<const libMesh::Elem*>& elems) {
412 
413  libmesh_assert(!_initialized);
414 
415  std::map<const libMesh::Node*, const libMesh::Node*>
416  intersection_object_to_mesh_node_map;
417 
418  std::vector<std::tuple<const libMesh::Node*, libMesh::Elem*, unsigned int>>
419  interior_node_association;
420 
421  for (unsigned int i=0; i<elems.size(); i++) {
422 
423  const libMesh::Elem
424  *sub_e = elems[i];
425 
426  // in case of intersection through node or collinear edge the
427  // parent element is the subelement. In case of a weak discontinuity
428  // nothing needs to be done since the C0 continuity will be maintained
429  // due to same nodes used across positive and negative level set values.
430  // However, for a strong discontinuity, the negative and positive
431  // values of level set reside on separate nodes. So, for intersection
432  // through a node we need to create a new node at this location.
433  // Similarly, for colinear edge we need to create new nodes at
434  // all nodes along this edge.
435  //
436  // For such cases, we will not do anythign for elements on positive
437  // level set value. Instead, we will add new elements for elements
438  // on the negative level set
439  if ((sub_e == &e) && positive_phi) continue;
440 
441  libMesh::Elem
442  *child = libMesh::Elem::build(sub_e->type()).release();
443 
444  // set nodes for this child element
445  for (unsigned int j=0; j<sub_e->n_nodes(); j++) {
446 
447  const libMesh::Node
448  *sub_e_node = sub_e->node_ptr(j);
449 
450  if (!intersect.if_node_is_new(*sub_e_node)) {
451 
452  // this is a node from the parent element. So, we use is as is
453  child->set_node(j) = const_cast<libMesh::Node*>(sub_e_node);
454 
455  // keep track of nodes for the addition of interior nodes
456  intersection_object_to_mesh_node_map[sub_e_node] = sub_e_node;
457  }
458  else if (intersect.if_interior_node(*sub_e_node)) {
459 
460  // this node will be added after all edge nodes have been
461  // added. This will be added as the jth node of the
462  // child elem
463  interior_node_association.push_back
464  (std::tuple<const libMesh::Node*, libMesh::Elem*, unsigned int>(sub_e_node, child, j));
465  }
466  else {
467 
468  // this is a new node. So, we ask the intersection object
469  // about the bounding nodes and add them to this new node
470  std::pair<const libMesh::Node*, const libMesh::Node*>
471  bounding_nodes = intersect.get_bounding_nodes_for_node(*sub_e_node);
472 
473  libMesh::Node*
474  child_node = _add_node(*sub_e_node,
475  strong_discontinuity,
476  positive_phi,
477  e.processor_id(),
478  bounding_nodes);
479  child->set_node(j) = child_node;
480 
481  // identify this node to as a hanging node
482  if (intersect.if_hanging_node(sub_e_node))
483  _hanging_node.insert(std::make_pair(child_node, bounding_nodes));
484 
485  // keep track for nodes for the addition of interior nodes
486  intersection_object_to_mesh_node_map[sub_e_node] = child_node;
487  }
488  }
489 
490  // set flags for this child element
491  //child->set_refinement_flag(libMesh::Elem::JUST_REFINED);
492  child->set_p_level(e.p_level());
493  child->set_p_refinement_flag(e.p_refinement_flag());
494  child->set_n_systems(e.n_systems());
495  // we need to offset the subdomain id for an element type that is
496  // not the same as the parent element since exodus output requires
497  // different subdomain ids for different element types.
498  if (child->type() == e.type())
499  child->subdomain_id() = e.subdomain_id();
500  else
501  child->subdomain_id() = e.subdomain_id()+1;
502 
503  // the negative level set is offset by the specified value so that
504  // the assembly routines can deal with them separately
505  if (!positive_phi) {
506 
507  child->subdomain_id() += negative_level_set_subdomain_offset;
508  _negative_level_set_ids.insert(child->subdomain_id());
509  }
510 
511 #if (LIBMESH_MAJOR_VERSION == 1 && LIBMESH_MINOR_VERSION >= 5)
512  libmesh_assert_equal_to (child->n_extra_integers(),
513  e.n_extra_integers());
514  for (unsigned int j=0; j != e.n_extra_integers(); ++j)
515  child->set_extra_integer(j, e.get_extra_integer(j));
516 #endif
517  _mesh.add_elem(child);
518 
519  if (intersect.has_side_on_interface(*sub_e))
520  _mesh.boundary_info->add_side(child,
521  intersect.get_side_on_interface(*sub_e),
522  level_set_boundary_id);
523 
524  _new_elems.push_back(child);
525  }
526 
527 
528  // now process the interior nodes
529  for (unsigned int i=0; i<interior_node_association.size(); i++) {
530 
531  const libMesh::Node
532  *sub_e_node = std::get<0>(interior_node_association[i]);
533 
534  libMesh::Elem
535  *child = std::get<1>(interior_node_association[i]);
536 
537  unsigned int
538  node_num = std::get<2>(interior_node_association[i]);
539 
540  std::pair<const libMesh::Node*, const libMesh::Node*>
541  bounding_nodes = intersect.get_bounding_nodes_for_node(*sub_e_node);
542 
543  // since the nodes in the map are based on newly created nodes, and
544  // not those created by the intersection object, we replace the
545  // bounding_nodes pair with those that were created here.
546  libmesh_assert(intersection_object_to_mesh_node_map.count(bounding_nodes.first));
547  libmesh_assert(intersection_object_to_mesh_node_map.count(bounding_nodes.second));
548  bounding_nodes.first = intersection_object_to_mesh_node_map[bounding_nodes.first];
549  bounding_nodes.second = intersection_object_to_mesh_node_map[bounding_nodes.second];
550 
551  libMesh::Node*
552  child_node = _add_node(*sub_e_node,
553  strong_discontinuity,
554  positive_phi,
555  e.processor_id(),
556  bounding_nodes);
557 
558  child->set_node(node_num) = child_node;
559  }
560 }
561 
562 
563 
564 
565 void
566 MAST::SubElemMeshRefinement::_process_negative_element(unsigned int negative_level_set_subdomain_offset,
567  unsigned level_set_boundary_id,
568  libMesh::Elem& e,
569  MAST::LevelSetIntersection& intersect) {
570 
571  libmesh_assert(!_initialized);
572 
573  std::set<libMesh::Node*>
574  side_nodes;
575 
576  // get the nodes on the side with the interface that will be replaced
577  // with new nodes on the negative phi
578  if (intersect.get_intersection_mode() == MAST::THROUGH_NODE)
579  side_nodes.insert(e.node_ptr(intersect.node_on_boundary()));
580  else if (intersect.get_intersection_mode() == MAST::COLINEAR_EDGE) {
581 
582  unsigned int i = intersect.edge_on_boundary();
583  std::unique_ptr<libMesh::Elem> side(e.side_ptr(i));
584  for (unsigned int j=0; j<side->n_nodes(); j++)
585  side_nodes.insert(side->node_ptr(j));
586  }
587  else {
588  // should not get here
589  libmesh_assert(false);
590  }
591 
592 
593  libMesh::Elem
594  *child = libMesh::Elem::build(e.type()).release();
595 
596  // set nodes for this new element
597  for (unsigned int j=0; j<e.n_nodes(); j++) {
598 
599  libMesh::Node
600  *e_node = e.node_ptr(j);
601 
602  if (!side_nodes.count(e_node))
603  child->set_node(j) = e_node;
604  else {
605 
606  std::pair<const libMesh::Node*, const libMesh::Node*>
607  bounding_nodes = std::make_pair(e_node, e_node);
608 
609  libMesh::Node*
610  child_node = _add_node(*e_node,
611  true, // this method only deals with strong discontinuity
612  false, // and with nodes on negative level set
613  e.processor_id(),
614  bounding_nodes);
615  child->set_node(j) = child_node;
616  }
617  }
618 
619  // set flags for this child element
620  //child->set_refinement_flag(libMesh::Elem::JUST_REFINED);
621  child->set_p_level(e.p_level());
622  child->set_p_refinement_flag(e.p_refinement_flag());
623  child->set_n_systems(e.n_systems());
624  // we need to offset the subdomain id for an element type that is
625  // not the same as the parent element since exodus output requires
626  // different subdomain ids for different element types.
627  if (child->type() == e.type())
628  child->subdomain_id() = e.subdomain_id() + negative_level_set_subdomain_offset;
629  else
630  child->subdomain_id() = e.subdomain_id()+1 + negative_level_set_subdomain_offset;
631 
632  _negative_level_set_ids.insert(child->subdomain_id());
633 
634 #if (LIBMESH_MAJOR_VERSION == 1 && LIBMESH_MINOR_VERSION >= 5)
635  libmesh_assert_equal_to (child->n_extra_integers(),
636  e.n_extra_integers());
637 
638  for (unsigned int j=0; j != e.n_extra_integers(); ++j)
639  child->set_extra_integer(j, e.get_extra_integer(j));
640 #endif
641  _mesh.add_elem(child);
642 
643  _new_elems.push_back(child);
644 }
645 
646 
647 
648 libMesh::Node*
650  bool strong_disontinuity,
651  bool positive_phi,
652  unsigned int processor_id,
653  const std::pair<const libMesh::Node*, const libMesh::Node*>& bounding_nodes) {
654 
655  libmesh_assert(!_initialized);
656 
657  unsigned int
658  id1 = std::min(bounding_nodes.first->id(), bounding_nodes.second->id()),
659  id2 = std::max(bounding_nodes.first->id(), bounding_nodes.second->id());
660 
661  std::pair<libMesh::Node*, libMesh::Node*>&
662  node_pair = _node_map->add(id1, id2);
663 
664  // if a weak discontinuity is requested, and if the node has already been
665  // created, then make sure that both nodes are the same
666  if (!strong_disontinuity) {
667 
668  if (node_pair.first) {
669  libmesh_assert_equal_to(node_pair.first, node_pair.second);
670  return node_pair.first;
671  }
672  else {
673 
674  // for a weak discontinuity nodes on either side of the discontinuity
675  // are the same
676  node_pair.first = _mesh.add_point(p, libMesh::DofObject::invalid_id, processor_id);
677  _new_nodes.push_back(node_pair.first);
678 
679  libmesh_assert(node_pair.first);
680 
681  node_pair.first->processor_id() = libMesh::DofObject::invalid_processor_id;
682  node_pair.second = node_pair.first;
683 
684  return node_pair.first;
685  }
686  }
687  else {
688 
689  if (positive_phi) {
690 
691  if (node_pair.first)
692  return node_pair.first;
693  else {
694 
695  // create and store a separate node for the positive side of the
696  // level set
697  node_pair.first = _mesh.add_point(p, libMesh::DofObject::invalid_id, processor_id);
698  _new_nodes.push_back(node_pair.first);
699 
700  libmesh_assert(node_pair.first);
701 
702  node_pair.first->processor_id() = libMesh::DofObject::invalid_processor_id;
703 
704  return node_pair.first;
705  }
706  }
707  else { // negative phi
708 
709  if (node_pair.second)
710  return node_pair.second;
711  else {
712 
713  // create and store a separate node for the positive side of the
714  // level set
715  node_pair.second = _mesh.add_point(p, libMesh::DofObject::invalid_id, processor_id);
716  _new_nodes.push_back(node_pair.second);
717 
718  libmesh_assert(node_pair.second);
719 
720  node_pair.second->processor_id() = libMesh::DofObject::invalid_processor_id;
721 
722  return node_pair.second;
723  }
724  }
725  }
726 }
727 
728 
unsigned int edge_on_boundary() const
bool process_mesh(const MAST::FieldFunction< Real > &phi, bool strong_discontinuity, Real time, unsigned int negative_level_set_subdomain_offset, unsigned int inactive_subdomain_offset, unsigned int level_set_boundary_id)
const std::vector< const libMesh::Elem * > & get_sub_elems_positive_phi() const
virtual void constrain()
provides implementation of the libMesh::System::Constraint::constrain() virtual method ...
unsigned int get_side_on_interface(const libMesh::Elem &e) const
std::vector< std::pair< libMesh::Elem *, unsigned int > > _old_elems
std::vector< libMesh::Node * > _new_nodes
MAST::LevelSet2DIntersectionMode get_intersection_mode() const
std::set< unsigned int > _negative_level_set_ids
bool if_node_is_new(const libMesh::Node &node) const
identifies if the node from the subelements is a new node or an existing node from the parent element...
bool if_hanging_node(const libMesh::Node *n) const
The case of two adjacent edges results in a new node on an edge that is not coincident with the level...
std::pair< const libMesh::Node *, const libMesh::Node * > get_bounding_nodes_for_node(const libMesh::Node &node) const
for new nodes required to create the subelements this method returns the nodes on an edge that bound ...
SubElemMeshRefinement(libMesh::MeshBase &mesh, libMesh::System &sys)
libMesh::Real Real
void init(const MAST::FieldFunction< Real > &phi, const libMesh::Elem &e, const Real t, unsigned int max_elem_id, unsigned int max_node_id)
std::vector< libMesh::Elem * > _new_elems
libMesh::Node * _add_node(const libMesh::Point &p, bool strong_disontinuity, bool positive_phi, unsigned int processor_id, const std::pair< const libMesh::Node *, const libMesh::Node *> &bounding_nodes)
bool if_interior_node(const libMesh::Node &node) const
identifies if the new node is on an edge along the level-set method in the interior of the element (a...
bool has_side_on_interface(const libMesh::Elem &e) const
unsigned int node_on_boundary() const
const std::vector< const libMesh::Elem * > & get_sub_elems_negative_phi() const
std::pair< libMesh::Node *, libMesh::Node * > & add(libMesh::dof_id_type bracket_node1, libMesh::dof_id_type bracket_node2)
void _process_negative_element(unsigned int negative_level_set_subdomain_offset, unsigned level_set_boundary_id, libMesh::Elem &e, MAST::LevelSetIntersection &intersect)
std::set< std::pair< const libMesh::Node *, std::pair< const libMesh::Node *, const libMesh::Node * > > > _hanging_node
void _process_sub_elements(bool strong_discontinuity, unsigned int negative_level_set_subdomain_offset, unsigned int level_set_boundary_id, libMesh::Elem &e, MAST::LevelSetIntersection &intersect, bool positive_phi, const std::vector< const libMesh::Elem *> &elems)
void clear()
clears the data structures