Flow123d  release_3.0.0-506-g34af125
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 "mesh/mesh.h"
22 #include "mesh/duplicate_nodes.h"
23 #include "mesh/partitioning.hh"
24 #include "mesh/long_idx.hh"
25 #include "mesh/accessors.hh"
26 #include "mesh/range_wrapper.hh"
27 #include "mesh/neighbours.h"
28 #include "la/distribution.hh"
29 
30 
31 
32 
34 {
35  if (dof_ds_ != nullptr) delete dof_ds_;
36 }
37 
38 
39 
40 //template<unsigned int dim, unsigned int spacedim> inline
41 //DOFHandler<dim,spacedim>::DOFHandler(Mesh & _mesh)
42 //: DOFHandlerBase(_mesh),
43 // finite_element(0)
44 //{
45 // object_dofs = new int**[mesh->n_elements()];
46 // for (int i=0; i<mesh->n_elements(); i++)
47 // object_dofs[i] = NULL;
48 //}
49 //
50 //
51 //template<unsigned int dim, unsigned int spacedim> inline
52 //DOFHandler<dim,spacedim>::~DOFHandler()
53 //{
54 // for (int i=0; i<mesh->n_elements(); i++)
55 // if (object_dofs[i] != NULL)
56 // {
57 // for (int j=0; j<mesh->element[i].dim(); j++)
58 // if (object_dofs[i][j] != NULL)
59 // delete[] object_dofs[i][j];
60 //
61 // delete[] object_dofs[i];
62 // }
63 // delete[] object_dofs;
64 //}
65 //
66 //
67 //template<unsigned int dim, unsigned int spacedim> inline
68 //void DOFHandler<dim,spacedim>::distribute_dofs(FiniteElement<dim,spacedim> & fe, const unsigned int offset)
69 //{
70 // // First check if dofs are already distributed.
71 // OLD_ASSERT(finite_element == 0, "Attempt to distribute DOFs multiple times!");
72 //
73 // unsigned int next_free_dof = offset;
74 // unsigned int n_obj_dofs[dim+1];
75 //
76 // finite_element = &fe;
77 // global_dof_offset = offset;
78 //
79 // for (unsigned int dm=0; dm <= dim; dm++)
80 // {
81 // n_obj_dofs[dm] = 0;
82 // for (unsigned int m=0; m<dof_multiplicities.size(); m++)
83 // n_obj_dofs[dm] += fe.n_object_dofs(dm, dof_multiplicities[m])*dof_multiplicities[m];
84 // }
85 //
86 // // Broadcast partition of elements to all processes.
87 // LongIdx *loc_part;
88 // int myp = mesh->get_part()->get_init_distr()->myp();
89 // if (myp == 0)
90 // {
91 // loc_part = (int*)mesh->get_part()->get_loc_part();
92 // }
93 // else
94 // {
95 // loc_part = new LongIdx[mesh->n_elements()];
96 // }
97 // MPI_Bcast(loc_part, mesh->n_elements(), MPI_INT, 0, mesh->get_part()->get_init_distr()->get_comm());
98 //
99 // // Distribute element dofs.
100 // // First we distribute dofs on elements associated to process 0 and so on.
101 // for (int proc=0; proc<mesh->get_part()->get_init_distr()->np(); proc++)
102 // {
103 // if (proc == myp)
104 // loffset_ = next_free_dof;
105 //
106 // for (auto cell : mesh->elements_range()) {
107 // if (cell->dim() != dim) continue;
108 //
109 // if (loc_part[cell.index()] != proc) continue;
110 //
111 // // distribute dofs
112 // // TODO: For the moment we distribute only dofs associated to the cell
113 // // In the future we want to distribute dofs on vertices, lines,
114 // // and triangles as well.
115 // object_dofs[cell.index()] = new int*[dim+1];
116 // for (int i=0; i<dim+1; i++)
117 // object_dofs[cell.index()][i] = NULL;
118 // object_dofs[cell.index()][dim] = new int[n_obj_dofs[dim]];
119 //
120 // for (unsigned int i=0; i<n_obj_dofs[dim]; i++)
121 // object_dofs[cell.index()][dim][i] = next_free_dof++;
122 // }
123 //
124 // if (proc == myp)
125 // lsize_ = next_free_dof - loffset_;
126 // }
127 //
128 // // Finally we free the unused array loc_part.
129 // if (mesh->get_part()->get_init_distr()->myp() != 0)
130 // delete[] loc_part;
131 //
132 //// for (auto cell : mesh->elements_range()) {
133 //// // skip cells of different dimension
134 //// if (cell->dim() != dim) continue;
135 ////
136 //// // distribute dofs
137 //// // TODO: For the moment we distribute only dofs associated to the cell
138 //// // In the future we want to distribute dofs on vertices, lines,
139 //// // and triangles as well.
140 //// object_dofs[dim][cell] = new int[n_obj_dofs[dim]];
141 //// for (unsigned int i=0; i<n_obj_dofs[dim]; i++)
142 //// object_dofs[dim][cell][i] = next_free_dof++;
143 //// }
144 //
145 //
146 //// for (auto cell : mesh->elements_range()) {
147 //// // skip cells of different dimension
148 //// if (cell->dim != dim) continue;
149 ////
150 //// // distribute dofs
151 //// for (int dm=0; dm<=dim; dm++)
152 //// {
153 //// for (int i=0; i<cell->n_sides_by_dim(dm); i++)
154 //// {
155 //// void *side = cell->side_by_dim(dm, i);
156 //// // check if node has already assigned dofs, otherwise
157 //// // distribute
158 //// if (object_dofs[dm].find(side) == object_dofs[dm].end())
159 //// {
160 //// object_dofs[dm][side] = new int[n_obj_dofs[dm]];
161 //// for (int i=0; i<n_obj_dofs[dm]; i++)
162 //// object_dofs[dm][side][i] = next_free_dof++;
163 //// }
164 //// }
165 //// }
166 //// }
167 //
168 // n_dofs = next_free_dof - offset;
169 //}
170 //
171 //
172 //
173 //template<unsigned int dim, unsigned int spacedim> inline
174 //const unsigned int DOFHandler<dim,spacedim>::n_local_dofs()
175 //{
176 // return finite_element->n_dofs();
177 //}
178 //
179 //
180 //
181 //template<unsigned int dim, unsigned int spacedim>
182 //void DOFHandler<dim,spacedim>::get_dof_indices(const CellIterator &cell, unsigned int indices[])
183 //{
184 //// void *side;
185 //// unsigned int offset, pid;
186 //
187 // for (unsigned int k=0; k<finite_element->n_object_dofs(dim,DOF_SINGLE); k++)
188 // indices[k] = object_dofs[cell.index()][dim][k];
189 //
190 //// indices.clear();
191 ////
192 //// get_object_dof_indices<0>(cell, indices);
193 //// get_object_dof_indices<1>(cell, indices);
194 //// get_object_dof_indices<2>(cell, indices);
195 //// get_object_dof_indices<3>(cell, indices);
196 //}
197 //
198 ////template<unsigned int dim> template<unsigned int obj_dim> inline void DOFHandler<dim>::get_object_dof_indices(const CellIterator &cell, unsigned int indices[])
199 ////{
200 // // TODO: implement for lower dimensional objects
201 //
202 //// void *side;
203 //// unsigned int offset, pid;
204 ////
205 //// // loop over cell points/lines/triangles/tetrahedra
206 //// for (int i=0; i<n_simplex_objects<dim>(obj_dim); i++)
207 //// {
208 //// side = cell->side_by_dim(obj_dim,i);
209 //// pid = permutation_id<dim,obj_dim>(cell,i);
210 //// offset = 0;
211 //// // loop over dof multiplicities (single dofs, pairs, triples, sextuples)
212 //// for (vector<unsigned int>::iterator m=dof_multiplicities.begin(); m!=dof_multiplicities.end(); m++)
213 //// {
214 //// // loop over particular single dofs/dof pairs/triples/sextuples
215 //// for (int j=0; j<finite_element.n_object_dofs(obj_dim,*m); j++)
216 //// {
217 //// // loop over particular dofs (the single dof/2 dofs in the pair etc.)
218 //// for (int k=0; k<*m; k++)
219 //// indices.push_back(object_dofs[obj_dim][side][offset+Simplex<obj_dim>::pair_permutations[pid][k]]);
220 ////
221 //// offset += *m;
222 //// }
223 //// }
224 //// }
225 ////}
226 //
227 //template<unsigned int dim, unsigned int spacedim> inline
228 //void DOFHandler<dim,spacedim>::get_dof_values(const CellIterator &cell, const Vec &values, double local_values[])
229 //{
230 // unsigned int indices[finite_element->n_dofs()];
231 //
232 // get_dof_indices(cell, indices);
233 // VecGetValues(values, finite_element->n_dofs(), (PetscInt *)indices, local_values);
234 //}
235 
236 
237 
238 DOFHandlerMultiDim::DOFHandlerMultiDim(Mesh& _mesh, bool make_elem_part)
239  : DOFHandlerBase(_mesh),
240  ds_(nullptr)
241 {
242  if (make_elem_part) make_elem_partitioning();
243 }
244 
245 
247 {
248  switch (cell->dim()) {
249  case 1:
250  return fe<1>(cell)->n_dofs();
251  break;
252  case 2:
253  return fe<2>(cell)->n_dofs();
254  break;
255  case 3:
256  return fe<3>(cell)->n_dofs();
257  break;
258  }
259 }
260 
261 
262 const Dof &DOFHandlerMultiDim::cell_dof(ElementAccessor<3> cell, unsigned int idof) const
263 {
264  switch (cell.dim())
265  {
266  case 1:
267  return fe<1>(cell)->dof(idof);
268  break;
269  case 2:
270  return fe<2>(cell)->dof(idof);
271  break;
272  case 3:
273  return fe<3>(cell)->dof(idof);
274  break;
275  }
276 }
277 
278 
280 {
281  // get number of dofs per element and then set up cell_starts
283  for (unsigned int loc_el=0; loc_el<el_ds_->lsize(); ++loc_el)
284  {
285  auto cell = mesh_->element_accessor(el_index(loc_el));
286  cell_starts[row_4_el[cell.idx()]+1] = n_dofs(cell);
287  max_elem_dofs_ = max((int)max_elem_dofs_, (int)n_dofs(cell));
288  }
289  for (unsigned int gid=0; gid<ghost_4_loc.size(); ++gid)
290  {
291  auto cell = mesh_->element_accessor(ghost_4_loc[gid]);
292  cell_starts[row_4_el[cell.idx()]+1] = n_dofs(cell);
293  max_elem_dofs_ = max((int)max_elem_dofs_, (int)n_dofs(cell));
294  }
295  for (unsigned int i=0; i<mesh_->n_elements(); ++i)
296  cell_starts[i+1] += cell_starts[i];
297 }
298 
299 
301 {
302  // initialize dofs on nodes
303  // We must separate dofs for dimensions because FE functions
304  // may be discontinuous on nodes shared by different
305  // dimensions.
306  unsigned int n_node_dofs = 0;
307 
308  for (unsigned int nid=0; nid<mesh_->tree->n_nodes(); nid++)
309  {
310  node_dof_starts.push_back(n_node_dofs);
311  n_node_dofs += ds_->n_node_dofs(nid);
312  }
313  node_dof_starts.push_back(n_node_dofs);
314 }
315 
316 
318 {
319  // mark local dofs
320  for (unsigned int loc_el=0; loc_el<el_ds_->lsize(); loc_el++)
321  {
323 
324  for (unsigned int n=0; n<cell->dim()+1; n++)
325  {
326  unsigned int nid = mesh_->tree->objects(cell->dim())[mesh_->tree->obj_4_el()[cell.idx()]].nodes[n];
327  node_status[nid] = VALID_NODE;
328  }
329  }
330 
331  // unmark dofs on ghost cells from lower procs
332  for (unsigned int gid=0; gid<ghost_4_loc.size(); gid++)
333  {
335  if (cell.proc() < el_ds_->myp())
336  {
337  for (unsigned int n=0; n<cell->dim()+1; n++)
338  {
339  unsigned int nid = mesh_->tree->objects(cell->dim())[mesh_->tree->obj_4_el()[cell.idx()]].nodes[n];
340  node_status[nid] = INVALID_NODE;
341  }
342  }
343  }
344 }
345 
346 
348 {
349  // send number of elements required from the other processor
350  unsigned int n_elems = ghost_proc_el[proc].size();
351  MPI_Send(&n_elems, 1, MPI_UNSIGNED, proc, 0, MPI_COMM_WORLD);
352 
353  // send indices of elements required
354  MPI_Send(&(ghost_proc_el[proc][0]), n_elems, MPI_LONG_IDX, proc, 1, MPI_COMM_WORLD);
355 
356  // receive numbers of dofs on required elements
357  vector<unsigned int> n_dofs(n_elems);
358  MPI_Recv(&(n_dofs[0]), n_elems, MPI_UNSIGNED, proc, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
359 
360  // receive dofs on required elements
361  unsigned int n_dofs_sum = 0;
362  for (auto nd : n_dofs) n_dofs_sum += nd;
363  dofs.resize(n_dofs_sum);
364  MPI_Recv(&(dofs[0]), n_dofs_sum, MPI_LONG_IDX, proc, 3, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
365 }
366 
367 
368 void DOFHandlerMultiDim::send_ghost_dofs(unsigned int proc)
369 {
370  // receive number of elements required by the other processor
371  unsigned int n_elems;
372  MPI_Recv(&n_elems, 1, MPI_UNSIGNED, proc, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
373 
374  // receive indices of elements required
375  vector<LongIdx> elems(n_elems);
376  MPI_Recv(&(elems[0]), n_elems, MPI_LONG_IDX, proc, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
377 
378  // send numbers of dofs on required elements
380  for (LongIdx el : elems) n_dofs.push_back(cell_starts[row_4_el[el]+1] - cell_starts[row_4_el[el]]);
381  MPI_Send(&(n_dofs[0]), n_elems, MPI_UNSIGNED, proc, 2, MPI_COMM_WORLD);
382 
383  // send dofs on the required elements
384  vector<LongIdx> dofs;
385  for (LongIdx el : elems)
386  dofs.insert(dofs.end(), dof_indices.begin()+cell_starts[row_4_el[el]], dof_indices.begin()+cell_starts[row_4_el[el]+1]);
387  MPI_Send(&(dofs[0]), dofs.size(), MPI_LONG_IDX, proc, 3, MPI_COMM_WORLD);
388 }
389 
390 
392  const std::vector<bool> &update_cells,
393  const std::vector<LongIdx> &dofs,
394  const std::vector<LongIdx> &node_dof_starts,
395  std::vector<LongIdx> &node_dofs
396  )
397 {
398  // update dof_indices on ghost cells
399  unsigned int dof_offset=0;
400  for (unsigned int gid=0; gid<ghost_proc_el[proc].size(); gid++)
401  {
402  auto cell = mesh_->element_accessor(ghost_proc_el[proc][gid]);
403 
404  for (unsigned dof=0; dof<n_dofs(cell); dof++)
405  dof_indices[cell_starts[row_4_el[cell.idx()]]+dof] = dofs[dof_offset+dof];
406 
407  vector<unsigned int> loc_node_dof_count(cell->n_nodes(), 0);
408  for (unsigned int idof = 0; idof<n_dofs(cell); ++idof)
409  {
410  if (cell_dof(cell, idof).dim == 0)
411  { // update nodal dof
412  unsigned int dof_nface_idx = cell_dof(cell, idof).n_face_idx;
413  unsigned int nid = mesh_->tree->objects(cell->dim())[mesh_->tree->obj_4_el()[cell.idx()]].nodes[dof_nface_idx];
414 
415  if (node_dofs[node_dof_starts[nid]+loc_node_dof_count[dof_nface_idx]] == INVALID_DOF)
416  node_dofs[node_dof_starts[nid]+loc_node_dof_count[dof_nface_idx]] = dofs[dof_offset+idof];
417 
418  loc_node_dof_count[dof_nface_idx]++;
419  }
420  }
421 
422  dof_offset += n_dofs(cell);
423  }
424 
425  // update dof_indices on local elements
426  for (unsigned int loc_el=0; loc_el < el_ds_->lsize(); loc_el++)
427  {
428  if (!update_cells[loc_el]) continue;
429 
431 
432  // loop over element dofs
433  vector<unsigned int> loc_node_dof_count(cell->n_nodes(), 0);
434  for (unsigned int idof = 0; idof<n_dofs(cell); ++idof)
435  {
436  if (cell_dof(cell,idof).dim == 0)
437  {
438  unsigned int dof_nface_idx = cell_dof(cell, idof).n_face_idx;
439  if (dof_indices[cell_starts[row_4_el[cell.idx()]]+idof] == INVALID_DOF)
440  { // update nodal dof
441  unsigned int nid = mesh_->tree->objects(cell->dim())[mesh_->tree->obj_4_el()[cell.idx()]].nodes[dof_nface_idx];
442  dof_indices[cell_starts[row_4_el[cell.idx()]]+idof] = node_dofs[node_dof_starts[nid]+loc_node_dof_count[dof_nface_idx]];
443  }
444  loc_node_dof_count[dof_nface_idx]++;
445  }
446  }
447  }
448 }
449 
450 
451 void DOFHandlerMultiDim::distribute_dofs(std::shared_ptr<DiscreteSpace> ds,
452  bool sequential)
453 {
454  // First check if dofs are already distributed.
455  OLD_ASSERT(ds_ == nullptr, "Attempt to distribute DOFs multiple times!");
456 
457  ds_ = ds;
458 
459  std::vector<LongIdx> node_dofs, node_dof_starts;
461  std::vector<bool> update_cells(el_ds_->lsize(), false);
462  unsigned int next_free_dof = 0;
463 
465  init_node_dof_starts(node_dof_starts);
466  node_dofs.resize(node_dof_starts[node_dof_starts.size()-1]);
467  init_node_status(node_status);
468 
469  // Distribute dofs on local elements.
470  dof_indices.resize(cell_starts[cell_starts.size()-1]);
471  for (unsigned int loc_el=0; loc_el < el_ds_->lsize(); loc_el++)
472  {
474 
475  // loop over element dofs
476  vector<unsigned int> loc_node_dof_count(cell->n_nodes(), 0);
477  for (unsigned int idof = 0; idof<n_dofs(cell); ++idof)
478  {
479  unsigned int dof_dim = cell_dof(cell, idof).dim;
480  unsigned int dof_nface_idx = cell_dof(cell, idof).n_face_idx;
481 
482  if (dof_dim == 0)
483  { // add dofs shared by nodes
484  unsigned int nid = mesh_->tree->objects(cell->dim())[mesh_->tree->obj_4_el()[cell.idx()]].nodes[dof_nface_idx];
485  unsigned int node_dof_idx = node_dof_starts[nid]+loc_node_dof_count[dof_nface_idx];
486 
487  switch (node_status[nid])
488  {
489  case VALID_NODE:
490  for (int i=0; i<node_dof_starts[nid+1] - node_dof_starts[nid]; i++)
491  node_dofs[node_dof_starts[nid]+i] = next_free_dof++;
492  node_status[nid] = ASSIGNED_NODE;
493  break;
494  case INVALID_NODE:
495  node_dofs[node_dof_idx] = INVALID_DOF;
496  update_cells[loc_el] = true;
497  break;
498  }
499  dof_indices[cell_starts[row_4_el[cell.idx()]]+idof] = node_dofs[node_dof_idx];
500  loc_node_dof_count[dof_nface_idx]++;
501  }
502  else if (dof_dim == cell.dim())
503  // add dofs owned only by the element
504  dof_indices[cell_starts[row_4_el[cell.idx()]]+idof] = next_free_dof++;
505  else
506  ASSERT(false).error("Unsupported dof n_face.");
507  }
508  }
509  node_status.clear();
510 
511  lsize_ = next_free_dof;
512 
513  // communicate n_dofs across all processes
514  dof_ds_ = new Distribution(lsize_, PETSC_COMM_WORLD);
516 
517  // shift dof indices
519  if (loffset_ > 0)
520  for (unsigned int i=0; i<dof_indices.size(); i++)
521  if (dof_indices[i] != INVALID_DOF)
522  dof_indices[i] += loffset_;
523 
524  // communicate dofs from ghost cells
525  // first propagate from lower procs to higher procs and then vice versa
526  for (unsigned int from_higher = 0; from_higher < 2; from_higher++)
527  {
528  for (unsigned int proc : ghost_proc)
529  {
530  if ((proc > el_ds_->myp()) == from_higher)
531  { // receive dofs from master processor
532  vector<LongIdx> dofs;
533  receive_ghost_dofs(proc, dofs);
534 
535  // update dof_indices and node_dofs on ghost elements
536  update_local_dofs(proc, update_cells, dofs, node_dof_starts, node_dofs);
537  }
538  else
539  send_ghost_dofs(proc);
540  }
541  }
542  update_cells.clear();
543  node_dofs.clear();
544  node_dof_starts.clear();
545 
546  if (sequential) create_sequential();
547 }
548 
549 
551 {
552  ASSERT(dof_indices.size() > 0).error("Attempt to create sequential dof handler from uninitialized or already sequential object!");
553 
554  // Auxiliary vectors cell_starts_loc and dof_indices_loc contain
555  // only local element data (without ghost elements).
556  // Then it is possible to create sequential vectors by simple reduce/gather operation.
557  vector<LongIdx> cell_starts_loc(mesh_->n_elements()+1, 0);
558  vector<LongIdx> dof_indices_loc;
559 
560  // construct cell_starts_loc
561  for (unsigned int loc_el=0; loc_el<el_ds_->lsize(); ++loc_el)
562  {
563  auto cell = mesh_->element_accessor(el_index(loc_el));
564  cell_starts_loc[row_4_el[cell.idx()]+1] = n_dofs(cell);
565  }
566  for (unsigned int i=0; i<mesh_->n_elements(); ++i)
567  cell_starts_loc[i+1] += cell_starts_loc[i];
568 
569  // construct dof_indices_loc
570  dof_indices_loc.resize(cell_starts_loc[mesh_->n_elements()]);
571  for (unsigned int loc_el=0; loc_el<el_ds_->lsize(); ++loc_el)
572  {
573  auto cell = mesh_->element_accessor(el_index(loc_el));
574  for (unsigned int idof=0; idof<n_dofs(cell); idof++)
575  dof_indices_loc[cell_starts_loc[row_4_el[cell.idx()]]+idof] = dof_indices[cell_starts[row_4_el[cell.idx()]]+idof];
576  }
577 
578  // Parallel data are no more used.
579  cell_starts.clear();
580  dof_indices.clear();
581 
582  Distribution distr(dof_indices_loc.size(), PETSC_COMM_WORLD);
583  cell_starts_seq.resize(mesh_->n_elements()+1);
584  dof_indices_seq.resize(distr.size());
585 
586  MPI_Allreduce( cell_starts_loc.data(),
588  cell_starts_loc.size(),
589  MPI_LONG_IDX,
590  MPI_SUM,
591  MPI_COMM_WORLD );
592 
593  MPI_Allgatherv( dof_indices_loc.data(),
594  dof_indices_loc.size(),
595  MPI_LONG_IDX,
597  (const int *)distr.get_lsizes_array(),
598  (const int *)distr.get_starts_array(),
599  MPI_LONG_IDX,
600  MPI_COMM_WORLD );
601 }
602 
603 
604 
606 {
607  unsigned int ndofs = 0;
608  if ( cell_starts_seq.size() > 0 && dof_indices_seq.size() > 0)
609  {
610  ndofs = cell_starts_seq[row_4_el[cell.idx()]+1]-cell_starts_seq[row_4_el[cell.idx()]];
611  for (unsigned int k=0; k<ndofs; k++)
612  indices[k] = dof_indices_seq[cell_starts_seq[row_4_el[cell.idx()]]+k];
613  }
614  else
615  {
616  ndofs = cell_starts[row_4_el[cell.idx()]+1]-cell_starts[row_4_el[cell.idx()]];
617  for (unsigned int k=0; k<ndofs; k++)
618  indices[k] = dof_indices[cell_starts[row_4_el[cell.idx()]]+k];
619  }
620 
621  return ndofs;
622 }
623 
624 
625 
627 {
628  unsigned int ndofs = 0;
629  if ( cell_starts_seq.size() > 0 && dof_indices_seq.size() > 0)
630  {
631  ndofs = cell_starts_seq[row_4_el[cell.idx()]+1]-cell_starts_seq[row_4_el[cell.idx()]];
632  for (unsigned int k=0; k<ndofs; k++)
633  indices[k] = cell_starts_seq[row_4_el[cell.idx()]]+k;
634  }
635  else
636  {
637  ndofs = cell_starts[row_4_el[cell.idx()]+1]-cell_starts[row_4_el[cell.idx()]];
638  for (unsigned int k=0; k<ndofs; k++)
639  indices[k] = cell_starts[row_4_el[cell.idx()]]+k;
640  }
641 
642  return ndofs;
643 }
644 
645 
647 {}
648 
649 
650 
652 {
653  // create local arrays of elements
654  el_ds_ = mesh_->get_el_ds();
657 
658  // create local array of edges
659  for (unsigned int iedg=0; iedg<mesh_->n_edges(); iedg++)
660  {
661  bool is_edge_local = false;
662  Edge *edg = &mesh_->edges[iedg];
663  for (int sid=0; sid<edg->n_sides; sid++)
664  if ( el_is_local(edg->side(sid)->element().idx()) )
665  {
666  is_edge_local = true;
667  break;
668  }
669  if (is_edge_local)
670  edg_4_loc.push_back(iedg);
671  }
672 
673  // create local array of neighbours
674  for (unsigned int inb=0; inb<mesh_->n_vb_neighbours(); inb++)
675  {
676  Neighbour *nb = &mesh_->vb_neighbours_[inb];
677  if ( el_is_local(nb->element().idx())
678  || el_is_local(nb->side()->element().idx()) )
679  nb_4_loc.push_back(inb);
680  }
681 
682  // create array of local nodes
683  std::vector<bool> node_is_local(mesh_->tree->n_nodes(), false);
684  for (unsigned int loc_el=0; loc_el<el_ds_->lsize(); loc_el++)
685  {
687  unsigned int obj_idx = mesh_->tree->obj_4_el()[cell.idx()];
688  for (unsigned int nid=0; nid<cell->n_nodes(); nid++)
689  node_is_local[mesh_->tree->objects(cell->dim())[obj_idx].nodes[nid]] = true;
690  }
691  for (unsigned int nid=0; nid<mesh_->tree->n_nodes(); nid++)
692  if (node_is_local[nid])
693  node_4_loc.push_back(nid);
694 
695  // create array of local ghost cells
696  for ( auto cell : mesh_->elements_range() )
697  {
698  if (cell.proc() != el_ds_->myp())
699  {
700  bool has_local_node = false;
701  unsigned int obj_idx = mesh_->tree->obj_4_el()[cell.idx()];
702  for (unsigned int nid=0; nid<cell->n_nodes(); nid++)
703  if (node_is_local[mesh_->tree->objects(cell->dim())[obj_idx].nodes[nid]])
704  {
705  has_local_node = true;
706  break;
707  }
708  if (has_local_node)
709  {
710  ghost_4_loc.push_back(cell.idx());
711  ghost_proc.insert(cell.proc());
712  ghost_proc_el[cell.proc()].push_back(cell.idx());
713  }
714  }
715  }
716 }
717 
718 
719 bool DOFHandlerMultiDim::el_is_local(int index) const
720 {
721  return el_ds_->is_local(row_4_el[index]);
722 }
723 
724 
725 std::size_t DOFHandlerMultiDim::hash() const {
726  return this->n_global_dofs_;
727 }
728 
#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:347
int LongIdx
Define type that represents indices of large arrays (elements, nodes, dofs etc.)
Definition: long_idx.hh:22
unsigned int size() const
get global size
virtual ~DOFHandlerBase()
Destructor.
Definition: dofhandler.cc:33
void create_sequential()
Communicate local dof indices to all processors.
Definition: dofhandler.cc:550
void init_cell_starts()
Initialize vector of starting indices for elements.
Definition: dofhandler.cc:279
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:391
unsigned int n_nodes() const
Definition: elements.h:129
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:626
LongIdx * get_row_4_el() const
Definition: mesh.h:171
std::vector< LongIdx > cell_starts_seq
Starting indices for element dofs (sequential version).
Definition: dofhandler.hh:376
const std::vector< MeshObject > & objects(unsigned int dim) const
#define MPI_LONG_IDX
Definition: long_idx.hh:24
DuplicateNodes * tree
Definition: mesh.h:268
Distribution * el_ds_
Distribution of elements.
Definition: dofhandler.hh:394
unsigned int dim
Association to n-face of given dimension (point, line, triangle, tetrahedron.
#define MPI_SUM
Definition: mpi.h:196
void distribute_dofs(std::shared_ptr< DiscreteSpace > ds, bool sequential=false)
Distributes degrees of freedom on the mesh needed for the given discrete space.
Definition: dofhandler.cc:451
Definition: mesh.h:80
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
int el_index(int loc_el) const
Returns the global index of local element.
Definition: dofhandler.hh:202
#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:391
ElementAccessor< 3 > element() const
Definition: side_impl.hh:53
unsigned int proc() const
Definition: accessors.hh:125
Distribution * dof_ds_
Distribution of dofs associated to local process.
Definition: dofhandler.hh:133
unsigned int lsize_
Number of dofs associated to local process.
Definition: dofhandler.hh:115
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:246
map< unsigned int, vector< LongIdx > > ghost_proc_el
Arrays of ghost cells for each neighbouring processor.
Definition: dofhandler.hh:412
std::vector< LongIdx > dof_indices_seq
Dof numbers on mesh elements (sequential version).
Definition: dofhandler.hh:384
void send_ghost_dofs(unsigned int proc)
Send dof numbers to other processor.
Definition: dofhandler.cc:368
const unsigned int * get_lsizes_array()
get local sizes array
unsigned int dim() const
Definition: elements.h:124
void init_node_status(std::vector< short int > &node_status)
Initialize node_status.
Definition: dofhandler.cc:317
std::vector< LongIdx > cell_starts
Starting indices for element dofs (parallel version).
Definition: dofhandler.hh:360
#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:338
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:605
bool is_local(unsigned int idx) const
identify local index
const unsigned int * get_starts_array() const
get local starts array
Mesh * mesh_
Pointer to the mesh to which the dof handler is associated.
Definition: dofhandler.hh:128
SideIter side()
Definition: neighbours.h:147
std::vector< LongIdx > dof_indices
Dof numbers on local and ghost elements (parallel version).
Definition: dofhandler.hh:368
vector< LongIdx > nb_4_loc
Local neighbour index -> global neighbour index.
Definition: dofhandler.hh:400
unsigned int max_elem_dofs_
Max. number of dofs per element.
Definition: dofhandler.hh:123
vector< LongIdx > ghost_4_loc
Indices of ghost cells (neighbouring with local elements).
Definition: dofhandler.hh:406
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:300
static const int ASSIGNED_NODE
Definition: dofhandler.hh:339
Distribution * get_el_ds() const
Definition: mesh.h:168
void make_elem_partitioning()
Prepare parallel distribution of elements, edges and neighbours.
Definition: dofhandler.cc:651
static const int INVALID_NODE
Definition: dofhandler.hh:337
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:397
virtual unsigned int n_elements(bool boundary=false) const
Returns count of boundary or bulk elements.
Definition: mesh.h:346
unsigned int loffset_
Index of the first dof on the local process.
Definition: dofhandler.hh:120
static const int INVALID_DOF
Definition: dofhandler.hh:340
const Dof & cell_dof(ElementAccessor< 3 > cell, unsigned int idof) const
Return dof on a given cell.
Definition: dofhandler.cc:262
set< unsigned int > ghost_proc
Processors of ghost elements.
Definition: dofhandler.hh:409
~DOFHandlerMultiDim() override
Destructor.
Definition: dofhandler.cc:646
vector< LongIdx > node_4_loc
Indices of local nodes in mesh tree.
Definition: dofhandler.hh:403
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:344
#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:110
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:719
DOFHandlerMultiDim(Mesh &_mesh, bool make_elem_part=true)
Constructor.
Definition: dofhandler.cc:238
const std::vector< unsigned int > & obj_4_el() const
Distribution * distr() const
Definition: dofhandler.hh:74
unsigned int idx() const
Return local idx of element in boundary / bulk part of element vector.
Definition: accessors.hh:111
LongIdx * get_el_4_loc() const
Definition: mesh.h:174
LongIdx * row_4_el
Global element index -> index according to partitioning.
Definition: dofhandler.hh:388
SideIter side(const unsigned int i) const
Definition: edges.h:31
Implementation of range helper class.
std::size_t hash() const override
Definition: dofhandler.cc:725
unsigned int lsize(int proc) const
get local size