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