Flow123d  JS_before_hm-2210-gb57a0a528
dofhandler.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 dofhandler.cc
15  * @brief Declaration of class which handles the ordering of degrees of freedom (dof) and mappings between local and global dofs.
16  * @author Jan Stebel
17  */
18 
19 #include "system/index_types.hh"
20 #include "fem/dofhandler.hh"
21 #include "fem/finite_element.hh"
22 #include "fem/fe_system.hh"
23 #include "fem/dh_cell_accessor.hh"
24 #include "mesh/mesh.h"
25 #include "mesh/duplicate_nodes.h"
26 #include "mesh/partitioning.hh"
27 #include "mesh/accessors.hh"
28 #include "mesh/range_wrapper.hh"
29 #include "mesh/neighbours.h"
30 #include "la/distribution.hh"
31 
32 
36 const int DOFHandlerMultiDim::INVALID_DOF = -1;
37 
38 
39 
40 
42 {}
43 
44 
45 
46 
47 
48 
50  : DOFHandlerBase(_mesh),
51  ds_(nullptr),
52  is_parallel_(true),
53  dh_seq_(nullptr),
54  scatter_to_seq_(nullptr),
55  el_ds_(nullptr)
56 {
57  if (make_elem_part) make_elem_partitioning();
58 }
59 
60 
61 std::shared_ptr<DOFHandlerMultiDim> DOFHandlerMultiDim::sequential()
62 {
64  return dh_seq_;
65 }
66 
67 
68 std::shared_ptr<VecScatter> DOFHandlerMultiDim::sequential_scatter()
69 {
71  return scatter_to_seq_;
72 }
73 
74 
76 {
77  // get number of dofs per element and then set up cell_starts
79  for (auto cell : this->local_range())
80  {
81  cell_starts[cell.local_idx()+1] = cell.n_dofs();
82  max_elem_dofs_ = max( (int)max_elem_dofs_, (int)cell.n_dofs() );
83  }
84  for (unsigned int i=0; i<cell_starts.size()-1; ++i)
85  cell_starts[i+1] += cell_starts[i];
86 }
87 
88 
90  std::vector<LongIdx> &node_dof_starts,
91  std::vector<LongIdx> &edge_dof_starts)
92 {
93  // initialize dofs on nodes
94  // We must separate dofs for dimensions because FE functions
95  // may be discontinuous on nodes shared by different
96  // dimensions.
97  unsigned int n_node_dofs = 0;
98  for (unsigned int nid=0; nid<mesh_->duplicate_nodes()->n_nodes(); nid++)
99  {
100  node_dof_starts.push_back(n_node_dofs);
101  n_node_dofs += ds_->n_node_dofs(nid);
102  }
103  node_dof_starts.push_back(n_node_dofs);
104 
105  unsigned int n_edge_dofs = 0;
106  for (auto edge : mesh_->edge_range())
107  {
108  edge_dof_starts.push_back(n_edge_dofs);
109  n_edge_dofs += ds_->n_edge_dofs(edge);
110  }
111  edge_dof_starts.push_back(n_edge_dofs);
112 }
113 
114 
116  std::vector<short int> &node_status,
117  std::vector<short int> &edge_status)
118 {
119  // mark local dofs
120  for (auto cell : this->own_range())
121  {
122  for (unsigned int n=0; n<cell.dim()+1; n++)
123  {
124  unsigned int nid = mesh_->duplicate_nodes()->objects(cell.dim())[mesh_->duplicate_nodes()->obj_4_el()[cell.elm_idx()]].nodes[n];
125  node_status[nid] = VALID_NFACE;
126  }
127  }
128 
129  // unmark dofs on ghost cells from lower procs
130  for (auto cell : this->ghost_range())
131  {
132  if (cell.elm().proc() < el_ds_->myp())
133  {
134  for (unsigned int n=0; n<cell.dim()+1; n++)
135  {
136  unsigned int nid = mesh_->duplicate_nodes()->objects(cell.dim())[mesh_->duplicate_nodes()->obj_4_el()[cell.elm_idx()]].nodes[n];
137  node_status[nid] = INVALID_NFACE;
138  }
139  }
140  }
141 
142  // edges are defined only in Mesh, so for BCMesh we skip the following part
143  if (dynamic_cast<Mesh*>(mesh_) != nullptr)
144  {
145  // mark local edges
146  for (auto eid : edg_4_loc)
147  edge_status[eid] = VALID_NFACE;
148 
149  // unmark dofs on ghost cells from lower procs
150  for (auto cell : this->ghost_range())
151  {
152  if (cell.elm().proc() < el_ds_->myp())
153  {
154  for (unsigned int n=0; n<cell.dim()+1; n++)
155  {
156  unsigned int eid = cell.elm().side(n)->edge_idx();
157  edge_status[eid] = INVALID_NFACE;
158  }
159  }
160  }
161  }
162 }
163 
164 
166 {
167  // send number of elements required from the other processor
168  unsigned int n_elems = ghost_proc_el[proc].size();
169  MPI_Send(&n_elems, 1, MPI_UNSIGNED, proc, 0, MPI_COMM_WORLD);
170 
171  // send indices of elements required
172  MPI_Send(&(ghost_proc_el[proc][0]), n_elems, MPI_LONG_IDX, proc, 1, MPI_COMM_WORLD);
173 
174  // receive numbers of dofs on required elements
175  vector<unsigned int> n_dofs(n_elems);
176  MPI_Recv(&(n_dofs[0]), n_elems, MPI_UNSIGNED, proc, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
177 
178  // receive dofs on required elements
179  unsigned int n_dofs_sum = 0;
180  for (auto nd : n_dofs) n_dofs_sum += nd;
181  dofs.resize(n_dofs_sum);
182  MPI_Recv(&(dofs[0]), n_dofs_sum, MPI_LONG_IDX, proc, 3, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
183 }
184 
185 
186 void DOFHandlerMultiDim::send_ghost_dofs(unsigned int proc)
187 {
188  // receive number of elements required by the other processor
189  unsigned int n_elems;
190  MPI_Recv(&n_elems, 1, MPI_UNSIGNED, proc, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
191 
192  // receive indices of elements required
193  vector<LongIdx> elems(n_elems);
194  MPI_Recv(&(elems[0]), n_elems, MPI_LONG_IDX, proc, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
195 
196  // send numbers of dofs on required elements
197  vector<unsigned int> n_dofs;
198  for (LongIdx el : elems)
199  {
200  auto cell = this->cell_accessor_from_element(el);
201  n_dofs.push_back(cell_starts[cell.local_idx()+1] - cell_starts[cell.local_idx()]);
202  }
203  MPI_Send(&(n_dofs[0]), n_elems, MPI_UNSIGNED, proc, 2, MPI_COMM_WORLD);
204 
205  // send dofs on the required elements
206  vector<LongIdx> dofs;
207  for (LongIdx el : elems)
208  {
209  auto cell = this->cell_accessor_from_element(el);
210  for (LongIdx i=cell_starts[cell.local_idx()]; i<cell_starts[cell.local_idx()+1]; i++)
211  dofs.push_back(local_to_global_dof_idx_[dof_indices[i]]);
212  }
213  MPI_Send(&(dofs[0]), dofs.size(), MPI_LONG_IDX, proc, 3, MPI_COMM_WORLD);
214 }
215 
216 
218  const std::vector<bool> &update_cells,
219  const std::vector<LongIdx> &dofs,
220  const std::vector<LongIdx> &node_dof_starts,
221  std::vector<LongIdx> &node_dofs,
222  const std::vector<LongIdx> &edge_dof_starts,
223  std::vector<LongIdx> &edge_dofs)
224 {
225  // update dof_indices on ghost cells
226  unsigned int dof_offset=0;
227  for (unsigned int gid=0; gid<ghost_proc_el[proc].size(); gid++)
228  {
229  DHCellAccessor dh_cell = this->cell_accessor_from_element( ghost_proc_el[proc][gid] );
230 
231  vector<unsigned int> loc_node_dof_count(dh_cell.elm()->n_nodes(), 0);
232  vector<unsigned int> loc_edge_dof_count(dh_cell.elm()->n_sides(), 0);
233  for (unsigned int idof = 0; idof<dh_cell.n_dofs(); ++idof)
234  {
235  if (dh_cell.cell_dof(idof).dim == 0)
236  { // update nodal dof
237  unsigned int dof_nface_idx = dh_cell.cell_dof(idof).n_face_idx;
238  unsigned int nid = mesh_->duplicate_nodes()->objects(dh_cell.dim())[mesh_->duplicate_nodes()->obj_4_el()[dh_cell.elm_idx()]].nodes[dof_nface_idx];
239  unsigned int node_dof_idx = node_dof_starts[nid]+loc_node_dof_count[dof_nface_idx];
240 
241  if (node_dofs[node_dof_idx] == INVALID_DOF)
242  {
243  node_dofs[node_dof_idx] = local_to_global_dof_idx_.size();
244  local_to_global_dof_idx_.push_back(dofs[dof_offset+idof]);
245  }
246  dof_indices[cell_starts[dh_cell.local_idx()]+idof] = node_dofs[node_dof_idx];
247 
248  loc_node_dof_count[dof_nface_idx]++;
249  }
250  else if (dh_cell.cell_dof(idof).dim == dh_cell.dim()-1)
251  { // update edge dof
252  unsigned int dof_nface_idx = dh_cell.cell_dof(idof).n_face_idx;
253  unsigned int eid = dh_cell.elm().side(dof_nface_idx)->edge_idx();
254  unsigned int edge_dof_idx = edge_dof_starts[eid]+loc_edge_dof_count[dof_nface_idx];
255 
256  if (edge_dofs[edge_dof_idx] == INVALID_DOF)
257  {
258  edge_dofs[edge_dof_idx] = local_to_global_dof_idx_.size();
259  local_to_global_dof_idx_.push_back(dofs[dof_offset+idof]);
260  }
261  dof_indices[cell_starts[dh_cell.local_idx()]+idof] = edge_dofs[edge_dof_idx];
262 
263  loc_edge_dof_count[dof_nface_idx]++;
264  } else if (dh_cell.cell_dof(idof).dim == dh_cell.dim())
265  {
266  dof_indices[cell_starts[dh_cell.local_idx()]+idof] = local_to_global_dof_idx_.size();
267  local_to_global_dof_idx_.push_back(dofs[dof_offset+idof]);
268  }
269  }
270 
271  dof_offset += dh_cell.n_dofs();
272  }
273 
274  // update dof_indices on local elements
275  for (auto cell : this->own_range())
276  {
277  if (!update_cells[cell.local_idx()]) continue;
278 
279  // loop over element dofs
280  vector<unsigned int> loc_node_dof_count(cell.elm()->n_nodes(), 0);
281  vector<unsigned int> loc_edge_dof_count(cell.elm()->n_sides(), 0);
282  for (unsigned int idof = 0; idof<cell.n_dofs(); ++idof)
283  {
284  unsigned int dof_nface_idx = cell.cell_dof(idof).n_face_idx;
285  if (cell.cell_dof(idof).dim == 0)
286  {
287  if (dof_indices[cell_starts[cell.local_idx()]+idof] == INVALID_DOF)
288  { // update nodal dof
289  unsigned int nid = mesh_->duplicate_nodes()->objects(cell.dim())[mesh_->duplicate_nodes()->obj_4_el()[cell.elm_idx()]].nodes[dof_nface_idx];
290  dof_indices[cell_starts[cell.local_idx()]+idof] = node_dofs[node_dof_starts[nid]+loc_node_dof_count[dof_nface_idx]];
291  }
292  loc_node_dof_count[dof_nface_idx]++;
293  } else if (cell.cell_dof(idof).dim == cell.dim()-1)
294  {
295  if (dof_indices[cell_starts[cell.local_idx()]+idof] == INVALID_DOF)
296  { // update edge dof
297  unsigned int eid = cell.elm().side(dof_nface_idx)->edge_idx();
298  dof_indices[cell_starts[cell.local_idx()]+idof] = edge_dofs[edge_dof_starts[eid]+loc_edge_dof_count[dof_nface_idx]];
299  }
300  loc_edge_dof_count[dof_nface_idx]++;
301  }
302  }
303  }
304 }
305 
306 
307 void DOFHandlerMultiDim::distribute_dofs(std::shared_ptr<DiscreteSpace> ds)
308 {
309  // First check if dofs are already distributed.
310  ASSERT_PERMANENT(ds_ == nullptr).error("Attempt to distribute DOFs multiple times!");
311 
312  ds_ = ds;
313 
314  std::vector<LongIdx> node_dofs, node_dof_starts, edge_dofs, edge_dof_starts;
316  edge_status(mesh_->n_edges(), INVALID_NFACE);
317  std::vector<bool> update_cells(el_ds_->lsize(), false);
318  unsigned int next_free_dof = 0;
319 
321  init_dof_starts(node_dof_starts, edge_dof_starts);
322  node_dofs.resize(node_dof_starts[node_dof_starts.size()-1], (LongIdx)INVALID_DOF);
323  edge_dofs.resize(edge_dof_starts[edge_dof_starts.size()-1], (LongIdx)INVALID_DOF);
324  init_status(node_status, edge_status);
325 
326  // Distribute dofs on local elements.
327  dof_indices.resize(cell_starts[cell_starts.size()-1]);
328  local_to_global_dof_idx_.reserve(dof_indices.size());
329  for (auto cell : this->own_range())
330  {
331 
332  // loop over element dofs
333  vector<unsigned int> loc_node_dof_count(cell.elm()->n_nodes(), 0);
334  vector<unsigned int> loc_edge_dof_count(cell.elm()->dim()+1, 0);
335  for (unsigned int idof = 0; idof<cell.n_dofs(); ++idof)
336  {
337  unsigned int dof_dim = cell.cell_dof(idof).dim;
338  unsigned int dof_nface_idx = cell.cell_dof(idof).n_face_idx;
339 
340  if (dof_dim == 0)
341  { // add dofs shared by nodes
342  unsigned int nid = mesh_->duplicate_nodes()->objects(cell.dim())[mesh_->duplicate_nodes()->obj_4_el()[cell.elm_idx()]].nodes[dof_nface_idx];
343  unsigned int node_dof_idx = node_dof_starts[nid]+loc_node_dof_count[dof_nface_idx];
344 
345  switch (node_status[nid])
346  {
347  case VALID_NFACE:
348  for (int i=0; i<node_dof_starts[nid+1] - node_dof_starts[nid]; i++)
349  {
350  local_to_global_dof_idx_.push_back(next_free_dof);
351  node_dofs[node_dof_starts[nid]+i] = next_free_dof++;
352  }
353  node_status[nid] = ASSIGNED_NFACE;
354  break;
355  case INVALID_NFACE:
356  node_dofs[node_dof_idx] = INVALID_DOF;
357  update_cells[cell.local_idx()] = true;
358  break;
359  }
360  dof_indices[cell_starts[cell.local_idx()]+idof] = node_dofs[node_dof_idx];
361  loc_node_dof_count[dof_nface_idx]++;
362  }
363  else if (dof_dim == cell.dim()-1)
364  { // add dofs shared by edges
365  unsigned int eid = cell.elm().side(dof_nface_idx)->edge_idx();
366  unsigned int edge_dof_idx = edge_dof_starts[eid]+loc_edge_dof_count[dof_nface_idx];
367  switch (edge_status[eid])
368  {
369  case VALID_NFACE:
370  for (int i=0; i<edge_dof_starts[eid+1] - edge_dof_starts[eid]; i++)
371  {
372  local_to_global_dof_idx_.push_back(next_free_dof);
373  edge_dofs[edge_dof_starts[eid]+i] = next_free_dof++;
374  }
375  edge_status[eid] = ASSIGNED_NFACE;
376  break;
377  case INVALID_NFACE:
378  edge_dofs[edge_dof_idx] = INVALID_DOF;
379  update_cells[cell.local_idx()] = true;
380  break;
381  }
382  dof_indices[cell_starts[cell.local_idx()]+idof] = edge_dofs[edge_dof_idx];
383  loc_edge_dof_count[dof_nface_idx]++;
384  }
385  else if (dof_dim == cell.dim())
386  { // add dofs owned only by the element
387  local_to_global_dof_idx_.push_back(next_free_dof);
388  dof_indices[cell_starts[cell.local_idx()]+idof] = next_free_dof++;
389  }
390  else
391  ASSERT_PERMANENT(false).error("Unsupported dof n_face.");
392  }
393  }
394  node_status.clear();
395  edge_status.clear();
396 
397  lsize_ = next_free_dof;
398 
399  // communicate n_dofs across all processes
400  dof_ds_ = std::make_shared<Distribution>(lsize_, PETSC_COMM_WORLD);
401  n_global_dofs_ = dof_ds_->size();
402 
403  // shift dof indices
404  loffset_ = dof_ds_->get_starts_array()[dof_ds_->myp()];
405  if (loffset_ > 0)
406  {
407  for (auto &i : local_to_global_dof_idx_)
408  i += loffset_;
409  }
410 
411  // communicate dofs from ghost cells
412  // first propagate from lower procs to higher procs and then vice versa
413  for (unsigned int from_higher = 0; from_higher < 2; from_higher++)
414  {
415  for (unsigned int proc : ghost_proc)
416  {
417  if ((proc > el_ds_->myp()) == from_higher)
418  { // receive dofs from master processor
419  vector<LongIdx> dofs;
420  receive_ghost_dofs(proc, dofs);
421 
422  // update dof_indices and node_dofs on ghost elements
423  update_local_dofs(proc,
424  update_cells,
425  dofs,
426  node_dof_starts,
427  node_dofs,
428  edge_dof_starts,
429  edge_dofs
430  );
431 
432  }
433  else
434  send_ghost_dofs(proc);
435  }
436  }
437  update_cells.clear();
438  node_dofs.clear();
439  node_dof_starts.clear();
440  edge_dofs.clear();
441  edge_dof_starts.clear();
442 }
443 
444 
446 {
447  if (dh_seq_ != nullptr) return;
448 
449  if ( !is_parallel_ )
450  {
451  dh_seq_ = std::make_shared<DOFHandlerMultiDim>(*this);
452  return;
453  }
454 
455  dh_seq_ = std::make_shared<DOFHandlerMultiDim>(*mesh_);
456 
457  dh_seq_->n_global_dofs_ = n_global_dofs_;
458  dh_seq_->lsize_ = n_global_dofs_;
459  dh_seq_->loffset_ = 0;
460  dh_seq_->mesh_ = mesh_;
461  dh_seq_->dof_ds_ = dof_ds_; // should be sequential distribution
462  dh_seq_->ds_ = ds_;
463  dh_seq_->is_parallel_ = false;
464  for (unsigned int i=0; i<n_global_dofs_; i++) dh_seq_->local_to_global_dof_idx_.push_back(i);
465 
468  &dh_seq_->max_elem_dofs_,
469  1,
470  MPI_UNSIGNED,
471  MPI_MAX,
473 
474  for (unsigned int i=0; i<mesh_->n_elements(); i++) dh_seq_->global_to_local_el_idx_[i] = mesh_->get_row_4_el()[i];
475 
476  // Auxiliary vectors cell_starts_loc and dof_indices_loc contain
477  // only local element data (without ghost elements).
478  // Then it is possible to create sequential vectors by simple reduce/gather operation.
479  vector<LongIdx> cell_starts_loc(mesh_->n_elements()+1, 0);
480  vector<LongIdx> dof_indices_loc;
481 
482  // construct cell_starts_loc
483  for (auto cell : this->own_range())
484  {
485  cell_starts_loc[mesh_->get_row_4_el()[cell.elm_idx()]+1] = cell.n_dofs();
486  }
487  for (unsigned int i=0; i<mesh_->n_elements(); ++i)
488  cell_starts_loc[i+1] += cell_starts_loc[i];
489 
490  // construct dof_indices_loc
491  dof_indices_loc.resize(cell_starts_loc[mesh_->n_elements()]);
492  for (auto cell : this->own_range())
493  {
494  for (unsigned int idof=0; idof<cell.n_dofs(); idof++)
495  dof_indices_loc[cell_starts_loc[mesh_->get_row_4_el()[cell.elm_idx()]]+idof] = local_to_global_dof_idx_[dof_indices[cell_starts[cell.local_idx()]+idof]];
496  }
497 
498  Distribution distr(dof_indices_loc.size(), PETSC_COMM_WORLD);
499  dh_seq_->cell_starts.resize(mesh_->n_elements()+1);
500  dh_seq_->dof_indices.resize(distr.size());
501 
502  MPI_Allreduce( cell_starts_loc.data(),
503  dh_seq_->cell_starts.data(),
504  cell_starts_loc.size(),
505  MPI_LONG_IDX,
506  MPI_SUM,
507  MPI_COMM_WORLD );
508 
509  MPI_Allgatherv( dof_indices_loc.data(),
510  dof_indices_loc.size(),
511  MPI_LONG_IDX,
512  dh_seq_->dof_indices.data(),
513  (const int *)distr.get_lsizes_array(),
514  (const int *)distr.get_starts_array(),
515  MPI_LONG_IDX,
516  MPI_COMM_WORLD );
517 
518  // create scatter from parallel to sequential vector
519  Vec v_from;
520  VecCreateMPI(PETSC_COMM_WORLD, lsize_, PETSC_DETERMINE, &v_from);
521  scatter_to_seq_ = std::make_shared<VecScatter>();
522  VecScatterCreateToAll(v_from, scatter_to_seq_.get(), NULL);
523  VecDestroy(&v_from);
524 
525  // create scatter for sequential dof handler (Warning: not tested)
526  Vec v_seq;
527  VecCreateSeq(PETSC_COMM_SELF, n_global_dofs_, &v_seq);
528  dh_seq_->scatter_to_seq_ = std::make_shared<VecScatter>();
529  VecScatterCreateToAll(v_seq, dh_seq_->scatter_to_seq_.get(), NULL);
530  VecDestroy(&v_seq);
531 }
532 
533 
535 {
536  if (is_parallel_ && el_ds_->np() > 1)
537  { // for parallel DH create vector with ghost values
539  VectorMPI vec(lsize_, ghost_dofs);
540  return vec;
541  } else {
542  VectorMPI vec(lsize_, PETSC_COMM_SELF);
543  return vec;
544  }
545 }
546 
547 
549 {
550  unsigned int ndofs = 0;
551  ndofs = cell_starts[cell.local_idx()+1]-cell_starts[cell.local_idx()];
552  indices.resize(ndofs);
553  for (unsigned int k=0; k<ndofs; k++)
555 
556  return ndofs;
557 }
558 
559 
561 {}
562 
563 
564 
566 {
567  // create local arrays of elements
568  el_ds_ = mesh_->get_el_ds();
569 
570  // create local array of edges
571  for (auto edge : mesh_->edge_range())
572  {
573  bool is_edge_local = false;
574  for (uint sid=0; sid<edge.n_sides(); sid++)
575  if ( el_is_local(edge.side(sid)->element().idx()) )
576  {
577  is_edge_local = true;
578  break;
579  }
580  if (is_edge_local)
581  edg_4_loc.push_back(edge.idx());
582  }
583 
584  // create local array of neighbours
585  for (unsigned int inb=0; inb<mesh_->n_vb_neighbours(); inb++)
586  {
587  const Neighbour *nb = &mesh_->vb_neighbour(inb);
588  if ( el_is_local(nb->element().idx())
589  || el_is_local(nb->side()->element().idx()) )
590  nb_4_loc.push_back(inb);
591  }
592 
593  // init global to local element map with locally owned elements (later add ghost elements)
594  for ( unsigned int iel = 0; iel < el_ds_->lsize(); iel++ )
596 
597  // create array of local nodes
598  std::vector<bool> node_is_local(mesh_->duplicate_nodes()->n_nodes(), false);
599  for (auto cell : this->own_range())
600  {
601  unsigned int obj_idx = mesh_->duplicate_nodes()->obj_4_el()[cell.elm_idx()];
602  for (unsigned int nid=0; nid<cell.elm()->n_nodes(); nid++)
603  node_is_local[mesh_->duplicate_nodes()->objects(cell.dim())[obj_idx].nodes[nid]] = true;
604  }
605 
606  // create array of local ghost cells
607  for ( auto cell : mesh_->elements_range() )
608  {
609  if (cell.proc() != el_ds_->myp())
610  {
611  bool has_local_node = false;
612  unsigned int obj_idx = mesh_->duplicate_nodes()->obj_4_el()[cell.idx()];
613  for (unsigned int nid=0; nid<cell->n_nodes(); nid++)
614  if (node_is_local[mesh_->duplicate_nodes()->objects(cell->dim())[obj_idx].nodes[nid]])
615  {
616  has_local_node = true;
617  break;
618  }
619  if (has_local_node)
620  {
621  ghost_4_loc.push_back(cell.idx());
622  ghost_proc.insert(cell.proc());
623  ghost_proc_el[cell.proc()].push_back(cell.idx());
624  global_to_local_el_idx_[cell.idx()] = el_ds_->lsize() - 1 + ghost_4_loc.size();
625  }
626  }
627  }
628  for (auto nb : nb_4_loc)
629  {
630  auto cell = mesh_->vb_neighbour(nb).element();
631  if (!el_is_local(cell.idx()) && find(ghost_4_loc.begin(), ghost_4_loc.end(), cell.idx()) == ghost_4_loc.end())
632  {
633  ghost_4_loc.push_back(cell.idx());
634  ghost_proc.insert(cell.proc());
635  ghost_proc_el[cell.proc()].push_back(cell.idx());
636  global_to_local_el_idx_[cell.idx()] = el_ds_->lsize() - 1 + ghost_4_loc.size();
637  }
638  cell = mesh_->vb_neighbour(nb).side()->element();
639  if (!el_is_local(cell.idx()) && find(ghost_4_loc.begin(), ghost_4_loc.end(), cell.idx()) == ghost_4_loc.end())
640  {
641  ghost_4_loc.push_back(cell.idx());
642  ghost_proc.insert(cell.proc());
643  ghost_proc_el[cell.proc()].push_back(cell.idx());
644  global_to_local_el_idx_[cell.idx()] = el_ds_->lsize() - 1 + ghost_4_loc.size();
645  }
646  }
647 }
648 
649 
650 bool DOFHandlerMultiDim::el_is_local(int index) const
651 {
652  return el_ds_->is_local(mesh_->get_row_4_el()[index]);
653 }
654 
655 
656 std::size_t DOFHandlerMultiDim::hash() const {
657  return this->n_global_dofs_;
658 }
659 
660 
662  auto bgn_it = make_iter<DHCellAccessor>( DHCellAccessor(this, 0) );
663  auto end_it = make_iter<DHCellAccessor>( DHCellAccessor(this, el_ds_->lsize()) );
664  return Range<DHCellAccessor>(bgn_it, end_it);
665 }
666 
667 
669  auto bgn_it = make_iter<DHCellAccessor>( DHCellAccessor(this, 0) );
670  auto end_it = make_iter<DHCellAccessor>( DHCellAccessor(this, el_ds_->lsize()+ghost_4_loc.size()) );
671  return Range<DHCellAccessor>(bgn_it, end_it);
672 }
673 
674 
676  auto bgn_it = make_iter<DHCellAccessor>( DHCellAccessor(this, el_ds_->lsize()) );
677  auto end_it = make_iter<DHCellAccessor>( DHCellAccessor(this, el_ds_->lsize()+ghost_4_loc.size()) );
678  return Range<DHCellAccessor>(bgn_it, end_it);
679 }
680 
681 
683  auto map_it = global_to_local_el_idx_.find((LongIdx)elm_idx); // find in global to local map
684  ASSERT( map_it != global_to_local_el_idx_.end() )(elm_idx).error("DH accessor can be create only for own or ghost elements!\n");
685  return DHCellAccessor(this, map_it->second);
686 }
687 
688 
690  stringstream s;
692 
693  s << "DOFHandlerMultiDim structure:" << endl;
694  s << "- is parallel: " << (is_parallel_?"true":"false") << endl;
695  s << "- proc id: " << el_ds_->myp() << endl;
696  s << "- global number of dofs: " << n_global_dofs_ << endl;
697  s << "- number of locally owned cells: " << el_ds_->lsize() << endl;
698  s << "- number of ghost cells: " << ghost_4_loc.size() << endl;
699  s << "- dofs on locally owned cells:" << endl;
700 
701  for (auto cell : own_range())
702  {
703  auto ndofs = cell.get_dof_indices(dofs);
704  s << "-- cell " << cell.elm().idx() << ": ";
705  for (unsigned int idof=0; idof<ndofs; idof++) s << dofs[idof] << " "; s << endl;
706  }
707  s << "- dofs on ghost cells:" << endl;
708  for (auto cell : ghost_range())
709  {
710  auto ndofs = cell.get_dof_indices(dofs);
711  s << "-- cell " << cell.elm().idx() << ": ";
712  for (unsigned int idof=0; idof<ndofs; idof++) s << dofs[idof] << " "; s << endl;
713  }
714  s << "- locally owned dofs (" << lsize_ << "): ";
715  for (unsigned int i=0; i<lsize_; i++) s << local_to_global_dof_idx_[i] << " "; s << endl;
716  s << "- ghost dofs (" << local_to_global_dof_idx_.size() - lsize_ << "): ";
717  for (unsigned int i=lsize_; i<local_to_global_dof_idx_.size(); i++) s << local_to_global_dof_idx_[i] << " "; s << endl;
718  s << "- global-to-local-cell map:" << endl;
719  for (auto cell : global_to_local_el_idx_) s << "-- " << cell.first << " -> " << cell.second << " " << endl;
720  s << endl;
721 
722  printf("%s", s.str().c_str());
723 }
724 
725 
726 
727 
728 
729 
730 
731 
732 
733 SubDOFHandlerMultiDim::SubDOFHandlerMultiDim(std::shared_ptr<DOFHandlerMultiDim> dh, unsigned int component_idx)
734 : DOFHandlerMultiDim(*dh->mesh()),
735  parent_(dh),
736  fe_idx_(component_idx)
737 {
738  // create discrete space, we assume equal type of FE on each cell.
739  ASSERT( dynamic_cast<EqualOrderDiscreteSpace *>(dh->ds().get()) != nullptr )
740  .error("sub_handler can be used only with dof handler using EqualOrderDiscreteSpace!");
741  FESystem<0> *fe_sys0 = dynamic_cast<FESystem<0>*>( dh->ds()->fe()[0_d].get() );
742  FESystem<1> *fe_sys1 = dynamic_cast<FESystem<1>*>( dh->ds()->fe()[1_d].get() );
743  FESystem<2> *fe_sys2 = dynamic_cast<FESystem<2>*>( dh->ds()->fe()[2_d].get() );
744  FESystem<3> *fe_sys3 = dynamic_cast<FESystem<3>*>( dh->ds()->fe()[3_d].get() );
745  ASSERT( fe_sys0 != nullptr ).error("sub_handler assumes that dof handler uses FESystem<0>!");
746  ASSERT( fe_sys1 != nullptr ).error("sub_handler assumes that dof handler uses FESystem<1>!");
747  ASSERT( fe_sys2 != nullptr ).error("sub_handler assumes that dof handler uses FESystem<2>!");
748  ASSERT( fe_sys3 != nullptr ).error("sub_handler assumes that dof handler uses FESystem<3>!");
749  MixedPtr<FiniteElement> sub_mixed(fe_sys0->fe()[component_idx],
750  fe_sys1->fe()[component_idx],
751  fe_sys2->fe()[component_idx],
752  fe_sys3->fe()[component_idx]);
753  ds_ = std::make_shared<EqualOrderDiscreteSpace>( mesh_, sub_mixed);
754 
755  is_parallel_ = dh->is_parallel_;
756 
757  // create list of dofs for sub_dh on one cell
758  FESystemFunctionSpace *fs[4] = {
759  dynamic_cast<FESystemFunctionSpace*>( fe_sys0->function_space_.get() ),
760  dynamic_cast<FESystemFunctionSpace*>( fe_sys1->function_space_.get() ),
761  dynamic_cast<FESystemFunctionSpace*>( fe_sys2->function_space_.get() ),
762  dynamic_cast<FESystemFunctionSpace*>( fe_sys3->function_space_.get() ) };
763  for (unsigned int d=0; d<=3; d++)
764  ASSERT( fs[d] != nullptr ).error("Function space must be of type FESystemFunctionSpace!" );
765  vector<unsigned int> sub_fe_dofs[4];
766  for (unsigned int i=0; i<fe_sys0->n_dofs(); i++)
767  if (fs[0]->dof_indices()[i].fe_index == component_idx) sub_fe_dofs[0].push_back(i);
768  for (unsigned int i=0; i<fe_sys1->n_dofs(); i++)
769  if (fs[1]->dof_indices()[i].fe_index == component_idx) sub_fe_dofs[1].push_back(i);
770  for (unsigned int i=0; i<fe_sys2->n_dofs(); i++)
771  if (fs[2]->dof_indices()[i].fe_index == component_idx) sub_fe_dofs[2].push_back(i);
772  for (unsigned int i=0; i<fe_sys3->n_dofs(); i++)
773  if (fs[3]->dof_indices()[i].fe_index == component_idx) sub_fe_dofs[3].push_back(i);
774 
776  dof_indices.resize(cell_starts[cell_starts.size()-1]);
777  // sub_local_indices maps local dofs of parent handler to local dofs of sub-handler
778  vector<LongIdx> sub_local_indices(dh->local_to_global_dof_idx_.size(), INVALID_DOF);
779  map<LongIdx,LongIdx> global_to_local_dof_idx;
780  // first add owned dofs to local_to_global_dof_idx_ and sub_local_indices
781  for (auto cell : dh->local_range())
782  {
783  LocDofVec cell_dof_indices = cell.get_loc_dof_indices();
784  for (auto sub_dof : sub_fe_dofs[cell.dim()])
785  {
786  if (cell_dof_indices[sub_dof] < static_cast<int>(dh->lsize_) &&
787  sub_local_indices[cell_dof_indices[sub_dof]] == INVALID_DOF)
788  {
789  sub_local_indices[cell_dof_indices[sub_dof]] = local_to_global_dof_idx_.size();
790  parent_dof_idx_.push_back(cell_dof_indices[sub_dof]);
791  global_to_local_dof_idx[parent_->local_to_global_dof_idx_[cell_dof_indices[sub_dof]]] = local_to_global_dof_idx_.size();
793  }
794  }
795  }
797  // then do the same for ghost dofs and set dof_indices
798  for (auto cell : dh->local_range())
799  {
800  LocDofVec cell_dof_indices = cell.get_loc_dof_indices();
801  unsigned int idof = 0;
802  for (auto sub_dof : sub_fe_dofs[cell.dim()])
803  {
804  if (sub_local_indices[cell_dof_indices[sub_dof]] == INVALID_DOF)
805  {
806  sub_local_indices[cell_dof_indices[sub_dof]] = local_to_global_dof_idx_.size();
807  parent_dof_idx_.push_back(cell_dof_indices[sub_dof]);
808  // temporarily we keep the global dof idx of parent dh, we replace it later from the owning processor
809  local_to_global_dof_idx_.push_back(parent_->local_to_global_dof_idx_[cell_dof_indices[sub_dof]]);
810  }
811  dof_indices[cell_starts[cell.local_idx()]+idof++] = sub_local_indices[cell_dof_indices[sub_dof]];
812  }
813  }
814 
815  dof_ds_ = std::make_shared<Distribution>(lsize_, PETSC_COMM_WORLD);
816  n_global_dofs_ = dof_ds_->size();
817  loffset_ = dof_ds_->get_starts_array()[dof_ds_->myp()];
818 
819  // shift dof indices
820  if (loffset_ > 0)
821  for (unsigned int i=0; i<lsize_; i++)
823 
824  // communicate ghost values
825  // first propagate from lower procs to higher procs and then vice versa
826  for (unsigned int from_higher = 0; from_higher < 2; from_higher++)
827  {
828  for (unsigned int proc : ghost_proc)
829  {
830  if ((proc > el_ds_->myp()) == from_higher)
831  { // receive dofs from master processor
832  vector<LongIdx> dofs;
833  receive_sub_ghost_dofs(proc, dofs);
834  }
835  else
836  send_sub_ghost_dofs(proc, global_to_local_dof_idx);
837  }
838  }
839 }
840 
841 
843 {
844  // send number of ghost dofs required from the other processor
846  for (unsigned int i=lsize_; i<local_to_global_dof_idx_.size(); i++)
847  if (parent_->dof_ds_->get_proc(parent_->local_to_global_dof_idx_[parent_dof_idx_[i]]) == proc)
848  dof_indices.push_back(parent_->local_to_global_dof_idx_[parent_dof_idx_[i]]);
849  unsigned int n_ghosts = dof_indices.size();
850  MPI_Send(&n_ghosts, 1, MPI_UNSIGNED, proc, 0, MPI_COMM_WORLD);
851 
852  // send indices of dofs required
853  MPI_Send(dof_indices.data(), n_ghosts, MPI_LONG_IDX, proc, 1, MPI_COMM_WORLD);
854 
855  // receive dofs
856  dofs.resize(n_ghosts);
857  MPI_Recv(dofs.data(), n_ghosts, MPI_LONG_IDX, proc, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
858 
859  // update ghost dofs
860  unsigned int idof = 0;
861  for (unsigned int i=lsize_; i<local_to_global_dof_idx_.size(); i++)
862  if (parent_->dof_ds_->get_proc(parent_->local_to_global_dof_idx_[parent_dof_idx_[i]]) == proc)
863  local_to_global_dof_idx_[i] = dofs[idof++];
864 }
865 
866 
867 void SubDOFHandlerMultiDim::send_sub_ghost_dofs(unsigned int proc, const map<LongIdx,LongIdx> &global_to_local_dof_idx)
868 {
869  // receive number of dofs required by the other processor
870  unsigned int n_ghosts;
871  MPI_Recv(&n_ghosts, 1, MPI_UNSIGNED, proc, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
872 
873  // receive global indices of dofs required
874  vector<LongIdx> dof_indices(n_ghosts);
876 
877  // send global dof indices relative to the sub-handler
878  vector<LongIdx> dofs;
879  for (auto global_dof : dof_indices)
880  dofs.push_back(global_to_local_dof_idx.at(global_dof) + dof_ds_->begin());
881  MPI_Send(dofs.data(), dofs.size(), MPI_LONG_IDX, proc, 2, MPI_COMM_WORLD);
882 }
883 
884 
886 {
887  ASSERT( vec.size() == parent_->local_to_global_dof_idx_.size() ).error("Incompatible parent vector in update_subvector()!");
888  ASSERT( subvec.size() == local_to_global_dof_idx_.size() ).error("Incompatible subvector in update_subvector()!");
889 
890  for (unsigned int i=0; i<parent_dof_idx_.size(); i++)
891  subvec.set( i, vec.get(parent_dof_idx_[i]) );
892 }
893 
894 
896 {
897  ASSERT( vec.size() == parent_->local_to_global_dof_idx_.size() ).error("Incompatible parent vector in update_subvector()!");
898  ASSERT( subvec.size() == local_to_global_dof_idx_.size() ).error("Incompatible subvector in update_subvector()!");
899 
900  for (unsigned int i=0; i<parent_dof_idx_.size(); i++)
901  vec.set( parent_dof_idx_[i], subvec.get(i) );
902 }
903 
904 
905 
906 
907 
908 
909 
910 
911 
MeshBase::get_row_4_el
LongIdx * get_row_4_el() const
Definition: mesh.h:125
DOFHandlerMultiDim::ghost_range
Range< DHCellAccessor > ghost_range() const
Returns range over ghosts DOF handler cells.
Definition: dofhandler.cc:675
LocDofVec
arma::Col< IntIdx > LocDofVec
Definition: index_types.hh:28
DOFHandlerMultiDim::local_to_global_dof_idx_
std::vector< LongIdx > local_to_global_dof_idx_
Maps local and ghost dof indices to global ones.
Definition: dofhandler.hh:435
Distribution::np
unsigned int np() const
get num of processors
Definition: distribution.hh:105
DOFHandlerMultiDim::INVALID_DOF
static const int INVALID_DOF
Definition: dofhandler.hh:389
Dof::n_face_idx
unsigned int n_face_idx
Index of n-face to which the dof is associated.
Definition: finite_element.hh:95
Armor::vec
ArmaVec< double, N > vec
Definition: armor.hh:885
DOFHandlerMultiDim::global_to_local_el_idx_
std::unordered_map< LongIdx, LongIdx > global_to_local_el_idx_
Maps global element index into local/ghost index (obsolete).
Definition: dofhandler.hh:440
DOFHandlerMultiDim::ghost_proc
set< unsigned int > ghost_proc
Processors of ghost elements.
Definition: dofhandler.hh:455
Distribution::lsize
unsigned int lsize(int proc) const
get local size
Definition: distribution.hh:115
neighbours.h
DOFHandlerMultiDim::ds
std::shared_ptr< DiscreteSpace > ds() const
Return pointer to discrete space for which the handler distributes dofs.
Definition: dofhandler.hh:255
Distribution::myp
unsigned int myp() const
get my processor
Definition: distribution.hh:107
ASSERT
#define ASSERT(expr)
Definition: asserts.hh:350
DOFHandlerMultiDim::SubDOFHandlerMultiDim
friend class SubDOFHandlerMultiDim
Definition: dofhandler.hh:268
MeshBase::get_el_ds
Distribution * get_el_ds() const
Definition: mesh.h:119
distribution.hh
Support classes for parallel programing.
DuplicateNodes::obj_4_el
const std::vector< unsigned int > & obj_4_el() const
Definition: duplicate_nodes.h:110
MPI_MAX
#define MPI_MAX
Definition: mpi.h:197
FESystemFunctionSpace
Definition: fe_system.hh:55
DOFHandlerBase::mesh_
MeshBase * mesh_
Pointer to the mesh to which the dof handler is associated.
Definition: dofhandler.hh:126
SubDOFHandlerMultiDim::update_subvector
void update_subvector(const VectorMPI &vec, VectorMPI &subvec)
Update values in subvector from parent vector.
Definition: dofhandler.cc:885
MeshBase::n_edges
unsigned int n_edges() const
Definition: mesh.h:114
DOFHandlerMultiDim::ghost_4_loc
vector< LongIdx > ghost_4_loc
Indices of ghost cells (neighbouring with local elements).
Definition: dofhandler.hh:452
std::vector< LongIdx >
Neighbour::side
SideIter side() const
Definition: neighbours.h:147
MPI_Send
#define MPI_Send(buf, count, datatype, dest, tag, comm)
Definition: mpi.h:263
DOFHandlerBase::~DOFHandlerBase
virtual ~DOFHandlerBase()
Destructor.
Definition: dofhandler.cc:41
DHCellAccessor::dim
unsigned int dim() const
Return dimension of element appropriate to cell.
Definition: dh_cell_accessor.hh:101
DOFHandlerMultiDim::el_ds_
Distribution * el_ds_
Distribution of elements.
Definition: dofhandler.hh:443
dofhandler.hh
Declaration of class which handles the ordering of degrees of freedom (dof) and mappings between loca...
uint
unsigned int uint
Definition: mh_dofhandler.hh:101
DOFHandlerMultiDim::local_range
Range< DHCellAccessor > local_range() const
Returns range over own and ghost cells of DOF handler.
Definition: dofhandler.cc:668
DOFHandlerMultiDim::ghost_proc_el
map< unsigned int, vector< LongIdx > > ghost_proc_el
Arrays of ghost cells for each neighbouring processor.
Definition: dofhandler.hh:458
duplicate_nodes.h
Neighbour
Definition: neighbours.h:117
MeshBase::elements_range
Range< ElementAccessor< 3 > > elements_range() const
Returns range of mesh elements.
Definition: mesh.cc:1168
index_types.hh
SubDOFHandlerMultiDim::receive_sub_ghost_dofs
void receive_sub_ghost_dofs(unsigned int proc, vector< LongIdx > &dofs)
Get global dof indices of ghost dofs for sub-handler.
Definition: dofhandler.cc:842
fe_system.hh
Class FESystem for compound finite elements.
Dof::dim
unsigned int dim
Association to n-face of given dimension (point, line, triangle, tetrahedron.
Definition: finite_element.hh:92
Neighbour::element
ElementAccessor< 3 > element() const
Definition: neighbours.h:163
MeshBase::vb_neighbour
const Neighbour & vb_neighbour(unsigned int nb) const
Return neighbour with given index.
Definition: mesh.cc:1360
VectorMPI::set
void set(unsigned int pos, double val)
Set value on given position.
Definition: vector_mpi.hh:111
FESystem::fe
const std::vector< std::shared_ptr< FiniteElement< dim > > > & fe() const
Definition: fe_system.hh:147
Distribution
Definition: distribution.hh:50
MPI_Recv
#define MPI_Recv(buf, count, datatype, source, tag, comm, status)
Definition: mpi.h:271
dh_cell_accessor.hh
Side::edge_idx
unsigned int edge_idx() const
Returns global index of the edge connected to the side.
Definition: accessors_impl.hh:223
DOFHandlerMultiDim::update_local_dofs
void update_local_dofs(unsigned int proc, const std::vector< bool > &update_cells, const std::vector< LongIdx > &dofs, const std::vector< LongIdx > &node_dof_starts, std::vector< LongIdx > &node_dofs, const std::vector< LongIdx > &edge_dof_starts, std::vector< LongIdx > &edge_dofs)
Update dofs on local elements from ghost element dofs.
Definition: dofhandler.cc:217
accessors.hh
DOFHandlerMultiDim::dh_seq_
std::shared_ptr< DOFHandlerMultiDim > dh_seq_
Sequential dof handler associated to the current (parallel) one.
Definition: dofhandler.hh:399
ASSERT_PERMANENT
#define ASSERT_PERMANENT(expr)
Allow use shorter versions of macro names if these names is not used with external library.
Definition: asserts.hh:347
DOFHandlerMultiDim::el_is_local
bool el_is_local(int index) const
Definition: dofhandler.cc:650
DOFHandlerMultiDim
Provides the numbering of the finite element degrees of freedom on the computational mesh.
Definition: dofhandler.hh:151
SubDOFHandlerMultiDim::update_parent_vector
void update_parent_vector(VectorMPI &vec, const VectorMPI &subvec)
Update values in parent vector from values of subvector.
Definition: dofhandler.cc:895
DHCellAccessor::local_idx
unsigned int local_idx() const
Return local index to element (index of DOF handler).
Definition: dh_cell_accessor.hh:58
DOFHandlerMultiDim::VALID_NFACE
static const int VALID_NFACE
Definition: dofhandler.hh:387
DOFHandlerMultiDim::own_range
Range< DHCellAccessor > own_range() const
Returns range of DOF handler cells (only range of own without ghost cells)
Definition: dofhandler.cc:661
finite_element.hh
Abstract class for description of finite elements.
DOFHandlerMultiDim::INVALID_NFACE
static const int INVALID_NFACE
Definition: dofhandler.hh:386
DOFHandlerMultiDim::distribute_dofs
void distribute_dofs(std::shared_ptr< DiscreteSpace > ds)
Distributes degrees of freedom on the mesh needed for the given discrete space.
Definition: dofhandler.cc:307
DOFHandlerMultiDim::receive_ghost_dofs
void receive_ghost_dofs(unsigned int proc, std::vector< LongIdx > &dofs)
Obtain dof numbers on ghost elements from other processor.
Definition: dofhandler.cc:165
DHCellAccessor::elm
const ElementAccessor< 3 > elm() const
Return ElementAccessor to element of loc_ele_idx_.
Definition: dh_cell_accessor.hh:71
DuplicateNodes::n_nodes
unsigned int n_nodes() const
Definition: duplicate_nodes.h:104
DOFHandlerMultiDim::create_vector
virtual VectorMPI create_vector()
Allocates PETSc vector according to the dof distribution.
Definition: dofhandler.cc:534
DOFHandlerBase::n_global_dofs_
unsigned int n_global_dofs_
Number of global dofs assigned by the handler.
Definition: dofhandler.hh:108
DOFHandlerBase::loffset_
unsigned int loffset_
Index of the first dof on the local process.
Definition: dofhandler.hh:118
SubDOFHandlerMultiDim::parent_
std::shared_ptr< DOFHandlerMultiDim > parent_
Parent dof handler.
Definition: dofhandler.hh:503
DOFHandlerMultiDim::sequential
std::shared_ptr< DOFHandlerMultiDim > sequential()
Returns sequential version of the current dof handler.
Definition: dofhandler.cc:61
Side::element
ElementAccessor< 3 > element() const
Returns iterator to the element of the side.
Definition: accessors_impl.hh:218
MPI_LONG_IDX
#define MPI_LONG_IDX
Definition: index_types.hh:30
mesh.h
DHCellAccessor::n_dofs
unsigned int n_dofs() const
Return number of dofs on given cell.
Definition: dh_cell_accessor.hh:420
DOFHandlerMultiDim::init_status
void init_status(std::vector< short int > &node_status, std::vector< short int > &edge_status)
Initialize node_status and edge_status.
Definition: dofhandler.cc:115
std::map
Definition: doxy_dummy_defs.hh:11
DOFHandlerBase::distr
std::shared_ptr< Distribution > distr() const
Definition: dofhandler.hh:73
DHCellAccessor::elm_idx
unsigned int elm_idx() const
Return serial idx to element of loc_ele_idx_.
Definition: dh_cell_accessor.hh:64
DOFHandlerMultiDim::DHCellAccessor
friend class DHCellAccessor
Definition: dofhandler.hh:265
partitioning.hh
FiniteElement::n_dofs
unsigned int n_dofs() const
Returns the number of degrees of freedom needed by the finite element.
Definition: finite_element.hh:262
DOFHandlerMultiDim::init_dof_starts
void init_dof_starts(std::vector< LongIdx > &node_dof_starts, std::vector< LongIdx > &edge_dof_starts)
Initialize auxiliary vector of starting indices of nodal/edge dofs.
Definition: dofhandler.cc:89
MPI_SUM
#define MPI_SUM
Definition: mpi.h:196
LongIdx
int LongIdx
Define type that represents indices of large arrays (elements, nodes, dofs etc.)
Definition: index_types.hh:24
DOFHandlerMultiDim::cell_accessor_from_element
const DHCellAccessor cell_accessor_from_element(unsigned int elm_idx) const
Return DHCellAccessor appropriate to ElementAccessor of given idx.
Definition: dofhandler.cc:682
Mesh
Definition: mesh.h:359
Element::n_sides
unsigned int n_sides() const
Definition: elements.h:131
MPI_STATUS_IGNORE
#define MPI_STATUS_IGNORE
Definition: mpi.h:203
DOFHandlerMultiDim::~DOFHandlerMultiDim
~DOFHandlerMultiDim() override
Destructor.
Definition: dofhandler.cc:560
DOFHandlerMultiDim::nb_4_loc
vector< LongIdx > nb_4_loc
Local neighbour index -> global neighbour index.
Definition: dofhandler.hh:449
Range
Range helper class.
Definition: range_wrapper.hh:65
DOFHandlerMultiDim::ds_
std::shared_ptr< DiscreteSpace > ds_
Pointer to the discrete space for which the handler distributes dofs.
Definition: dofhandler.hh:393
DOFHandlerBase
Definition: dofhandler.hh:47
DHCellAccessor
Cell accessor allow iterate over DOF handler cells.
Definition: dh_cell_accessor.hh:43
MPI_Allreduce
#define MPI_Allreduce(sendbuf, recvbuf, count, datatype, op, comm)
Definition: mpi.h:612
fmt::printf
void printf(BasicWriter< Char > &w, BasicCStringRef< Char > format, ArgList args)
Definition: printf.h:444
MeshBase::get_el_4_loc
LongIdx * get_el_4_loc() const
Definition: mesh.h:122
DOFHandlerMultiDim::cell_starts
std::vector< LongIdx > cell_starts
Starting indices for local (owned+ghost) element dofs.
Definition: dofhandler.hh:419
DOFHandlerMultiDim::print
void print() const
Output structure of dof handler.
Definition: dofhandler.cc:689
DuplicateNodes::objects
const std::vector< MeshObject > & objects(unsigned int dim) const
Definition: duplicate_nodes.h:107
DOFHandlerMultiDim::make_elem_partitioning
void make_elem_partitioning()
Prepare parallel distribution of elements, edges and neighbours.
Definition: dofhandler.cc:565
MeshBase
Base class for Mesh and BCMesh.
Definition: mesh.h:96
DOFHandlerMultiDim::dof_indices
std::vector< IntIdx > dof_indices
Dof numbers on local and ghost elements.
Definition: dofhandler.hh:427
DOFHandlerBase::max_elem_dofs_
unsigned int max_elem_dofs_
Max. number of dofs per element.
Definition: dofhandler.hh:121
DOFHandlerMultiDim::create_sequential
void create_sequential()
Communicate local dof indices to all processors and create new sequential dof handler.
Definition: dofhandler.cc:445
DOFHandlerBase::lsize_
unsigned int lsize_
Number of dofs associated to local process.
Definition: dofhandler.hh:113
DOFHandlerMultiDim::DOFHandlerMultiDim
DOFHandlerMultiDim(MeshBase &_mesh, bool make_elem_part=true)
Constructor.
Definition: dofhandler.cc:49
MixedPtr< FiniteElement >
SubDOFHandlerMultiDim::send_sub_ghost_dofs
void send_sub_ghost_dofs(unsigned int proc, const map< LongIdx, LongIdx > &global_to_local_dof_idx)
Send global indices of dofs that are ghost on other processors.
Definition: dofhandler.cc:867
MeshBase::n_vb_neighbours
unsigned int n_vb_neighbours() const
Definition: mesh.cc:137
SubDOFHandlerMultiDim::parent_dof_idx_
std::vector< LongIdx > parent_dof_idx_
Local indices in the parent handler.
Definition: dofhandler.hh:509
MPI_COMM_WORLD
#define MPI_COMM_WORLD
Definition: mpi.h:123
std::vector::data
T data
Definition: doxy_dummy_defs.hh:7
DOFHandlerMultiDim::scatter_to_seq_
std::shared_ptr< VecScatter > scatter_to_seq_
Scatter context for parallel to sequential vectors.
Definition: dofhandler.hh:402
MeshBase::edge_range
Range< Edge > edge_range() const
Return range of edges.
Definition: mesh.cc:125
ElementAccessor::idx
unsigned int idx() const
We need this method after replacing Region by RegionIdx, and movinf RegionDB instance into particular...
Definition: accessors.hh:215
FiniteElement::function_space_
std::shared_ptr< FunctionSpace > function_space_
Function space defining the FE.
Definition: finite_element.hh:385
DOFHandlerMultiDim::sequential_scatter
std::shared_ptr< VecScatter > sequential_scatter()
Returns scatter context from parallel to sequential vectors.
Definition: dofhandler.cc:68
MPI_Allgatherv
#define MPI_Allgatherv(sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, comm)
Definition: mpi.h:587
VectorMPI::get
double get(unsigned int pos) const
Return value on given position.
Definition: vector_mpi.hh:105
DOFHandlerMultiDim::is_parallel_
bool is_parallel_
Indicator for parallel/sequential dof handler.
Definition: dofhandler.hh:396
MeshBase::n_elements
unsigned int n_elements() const
Definition: mesh.h:111
DOFHandlerMultiDim::ASSIGNED_NFACE
static const int ASSIGNED_NFACE
Definition: dofhandler.hh:388
VectorMPI
Definition: vector_mpi.hh:43
edge
@ edge
Definition: generic_assembly.hh:34
MPI_UNSIGNED
#define MPI_UNSIGNED
Definition: mpi.h:165
DOFHandlerMultiDim::hash
std::size_t hash() const override
Definition: dofhandler.cc:656
DOFHandlerMultiDim::send_ghost_dofs
void send_ghost_dofs(unsigned int proc)
Send dof numbers to other processor.
Definition: dofhandler.cc:186
ElementAccessor::side
SideIter side(const unsigned int loc_index)
Definition: accessors_impl.hh:131
DHCellAccessor::cell_dof
const Dof & cell_dof(unsigned int idof) const
Return dof on a given cell.
Definition: dh_cell_accessor.hh:440
EqualOrderDiscreteSpace
Definition: discrete_space.hh:92
FESystem
Compound finite element on dim dimensional simplex.
Definition: fe_system.hh:101
Distribution::is_local
bool is_local(unsigned int idx) const
identify local index
Definition: distribution.hh:120
DOFHandlerMultiDim::get_dof_indices
unsigned int get_dof_indices(const DHCellAccessor &cell, std::vector< LongIdx > &indices) const override
Returns the global indices of dofs associated to the cell.
Definition: dofhandler.cc:548
MeshBase::duplicate_nodes
const DuplicateNodes * duplicate_nodes() const
Definition: mesh.h:147
VectorMPI::size
unsigned int size() const
Return size of output data.
Definition: vector_mpi.hh:98
DOFHandlerBase::dof_ds_
std::shared_ptr< Distribution > dof_ds_
Distribution of dofs associated to local process.
Definition: dofhandler.hh:131
DOFHandlerMultiDim::init_cell_starts
void init_cell_starts()
Initialize vector of starting indices for elements.
Definition: dofhandler.cc:75
Element::n_nodes
unsigned int n_nodes() const
Definition: elements.h:125
range_wrapper.hh
Implementation of range helper class.
DOFHandlerMultiDim::edg_4_loc
vector< LongIdx > edg_4_loc
Local edge index -> global edge index.
Definition: dofhandler.hh:446