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