Flow123d  JS_before_hm-1016-g09ec2cb
mesh.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file mesh.cc
15  * @ingroup mesh
16  * @brief Mesh construction
17  */
18 
19 #include <unistd.h>
20 #include <set>
21 #include <unordered_map>
22 
23 #include "system/system.hh"
24 #include "system/exceptions.hh"
25 #include "system/index_types.hh"
27 #include "input/input_type.hh"
28 #include "input/accessors.hh"
29 #include "system/sys_profiler.hh"
30 #include "la/distribution.hh"
31 
32 #include "mesh/mesh.h"
33 #include "mesh/bc_mesh.hh"
34 #include "mesh/ref_element.hh"
35 #include "mesh/region_set.hh"
36 #include "mesh/range_wrapper.hh"
37 
38 // think about following dependencies
39 #include "mesh/accessors.hh"
40 #include "mesh/node_accessor.hh"
41 #include "mesh/partitioning.hh"
42 #include "mesh/neighbours.h"
43 
44 
45 #include "mesh/bih_tree.hh"
46 #include "mesh/duplicate_nodes.h"
47 
49 
50 
51 
52 //TODO: sources, concentrations, initial condition and similarly boundary conditions should be
53 // instances of a Element valued field
54 // concentrations is in fact reimplemented in transport REMOVE it HERE
55 
56 // After removing non-geometrical things from mesh, this should be part of mash initializing.
57 #include "mesh/region.hh"
58 
59 #define NDEF -1
60 
61 namespace IT = Input::Type;
62 
64  return Input::Type::Selection("Types of search algorithm for finding intersection candidates.")
65  .add_value(Mesh::BIHsearch, "BIHsearch",
66  "Use BIH for finding initial candidates, then continue by prolongation.")
67  .add_value(Mesh::BIHonly, "BIHonly",
68  "Use BIH for finding all candidates.")
69  .add_value(Mesh::BBsearch, "BBsearch",
70  "Use bounding boxes for finding initial candidates, then continue by prolongation.")
71  .close();
72 }
73 
75  return IT::Record("Mesh","Record with mesh related data." )
76  .allow_auto_conversion("mesh_file")
78  "Input file with mesh description.")
80  "List of additional region and region set definitions not contained in the mesh. "
81  "There are three region sets implicitly defined:\n\n"
82  "- ALL (all regions of the mesh)\n"
83  "- .BOUNDARY (all boundary regions)\n"
84  "- BULK (all bulk regions)")
85  .declare_key("partitioning", Partitioning::get_input_type(), IT::Default("\"any_neighboring\""), "Parameters of mesh partitioning algorithms.\n" )
86  .declare_key("print_regions", IT::Bool(), IT::Default("true"), "If true, print table of all used regions.")
87  .declare_key("intersection_search", Mesh::get_input_intersection_variant(),
88  IT::Default("\"BIHsearch\""), "Search algorithm for element intersections.")
89  .declare_key("global_snap_radius", IT::Double(0.0), IT::Default("1E-3"),
90  "Maximal snapping distance from the mesh in various search operations. In particular, it is used "
91  "to find the closest mesh element of an observe point; and in FieldFormula to find closest surface "
92  "element in plan view (Z projection).")
94  "Output file with neighboring data from mesh.")
95  .close();
96 }
97 
98 const unsigned int Mesh::undef_idx;
99 
101 : tree(nullptr),
102  bulk_size_(0),
103  nodes_(3, 1, 0),
104  row_4_el(nullptr),
105  el_4_loc(nullptr),
106  el_ds(nullptr),
107  node_4_loc_(nullptr),
108  node_ds_(nullptr),
109  bc_mesh_(nullptr)
110 
111 {}
112 
113 
114 
116 : tree(nullptr),
117  in_record_(in_record),
118  comm_(com),
119  bulk_size_(0),
120  nodes_(3, 1, 0),
121  row_4_el(nullptr),
122  el_4_loc(nullptr),
123  el_ds(nullptr),
124  node_4_loc_(nullptr),
125  node_ds_(nullptr),
126  bc_mesh_(nullptr)
127 {
128  // set in_record_, if input accessor is empty
129  if (in_record_.is_empty()) {
130  istringstream is("{mesh_file=\"\"}");
131  Input::ReaderToStorage reader;
132  IT::Record &in_rec = const_cast<IT::Record &>(Mesh::get_input_type());
133  in_rec.finish();
134  reader.read_stream(is, in_rec, Input::FileFormat::format_JSON);
136  }
137 
138  int rank;
140  if (rank == 0) {
141  // optionally open raw output file
142  FilePath raw_output_file_path;
143  if (in_record_.opt_val("raw_ngh_output", raw_output_file_path)) {
144  MessageOut() << "Opening raw ngh output: " << raw_output_file_path << "\n";
145  try {
146  raw_output_file_path.open_stream(raw_ngh_output_file);
147  } INPUT_CATCH(FilePath::ExcFileOpen, FilePath::EI_Address_String, (in_record_))
148  }
149 
150  }
151  init();
152 }
153 
155 {
156  return in_record_.val<Mesh::IntersectionSearch>("intersection_search");
157 }
158 
159 
161 {
162 
163  n_insides = NDEF;
164  n_exsides = NDEF;
165  n_sides_ = NDEF;
166 
167  // number of element of particular dimension
168  n_lines = 0;
169  n_triangles = 0;
170  n_tetrahedras = 0;
171 
172  for (int d=0; d<3; d++) max_edge_sides_[d] = 0;
173 
174  // Initialize numbering of nodes on sides.
175  // This is temporary solution, until class Element is templated
176  // by dimension. Then we can replace Mesh::side_nodes by
177  // RefElement<dim>::side_nodes.
178 
179  // indices of side nodes in element node array
180  // Currently this is made ad libitum
181  // with some ordering here we can get sides with correct orientation.
182  // This speedup normal calculation.
183 
184  side_nodes.resize(3); // three side dimensions
185  for(int dim=0; dim < 3; dim++) {
186  side_nodes[dim].resize(dim+2); // number of sides
187  for(int i_side=0; i_side < dim+2; i_side++)
188  side_nodes[dim][i_side].resize(dim+1);
189  }
190 
191  for (unsigned int sid=0; sid<RefElement<1>::n_sides; sid++)
192  for (unsigned int nid=0; nid<RefElement<1>::n_nodes_per_side; nid++)
193  side_nodes[0][sid][nid] = RefElement<1>::interact(Interaction<0,0>(sid))[nid];
194 
195  for (unsigned int sid=0; sid<RefElement<2>::n_sides; sid++)
196  for (unsigned int nid=0; nid<RefElement<2>::n_nodes_per_side; nid++)
197  side_nodes[1][sid][nid] = RefElement<2>::interact(Interaction<0,1>(sid))[nid];
198 
199  for (unsigned int sid=0; sid<RefElement<3>::n_sides; sid++)
200  for (unsigned int nid=0; nid<RefElement<3>::n_nodes_per_side; nid++)
201  side_nodes[2][sid][nid] = RefElement<3>::interact(Interaction<0,2>(sid))[nid];
202 }
203 
204 
206  for(EdgeData &edg : this->edges)
207  if (edg.side_) delete[] edg.side_;
208 
209  for (unsigned int idx=0; idx < bulk_size_; idx++) {
210  Element *ele=&(element_vec_[idx]);
211  if (ele->boundary_idx_) delete[] ele->boundary_idx_;
212  if (ele->neigh_vb) delete[] ele->neigh_vb;
213  }
214 
215  for(unsigned int idx=bulk_size_; idx < element_vec_.size(); idx++) {
216  Element *ele=&(element_vec_[idx]);
217  if (ele->boundary_idx_) delete[] ele->boundary_idx_;
218  }
219 
220  if (row_4_el != nullptr) delete[] row_4_el;
221  if (el_4_loc != nullptr) delete[] el_4_loc;
222  if (el_ds != nullptr) delete el_ds;
223  if (node_4_loc_ != nullptr) delete[] node_4_loc_;
224  if (node_ds_ != nullptr) delete node_ds_;
225  if (bc_mesh_ != nullptr) delete bc_mesh_;
226  if (tree != nullptr) delete tree;
227 }
228 
229 
230 unsigned int Mesh::n_sides() const
231 {
232  if (n_sides_ == NDEF) {
233  n_sides_=0;
234  for (auto ele : this->elements_range()) n_sides_ += ele->n_sides();
235  }
236  return n_sides_;
237 }
238 
239 unsigned int Mesh::n_vb_neighbours() const {
240  return vb_neighbours_.size();
241  }
242 
243 
244 unsigned int Mesh::n_corners() {
245  unsigned int li, count = 0;
246  for (auto ele : this->elements_range()) {
247  for (li=0; li<ele->n_nodes(); li++) {
248  count++;
249  }
250  }
251  return count;
252 }
253 
254 Edge Mesh::edge(uint edge_idx) const
255 {
256  ASSERT_LT_DBG(edge_idx, edges.size());
257  return Edge(this, edge_idx);
258 }
259 
261 {
262  ASSERT_LT_DBG(bc_idx, boundary_.size());
263  return Boundary(&boundary_[bc_idx]);
264 }
265 
267  return part_.get();
268 }
269 
271  return (LongIdx*)this->get_part()->get_loc_part();
272 }
273 
274 
275 //=============================================================================
276 // COUNT ELEMENT TYPES
277 //=============================================================================
278 
280  for (auto elm : this->elements_range())
281  switch (elm->dim()) {
282  case 1:
283  n_lines++;
284  break;
285  case 2:
286  n_triangles++;
287  break;
288  case 3:
289  n_tetrahedras++;
290  break;
291  }
292 }
293 
294 
295 
297 
298  // get dim of the first element in the map, if it exists
299  uint dim_to_check = RegionDB::undefined_dim;
300  std::string reg_name = "UndefinedRegion";
301  if(map.size() > 0){
302  Element &ele = element_vec_[ elem_index(map.begin()->first) ];
303  dim_to_check = ele.dim();
304  reg_name = region_db_.find_id(map.begin()->second).label();
305  }
306 
307  for (auto elem_to_region : map) {
308  Element &ele = element_vec_[ elem_index(elem_to_region.first) ];
309 
310  if( ele.dim() != dim_to_check){
311  xprintf(UsrErr, "User defined region '%s' (id %d) by 'From_Elements' cannot have elements of different dimensions.\n"
312  "Thrown due to: dim %d neq dim %d (ele id %d).\n"
313  "Split elements by dim, create separate regions and then possibly use Union.\n",
314  reg_name.c_str(), elem_to_region.second, dim_to_check, ele.dim(), elem_to_region.first);
315  }
316 
317  ele.region_idx_ = region_db_.get_region( elem_to_region.second, ele.dim() );
319  }
320 }
321 
322 
324  std::vector<uint> nodes_new_idx( this->n_nodes(), Mesh::undef_idx );
325 
326  // check element quality and flag used nodes
327  for (auto ele : this->elements_range()) {
328  // element quality
329  double quality = ele.quality_measure_smooth(ele.side(0));
330  if ( quality< 0.001)
331  WarningOut().fmt("Bad quality (<0.001) of the element {}.\n", ele.idx());
332 
333  // flag used nodes
334  for (uint ele_node=0; ele_node<ele->n_nodes(); ele_node++) {
335  uint inode = ele->node_idx(ele_node);
336  nodes_new_idx[inode] = inode;
337  }
338  }
339 
340  // possibly build new node ids map
341  BidirectionalMap<int> new_node_ids_;
342  new_node_ids_.reserve(node_ids_.size());
343 
344  // remove unused nodes from the mesh
345  uint inode_new = 0;
346  for(uint inode = 0; inode < nodes_new_idx.size(); inode++) {
347  if(nodes_new_idx[inode] == Mesh::undef_idx){
348  WarningOut().fmt("A node {} does not belong to any element "
349  " and will be removed.",
350  find_node_id(inode));
351  }
352  else{
353  // map new node numbering
354  nodes_new_idx[inode] = inode_new;
355 
356  // possibly move the nodes
357  nodes_.vec<3>(inode_new) = nodes_.vec<3>(inode);
358  new_node_ids_.add_item(node_ids_[inode]);
359 
360  inode_new++;
361  }
362  }
363 
364  uint n_nodes_new = inode_new;
365 
366  // if some node erased, update node ids in elements
367  if(n_nodes_new < nodes_new_idx.size()){
368 
369  DebugOut() << "Updating node-element numbering due to unused nodes: "
370  << print_var(n_nodes_new) << print_var(nodes_new_idx.size()) << "\n";
371 
372  // throw away unused nodes
373  nodes_.resize(n_nodes_new);
374  node_ids_ = new_node_ids_;
375 
376  // update node-element numbering
377  for (auto ele : this->elements_range()) {
378  for (uint ele_node=0; ele_node<ele->n_nodes(); ele_node++) {
379  uint inode_orig = ele->node_idx(ele_node);
380  uint inode = nodes_new_idx[inode_orig];
381  ASSERT_DBG(inode != Mesh::undef_idx);
382  const_cast<Element*>(ele.element())->nodes_[ele_node] = inode;
383  }
384  }
385  }
386 }
387 
389  START_TIMER("MESH - setup topology");
390 
393 
398 
399  tree = new DuplicateNodes(this);
400 
401  part_ = std::make_shared<Partitioning>(this, in_record_.val<Input::Record>("partitioning") );
402 
403  // create parallel distribution and numbering of elements
404  LongIdx *id_4_old = new LongIdx[n_elements()];
405  int i = 0;
406  for (auto ele : this->elements_range())
407  id_4_old[i++] = ele.idx();
408  part_->id_maps(n_elements(), id_4_old, el_ds, el_4_loc, row_4_el);
409 
410  delete[] id_4_old;
411 
412  this->distribute_nodes();
413 
415 }
416 
417 
418 //
420 {
421 
422  n_insides = 0;
423  n_exsides = 0;
424  for (auto ele : this->elements_range())
425  for(SideIter sde = ele.side(0); sde->side_idx() < ele->n_sides(); ++sde) {
426  if (sde->is_external()) n_exsides++;
427  else n_insides++;
428  }
429 }
430 
431 
432 
434  // for each node we make a list of elements that use this node
435  node_elements_.resize( this->n_nodes() );
436 
437  for (auto ele : this->elements_range())
438  for (unsigned int n=0; n<ele->n_nodes(); n++)
439  node_elements_[ele.node(n).idx()].push_back(ele.idx());
440 
441  for (vector<vector<unsigned int> >::iterator n=node_elements_.begin(); n!=node_elements_.end(); n++)
442  stable_sort(n->begin(), n->end());
443 }
444 
445 
446 void Mesh::intersect_element_lists(vector<unsigned int> const &nodes_list, vector<unsigned int> &intersection_element_list)
447 {
448  if (node_elements_.size() == 0) {
450  }
451 
452  if (nodes_list.size() == 0) {
453  intersection_element_list.clear();
454  } else if (nodes_list.size() == 1) {
455  intersection_element_list = node_elements_[ nodes_list[0] ];
456  } else {
457  vector<unsigned int>::const_iterator it1=nodes_list.begin();
459  intersection_element_list.resize( node_elements_[*it1].size() ); // make enough space
460 
461  it1=set_intersection(
462  node_elements_[*it1].begin(), node_elements_[*it1].end(),
463  node_elements_[*it2].begin(), node_elements_[*it2].end(),
464  intersection_element_list.begin());
465  intersection_element_list.resize(it1-intersection_element_list.begin()); // resize to true size
466 
467  for(;it2<nodes_list.end();++it2) {
468  it1=set_intersection(
469  intersection_element_list.begin(), intersection_element_list.end(),
470  node_elements_[*it2].begin(), node_elements_[*it2].end(),
471  intersection_element_list.begin());
472  intersection_element_list.resize(it1-intersection_element_list.begin()); // resize to true size
473  }
474  }
475 }
476 
477 
478 bool Mesh::find_lower_dim_element( vector<unsigned int> &element_list, unsigned int dim, unsigned int &element_idx) {
479  bool is_neighbour = false;
480 
481  vector<unsigned int>::iterator e_dest=element_list.begin();
482  for( vector<unsigned int>::iterator ele = element_list.begin(); ele!=element_list.end(); ++ele) {
483  if (element_vec_[*ele].dim() == dim) { // keep only indexes of elements of same dimension
484  *e_dest=*ele;
485  ++e_dest;
486  } else if (element_vec_[*ele].dim() == dim-1) { // get only first element of lower dimension
487  if (is_neighbour) xprintf(UsrErr, "Too matching elements id: %d and id: %d in the same mesh.\n",
488  this->elem_index(*ele), this->elem_index(element_idx) );
489 
490  is_neighbour = true;
491  element_idx = *ele;
492  }
493  }
494  element_list.resize( e_dest - element_list.begin());
495  return is_neighbour;
496 }
497 
499  // check if nodes lists match (this is slow and will be faster only when we convert whole mesh into hierarchical design like in deal.ii)
500  unsigned int ni=0;
501  while ( ni < si->n_nodes()
502  && find(side_nodes.begin(), side_nodes.end(), si->node(ni).idx() ) != side_nodes.end() ) ni++;
503  return ( ni == si->n_nodes() );
504 }
505 
506 /**
507  * TODO:
508  * - use std::is_any for setting is_neigbour
509  * - possibly make appropriate constructors for Edge and Neighbour
510  * - check side!=-1 when searching neigbouring element
511  * - process boundary elements first, there should be no Neigh, but check it
512  * set Edge and boundary there
513  */
514 
516 {
517  ASSERT(bc_element_tmp_.size()==0)
518  .error("Temporary structure of boundary element data is not empty. Did you call create_boundary_elements?");
519 
520  Neighbour neighbour;
521  EdgeData *edg = nullptr;
522  unsigned int ngh_element_idx;
523  unsigned int last_edge_idx = Mesh::undef_idx;
524 
525  neighbour.mesh_ = this;
526 
528 
529  // pointers to created edges
530  //vector<Edge *> tmp_edges;
531  edges.resize(0); // be sure that edges are empty
532 
534  vector<unsigned int> intersection_list; // list of elements in intersection of node element lists
535 
536  for( unsigned int i=bulk_size_; i<element_vec_.size(); ++i) {
537 
538  ElementAccessor<3> bc_ele = this->element_accessor(i);
539  ASSERT(bc_ele.region().is_boundary());
540  // Find all elements that share this side.
541  side_nodes.resize(bc_ele->n_nodes());
542  for (unsigned n=0; n<bc_ele->n_nodes(); n++) side_nodes[n] = bc_ele->node_idx(n);
543  intersect_element_lists(side_nodes, intersection_list);
544  bool is_neighbour = find_lower_dim_element(intersection_list, bc_ele->dim() +1, ngh_element_idx);
545  if (is_neighbour) {
546  xprintf(UsrErr, "Boundary element (id: %d) match a regular element (id: %d) of lower dimension.\n",
547  bc_ele.idx(), this->elem_index(ngh_element_idx));
548  } else {
549  if (intersection_list.size() == 0) {
550  // no matching dim+1 element found
551  WarningOut().fmt("Lonely boundary element, id: {}, region: {}, dimension {}.\n",
552  bc_ele.idx(), bc_ele.region().id(), bc_ele->dim());
553  continue; // skip the boundary element
554  }
555  last_edge_idx=edges.size();
556  edges.resize(last_edge_idx+1);
557  edg = &( edges.back() );
558  edg->n_sides = 0;
559  edg->side_ = new struct SideIter[ intersection_list.size() ];
560 
561  // common boundary object
562  unsigned int bdr_idx=boundary_.size();
563  boundary_.resize(bdr_idx+1);
564  BoundaryData &bdr=boundary_.back();
565  bdr.bc_ele_idx_ = i;
566  bdr.edge_idx_ = last_edge_idx;
567  bdr.mesh_=this;
568 
569  // for 1d boundaries there can be more then one 1d elements connected to the boundary element
570  // we do not detect this case later in the main search over bulk elements
571  for( vector<unsigned int>::iterator isect = intersection_list.begin(); isect!=intersection_list.end(); ++isect) {
572  ElementAccessor<3> elem = this->element_accessor(*isect);
573  for (unsigned int ecs=0; ecs<elem->n_sides(); ecs++) {
574  SideIter si = elem.side(ecs);
575  if ( same_sides( si, side_nodes) ) {
576  if (elem->edge_idx(ecs) != Mesh::undef_idx) {
577  OLD_ASSERT(elem->boundary_idx_!=nullptr, "Null boundary idx array.\n");
578  int last_bc_ele_idx=this->boundary_[elem->boundary_idx_[ecs]].bc_ele_idx_;
579  int new_bc_ele_idx=i;
580  THROW( ExcDuplicateBoundary()
581  << EI_ElemLast(this->find_elem_id(last_bc_ele_idx))
582  << EI_RegLast(this->element_accessor(last_bc_ele_idx).region().label())
583  << EI_ElemNew(this->find_elem_id(new_bc_ele_idx))
584  << EI_RegNew(this->element_accessor(new_bc_ele_idx).region().label())
585  );
586  }
587  element_vec_[*isect].edge_idx_[ecs] = last_edge_idx;
588  edg->side_[ edg->n_sides++ ] = si;
589 
590  if (elem->boundary_idx_ == NULL) {
591  Element *el = &(element_vec_[*isect]);
592  el->boundary_idx_ = new unsigned int [ el->n_sides() ];
593  std::fill( el->boundary_idx_, el->boundary_idx_ + el->n_sides(), Mesh::undef_idx);
594  }
595  elem->boundary_idx_[ecs] = bdr_idx;
596  break; // next element in intersection list
597  }
598  }
599  }
600 
601  }
602 
603  }
604  // Now we go through all element sides and create edges and neighbours
605  for (auto e : this->elements_range()) {
606  for (unsigned int s=0; s<e->n_sides(); s++)
607  {
608  // skip sides that were already found
609  if (e->edge_idx(s) != Mesh::undef_idx) continue;
610 
611 
612  // Find all elements that share this side.
613  side_nodes.resize(e.side(s)->n_nodes());
614  for (unsigned n=0; n<e.side(s)->n_nodes(); n++) side_nodes[n] = e.side(s)->node(n).idx();
615  intersect_element_lists(side_nodes, intersection_list);
616 
617  bool is_neighbour = find_lower_dim_element(intersection_list, e->dim(), ngh_element_idx);
618 
619  if (is_neighbour) { // edge connects elements of different dimensions
620  // Initialize for the neighbour case.
621  neighbour.elem_idx_ = ngh_element_idx;
622  } else { // edge connects only elements of the same dimension
623  // Initialize for the edge case.
624  last_edge_idx=edges.size();
625  edges.resize(last_edge_idx+1);
626  edg = &( edges.back() );
627  edg->n_sides = 0;
628  edg->side_ = new struct SideIter[ intersection_list.size() ];
629  if (intersection_list.size() > max_edge_sides_[e->dim()-1])
630  max_edge_sides_[e->dim()-1] = intersection_list.size();
631 
632  if (intersection_list.size() == 1) {
633  // outer edge, create boundary object as well
634  Element &elm = element_vec_[e.idx()];
635  edg->n_sides=1;
636  edg->side_[0] = e.side(s);
637  element_vec_[e.idx()].edge_idx_[s] = last_edge_idx;
638 
639  if (e->boundary_idx_ == NULL) {
640  elm.boundary_idx_ = new unsigned int [ e->n_sides() ];
641  std::fill( elm.boundary_idx_, elm.boundary_idx_ + e->n_sides(), Mesh::undef_idx);
642  }
643 
644  unsigned int bdr_idx=boundary_.size()+1; // need for VTK mesh that has no boundary elements
645  // and bulk elements are indexed from 0
646  boundary_.resize(bdr_idx+1);
647  BoundaryData &bdr=boundary_.back();
648  elm.boundary_idx_[s] = bdr_idx;
649 
650  // fill boundary element
651  Element * bc_ele = add_element_to_vector(-bdr_idx);
652  bc_ele->init(e->dim()-1, region_db_.implicit_boundary_region() );
654  for(unsigned int ni = 0; ni< side_nodes.size(); ni++) bc_ele->nodes_[ni] = side_nodes[ni];
655 
656  // fill Boundary object
657  bdr.edge_idx_ = last_edge_idx;
658  bdr.bc_ele_idx_ = elem_index(-bdr_idx);
659  bdr.mesh_=this;
660 
661  continue; // next side of element e
662  }
663  }
664 
665  // go through the elements connected to the edge or neighbour
666  // setup neigbour or edge
667  for( vector<unsigned int>::iterator isect = intersection_list.begin(); isect!=intersection_list.end(); ++isect) {
668  ElementAccessor<3> elem = this->element_accessor(*isect);
669  for (unsigned int ecs=0; ecs<elem->n_sides(); ecs++) {
670  if (elem->edge_idx(ecs) != Mesh::undef_idx) continue; // ??? This should not happen.
671  SideIter si = elem.side(ecs);
672  if ( same_sides( si, side_nodes) ) {
673  if (is_neighbour) {
674  // create a new edge and neighbour for this side, and element to the edge
675  last_edge_idx=edges.size();
676  edges.resize(last_edge_idx+1);
677  edg = &( edges.back() );
678  edg->n_sides = 1;
679  edg->side_ = new struct SideIter[1];
680  edg->side_[0] = si;
681  element_vec_[elem.idx()].edge_idx_[ecs] = last_edge_idx;
682 
683  neighbour.edge_idx_ = last_edge_idx;
684 
685  vb_neighbours_.push_back(neighbour); // copy neighbour with this edge setting
686  } else {
687  // connect the side to the edge, and side to the edge
688  ASSERT_PTR_DBG(edg);
689  edg->side_[ edg->n_sides++ ] = si;
690  ASSERT_DBG(last_edge_idx != Mesh::undef_idx);
691  element_vec_[elem.idx()].edge_idx_[ecs] = last_edge_idx;
692  }
693  break; // next element from intersection list
694  }
695  } // search for side of other connected element
696  } // connected elements
697 
698  if (! is_neighbour)
699  ASSERT_EQ( (unsigned int) edg->n_sides, intersection_list.size())(e.index())(s).error("Missing edge sides.");
700  } // for element sides
701  } // for elements
702 
703  MessageOut().fmt( "Created {} edges and {} neighbours.\n", edges.size(), vb_neighbours_.size() );
704 }
705 
706 
707 
709 {
710  // node numbers is the local index of the node on the last side
711  // this maps the side nodes to the nodes of the reference side(0)
712  std::unordered_map<unsigned int,unsigned int> node_numbers;
713 
714  for (auto edg : edge_range())
715  {
716  unsigned int n_side_nodes = edg.side(0)->n_nodes();
717  // side 0 is reference, so its permutation is 0
718  edg.side(0)->element()->permutation_idx_[edg.side(0)->side_idx()] = 0;
719 
720  if (edg.n_sides() > 1)
721  {
722  // For every node on the reference side(0) give its local idx on the current side.
723  unsigned int permutation[n_side_nodes];
724 
725 
726  node_numbers.clear();
727  for (uint i=0; i<n_side_nodes; i++)
728  node_numbers[edg.side(0)->node(i).idx()] = i;
729 
730  for (uint sid=1; sid<edg.n_sides(); sid++)
731  {
732  for (uint i=0; i<n_side_nodes; i++)
733  permutation[node_numbers[edg.side(sid)->node(i).idx()]] = i;
734 
735  switch (edg.side(0)->dim())
736  {
737  case 0:
738  edg.side(sid)->element()->permutation_idx_[edg.side(sid)->side_idx()] = RefElement<1>::permutation_index(permutation);
739  break;
740  case 1:
741  edg.side(sid)->element()->permutation_idx_[edg.side(sid)->side_idx()] = RefElement<2>::permutation_index(permutation);
742  break;
743  case 2:
744  edg.side(sid)->element()->permutation_idx_[edg.side(sid)->side_idx()] = RefElement<3>::permutation_index(permutation);
745  break;
746  }
747  }
748  }
749  }
750 
751  for (vector<Neighbour>::iterator nb=vb_neighbours_.begin(); nb!=vb_neighbours_.end(); nb++)
752  {
753  // node numbers is the local index of the node on the last side
754  // this maps the side nodes to the nodes of the side(0)
755  unsigned int n_side_nodes = nb->element()->n_nodes();
756  unsigned int permutation[n_side_nodes];
757  node_numbers.clear();
758 
759  // element of lower dimension is reference, so
760  // we calculate permutation for the adjacent side
761  for (unsigned int i=0; i<n_side_nodes; i++)
762  node_numbers[nb->element().node(i).idx()] = i;
763 
764  for (unsigned int i=0; i<n_side_nodes; i++)
765  permutation[node_numbers[nb->side()->node(i).idx()]] = i;
766 
767  switch (nb->side()->dim())
768  {
769  case 0:
770  nb->side()->element()->permutation_idx_[nb->side()->side_idx()] = RefElement<1>::permutation_index(permutation);
771  break;
772  case 1:
773  nb->side()->element()->permutation_idx_[nb->side()->side_idx()] = RefElement<2>::permutation_index(permutation);
774  break;
775  case 2:
776  nb->side()->element()->permutation_idx_[nb->side()->side_idx()] = RefElement<3>::permutation_index(permutation);
777  break;
778  }
779  }
780 }
781 
782 
783 
784 
785 
786 //=============================================================================
787 //
788 //=============================================================================
790 {
791 
792  //MessageOut() << "Element to neighbours of vb2 type... "/*orig verb 5*/;
793 
794  for (vector<Element>::iterator ele = element_vec_.begin(); ele!= element_vec_.begin()+bulk_size_; ++ele)
795  ele->n_neighs_vb_ =0;
796 
797  // count vb neighs per element
798  for (auto & ngh : this->vb_neighbours_) ngh.element()->n_neighs_vb_++;
799 
800  // Allocation of the array per element
801  for (vector<Element>::iterator ele = element_vec_.begin(); ele!= element_vec_.begin()+bulk_size_; ++ele)
802  if( ele->n_neighs_vb() > 0 ) {
803  ele->neigh_vb = new struct Neighbour* [ele->n_neighs_vb()];
804  ele->n_neighs_vb_=0;
805  }
806 
807  // fill
808  ElementAccessor<3> ele;
809  for (auto & ngh : this->vb_neighbours_) {
810  ele = ngh.element();
811  ele->neigh_vb[ ele->n_neighs_vb_++ ] = &ngh;
812  }
813 
814  //MessageOut() << "... O.K.\n"/*orig verb 6*/;
815 }
816 
817 
818 
819 
820 
821 
823  /* Algorithm:
824  *
825  * 1) create BIH tree
826  * 2) for every 1D, find list of candidates
827  * 3) compute intersections for 1d, store it to master_elements
828  *
829  */
830  if (! intersections) {
831  intersections = std::make_shared<MixedMeshIntersections>(this);
832  intersections->compute_intersections();
833  }
834  return *intersections;
835 }
836 
837 
838 
840  return ElementAccessor<3>(this, idx);
841 }
842 
843 
844 
845 NodeAccessor<3> Mesh::node(unsigned int idx) const {
846  return NodeAccessor<3>(this, idx);
847 }
848 
849 
850 
851 void Mesh::elements_id_maps( vector<LongIdx> & bulk_elements_id, vector<LongIdx> & boundary_elements_id) const
852 {
853  if (bulk_elements_id.size() ==0) {
855  LongIdx last_id;
856 
857  bulk_elements_id.resize(n_elements());
858  map_it = bulk_elements_id.begin();
859  last_id = -1;
860  for(unsigned int idx=0; idx < n_elements(); idx++, ++map_it) {
861  LongIdx id = this->find_elem_id(idx);
862  if (last_id >= id) xprintf(UsrErr, "Element IDs in non-increasing order, ID: %d\n", id);
863  last_id=*map_it = id;
864  }
865 
866  boundary_elements_id.resize(n_elements(true));
867  map_it = boundary_elements_id.begin();
868  last_id = -1;
869  for(unsigned int idx=bulk_size_; idx<element_vec_.size(); idx++, ++map_it) {
870  LongIdx id = this->find_elem_id(idx);
871  // We set ID for boundary elements created by the mesh itself to "-1"
872  // this force gmsh reader to skip all remaining entries in boundary_elements_id
873  // and thus report error for any remaining data lines
874  if (id < 0) last_id=*map_it=-1;
875  else {
876  if (last_id >= id) xprintf(UsrErr, "Element IDs in non-increasing order, ID: %d\n", id);
877  last_id=*map_it = id;
878  }
879  }
880  }
881 }
882 
883 
884 bool compare_points(const arma::vec3 &p1, const arma::vec3 &p2) {
885  static const double point_tolerance = 1E-10;
886  return fabs(p1[0]-p2[0]) < point_tolerance
887  && fabs(p1[1]-p2[1]) < point_tolerance
888  && fabs(p1[2]-p2[2]) < point_tolerance;
889 }
890 
891 
892 std::shared_ptr<std::vector<LongIdx>> Mesh::check_compatible_mesh( Mesh & input_mesh)
893 {
894  std::vector<unsigned int> node_ids; // allow mapping ids of nodes from source mesh to target mesh
895  std::vector<unsigned int> node_list;
896  std::vector<unsigned int> candidate_list; // returned by intersect_element_lists
897  std::vector<unsigned int> result_list; // list of elements with same dimension as vtk element
898  unsigned int i; // counter over vectors
899  std::shared_ptr<std::vector<LongIdx>> map_ptr = std::make_shared<std::vector<LongIdx>>(this->n_elements()+this->n_elements(true));
900  std::vector<LongIdx> &element_ids_map = *(map_ptr.get());
901 
902  {
903  // iterates over node vector of \p this object
904  // to each node must be found just only one node in target \p mesh
905  // store orders (mapping between source and target meshes) into node_ids vector
906  std::vector<unsigned int> searched_elements; // for BIH tree
907  unsigned int i_node, i_elm_node;
908  const BIHTree &bih_tree=this->get_bih_tree();
909 
910  // create nodes of mesh
911  node_ids.resize( this->n_nodes(), Mesh::undef_idx );
912  i=0;
913  for (auto nod : input_mesh.node_range()) {
914  uint found_i_node = Mesh::undef_idx;
915  bih_tree.find_point(*nod, searched_elements);
916 
917  for (std::vector<unsigned int>::iterator it = searched_elements.begin(); it!=searched_elements.end(); it++) {
918  ElementAccessor<3> ele = this->element_accessor( *it );
919  for (i_node=0; i_node<ele->n_nodes(); i_node++)
920  {
921  static const double point_tolerance = 1E-10;
922  if ( arma::norm(*ele.node(i_node) - *nod, 1) < point_tolerance) {
923  i_elm_node = ele.node(i_node).idx();
924  if (found_i_node == Mesh::undef_idx) found_i_node = i_elm_node;
925  else if (found_i_node != i_elm_node) {
926  // duplicate nodes in target mesh - not compatible
927  return std::make_shared<std::vector<LongIdx>>(0);
928  }
929  }
930  }
931  }
932  if (found_i_node!=Mesh::undef_idx) node_ids[found_i_node] = i;
933  searched_elements.clear();
934  i++;
935  }
936  }
937  {
938  // iterates over bulk elements of \p this object
939  // elements in both meshes must be in ratio 1:1
940  // store orders (mapping between both mesh files) into bulk_elements_id vector
941  // iterate trough bulk part of element vector, to each element in source mesh must exist only one element in target mesh
942  i=0;
943  unsigned int n_found=0; // number of found equivalent elements
944  bool valid_nodes;
945  for (auto elm : this->elements_range()) {
946  valid_nodes = true;
947  for (unsigned int j=0; j<elm->n_nodes(); j++) { // iterate trough all nodes of any element
948  if (node_ids[ elm->node_idx(j) ] == Mesh::undef_idx) valid_nodes = false;
949  node_list.push_back( node_ids[ elm->node_idx(j) ] );
950  }
951  if (valid_nodes) {
952  input_mesh.intersect_element_lists(node_list, candidate_list);
953  for (auto i_elm : candidate_list) {
954  if ( input_mesh.element_accessor(i_elm)->dim() == elm.dim() ) result_list.push_back(i_elm);
955  }
956  }
957  if (result_list.size() == 1) {
958  element_ids_map[i] = (LongIdx)result_list[0];
959  n_found++;
960  } else {
961  element_ids_map[i] = (LongIdx)Mesh::undef_idx;
962  }
963  node_list.clear();
964  result_list.clear();
965  i++;
966  }
967 
968  if (n_found==0) {
969  // no equivalent bulk element found - mesh is not compatible
970  return std::make_shared<std::vector<LongIdx>>(0);
971  }
972  }
973 
974  {
975  // iterates over boundary elements of \p this object
976  // elements in both meshes must be in ratio 1:1
977  // store orders (mapping between both mesh files) into boundary_elements_id vector
978  auto bc_mesh = this->get_bc_mesh();
979  auto input_bc_mesh = input_mesh.get_bc_mesh();
980  // iterate trough boundary part of element vector, to each element in source mesh must exist only one element in target mesh
981  // fill boundary_elements_id vector
982  bool valid_nodes;
983  i=this->n_elements();
984  for (auto elm : bc_mesh->elements_range()) {
985  valid_nodes = true;
986  for (unsigned int j=0; j<elm->n_nodes(); j++) { // iterate trough all nodes of any element
987  if (node_ids[ elm->node_idx(j) ] == Mesh::undef_idx) valid_nodes = false;
988  node_list.push_back( node_ids[ elm->node_idx(j) ] );
989  }
990  if (valid_nodes) {
991  input_bc_mesh->intersect_element_lists(node_list, candidate_list);
992  for (auto i_elm : candidate_list) {
993  if ( input_bc_mesh->element_accessor(i_elm)->dim() == elm.dim() ) result_list.push_back(i_elm);
994  }
995  }
996  if (result_list.size() == 1) {
997  element_ids_map[i] = (LongIdx)result_list[0];
998  } else {
999  element_ids_map[i] = (LongIdx)Mesh::undef_idx;
1000  }
1001  node_list.clear();
1002  result_list.clear();
1003  i++;
1004  }
1005  }
1006 
1007  return map_ptr;
1008 }
1009 
1011 {
1013  it != region_list.end();
1014  ++it) {
1015  // constructor has side effect in the mesh - create new region or set and store them to Mesh::region_db_
1016  (*it).factory< RegionSetBase, const Input::Record &, Mesh * >(*it, this);
1017  }
1018 }
1019 
1021 {
1023  region_db_.el_to_reg_map_.clear();
1024  region_db_.close();
1026 
1027  if ( in_record_.val<bool>("print_regions") ) {
1028  stringstream ss;
1030  MessageOut() << ss.str();
1031  }
1032 }
1033 
1034 
1036  START_TIMER("Mesh::compute_element_boxes");
1038 
1039  // make element boxes
1040  unsigned int i=0;
1041  boxes.resize(this->n_elements());
1042  for (auto element : this->elements_range()) {
1043  boxes[i] = element.bounding_box();
1044  i++;
1045  }
1046 
1047  return boxes;
1048 }
1049 
1051  if (! this->bih_tree_) {
1052  bih_tree_ = std::make_shared<BIHTree>();
1053  bih_tree_->add_boxes( this->get_element_boxes() );
1054  bih_tree_->construct();
1055  }
1056  return *bih_tree_;
1057 }
1058 
1060  return in_record_.val<double>("global_snap_radius");
1061 }
1062 
1063 void Mesh::add_physical_name(unsigned int dim, unsigned int id, std::string name) {
1064  region_db_.add_region(id, name, dim, "$PhysicalNames");
1065 }
1066 
1067 
1068 void Mesh::add_node(unsigned int node_id, arma::vec3 coords) {
1069 
1070  nodes_.append(coords);
1071  node_ids_.add_item(node_id);
1072 }
1073 
1074 
1075 void Mesh::add_element(unsigned int elm_id, unsigned int dim, unsigned int region_id, unsigned int partition_id,
1076  std::vector<unsigned int> node_ids) {
1077  RegionIdx region_idx = region_db_.get_region( region_id, dim );
1078  if ( !region_idx.is_valid() ) {
1079  region_idx = region_db_.add_region( region_id, region_db_.create_label_from_id(region_id), dim, "$Element" );
1080  }
1081  region_db_.mark_used_region(region_idx.idx());
1082 
1083  if (region_idx.is_boundary()) {
1084  bc_element_tmp_.push_back( ElementTmpData(elm_id, dim, region_idx, partition_id, node_ids) );
1085  } else {
1086  if(dim == 0 ) {
1087  WarningOut().fmt("Bulk elements of zero size(dim=0) are not supported. Element ID: {}.\n", elm_id);
1088  }
1089  else {
1090  Element *ele = add_element_to_vector(elm_id);
1091  bulk_size_++;
1092  this->init_element(ele, elm_id, dim, region_idx, partition_id, node_ids);
1093  }
1094  }
1095 }
1096 
1097 
1098 void Mesh::init_element(Element *ele, unsigned int elm_id, unsigned int dim, RegionIdx region_idx, unsigned int partition_id,
1099  std::vector<unsigned int> node_ids) {
1100  ele->init(dim, region_idx);
1101  ele->pid_ = partition_id;
1102 
1103  for (unsigned int ni=0; ni<ele->n_nodes(); ni++) {
1104  ele->nodes_[ni] = this->node_index(node_ids[ni]);
1105  }
1106 
1107  // check that tetrahedron element is numbered correctly and is not degenerated
1108  if(ele->dim() == 3)
1109  {
1110  ElementAccessor<3> ea = this->element_accessor( this->elem_index(elm_id) );
1111  double jac = ea.tetrahedron_jacobian();
1112  if( ! (jac > 0) ) {
1113  WarningOut().fmt("Tetrahedron element with id {} has wrong numbering or is degenerated (Jacobian = {}).",elm_id, jac);
1114  }
1115  }
1116 }
1117 
1118 
1120  if (node_elements_.size() == 0) {
1121  this->create_node_element_lists();
1122  }
1123  return node_elements_;
1124 }
1125 
1126 
1127 void Mesh::init_element_vector(unsigned int size) {
1128  element_vec_.clear();
1129  element_ids_.clear();
1130  element_vec_.reserve(size);
1131  element_ids_.reserve(size);
1132  bc_element_tmp_.clear();
1133  bc_element_tmp_.reserve(size);
1134  bulk_size_ = 0;
1136 }
1137 
1138 
1139 void Mesh::init_node_vector(unsigned int size) {
1140  nodes_.reinit(size);
1141  node_ids_.clear();
1142  node_ids_.reserve(size);
1143 }
1144 
1145 
1147  element_vec_.push_back( Element() );
1148  Element * elem = &element_vec_.back(); //[element_vec_.size()-1];
1149  element_ids_.add_item((unsigned int)(id));
1150  return elem;
1151 }
1152 
1154  auto bgn_it = make_iter<ElementAccessor<3>>( ElementAccessor<3>(this, 0) );
1155  auto end_it = make_iter<ElementAccessor<3>>( ElementAccessor<3>(this, bulk_size_) );
1156  return Range<ElementAccessor<3>>(bgn_it, end_it);
1157 }
1158 
1160  auto bgn_it = make_iter<NodeAccessor<3>>( NodeAccessor<3>(this, 0) );
1161  auto end_it = make_iter<NodeAccessor<3>>( NodeAccessor<3>(this, n_nodes()) );
1162  return Range<NodeAccessor<3>>(bgn_it, end_it);
1163 }
1164 
1166  auto bgn_it = make_iter<Edge>( Edge(this, 0) );
1167  auto end_it = make_iter<Edge>( Edge(this, edges.size()) );
1168  return Range<Edge>(bgn_it, end_it);
1169 }
1170 
1171 inline void Mesh::check_element_size(unsigned int elem_idx) const
1172 {
1173  ASSERT(elem_idx < element_vec_.size())(elem_idx)(element_vec_.size()).error("Index of element is out of bound of element vector!");
1174 }
1175 
1176 /*
1177  * Output of internal flow data.
1178  */
1180 {
1181  START_TIMER("Mesh::output_internal_ngh_data");
1182 
1183  if (! raw_ngh_output_file.is_open()) return;
1184 
1185  // header
1186  raw_ngh_output_file << "// fields:\n//ele_id n_sides ns_side_neighbors[n] neighbors[n*ns] n_vb_neighbors vb_neighbors[n_vb]\n";
1188 
1189  int cit = 0;
1190 
1191  // map from higher dim elements to its lower dim neighbors, using gmsh IDs: ele->id()
1192  unsigned int undefined_ele_id = -1;
1194  for (auto ele : this->elements_range()) {
1195  if(ele->n_neighs_vb() > 0){
1196  for (unsigned int i = 0; i < ele->n_neighs_vb(); i++){
1197  ElementAccessor<3> higher_ele = ele->neigh_vb[i]->side()->element();
1198 
1199  auto search = neigh_vb_map.find(higher_ele.idx());
1200  if(search != neigh_vb_map.end()){
1201  // if found, add id to correct local side idx
1202  search->second[ele->neigh_vb[i]->side()->side_idx()] = ele.idx();
1203  }
1204  else{
1205  // if not found, create new vector, each side can have one vb neighbour
1206  std::vector<unsigned int> higher_ele_side_ngh(higher_ele->n_sides(), undefined_ele_id);
1207  higher_ele_side_ngh[ele->neigh_vb[i]->side()->side_idx()] = ele.idx();
1208  neigh_vb_map[higher_ele.idx()] = higher_ele_side_ngh;
1209  }
1210  }
1211  }
1212  }
1213 
1214  for (auto ele : this->elements_range()) {
1215  raw_ngh_output_file << ele.idx() << " ";
1216  raw_ngh_output_file << ele->n_sides() << " ";
1217 
1218  auto search_neigh = neigh_vb_map.end();
1219  for (unsigned int i = 0; i < ele->n_sides(); i++) {
1220  unsigned int n_side_neighs = ele.side(i)->edge().n_sides()-1; //n_sides - the current one
1221  // check vb neighbors (lower dimension)
1222  if(n_side_neighs == 0){
1223  //update search
1224  if(search_neigh == neigh_vb_map.end())
1225  search_neigh = neigh_vb_map.find(ele.idx());
1226 
1227  if(search_neigh != neigh_vb_map.end())
1228  if(search_neigh->second[i] != undefined_ele_id)
1229  n_side_neighs = 1;
1230  }
1231  raw_ngh_output_file << n_side_neighs << " ";
1232  }
1233 
1234  for (unsigned int i = 0; i < ele->n_sides(); i++) {
1235  Edge edge = ele.side(i)->edge();
1236  if(edge.n_sides() > 1){
1237  for (uint j = 0; j < edge.n_sides(); j++) {
1238  if(edge.side(j) != ele.side(i))
1239  raw_ngh_output_file << edge.side(j)->element().idx() << " ";
1240  }
1241  }
1242  //check vb neighbour
1243  else if(search_neigh != neigh_vb_map.end()
1244  && search_neigh->second[i] != undefined_ele_id){
1245  raw_ngh_output_file << search_neigh->second[i] << " ";
1246  }
1247  }
1248 
1249  // list higher dim neighbours
1250  raw_ngh_output_file << ele->n_neighs_vb() << " ";
1251  for (unsigned int i = 0; i < ele->n_neighs_vb(); i++)
1252  raw_ngh_output_file << ele->neigh_vb[i]->side()->element().idx() << " ";
1253 
1254  raw_ngh_output_file << endl;
1255  cit ++;
1256  }
1257  raw_ngh_output_file << "$EndFlowField\n" << endl;
1258 }
1259 
1260 
1262  // Copy boundary elements in temporary storage to the second part of the element vector
1263  for(ElementTmpData &e_data : bc_element_tmp_) {
1264  Element *ele = add_element_to_vector(e_data.elm_id);
1265  this->init_element(ele, e_data.elm_id, e_data.dim, e_data.region_idx,
1266  e_data.partition_id, e_data.node_ids);
1267  }
1268  // release memory
1269  vector<ElementTmpData>().swap(bc_element_tmp_);
1270 }
1271 
1272 
1273 void Mesh::permute_tetrahedron(unsigned int elm_idx, std::vector<unsigned int> permutation_vec)
1274 {
1275  ASSERT_LT_DBG(elm_idx, element_vec_.size());
1276  ASSERT_EQ_DBG(permutation_vec.size(), 4);
1277 
1278  std::array<unsigned int, 4> tmp_nodes;
1279  Element &elem = element_vec_[elm_idx];
1280  ASSERT_EQ_DBG(elem.dim(), 3);
1281 
1282  for(unsigned int i=0; i<elem.n_nodes(); i++)
1283  {
1284  tmp_nodes[i] = elem.nodes_[permutation_vec[i]];
1285  }
1286  elem.nodes_ = tmp_nodes;
1287 }
1288 
1289 
1290 void Mesh::permute_triangle(unsigned int elm_idx, std::vector<unsigned int> permutation_vec)
1291 {
1292  ASSERT_LT_DBG(elm_idx, element_vec_.size());
1293  ASSERT_EQ_DBG(permutation_vec.size(), 3);
1294 
1295  std::array<unsigned int, 4> tmp_nodes;
1296  Element &elem = element_vec_[elm_idx];
1297  ASSERT_EQ_DBG(elem.dim(), 2);
1298 
1299  for(unsigned int i=0; i<elem.n_nodes(); i++)
1300  {
1301  tmp_nodes[i] = elem.nodes_[permutation_vec[i]];
1302  }
1303  elem.nodes_ = tmp_nodes;
1304 }
1305 
1306 
1308  if (bc_mesh_ == nullptr) bc_mesh_ = new BCMesh(this);
1309  return bc_mesh_;
1310 }
1311 
1312 
1314  ASSERT_PTR(el_4_loc).error("Array 'el_4_loc' is not initialized. Did you call Partitioning::id_maps?\n");
1315 
1316  unsigned int i_proc, i_node, i_ghost_node, elm_node;
1317  unsigned int my_proc = el_ds->myp();
1318  unsigned int n_proc = el_ds->np();
1319 
1320  // distribute nodes between processes, every node is assigned to minimal process of elements that own node
1321  // fill node_proc vector with same values on all processes
1322  std::vector<unsigned int> node_proc( this->n_nodes(), n_proc );
1323  std::vector<bool> local_node_flag( this->n_nodes(), false );
1324 
1325  for ( auto elm : this->elements_range() ) {
1326  i_proc = elm.proc();
1327  for (elm_node=0; elm_node<elm->n_nodes(); elm_node++) {
1328  i_node = elm->node_idx(elm_node);
1329  if (i_proc == my_proc) local_node_flag[i_node] = true;
1330  if (i_proc < node_proc[i_node]) node_proc[i_node] = i_proc;
1331  }
1332  }
1333 
1334  unsigned int n_own_nodes=0, n_local_nodes=0; // number of own and ghost nodes
1335  for(uint loc_flag : local_node_flag) if (loc_flag) n_local_nodes++;
1336  for(uint i_proc : node_proc) {
1337  if (i_proc == my_proc)
1338  n_own_nodes++;
1339  else if (i_proc == n_proc)
1340  ASSERT(0)(find_node_id(n_own_nodes)).error("A node does not belong to any element!");
1341  }
1342 
1343  //DebugOut() << print_var(n_own_nodes) << print_var(n_local_nodes) << this->n_nodes();
1344  // create and fill node_4_loc_ (mapping local to global indexes)
1345  node_4_loc_ = new LongIdx [ n_local_nodes ];
1346  i_node=0;
1347  i_ghost_node = n_own_nodes;
1348  for (unsigned int i=0; i<this->n_nodes(); ++i) {
1349  if (local_node_flag[i]) {
1350  if (node_proc[i]==my_proc)
1351  node_4_loc_[i_node++] = i;
1352  else
1353  node_4_loc_[i_ghost_node++] = i;
1354  }
1355  }
1356 
1357  // Construct node distribution object, set number of local nodes (own+ghost)
1358  node_ds_ = new Distribution(n_own_nodes, PETSC_COMM_WORLD);
1359  node_ds_->get_lsizes_array(); // need to initialize lsizes data member
1361 
1362 }
1363 
1364 //-----------------------------------------------------------------------------
1365 // vim: set cindent:
int n_triangles
Definition: mesh.h:274
Distribution * el_ds
Parallel distribution of elements.
Definition: mesh.h:565
Class for the mesh partitioning. This should provide:
Definition: partitioning.hh:52
Iterator< ValueType > begin() const
void read_stream(istream &in, const Type::TypeBase &root_type, FileFormat format)
This method actually reads the given stream in.
unsigned int n_sides() const
Returns number of sides aligned with the edge.
Definition: accessors.hh:300
void output_internal_ngh_data()
Output of neighboring data into raw output.
Definition: mesh.cc:1179
const Element * element() const
Definition: accessors.hh:160
void resize(uint size)
Definition: armor.hh:700
unsigned int n_nodes() const
Definition: elements.h:126
std::array< unsigned int, 4 > nodes_
indices to element&#39;s nodes
Definition: elements.h:111
vector< Element > element_vec_
Definition: mesh.h:517
BidirectionalMap< int > node_ids_
Maps node ids to indexes into vector node_vec_.
Definition: mesh.h:537
vector< vector< unsigned int > > const & node_elements()
Definition: mesh.cc:1119
#define ASSERT_EQ_DBG(a, b)
Definition of comparative assert macro (EQual) only for debug mode.
Definition: asserts.hh:332
unsigned int size() const
Return size of map.
Accessor to input data conforming to declared Array.
Definition: accessors.hh:566
void reserve(unsigned int init_size=0)
Reset data of map, reserve space for given size.
unsigned int n_local_nodes_
Hold number of local nodes (own + ghost), value is equal with size of node_4_loc array.
Definition: mesh.h:571
unsigned int * boundary_idx_
Definition: elements.h:80
void permute_tetrahedron(unsigned int elm_idx, std::vector< unsigned int > permutation_vec)
Permute nodes of 3D elements of given elm_idx.
Definition: mesh.cc:1273
bool is_boundary() const
Returns true if it is a Boundary region and false if it is a Bulk region.
Definition: region.hh:74
unsigned int uint
unsigned int bc_ele_idx_
Definition: mesh_data.hh:53
friend class Element
Definition: mesh.h:546
void count_side_types()
Definition: mesh.cc:419
int MPI_Comm
Definition: mpi.h:141
BCMesh * bc_mesh_
Boundary mesh, object is created only if it&#39;s necessary.
Definition: mesh.h:573
unsigned int side_idx() const
Returns local index of the side on the element.
Definition: accessors.hh:415
void check_and_finish()
Definition: mesh.cc:1020
MapElementIDToRegionID el_to_reg_map_
Definition: region.hh:571
Reader for (slightly) modified input files.
void init_element_vector(unsigned int size)
Initialize element_vec_, set size and reset counters of boundary and bulk elements.
Definition: mesh.cc:1127
virtual const LongIdx * get_local_part()
Definition: mesh.cc:270
MixedMeshIntersections & mixed_intersections()
Definition: mesh.cc:822
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:61
BidirectionalMap< int > element_ids_
Maps element ids to indexes into vector element_vec_.
Definition: mesh.h:529
Class for declaration of the input of type Bool.
Definition: type_base.hh:452
Edge edge() const
Returns pointer to the edge connected to the side.
void append(const ArmaMat< Type, nr, nc > &item)
Definition: armor.hh:726
void add_node(unsigned int node_id, arma::vec3 coords)
Add new node of given id and coordinates to mesh.
Definition: mesh.cc:1068
LongIdx * node_4_loc_
Index set assigning to local node index its global index.
Definition: mesh.h:567
#define MessageOut()
Macro defining &#39;message&#39; record of log.
Definition: logger.hh:267
DuplicateNodes * tree
Definition: mesh.h:262
virtual std::shared_ptr< std::vector< LongIdx > > check_compatible_mesh(Mesh &input_mesh)
Definition: mesh.cc:892
unsigned int elem_idx_
Index of element in Mesh::element_vec_.
Definition: neighbours.h:137
int n_lines
Definition: mesh.h:273
static const Input::Type::Record & get_input_type()
Definition: partitioning.cc:49
static const unsigned int undef_idx
Definition: mesh.h:104
std::vector< BoundingBox > get_element_boxes()
Compute bounding boxes of elements contained in mesh.
Definition: mesh.cc:1035
void init()
Definition: mesh.cc:160
ofstream raw_ngh_output_file
Definition: mesh.h:575
std::string format(CStringRef format_str, ArgList args)
Definition: format.h:3141
#define INPUT_CATCH(ExceptionType, AddressEITag, input_accessor)
Definition: accessors.hh:63
void create_node_element_lists()
Definition: mesh.cc:433
static unsigned int permutation_index(unsigned int p[n_nodes_per_side])
Definition: ref_element.cc:552
BCMesh * get_bc_mesh()
Create boundary mesh if doesn&#39;t exist and return it.
Definition: mesh.cc:1307
static const Input::Type::Record & get_input_type()
Definition: mesh.cc:74
int elem_index(int elem_id) const
For element of given elem_id returns index in element_vec_ or (-1) if element doesn&#39;t exist...
Definition: mesh.h:353
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:110
std::shared_ptr< MixedMeshIntersections > intersections
Definition: mesh.h:254
double global_snap_radius() const
Maximal distance of observe point from Mesh relative to its size.
Definition: mesh.cc:1059
unsigned int max_edge_sides_[3]
Maximal number of sides per one edge in the actual mesh (set in make_neighbours_and_edges()).
Definition: mesh.h:481
Definition: mesh.h:78
unsigned int n_local_nodes() const
Definition: mesh.h:169
std::vector< EdgeData > edges
Vector of MH edges, this should not be part of the geometrical mesh.
Definition: mesh.h:540
Input::Record in_record_
Definition: mesh.h:505
std::string create_label_from_id(unsigned int id) const
Definition: region.cc:337
vector< vector< vector< unsigned int > > > side_nodes
Definition: mesh.h:287
SideIter side(const unsigned int loc_index)
int n_tetrahedras
Definition: mesh.h:275
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:347
virtual unsigned int n_nodes() const
Definition: mesh.h:126
vector< BoundaryData > boundary_
Definition: mesh.h:246
Boundary boundary(uint edge_idx) const
Definition: mesh.cc:260
void add_physical_name(unsigned int dim, unsigned int id, std::string name)
Add new node of given id and coordinates to mesh.
Definition: mesh.cc:1063
ArmaVec< Type, nr > vec(uint mat_index) const
Definition: armor.hh:807
int node_index(int node_id) const
For node of given node_id returns index in element_vec_ or (-1) if node doesn&#39;t exist.
Definition: mesh.h:365
ElementAccessor< 3 > element() const
Returns iterator to the element of the side.
virtual Partitioning * get_part()
Definition: mesh.cc:266
NodeAccessor< 3 > node(unsigned int ni) const
Definition: accessors.hh:200
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:304
Class for declaration of inputs sequences.
Definition: type_base.hh:339
virtual ElementAccessor< 3 > element_accessor(unsigned int idx) const
Create and return ElementAccessor to element of given idx.
Definition: mesh.cc:839
int n_exsides
Definition: mesh.h:270
void check_mesh_on_read()
Definition: mesh.cc:323
void init(unsigned int dim, RegionIdx reg)
Definition: elements.cc:52
IteratorBase end() const
const unsigned int * get_lsizes_array()
get local sizes array
Armor::Array< double > nodes_
Definition: mesh.h:534
Region get_region(unsigned int id, unsigned int dim)
Definition: region.cc:150
unsigned int dim() const
Definition: elements.h:121
static Default optional()
The factory function to make an empty default value which is optional.
Definition: type_record.hh:124
#define OLD_ASSERT(...)
Definition: global_defs.h:131
unsigned int n_vb_neighbours() const
Definition: mesh.cc:239
ElementAccessor< 3 > element()
Definition: neighbours.h:161
void open_stream(Stream &stream) const
Definition: file_path.cc:211
bool opt_val(const string &key, Ret &value) const
unsigned int edge_idx_
Index of Edge in Mesh.
Definition: neighbours.h:138
void read_regions_from_input(Input::Array region_list)
Definition: mesh.cc:1010
unsigned int boundary_loaded_size_
Count of boundary elements loaded from mesh file.
Definition: mesh.h:526
virtual Record & allow_auto_conversion(const string &from_key)
Allows shorter input of the Record providing only value of the from_key given as the parameter...
Definition: type_record.cc:133
bool same_sides(const SideIter &si, vector< unsigned int > &side_nodes)
Definition: mesh.cc:498
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:534
int find_elem_id(unsigned int pos) const
Return element id (in GMSH file) of element of given position in element vector.
Definition: mesh.h:359
unsigned int add_item(T val)
Add new item at the end position of map.
Mesh * mesh_
Definition: mesh_data.hh:54
unsigned int node_idx(unsigned int ni) const
Return index (in Mesh::node_vec) of ni-th node.
Definition: elements.h:72
void check_element_size(unsigned int elem_idx) const
Check if given index is in element_vec_.
Definition: mesh.cc:1171
void setup_topology()
Definition: mesh.cc:388
IntersectionSearch get_intersection_search()
Getter for input type selection for intersection search algorithm.
Definition: mesh.cc:154
Neighbour ** neigh_vb
Definition: elements.h:84
Region find_id(unsigned int id, unsigned int dim) const
Definition: region.cc:180
LongIdx * el_4_loc
Index set assigning to local element index its global index.
Definition: mesh.h:563
Range helper class.
friend class BCMesh
Definition: mesh.h:549
T get_root_interface() const
Returns the root accessor.
unsigned int edge_idx(unsigned int edg_idx) const
Return edge_idx of given index.
Definition: elements.h:136
friend class RegionSetBase
Definition: mesh.h:545
static const Input::Type::Selection & get_input_intersection_variant()
The definition of input record for selection of variant of file format.
Definition: mesh.cc:63
static FileName input()
The factory function for declaring type FileName for input files.
Definition: type_base.cc:524
SideIter side()
Definition: neighbours.h:145
Accessor to the data with type Type::Record.
Definition: accessors.hh:291
unsigned int edge_idx_
Definition: mesh_data.hh:49
#define NDEF
Definition: mesh.cc:59
const Ret val(const string &key) const
unsigned int n_sides() const
Definition: elements.h:132
#define xprintf(...)
Definition: system.hh:93
#define START_TIMER(tag)
Starts a timer with specified tag.
void reinit(uint size)
Definition: armor.hh:688
Class for O(log N) lookup for intersections with a set of bounding boxes.
Definition: bih_tree.hh:38
Selection & add_value(const int value, const std::string &key, const std::string &description="", TypeBase::attribute_map attributes=TypeBase::attribute_map())
Adds one new value with name given by key to the Selection.
unsigned int n_corners()
Definition: mesh.cc:244
LongIdx * row_4_el
Index set assigning to global element index the local index used in parallel vectors.
Definition: mesh.h:561
BoundingBox bounding_box() const
Definition: accessors.hh:208
Record & declare_key(const string &key, std::shared_ptr< TypeBase > type, const Default &default_value, const string &description, TypeBase::attribute_map key_attributes=TypeBase::attribute_map())
Declares a new key of the Record.
Definition: type_record.cc:503
void close()
Definition: region.cc:249
bool is_empty() const
Definition: accessors.hh:365
Region implicit_boundary_region()
Definition: region.cc:75
virtual Range< ElementAccessor< 3 > > elements_range() const
Returns range of bulk elements.
Definition: mesh.cc:1153
Element * add_element_to_vector(int id)
Adds element to mesh data structures (element_vec_, element_ids_), returns pointer to this element...
Definition: mesh.cc:1146
NodeAccessor< 3 > node(unsigned int idx) const
Create and return NodeAccessor to node of given idx.
Definition: mesh.cc:845
unsigned int np() const
get num of processors
unsigned int n_sides() const
Definition: mesh.cc:230
std::shared_ptr< BIHTree > bih_tree_
Definition: mesh.h:499
void swap(nlohmann::json &j1, nlohmann::json &j2) noexcept(is_nothrow_move_constructible< nlohmann::json >::value andis_nothrow_move_assignable< nlohmann::json >::value)
exchanges the values of two JSON objects
Definition: json.hpp:8688
vector< vector< unsigned int > > node_elements_
For each node the vector contains a list of elements that use this node.
Definition: mesh.h:350
NodeAccessor< 3 > node(unsigned int i) const
Returns node for given local index i on the side.
friend class Boundary
Definition: mesh.h:548
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:458
Region region() const
Definition: accessors.hh:165
void elements_id_maps(vector< LongIdx > &bulk_elements_id, vector< LongIdx > &boundary_elements_id) const
Definition: mesh.cc:851
void count_element_types()
Definition: mesh.cc:279
bool compare_points(const arma::vec3 &p1, const arma::vec3 &p2)
Definition: mesh.cc:884
const BIHTree & get_bih_tree()
Getter for BIH. Creates and compute BIH at first call.
Definition: mesh.cc:1050
void create_boundary_elements()
Create boundary elements from data of temporary structure, this method MUST be call after read mesh f...
Definition: mesh.cc:1261
#define MPI_Comm_rank
Definition: mpi.h:236
void check_regions()
Definition: region.cc:461
Dedicated class for storing path to input and output files.
Definition: file_path.hh:54
unsigned int myp() const
get my processor
Definition: system.hh:65
void mark_used_region(unsigned int idx)
Definition: region.cc:235
Support classes for parallel programing.
Region add_region(unsigned int id, const std::string &label, unsigned int dim, const std::string &address="implicit")
Definition: region.cc:85
vector< Neighbour > vb_neighbours_
Definition: mesh.h:267
int LongIdx
Define type that represents indices of large arrays (elements, nodes, dofs etc.)
Definition: index_types.hh:24
Distribution * node_ds_
Parallel distribution of nodes. Depends on elements distribution.
Definition: mesh.h:569
FinishStatus finish(FinishStatus finish_type=FinishStatus::regular_) override
Finish declaration of the Record type.
Definition: type_record.cc:243
virtual unsigned int n_elements(bool boundary=false) const
Returns count of boundary or bulk elements.
Definition: mesh.h:344
void distribute_nodes()
Fill array node_4_loc_ and create object node_ds_ according to element distribution.
Definition: mesh.cc:1313
void find_point(const Space< 3 >::Point &point, std::vector< unsigned int > &result_list, bool full_list=false) const
Definition: bih_tree.cc:287
int n_sides_
Definition: mesh.h:271
RegionIdx region_idx_
Definition: elements.h:107
Class represents boundary part of mesh.
Definition: bc_mesh.hh:35
#define ASSERT_PTR(ptr)
Definition of assert macro checking non-null pointer (PTR)
Definition: asserts.hh:336
const Selection & close() const
Close the Selection, no more values can be added.
RegionDB region_db_
Definition: mesh.h:490
MPI_Comm comm_
Definition: mesh.h:510
#define ASSERT_DBG(expr)
bool find_lower_dim_element(vector< unsigned int > &element_list, unsigned int dim, unsigned int &element_idx)
Definition: mesh.cc:478
int pid_
Id # of mesh partition.
Definition: elements.h:89
int n_insides
Definition: mesh.h:269
void print_region_table(std::ostream &stream) const
Definition: region.cc:409
void intersect_element_lists(vector< unsigned int > const &nodes_list, vector< unsigned int > &intersection_element_list)
Definition: mesh.cc:446
void modify_element_ids(const RegionDB::MapElementIDToRegionID &map)
Definition: mesh.cc:296
#define WarningOut()
Macro defining &#39;warning&#39; record of log.
Definition: logger.hh:270
#define MPI_COMM_WORLD
Definition: mpi.h:123
void make_edge_permutations()
Definition: mesh.cc:708
double tetrahedron_jacobian() const
Class RefElement defines numbering of vertices, sides, calculation of normal vectors etc...
static Input::Type::Abstract & get_input_type()
Definition: region_set.cc:25
Range< NodeAccessor< 3 > > node_range() const
Returns range of nodes.
Definition: mesh.cc:1159
SideIter * side_
Definition: mesh_data.hh:32
Edge edge(uint edge_idx) const
Definition: mesh.cc:254
const LongIdx * get_loc_part() const
Definition: partitioning.cc:85
void add_element(unsigned int elm_id, unsigned int dim, unsigned int region_id, unsigned int partition_id, std::vector< unsigned int > node_ids)
Add new element of given id to mesh.
Definition: mesh.cc:1075
#define print_var(var)
Definition: logger.hh:284
Record type proxy class.
Definition: type_record.hh:182
static const unsigned int undefined_dim
Definition: region.hh:332
bool is_valid() const
Returns false if the region has undefined/invalid value.
Definition: region.hh:78
IntersectionSearch
Types of search algorithm for finding intersection candidates.
Definition: mesh.h:93
void element_to_neigh_vb()
Definition: mesh.cc:789
void init_element(Element *ele, unsigned int elm_id, unsigned int dim, RegionIdx region_idx, unsigned int partition_id, std::vector< unsigned int > node_ids)
Initialize element.
Definition: mesh.cc:1098
friend class Edge
Definition: mesh.h:543
Mesh()
Definition: mesh.cc:100
static FileName output()
The factory function for declaring type FileName for input files.
Definition: type_base.cc:531
unsigned int n_neighs_vb_
of neighbours, V-B type (comp.)
Definition: elements.h:91
void permute_triangle(unsigned int elm_idx, std::vector< unsigned int > permutation_vec)
Permute nodes of 2D elements of given elm_idx.
Definition: mesh.cc:1290
#define DebugOut()
Macro defining &#39;debug&#39; record of log.
Definition: logger.hh:276
#define ASSERT_PTR_DBG(ptr)
Definition of assert macro checking non-null pointer (PTR) only for debug mode.
Definition: asserts.hh:340
unsigned int idx() const
Return local idx of element in boundary / bulk part of element vector.
Definition: accessors.hh:181
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
SideIter side(const unsigned int i) const
Gets side iterator of the i -th side.
void clear()
Clear the content. Do not release memory.
Range< Edge > edge_range() const
Returns range of edges.
Definition: mesh.cc:1165
Template for classes storing finite set of named values.
Implementation of range helper class.
unsigned int bulk_size_
Count of bulk elements.
Definition: mesh.h:523
std::shared_ptr< Partitioning > part_
Definition: mesh.h:494
void make_neighbours_and_edges()
Definition: mesh.cc:515
vector< ElementTmpData > bc_element_tmp_
Hold data of boundary elements during reading mesh (allow to preserve correct order during reading of...
Definition: mesh.h:520
Mesh * mesh_
Pointer to Mesh to which belonged.
Definition: neighbours.h:136
#define ASSERT_EQ(a, b)
Definition of comparative assert macro (EQual)
Definition: asserts.hh:328
void init_node_vector(unsigned int size)
Initialize node_vec_, set size.
Definition: mesh.cc:1139
unsigned int id() const
Returns id of the region (using RegionDB)
Definition: region.cc:37
Main class for computation of intersection of meshes of combined dimensions.
int find_node_id(unsigned int pos) const
Return node id (in GMSH file) of node of given position in node vector.
Definition: mesh.h:371
unsigned int n_nodes() const
Returns number of nodes of the side.
Definition: accessors.hh:407
virtual ~Mesh()
Destructor.
Definition: mesh.cc:205
unsigned int idx() const
Returns a global index of the region.
Definition: region.hh:82
#define ASSERT_LT_DBG(a, b)
Definition of comparative assert macro (Less Than) only for debug mode.
Definition: asserts.hh:300
unsigned int n_sides
Definition: mesh_data.hh:29