Flow123d  release_3.0.0-1191-g7740876
mh_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 mh_dofhandler.cc
15  * @brief
16  */
17 
18 #include "mesh/side_impl.hh"
19 #include "flow/mh_dofhandler.hh"
21 #include "mesh/long_idx.hh"
22 #include "mesh/mesh.h"
23 #include "mesh/partitioning.hh"
24 #include "mesh/side_impl.hh"
25 #include "mesh/accessors.hh"
26 #include "mesh/range_wrapper.hh"
27 #include "mesh/neighbours.h"
28 #include "system/sys_profiler.hh"
29 
31 :
32 el_4_loc(nullptr),
33 row_4_el(nullptr),
34 side_id_4_loc(nullptr),
35 side_row_4_id(nullptr),
36 edge_4_loc(nullptr),
37 row_4_edge(nullptr),
38 edge_ds(nullptr),
39 el_ds(nullptr),
40 side_ds(nullptr)
41 {}
42 
44 {
45  delete edge_ds;
46  // delete el_ds;
47  delete side_ds;
48 
49  // xfree(el_4_loc);
50  delete [] row_4_el;
51  delete [] side_id_4_loc;
52  delete [] side_row_4_id;
53  delete [] edge_4_loc;
54  delete [] row_4_edge;
55 }
56 
57 
59  mesh_ = mesh;
60  elem_side_to_global.resize(mesh->n_elements() );
61  for (auto ele : mesh->elements_range()) elem_side_to_global[ ele.idx() ].resize(ele->n_sides());
62 
63  unsigned int i_side_global=0;
64  for (auto ele : mesh->elements_range()) {
65  for(unsigned int i_lside=0; i_lside < ele->n_sides(); i_lside++)
66  elem_side_to_global[ ele.idx() ][i_lside] = i_side_global++;
67  }
68 
70 
71 }
72 
73 
74 
75 
76 // ====================================================================================
77 // - compute optimal edge partitioning
78 // - compute appropriate partitioning of elements and sides
79 // - make arrays: *_id_4_loc and *_row_4_id to allow parallel assembly of the MH matrix
80 // ====================================================================================
82 
83  START_TIMER("prepare parallel");
84 
85  LongIdx *loc_part; // optimal (edge,el) partitioning (local chunk)
86  LongIdx *id_4_old; // map from old idx to ids (edge,el)
87  int loc_i;
88 
89  int e_idx;
90 
91 
92  //ierr = MPI_Barrier(PETSC_COMM_WORLD);
93  //OLD_ASSERT(ierr == 0, "Error in MPI_Barrier.");
94 
95  // row_4_el will be modified so we make a copy of the array from mesh
96  row_4_el = new LongIdx[mesh_->n_elements()];
99  el_ds = mesh_->get_el_ds();
100 
101  //optimal element part; loc. els. id-> new el. numbering
102  Distribution init_edge_ds(DistributionLocalized(), mesh_->n_edges(), PETSC_COMM_WORLD);
103  // partitioning of edges, edge belongs to the proc of his first element
104  // this is not optimal but simple
105  loc_part = new LongIdx[init_edge_ds.lsize()];
106  id_4_old = new LongIdx[mesh_->n_edges()];
107  {
108  loc_i = 0;
109  for( vector<Edge>::iterator edg = mesh_->edges.begin(); edg != mesh_->edges.end(); ++edg) {
110  unsigned int i_edg = edg - mesh_->edges.begin();
111  // partition
112  e_idx = edg->side(0)->element().idx();
113  if (init_edge_ds.is_local(i_edg)) {
114  // find (new) proc of the first element of the edge
115  loc_part[loc_i++] = el_ds->get_proc(row_4_el[e_idx]);
116  }
117  // id array
118  id_4_old[i_edg] = i_edg;
119  }
120  }
121  Partitioning::id_maps(mesh_->n_edges(), id_4_old, init_edge_ds, loc_part, edge_ds, edge_4_loc, row_4_edge);
122  delete[] loc_part;
123  delete[] id_4_old;
124 
125  // create map from mesh global edge id to new local edge id
126  unsigned int loc_edge_idx=0;
127  for (unsigned int i_el_loc = 0; i_el_loc < el_ds->lsize(); i_el_loc++) {
128  auto ele = mesh_->element_accessor( el_4_loc[i_el_loc] );
129  for (unsigned int i = 0; i < ele->n_sides(); i++) {
130  unsigned int mesh_edge_idx= ele.side(i)->edge_idx();
131  if ( edge_new_local_4_mesh_idx_.count(mesh_edge_idx) == 0 )
132  // new local edge
133  edge_new_local_4_mesh_idx_[mesh_edge_idx] = loc_edge_idx++;
134  }
135  }
136 
137  //optimal side part; loc. sides; id-> new side numbering
138  Distribution init_side_ds(DistributionBlock(), mesh_->n_sides(), PETSC_COMM_WORLD);
139  // partitioning of sides follows elements
140  loc_part = new LongIdx[init_side_ds.lsize()];
141  id_4_old = new LongIdx[mesh_->n_sides()];
142  {
143  int is = 0;
144  loc_i = 0;
145  for (auto ele : mesh_->elements_range())
146  for(SideIter side = ele.side(0); side->side_idx() < ele->n_sides(); ++side) {
147  // partition
148  if (init_side_ds.is_local(is)) {
149  // find (new) proc of the element of the side
150  loc_part[loc_i++] = el_ds->get_proc(
151  row_4_el[ side->element().idx() ]);
152  }
153  // id array
154  id_4_old[is++] = side_dof( side );
155  }
156  }
157 
158  Partitioning::id_maps(mesh_->n_sides(), id_4_old, init_side_ds, loc_part, side_ds,
160  delete [] loc_part;
161  delete [] id_4_old;
162 
163  // convert row_4_id arrays from separate numberings to global numbering of rows
165 
166 }
167 
168 // ========================================================================
169 // to finish row_4_id arrays we have to convert individual numberings of
170 // sides/els/edges to whole numbering of rows. To this end we count shifts
171 // for sides/els/edges on each proc and then we apply them on row_4_id
172 // arrays.
173 // we employ macros to avoid code redundancy
174 // =======================================================================
176  int i, shift;
177  int np = edge_ds->np();
178  int edge_shift[np], el_shift[np], side_shift[np];
179  unsigned int rows_starts[np];
180 
181  int edge_n_id = mesh_->n_edges(),
182  el_n_id = mesh_->n_elements(),
183  side_n_id = mesh_->n_sides();
184 
185  // compute shifts on every proc
186  shift = 0; // in this var. we count new starts of arrays chunks
187  for (i = 0; i < np; i++) {
188  side_shift[i] = shift - (side_ds->begin(i)); // subtract actual start of the chunk
189  shift += side_ds->lsize(i);
190  el_shift[i] = shift - (el_ds->begin(i));
191  shift += el_ds->lsize(i);
192  edge_shift[i] = shift - (edge_ds->begin(i));
193  shift += edge_ds->lsize(i);
194  rows_starts[i] = shift;
195  }
196  // apply shifts
197  for (i = 0; i < side_n_id; i++) {
198  LongIdx &what = side_row_4_id[i];
199  if (what >= 0)
200  what += side_shift[side_ds->get_proc(what)];
201  }
202  for (i = 0; i < el_n_id; i++) {
203  LongIdx &what = row_4_el[i];
204  if (what >= 0)
205  what += el_shift[el_ds->get_proc(what)];
206 
207  }
208  for (i = 0; i < edge_n_id; i++) {
209  LongIdx &what = row_4_edge[i];
210  if (what >= 0)
211  what += edge_shift[edge_ds->get_proc(what)];
212  }
213  // make distribution of rows
214  for (i = np - 1; i > 0; i--)
215  rows_starts[i] -= rows_starts[i - 1];
216 
217  rows_ds = std::make_shared<Distribution>(&(rows_starts[0]), PETSC_COMM_WORLD);
218 }
219 
220 
222 #ifdef FLOW123D_HAVE_BDDCML
223  // auxiliary
225  LongIdx side_row, edge_row;
226 
227  global_row_4_sub_row = std::make_shared<LocalToGlobalMap>(rows_ds);
228 
229  //
230  // ordering of dofs
231  // for each subdomain:
232  // | velocities (at sides) | pressures (at elements) | L. mult. (at edges) |
233  for (unsigned int i_loc = 0; i_loc < el_ds->lsize(); i_loc++) {
234  el = mesh_->element_accessor( el_4_loc[i_loc] );
235  LongIdx el_row = row_4_el[el_4_loc[i_loc]];
236 
237  global_row_4_sub_row->insert( el_row );
238 
239  unsigned int nsides = el->n_sides();
240  for (unsigned int i = 0; i < nsides; i++) {
241  side_row = side_row_4_id[ side_dof( el.side(i) ) ];
242  edge_row = row_4_edge[el.side(i)->edge_idx()];
243 
244  global_row_4_sub_row->insert( side_row );
245  global_row_4_sub_row->insert( edge_row );
246  }
247 
248  for (unsigned int i_neigh = 0; i_neigh < el->n_neighs_vb(); i_neigh++) {
249  // mark this edge
250  edge_row = row_4_edge[el->neigh_vb[i_neigh]->edge_idx() ];
251  global_row_4_sub_row->insert( edge_row );
252  }
253  }
254  global_row_4_sub_row->finalize();
255 #endif // FLOW123D_HAVE_BDDCML
256 }
257 
258 
259 
260 unsigned int MH_DofHandler::side_dof(const SideIter side) const {
261  return elem_side_to_global[ side->element().idx() ][ side->side_idx() ];
262 }
263 
264 
265 void MH_DofHandler::set_solution( double time, double * solution, double precision) {
266  OLD_ASSERT( solution != NULL, "Empty solution.\n");
267  mh_solution = solution;
269  time_ = time;
270 }
271 
272 /// temporary replacement for DofHandler accessor, flux through given side
273 double MH_DofHandler::side_flux(const Side &side) const {
274  return mh_solution[ elem_side_to_global[ side.element().idx() ][ side.side_idx() ] ];
275 }
276 
277 /// temporary replacement for DofHandler accessor, scalar (pressure) on edge of the side
278 double MH_DofHandler::side_scalar(const Side &side) const {
279  unsigned int i_edg = side.edge_idx();
280  return mh_solution[ side.mesh()->n_sides() + side.mesh()->n_elements() + i_edg ];
281 }
282 
283 
285  return mh_solution[ mesh_->n_sides() + ele.idx() ];
286 }
287 
288 
290  return LocalElementAccessorBase<3>(this, local_ele_idx);
291 }
Definition: sides.h:39
int LongIdx
Define type that represents indices of large arrays (elements, nodes, dofs etc.)
Definition: long_idx.hh:22
unsigned int get_proc(unsigned int idx) const
get processor of the given index
Distribution * side_ds
void reinit(Mesh *mesh)
void make_row_numberings()
LongIdx * get_row_4_el() const
Definition: mesh.h:167
unsigned int uint
LongIdx * el_4_loc
unsigned int side_idx() const
Definition: side_impl.hh:82
unsigned int edge_idx() const
Definition: side_impl.hh:62
LongIdx * side_row_4_id
Definition: mesh.h:76
Distribution * el_ds
SideIter side(const unsigned int loc_index)
Definition: accessors.hh:137
ElementAccessor< 3 > element() const
Definition: side_impl.hh:53
LongIdx * row_4_el
LongIdx * side_id_4_loc
virtual ElementAccessor< 3 > element_accessor(unsigned int idx) const
Create and return ElementAccessor to element of given idx.
Definition: mesh.cc:727
std::unordered_map< unsigned int, unsigned int > edge_new_local_4_mesh_idx_
std::shared_ptr< LocalToGlobalMap > global_row_4_sub_row
Necessary only for BDDC solver.
double precision() const
vector< vector< unsigned int > > elem_side_to_global
#define OLD_ASSERT(...)
Definition: global_defs.h:131
double element_scalar(ElementAccessor< 3 > &ele) const
temporary replacement for DofHandler accessor, scalar (pressure) on element
unsigned int edge_idx()
Definition: neighbours.h:153
Neighbour ** neigh_vb
Definition: elements.h:87
unsigned int begin(int proc) const
get starting local index
unsigned int n_sides() const
Definition: elements.h:135
#define START_TIMER(tag)
Starts a timer with specified tag.
Distribution * edge_ds
unsigned int side_dof(const SideIter side) const
virtual Range< ElementAccessor< 3 > > elements_range() const
Returns range of bulk elements.
Definition: mesh.cc:1041
unsigned int np() const
get num of processors
unsigned int n_sides() const
Definition: mesh.cc:227
Distribution * get_el_ds() const
Definition: mesh.h:164
void id_maps(int n_ids, LongIdx *id_4_old, Distribution *&new_ds, LongIdx *&id_4_loc, LongIdx *&new_4_id)
double side_flux(const Side &side) const
temporary replacement for DofHandler accessor, flux through given side
LongIdx * row_4_edge
virtual unsigned int n_elements(bool boundary=false) const
Returns count of boundary or bulk elements.
Definition: mesh.h:346
LongIdx * edge_4_loc
void prepare_parallel()
std::shared_ptr< Distribution > rows_ds
LocalElementAccessorBase< 3 > accessor(uint local_ele_idx)
std::vector< Edge > edges
Vector of MH edges, this should not be part of the geometrical mesh.
Definition: mesh.h:252
void prepare_parallel_bddc()
double * mh_solution
void set_solution(double time, double *solution, double precision)
unsigned int n_edges() const
Definition: mesh.h:137
double side_scalar(const Side &side) const
temporary replacement for DofHandler accessor, scalar (pressure) on edge of the side ...
double solution_precision
const Mesh * mesh() const
Definition: side_impl.hh:58
unsigned int n_neighs_vb() const
Return number of neighbours.
Definition: elements.h:70
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:170
Implementation of range helper class.
unsigned int lsize(int proc) const
get local size