Flow123d  release_3.0.0-680-gbed5aba
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 "fem/dofhandler.hh"
20 #include "fem/finite_element.hh"
21 #include "fem/dh_cell_accessor.hh"
22 #include "mesh/mesh.h"
23 #include "mesh/duplicate_nodes.h"
24 #include "mesh/partitioning.hh"
25 #include "mesh/long_idx.hh"
26 #include "mesh/accessors.hh"
27 #include "mesh/range_wrapper.hh"
28 #include "mesh/neighbours.h"
29 #include "la/distribution.hh"
30 
31 
32 
33 
35 {}
36 
37 
38 
39 
40 
41 
42 DOFHandlerMultiDim::DOFHandlerMultiDim(Mesh& _mesh, bool make_elem_part)
43  : DOFHandlerBase(_mesh),
44  ds_(nullptr),
45  is_parallel_(true),
46  dh_seq_(nullptr),
47  scatter_to_seq_(nullptr),
48  row_4_el(nullptr),
49  el_4_loc(nullptr),
50  el_ds_(nullptr)
51 {
52  if (make_elem_part) make_elem_partitioning();
53 }
54 
55 
57 {
58  switch (cell->dim()) {
59  case 1:
60  return fe<1>(cell)->n_dofs();
61  break;
62  case 2:
63  return fe<2>(cell)->n_dofs();
64  break;
65  case 3:
66  return fe<3>(cell)->n_dofs();
67  break;
68  }
69 }
70 
71 
72 const Dof &DOFHandlerMultiDim::cell_dof(ElementAccessor<3> cell, unsigned int idof) const
73 {
74  switch (cell.dim())
75  {
76  case 1:
77  return fe<1>(cell)->dof(idof);
78  break;
79  case 2:
80  return fe<2>(cell)->dof(idof);
81  break;
82  case 3:
83  return fe<3>(cell)->dof(idof);
84  break;
85  }
86 }
87 
88 std::shared_ptr<DOFHandlerMultiDim> DOFHandlerMultiDim::sequential()
89 {
91  return dh_seq_;
92 }
93 
94 
95 std::shared_ptr<VecScatter> DOFHandlerMultiDim::sequential_scatter()
96 {
98  return scatter_to_seq_;
99 }
100 
101 
103 {
104  // get number of dofs per element and then set up cell_starts
106  for (auto cell : this->local_range())
107  {
108  cell_starts[row_4_el[cell.elm_idx()]+1] = cell.n_dofs();
109  max_elem_dofs_ = max( (int)max_elem_dofs_, (int)cell.n_dofs() );
110  }
111  for (unsigned int i=0; i<mesh_->n_elements(); ++i)
112  cell_starts[i+1] += cell_starts[i];
113 }
114 
115 
117 {
118  // initialize dofs on nodes
119  // We must separate dofs for dimensions because FE functions
120  // may be discontinuous on nodes shared by different
121  // dimensions.
122  unsigned int n_node_dofs = 0;
123 
124  for (unsigned int nid=0; nid<mesh_->tree->n_nodes(); nid++)
125  {
126  node_dof_starts.push_back(n_node_dofs);
127  n_node_dofs += ds_->n_node_dofs(nid);
128  }
129  node_dof_starts.push_back(n_node_dofs);
130 }
131 
132 
134 {
135  // mark local dofs
136  for (auto cell : this->own_range())
137  {
138  for (unsigned int n=0; n<cell.dim()+1; n++)
139  {
140  unsigned int nid = mesh_->tree->objects(cell.dim())[mesh_->tree->obj_4_el()[cell.elm_idx()]].nodes[n];
141  node_status[nid] = VALID_NODE;
142  }
143  }
144 
145  // unmark dofs on ghost cells from lower procs
146  for (auto cell : this->ghost_range())
147  {
148  if (cell.elm().proc() < el_ds_->myp())
149  {
150  for (unsigned int n=0; n<cell.dim()+1; n++)
151  {
152  unsigned int nid = mesh_->tree->objects(cell.dim())[mesh_->tree->obj_4_el()[cell.elm_idx()]].nodes[n];
153  node_status[nid] = INVALID_NODE;
154  }
155  }
156  }
157 }
158 
159 
161 {
162  // send number of elements required from the other processor
163  unsigned int n_elems = ghost_proc_el[proc].size();
164  MPI_Send(&n_elems, 1, MPI_UNSIGNED, proc, 0, MPI_COMM_WORLD);
165 
166  // send indices of elements required
167  MPI_Send(&(ghost_proc_el[proc][0]), n_elems, MPI_LONG_IDX, proc, 1, MPI_COMM_WORLD);
168 
169  // receive numbers of dofs on required elements
170  vector<unsigned int> n_dofs(n_elems);
171  MPI_Recv(&(n_dofs[0]), n_elems, MPI_UNSIGNED, proc, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
172 
173  // receive dofs on required elements
174  unsigned int n_dofs_sum = 0;
175  for (auto nd : n_dofs) n_dofs_sum += nd;
176  dofs.resize(n_dofs_sum);
177  MPI_Recv(&(dofs[0]), n_dofs_sum, MPI_LONG_IDX, proc, 3, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
178 }
179 
180 
181 void DOFHandlerMultiDim::send_ghost_dofs(unsigned int proc)
182 {
183  // receive number of elements required by the other processor
184  unsigned int n_elems;
185  MPI_Recv(&n_elems, 1, MPI_UNSIGNED, proc, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
186 
187  // receive indices of elements required
188  vector<LongIdx> elems(n_elems);
189  MPI_Recv(&(elems[0]), n_elems, MPI_LONG_IDX, proc, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
190 
191  // send numbers of dofs on required elements
193  for (LongIdx el : elems) n_dofs.push_back(cell_starts[row_4_el[el]+1] - cell_starts[row_4_el[el]]);
194  MPI_Send(&(n_dofs[0]), n_elems, MPI_UNSIGNED, proc, 2, MPI_COMM_WORLD);
195 
196  // send dofs on the required elements
197  vector<LongIdx> dofs;
198  for (LongIdx el : elems)
199  dofs.insert(dofs.end(), dof_indices.begin()+cell_starts[row_4_el[el]], dof_indices.begin()+cell_starts[row_4_el[el]+1]);
200  MPI_Send(&(dofs[0]), dofs.size(), MPI_LONG_IDX, proc, 3, MPI_COMM_WORLD);
201 }
202 
203 
205  const std::vector<bool> &update_cells,
206  const std::vector<LongIdx> &dofs,
207  const std::vector<LongIdx> &node_dof_starts,
208  std::vector<LongIdx> &node_dofs
209  )
210 {
211  // update dof_indices on ghost cells
212  unsigned int dof_offset=0;
213  for (unsigned int gid=0; gid<ghost_proc_el[proc].size(); gid++)
214  {
215  auto cell = mesh_->element_accessor(ghost_proc_el[proc][gid]);
216  //auto dh_cell = this->cell_accessor_from_element( cell.idx() );
217 
218  for (unsigned dof=0; dof<n_dofs(cell); dof++)
219  dof_indices[cell_starts[row_4_el[cell.idx()]]+dof] = dofs[dof_offset+dof];
220 
221  vector<unsigned int> loc_node_dof_count(cell->n_nodes(), 0);
222  for (unsigned int idof = 0; idof<n_dofs(cell); ++idof)
223  {
224  if (cell_dof(cell, idof).dim == 0)
225  { // update nodal dof
226  unsigned int dof_nface_idx = cell_dof(cell, idof).n_face_idx;
227  unsigned int nid = mesh_->tree->objects(cell->dim())[mesh_->tree->obj_4_el()[cell.idx()]].nodes[dof_nface_idx];
228 
229  if (node_dofs[node_dof_starts[nid]+loc_node_dof_count[dof_nface_idx]] == INVALID_DOF)
230  node_dofs[node_dof_starts[nid]+loc_node_dof_count[dof_nface_idx]] = dofs[dof_offset+idof];
231 
232  loc_node_dof_count[dof_nface_idx]++;
233  }
234  }
235 
236  dof_offset += n_dofs(cell);
237  }
238 
239  // update dof_indices on local elements
240  for (auto cell : this->own_range())
241  {
242  if (!update_cells[cell.local_idx()]) continue;
243 
244  // loop over element dofs
245  vector<unsigned int> loc_node_dof_count(cell.elm()->n_nodes(), 0);
246  for (unsigned int idof = 0; idof<cell.n_dofs(); ++idof)
247  {
248  if (cell.cell_dof(idof).dim == 0)
249  {
250  unsigned int dof_nface_idx = cell.cell_dof(idof).n_face_idx;
251  if (dof_indices[cell_starts[row_4_el[cell.elm_idx()]]+idof] == INVALID_DOF)
252  { // update nodal dof
253  unsigned int nid = mesh_->tree->objects(cell.dim())[mesh_->tree->obj_4_el()[cell.elm_idx()]].nodes[dof_nface_idx];
254  dof_indices[cell_starts[row_4_el[cell.elm_idx()]]+idof] = node_dofs[node_dof_starts[nid]+loc_node_dof_count[dof_nface_idx]];
255  }
256  loc_node_dof_count[dof_nface_idx]++;
257  }
258  }
259  }
260 }
261 
262 
263 void DOFHandlerMultiDim::distribute_dofs(std::shared_ptr<DiscreteSpace> ds)
264 {
265  // First check if dofs are already distributed.
266  OLD_ASSERT(ds_ == nullptr, "Attempt to distribute DOFs multiple times!");
267 
268  ds_ = ds;
269 
270  std::vector<LongIdx> node_dofs, node_dof_starts;
272  std::vector<bool> update_cells(el_ds_->lsize(), false);
273  unsigned int next_free_dof = 0;
274 
276  init_node_dof_starts(node_dof_starts);
277  node_dofs.resize(node_dof_starts[node_dof_starts.size()-1]);
278  init_node_status(node_status);
279 
280  // Distribute dofs on local elements.
281  dof_indices.resize(cell_starts[cell_starts.size()-1]);
282  local_to_global_dof_idx_.reserve(dof_indices.size());
283  for (auto cell : this->own_range())
284  {
285 
286  // loop over element dofs
287  vector<unsigned int> loc_node_dof_count(cell.elm()->n_nodes(), 0);
288  for (unsigned int idof = 0; idof<cell.n_dofs(); ++idof)
289  {
290  unsigned int dof_dim = cell.cell_dof(idof).dim;
291  unsigned int dof_nface_idx = cell.cell_dof(idof).n_face_idx;
292 
293  if (dof_dim == 0)
294  { // add dofs shared by nodes
295  unsigned int nid = mesh_->tree->objects(cell.dim())[mesh_->tree->obj_4_el()[cell.elm_idx()]].nodes[dof_nface_idx];
296  unsigned int node_dof_idx = node_dof_starts[nid]+loc_node_dof_count[dof_nface_idx];
297 
298  switch (node_status[nid])
299  {
300  case VALID_NODE:
301  for (int i=0; i<node_dof_starts[nid+1] - node_dof_starts[nid]; i++)
302  {
303  local_to_global_dof_idx_.push_back(next_free_dof);
304  node_dofs[node_dof_starts[nid]+i] = next_free_dof++;
305  }
306  node_status[nid] = ASSIGNED_NODE;
307  break;
308  case INVALID_NODE:
309  node_dofs[node_dof_idx] = INVALID_DOF;
310  update_cells[cell.local_idx()] = true;
311  break;
312  }
313  dof_indices[cell_starts[row_4_el[cell.elm_idx()]]+idof] = node_dofs[node_dof_idx];
314  loc_node_dof_count[dof_nface_idx]++;
315  }
316  else if (dof_dim == cell.dim())
317  {
318  // add dofs owned only by the element
319  local_to_global_dof_idx_.push_back(next_free_dof);
320  dof_indices[cell_starts[row_4_el[cell.elm_idx()]]+idof] = next_free_dof++;
321  }
322  else
323  ASSERT(false).error("Unsupported dof n_face.");
324  }
325  }
326  node_status.clear();
327 
328  lsize_ = next_free_dof;
329 
330  // communicate n_dofs across all processes
331  dof_ds_ = std::make_shared<Distribution>(lsize_, PETSC_COMM_WORLD);
332  n_global_dofs_ = dof_ds_->size();
333 
334  // shift dof indices
335  loffset_ = dof_ds_->get_starts_array()[dof_ds_->myp()];
336  if (loffset_ > 0)
337  for (unsigned int i=0; i<dof_indices.size(); i++)
338  if (dof_indices[i] != INVALID_DOF)
339  dof_indices[i] += loffset_;
340 
341  // communicate dofs from ghost cells
342  // first propagate from lower procs to higher procs and then vice versa
343  for (unsigned int from_higher = 0; from_higher < 2; from_higher++)
344  {
345  for (unsigned int proc : ghost_proc)
346  {
347  if ((proc > el_ds_->myp()) == from_higher)
348  { // receive dofs from master processor
349  vector<LongIdx> dofs;
350  receive_ghost_dofs(proc, dofs);
351 
352  // update dof_indices and node_dofs on ghost elements
353  update_local_dofs(proc, update_cells, dofs, node_dof_starts, node_dofs);
354 
355  for (auto dof : dofs)
356  local_to_global_dof_idx_.push_back(dof);
357  }
358  else
359  send_ghost_dofs(proc);
360  }
361  }
362  update_cells.clear();
363  node_dofs.clear();
364  node_dof_starts.clear();
365 }
366 
367 
369 {
370  if (dh_seq_ != nullptr) return;
371 
372  if ( !is_parallel_ )
373  {
374  dh_seq_ = std::make_shared<DOFHandlerMultiDim>(*this);
375  return;
376  }
377 
378  dh_seq_ = std::make_shared<DOFHandlerMultiDim>(*mesh_);
379 
380  dh_seq_->n_global_dofs_ = n_global_dofs_;
381  dh_seq_->lsize_ = n_global_dofs_;
382  dh_seq_->loffset_ = 0;
383  dh_seq_->mesh_ = mesh_;
384  dh_seq_->dof_ds_ = dof_ds_; // should be sequential distribution
385  dh_seq_->ds_ = ds_;
386  dh_seq_->is_parallel_ = false;
387 
390  &dh_seq_->max_elem_dofs_,
391  1,
392  MPI_UNSIGNED,
393  MPI_MAX,
395 
396 
397  // Auxiliary vectors cell_starts_loc and dof_indices_loc contain
398  // only local element data (without ghost elements).
399  // Then it is possible to create sequential vectors by simple reduce/gather operation.
400  vector<LongIdx> cell_starts_loc(mesh_->n_elements()+1, 0);
401  vector<LongIdx> dof_indices_loc;
402 
403  // construct cell_starts_loc
404  for (auto cell : this->own_range())
405  {
406  cell_starts_loc[row_4_el[cell.elm_idx()]+1] = cell.n_dofs();
407  }
408  for (unsigned int i=0; i<mesh_->n_elements(); ++i)
409  cell_starts_loc[i+1] += cell_starts_loc[i];
410 
411  // construct dof_indices_loc
412  dof_indices_loc.resize(cell_starts_loc[mesh_->n_elements()]);
413  for (auto cell : this->own_range())
414  {
415  for (unsigned int idof=0; idof<cell.n_dofs(); idof++)
416  dof_indices_loc[cell_starts_loc[row_4_el[cell.elm_idx()]]+idof] = dof_indices[cell_starts[row_4_el[cell.elm_idx()]]+idof];
417  }
418 
419  Distribution distr(dof_indices_loc.size(), PETSC_COMM_WORLD);
420  dh_seq_->cell_starts.resize(mesh_->n_elements()+1);
421  dh_seq_->dof_indices.resize(distr.size());
422 
423  MPI_Allreduce( cell_starts_loc.data(),
424  dh_seq_->cell_starts.data(),
425  cell_starts_loc.size(),
426  MPI_LONG_IDX,
427  MPI_SUM,
428  MPI_COMM_WORLD );
429 
430  MPI_Allgatherv( dof_indices_loc.data(),
431  dof_indices_loc.size(),
432  MPI_LONG_IDX,
433  dh_seq_->dof_indices.data(),
434  (const int *)distr.get_lsizes_array(),
435  (const int *)distr.get_starts_array(),
436  MPI_LONG_IDX,
437  MPI_COMM_WORLD );
438 
439  // create scatter from parallel to sequential vector
440  Vec v_from;
441  VecCreateMPI(PETSC_COMM_WORLD, lsize_, PETSC_DETERMINE, &v_from);
442  scatter_to_seq_ = std::make_shared<VecScatter>();
443  VecScatterCreateToAll(v_from, scatter_to_seq_.get(), NULL);
444  VecDestroy(&v_from);
445 
446  // create scatter for sequential dof handler (Warning: not tested)
447  Vec v_seq;
448  VecCreateSeq(PETSC_COMM_SELF, n_global_dofs_, &v_seq);
449  dh_seq_->scatter_to_seq_ = std::make_shared<VecScatter>();
450  VecScatterCreateToAll(v_seq, dh_seq_->scatter_to_seq_.get(), NULL);
451  VecDestroy(&v_seq);
452 }
453 
454 
455 
457 {
458  unsigned int ndofs = 0;
459  ndofs = cell_starts[row_4_el[cell.idx()]+1]-cell_starts[row_4_el[cell.idx()]];
460  for (unsigned int k=0; k<ndofs; k++)
461  indices[k] = dof_indices[cell_starts[row_4_el[cell.idx()]]+k];
462 
463  return ndofs;
464 }
465 
466 
467 
469 {
470  unsigned int ndofs = 0;
471  ndofs = cell_starts[row_4_el[cell.idx()]+1]-cell_starts[row_4_el[cell.idx()]];
472  for (unsigned int k=0; k<ndofs; k++)
473  indices[k] = cell_starts[row_4_el[cell.idx()]]+k;
474 
475  return ndofs;
476 }
477 
478 
480 {}
481 
482 
483 
485 {
486  // create local arrays of elements
487  el_ds_ = mesh_->get_el_ds();
490 
491  // create local array of edges
492  for (unsigned int iedg=0; iedg<mesh_->n_edges(); iedg++)
493  {
494  bool is_edge_local = false;
495  Edge *edg = &mesh_->edges[iedg];
496  for (int sid=0; sid<edg->n_sides; sid++)
497  if ( el_is_local(edg->side(sid)->element().idx()) )
498  {
499  is_edge_local = true;
500  break;
501  }
502  if (is_edge_local)
503  edg_4_loc.push_back(iedg);
504  }
505 
506  // create local array of neighbours
507  for (unsigned int inb=0; inb<mesh_->n_vb_neighbours(); inb++)
508  {
509  Neighbour *nb = &mesh_->vb_neighbours_[inb];
510  if ( el_is_local(nb->element().idx())
511  || el_is_local(nb->side()->element().idx()) )
512  nb_4_loc.push_back(inb);
513  }
514 
515  // create array of local nodes
516  std::vector<bool> node_is_local(mesh_->tree->n_nodes(), false);
517  for (auto cell : this->own_range())
518  {
519  unsigned int obj_idx = mesh_->tree->obj_4_el()[cell.elm_idx()];
520  for (unsigned int nid=0; nid<cell.elm()->n_nodes(); nid++)
521  node_is_local[mesh_->tree->objects(cell.dim())[obj_idx].nodes[nid]] = true;
522  }
523  for (unsigned int nid=0; nid<mesh_->tree->n_nodes(); nid++)
524  if (node_is_local[nid])
525  node_4_loc.push_back(nid);
526 
527  // create array of local ghost cells
528  for ( auto cell : mesh_->elements_range() )
529  {
530  if (cell.proc() != el_ds_->myp())
531  {
532  bool has_local_node = false;
533  unsigned int obj_idx = mesh_->tree->obj_4_el()[cell.idx()];
534  for (unsigned int nid=0; nid<cell->n_nodes(); nid++)
535  if (node_is_local[mesh_->tree->objects(cell->dim())[obj_idx].nodes[nid]])
536  {
537  has_local_node = true;
538  break;
539  }
540  if (has_local_node)
541  {
542  ghost_4_loc.push_back(cell.idx());
543  ghost_proc.insert(cell.proc());
544  ghost_proc_el[cell.proc()].push_back(cell.idx());
545  }
546  }
547  }
548  for (auto nb : nb_4_loc)
549  {
550  auto cell = mesh_->vb_neighbours_[nb].element();
551  if (!el_is_local(cell.idx()) && find(ghost_4_loc.begin(), ghost_4_loc.end(), cell.idx()) == ghost_4_loc.end())
552  {
553  ghost_4_loc.push_back(cell.idx());
554  ghost_proc.insert(cell.proc());
555  ghost_proc_el[cell.proc()].push_back(cell.idx());
556  }
557  cell = mesh_->vb_neighbours_[nb].side()->element();
558  if (!el_is_local(cell.idx()) && find(ghost_4_loc.begin(), ghost_4_loc.end(), cell.idx()) == ghost_4_loc.end())
559  {
560  ghost_4_loc.push_back(cell.idx());
561  ghost_proc.insert(cell.proc());
562  ghost_proc_el[cell.proc()].push_back(cell.idx());
563  }
564  }
565 }
566 
567 
568 bool DOFHandlerMultiDim::el_is_local(int index) const
569 {
570  return el_ds_->is_local(row_4_el[index]);
571 }
572 
573 
574 std::size_t DOFHandlerMultiDim::hash() const {
575  return this->n_global_dofs_;
576 }
577 
578 
580  auto bgn_it = make_iter<DHCellAccessor>( DHCellAccessor(this, 0) );
581  auto end_it = make_iter<DHCellAccessor>( DHCellAccessor(this, el_ds_->lsize()) );
582  return Range<DHCellAccessor>(bgn_it, end_it);
583 }
584 
585 
587  auto bgn_it = make_iter<DHCellAccessor>( DHCellAccessor(this, 0) );
588  auto end_it = make_iter<DHCellAccessor>( DHCellAccessor(this, el_ds_->lsize()+ghost_4_loc.size()) );
589  return Range<DHCellAccessor>(bgn_it, end_it);
590 }
591 
592 
594  auto bgn_it = make_iter<DHCellAccessor>( DHCellAccessor(this, el_ds_->lsize()) );
595  auto end_it = make_iter<DHCellAccessor>( DHCellAccessor(this, el_ds_->lsize()+ghost_4_loc.size()) );
596  return Range<DHCellAccessor>(bgn_it, end_it);
597 }
598 
599 
601  // TODO: We need replace ASSERT with if condition and return accessor of own element.
602  // In else case we create and return accessor of ghost element.
603  ASSERT( el_is_local(elm_idx) )(elm_idx);
604  return DHCellAccessor(this, row_4_el[elm_idx]-mesh_->get_el_ds()->begin());
605 }
606 
#define MPI_Recv(buf, count, datatype, source, tag, comm, status)
Definition: mpi.h:271
void receive_ghost_dofs(unsigned int proc, std::vector< LongIdx > &dofs)
Obtain dof numbers on ghost elements from other processor.
Definition: dofhandler.cc:160
int LongIdx
Define type that represents indices of large arrays (elements, nodes, dofs etc.)
Definition: long_idx.hh:22
std::shared_ptr< DOFHandlerMultiDim > sequential()
Returns sequential version of the current dof handler.
Definition: dofhandler.cc:88
virtual ~DOFHandlerBase()
Destructor.
Definition: dofhandler.cc:34
void create_sequential()
Communicate local dof indices to all processors and create new sequential dof handler.
Definition: dofhandler.cc:368
void init_cell_starts()
Initialize vector of starting indices for elements.
Definition: dofhandler.cc:102
Declaration of class which handles the ordering of degrees of freedom (dof) and mappings between loca...
LongIdx * el_4_loc
Local element index -> global element index.
Definition: dofhandler.hh:422
unsigned int get_loc_dof_indices(const ElementAccessor< 3 > &cell, std::vector< LongIdx > &indices) const override
Returns the indices of dofs associated to the cell on the local process.
Definition: dofhandler.cc:468
LongIdx * get_row_4_el() const
Definition: mesh.h:171
const std::vector< MeshObject > & objects(unsigned int dim) const
#define MPI_LONG_IDX
Definition: long_idx.hh:24
DuplicateNodes * tree
Definition: mesh.h:268
Range helper class.
Definition: mesh.h:52
Distribution * el_ds_
Distribution of elements.
Definition: dofhandler.hh:425
unsigned int dim
Association to n-face of given dimension (point, line, triangle, tetrahedron.
void distribute_dofs(std::shared_ptr< DiscreteSpace > ds)
Distributes degrees of freedom on the mesh needed for the given discrete space.
Definition: dofhandler.cc:263
#define MPI_SUM
Definition: mpi.h:196
Definition: mesh.h:80
std::shared_ptr< VecScatter > sequential_scatter()
Returns scatter context from parallel to sequential vectors.
Definition: dofhandler.cc:95
std::vector< LongIdx > local_to_global_dof_idx_
Maps local and ghost dof indices to global ones.
Definition: dofhandler.hh:416
int n_sides
Definition: edges.h:36
Definition: edges.h:26
#define MPI_Send(buf, count, datatype, dest, tag, comm)
Definition: mpi.h:263
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:346
std::shared_ptr< Distribution > dof_ds_
Distribution of dofs associated to local process.
Definition: dofhandler.hh:135
#define MPI_Allgatherv(sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, comm)
Definition: mpi.h:587
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)
Update dofs on local elements from ghost element dofs.
Definition: dofhandler.cc:204
ElementAccessor< 3 > element() const
Definition: side_impl.hh:53
std::shared_ptr< DOFHandlerMultiDim > dh_seq_
Sequential dof handler associated to the current (parallel) one.
Definition: dofhandler.hh:380
unsigned int lsize_
Number of dofs associated to local process.
Definition: dofhandler.hh:117
virtual ElementAccessor< 3 > element_accessor(unsigned int idx) const
Create and return ElementAccessor to element of given idx.
Definition: mesh.cc:719
unsigned int n_face_idx
Index of n-face to which the dof is associated.
unsigned int n_dofs(ElementAccessor< 3 > cell) const
Return number of dofs on given cell.
Definition: dofhandler.cc:56
map< unsigned int, vector< LongIdx > > ghost_proc_el
Arrays of ghost cells for each neighbouring processor.
Definition: dofhandler.hh:443
void send_ghost_dofs(unsigned int proc)
Send dof numbers to other processor.
Definition: dofhandler.cc:181
unsigned int dim() const
Definition: elements.h:124
void init_node_status(std::vector< short int > &node_status)
Initialize node_status.
Definition: dofhandler.cc:133
std::vector< LongIdx > cell_starts
Starting indices for element dofs.
Definition: dofhandler.hh:400
#define OLD_ASSERT(...)
Definition: global_defs.h:131
unsigned int n_vb_neighbours() const
Definition: mesh.cc:230
ElementAccessor< 3 > element()
Definition: neighbours.h:163
static const int VALID_NODE
Definition: dofhandler.hh:368
unsigned int get_dof_indices(const ElementAccessor< 3 > &cell, std::vector< LongIdx > &indices) const override
Returns the global indices of dofs associated to the cell.
Definition: dofhandler.cc:456
bool is_local(unsigned int idx) const
identify local index
Mesh * mesh_
Pointer to the mesh to which the dof handler is associated.
Definition: dofhandler.hh:130
unsigned int begin(int proc) const
get starting local index
SideIter side()
Definition: neighbours.h:147
std::vector< LongIdx > dof_indices
Dof numbers on local and ghost elements.
Definition: dofhandler.hh:408
Range< DHCellAccessor > ghost_range() const
Returns range over ghosts DOF handler cells.
Definition: dofhandler.cc:593
vector< LongIdx > nb_4_loc
Local neighbour index -> global neighbour index.
Definition: dofhandler.hh:431
unsigned int max_elem_dofs_
Max. number of dofs per element.
Definition: dofhandler.hh:125
vector< LongIdx > ghost_4_loc
Indices of ghost cells (neighbouring with local elements).
Definition: dofhandler.hh:437
virtual Range< ElementAccessor< 3 > > elements_range() const
Returns range of bulk elements.
Definition: mesh.cc:1033
unsigned int n_nodes() const
void init_node_dof_starts(std::vector< LongIdx > &node_dof_starts)
Initialize auxiliary vector of starting indices of nodal dofs.
Definition: dofhandler.cc:116
static const int ASSIGNED_NODE
Definition: dofhandler.hh:369
Distribution * get_el_ds() const
Definition: mesh.h:168
void make_elem_partitioning()
Prepare parallel distribution of elements, edges and neighbours.
Definition: dofhandler.cc:484
static const int INVALID_NODE
Definition: dofhandler.hh:367
std::shared_ptr< Distribution > distr() const
Definition: dofhandler.hh:76
unsigned int myp() const
get my processor
Support classes for parallel programing.
#define MPI_Allreduce(sendbuf, recvbuf, count, datatype, op, comm)
Definition: mpi.h:612
vector< Neighbour > vb_neighbours_
Definition: mesh.h:273
#define MPI_STATUS_IGNORE
Definition: mpi.h:203
vector< LongIdx > edg_4_loc
Local edge index -> global edge index.
Definition: dofhandler.hh:428
virtual unsigned int n_elements(bool boundary=false) const
Returns count of boundary or bulk elements.
Definition: mesh.h:346
Range< DHCellAccessor > own_range() const
Returns range of DOF handler cells (only range of own without ghost cells)
Definition: dofhandler.cc:579
unsigned int loffset_
Index of the first dof on the local process.
Definition: dofhandler.hh:122
static const int INVALID_DOF
Definition: dofhandler.hh:370
const Dof & cell_dof(ElementAccessor< 3 > cell, unsigned int idof) const
Return dof on a given cell.
Definition: dofhandler.cc:72
set< unsigned int > ghost_proc
Processors of ghost elements.
Definition: dofhandler.hh:440
~DOFHandlerMultiDim() override
Destructor.
Definition: dofhandler.cc:479
vector< LongIdx > node_4_loc
Indices of local nodes in mesh tree.
Definition: dofhandler.hh:434
std::vector< Edge > edges
Vector of MH edges, this should not be part of the geometrical mesh.
Definition: mesh.h:252
#define MPI_COMM_WORLD
Definition: mpi.h:123
std::shared_ptr< DiscreteSpace > ds_
Pointer to the discrete space for which the handler distributes dofs.
Definition: dofhandler.hh:374
#define MPI_MAX
Definition: mpi.h:197
#define MPI_UNSIGNED
Definition: mpi.h:165
Abstract class for description of finite elements.
unsigned int n_global_dofs_
Number of global dofs assigned by the handler.
Definition: dofhandler.hh:112
unsigned int n_edges() const
Definition: mesh.h:141
unsigned int dim() const
Definition: accessors.hh:87
bool el_is_local(int index) const
Definition: dofhandler.cc:568
DOFHandlerMultiDim(Mesh &_mesh, bool make_elem_part=true)
Constructor.
Definition: dofhandler.cc:42
Range< DHCellAccessor > local_range() const
Returns range over own and ghost cells of DOF handler.
Definition: dofhandler.cc:586
const std::vector< unsigned int > & obj_4_el() const
bool is_parallel_
Indicator for parallel/sequential dof handler.
Definition: dofhandler.hh:377
unsigned int idx() const
Return local idx of element in boundary / bulk part of element vector.
Definition: accessors.hh:111
DHCellAccessor cell_accessor_from_element(unsigned int elm_idx) const
Return DHCellAccessor appropriate to ElementAccessor of given idx.
Definition: dofhandler.cc:600
std::shared_ptr< VecScatter > scatter_to_seq_
Scatter context for parallel to sequential vectors.
Definition: dofhandler.hh:383
LongIdx * get_el_4_loc() const
Definition: mesh.h:174
LongIdx * row_4_el
Global element index -> index according to partitioning.
Definition: dofhandler.hh:419
SideIter side(const unsigned int i) const
Definition: edges.h:31
Implementation of range helper class.
friend class DHCellAccessor
Definition: dofhandler.hh:294
std::size_t hash() const override
Definition: dofhandler.cc:574
unsigned int lsize(int proc) const
get local size