Reference documentation for deal.II version 8.5.1
grid_refinement.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2000 - 2016 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #include <deal.II/base/utilities.h>
18 #include <deal.II/base/std_cxx11/bind.h>
19 #include <deal.II/lac/vector.h>
20 #include <deal.II/lac/block_vector.h>
21 #include <deal.II/lac/petsc_vector.h>
22 #include <deal.II/lac/petsc_block_vector.h>
23 #include <deal.II/lac/trilinos_vector.h>
24 #include <deal.II/lac/trilinos_block_vector.h>
25 
26 #ifdef DEAL_II_WITH_P4EST
27 
28 #include <deal.II/grid/grid_refinement.h>
29 #include <deal.II/grid/tria_accessor.h>
30 #include <deal.II/grid/tria_iterator.h>
31 #include <deal.II/grid/tria.h>
32 
33 #include <deal.II/distributed/grid_refinement.h>
34 
35 #include <numeric>
36 #include <algorithm>
37 #include <limits>
38 
39 
40 DEAL_II_NAMESPACE_OPEN
41 
42 
43 namespace
44 {
45  template <typename number>
46  inline
47  number
48  max_element (const Vector<number> &criteria)
49  {
50  return (criteria.size()>0)
51  ?
52  (*std::max_element(criteria.begin(), criteria.end()))
53  :
54  std::numeric_limits<number>::min();
55  }
56 
57 
58 
59  template <typename number>
60  inline
61  number
62  min_element (const Vector<number> &criteria)
63  {
64  return (criteria.size()>0)
65  ?
66  (*std::min_element(criteria.begin(), criteria.end()))
67  :
68  std::numeric_limits<number>::max();
69  }
70 
71 
79  template <typename number>
80  std::pair<number,number>
81  compute_global_min_and_max_at_root (const Vector<number> &criteria,
82  MPI_Comm mpi_communicator)
83  {
84  // we'd like to compute the
85  // global max and min from the
86  // local ones in one MPI
87  // communication. we can do that
88  // by taking the elementwise
89  // minimum of the local min and
90  // the negative maximum over all
91  // processors
92 
93  const double local_min = min_element (criteria),
94  local_max = max_element (criteria);
95  double comp[2] = { local_min, -local_max };
96  double result[2] = { 0, 0 };
97 
98  // compute the minimum on
99  // processor zero
100  const int ierr = MPI_Reduce (comp, result, 2, MPI_DOUBLE,
101  MPI_MIN, 0, mpi_communicator);
102  AssertThrowMPI(ierr);
103 
104  // make sure only processor zero
105  // got something
106  if (Utilities::MPI::this_mpi_process (mpi_communicator) != 0)
107  Assert ((result[0] == 0) && (result[1] == 0),
108  ExcInternalError());
109 
110  return std::make_pair (result[0], -result[1]);
111  }
112 
113 
114 
122  template <typename number>
123  double
124  compute_global_sum (const Vector<number> &criteria,
125  MPI_Comm mpi_communicator)
126  {
127  double my_sum = std::accumulate (criteria.begin(),
128  criteria.end(),
129  /* do accumulation in the correct data type: */
130  number());
131 
132  double result = 0;
133  // compute the minimum on
134  // processor zero
135  const int ierr = MPI_Reduce (&my_sum, &result, 1, MPI_DOUBLE,
136  MPI_SUM, 0, mpi_communicator);
137  AssertThrowMPI(ierr);
138 
139  // make sure only processor zero
140  // got something
141  if (Utilities::MPI::this_mpi_process (mpi_communicator) != 0)
142  Assert (result == 0, ExcInternalError());
143 
144  return result;
145  }
146 
147 
148 
155  template <int dim, int spacedim, typename VectorType>
156  void
157  get_locally_owned_indicators (const parallel::distributed::Triangulation<dim,spacedim> &tria,
158  const VectorType &criteria,
159  Vector<typename VectorType::value_type> &locally_owned_indicators)
160  {
161  Assert (locally_owned_indicators.size() == tria.n_locally_owned_active_cells(),
162  ExcInternalError());
163 
164  unsigned int owned_index = 0;
166  cell = tria.begin_active();
167  cell != tria.end(); ++cell)
168  if (cell->subdomain_id() == tria.locally_owned_subdomain())
169  {
170  locally_owned_indicators(owned_index)
171  = criteria(cell->active_cell_index());
172  ++owned_index;
173  }
174  Assert (owned_index == tria.n_locally_owned_active_cells(),
175  ExcInternalError());
176  }
177 
178 
179  // we compute refinement
180  // thresholds by bisection of the
181  // interval spanned by the
182  // smallest and largest error
183  // indicator. this leads to a
184  // small problem: if, for
185  // example, we want to coarsen
186  // zero per cent of the cells,
187  // then we need to pick a
188  // threshold equal to the
189  // smallest indicator, but of
190  // course the bisection algorithm
191  // can never find a threshold
192  // equal to one of the end points
193  // of the interval. So we
194  // slightly increase the interval
195  // before we even start
196  void adjust_interesting_range (double (&interesting_range)[2])
197  {
198  Assert (interesting_range[0] <= interesting_range[1],
199  ExcInternalError());
200 
201  Assert (interesting_range[0] >= 0,
202  ExcInternalError());
203 
204  // adjust the lower bound only
205  // if the end point is not equal
206  // to zero, otherwise it could
207  // happen, that the result
208  // becomes negative
209  if (interesting_range[0] > 0)
210  interesting_range[0] *= 0.99;
211 
212  if (interesting_range[1] > 0)
213  interesting_range[1] *= 1.01;
214  else
215  interesting_range[1]
216  += 0.01 * (interesting_range[1] - interesting_range[0]);
217  }
218 
219 
220 
228  template <int dim, int spacedim, typename VectorType>
229  void
231  const VectorType &criteria,
232  const double top_threshold,
233  const double bottom_threshold)
234  {
235  ::GridRefinement::refine (tria, criteria, top_threshold);
236  ::GridRefinement::coarsen (tria, criteria, bottom_threshold);
237 
238  // as a final good measure,
239  // delete all flags again
240  // from cells that we don't
241  // locally own
243  cell = tria.begin_active();
244  cell != tria.end(); ++cell)
245  if (cell->subdomain_id() != tria.locally_owned_subdomain())
246  {
247  cell->clear_refine_flag ();
248  cell->clear_coarsen_flag ();
249  }
250  }
251 
252 
253 
254 
256  {
262  template <typename number>
263  number
264  compute_threshold (const Vector<number> &criteria,
265  const std::pair<double,double> global_min_and_max,
266  const unsigned int n_target_cells,
267  MPI_Comm mpi_communicator)
268  {
269  double interesting_range[2] = { global_min_and_max.first,
270  global_min_and_max.second
271  };
272  adjust_interesting_range (interesting_range);
273 
274  const unsigned int master_mpi_rank = 0;
275  unsigned int iteration = 0;
276 
277  do
278  {
279  int ierr = MPI_Bcast (&interesting_range[0], 2, MPI_DOUBLE,
280  master_mpi_rank, mpi_communicator);
281  AssertThrowMPI(ierr);
282 
283  if (interesting_range[0] == interesting_range[1])
284  return interesting_range[0];
285 
286  const double test_threshold
287  = (interesting_range[0] > 0
288  ?
289  std::sqrt(interesting_range[0] * interesting_range[1])
290  :
291  (interesting_range[0] + interesting_range[1]) / 2);
292 
293  // count how many of our own
294  // elements would be above
295  // this threshold and then
296  // add to it the number for
297  // all the others
298  unsigned int
299  my_count = std::count_if (criteria.begin(),
300  criteria.end(),
301  std_cxx11::bind (std::greater<double>(),
302  std_cxx11::_1,
303  test_threshold));
304 
305  unsigned int total_count;
306  ierr = MPI_Reduce (&my_count, &total_count, 1, MPI_UNSIGNED,
307  MPI_SUM, master_mpi_rank, mpi_communicator);
308  AssertThrowMPI(ierr);
309 
310  // now adjust the range. if
311  // we have to many cells, we
312  // take the upper half of the
313  // previous range, otherwise
314  // the lower half. if we have
315  // hit the right number, then
316  // set the range to the exact
317  // value.
318  // slave nodes also update their own interesting_range, however
319  // their results are not significant since the values will be
320  // overwritten by MPI_Bcast from the master node in next loop.
321  if (total_count > n_target_cells)
322  interesting_range[0] = test_threshold;
323  else if (total_count < n_target_cells)
324  interesting_range[1] = test_threshold;
325  else
326  interesting_range[0] = interesting_range[1] = test_threshold;
327 
328  // terminate the iteration after 25 go-arounds. this is necessary
329  // because oftentimes error indicators on cells have exactly the
330  // same value, and so there may not be a particular value that cuts
331  // the indicators in such a way that we can achieve the desired
332  // number of cells. using a maximal number of iterations means that
333  // we terminate the iteration after a fixed number N of steps if the
334  // indicators were perfectly badly distributed, and we make at most
335  // a mistake of 1/2^N in the number of cells flagged if indicators
336  // are perfectly equidistributed
337  ++iteration;
338  if (iteration == 25)
339  interesting_range[0] = interesting_range[1] = test_threshold;
340  }
341  while (true);
342 
343  Assert (false, ExcInternalError());
344  return -1;
345  }
346  }
347 
348 
349 
350 
352  {
359  template <typename number>
360  number
361  compute_threshold (const Vector<number> &criteria,
362  const std::pair<double,double> global_min_and_max,
363  const double target_error,
364  MPI_Comm mpi_communicator)
365  {
366  double interesting_range[2] = { global_min_and_max.first,
367  global_min_and_max.second
368  };
369  adjust_interesting_range (interesting_range);
370 
371  const unsigned int master_mpi_rank = 0;
372  unsigned int iteration = 0;
373 
374  do
375  {
376  int ierr = MPI_Bcast (&interesting_range[0], 2, MPI_DOUBLE,
377  master_mpi_rank, mpi_communicator);
378  AssertThrowMPI(ierr);
379 
380  if (interesting_range[0] == interesting_range[1])
381  {
382  // so we have found our threshold. since we adjust
383  // the range at the top of the function to be slightly
384  // larger than the actual extremes of the refinement
385  // criteria values, we can end up in a situation where
386  // the threshold is in fact larger than the maximal
387  // refinement indicator. in such cases, we get no
388  // refinement at all. thus, cap the threshold by the
389  // actual largest value
390  double final_threshold = std::min (interesting_range[0],
391  global_min_and_max.second);
392  ierr = MPI_Bcast (&final_threshold, 1, MPI_DOUBLE,
393  master_mpi_rank, mpi_communicator);
394  AssertThrowMPI(ierr);
395 
396  return final_threshold;
397  }
398 
399  const double test_threshold
400  = (interesting_range[0] > 0
401  ?
402  std::sqrt(interesting_range[0] * interesting_range[1])
403  :
404  (interesting_range[0] + interesting_range[1]) / 2);
405 
406  // accumulate the error of those our own elements above this
407  // threshold and then add to it the number for all the
408  // others
409  double my_error = 0;
410  for (unsigned int i=0; i<criteria.size(); ++i)
411  if (criteria(i) > test_threshold)
412  my_error += criteria(i);
413 
414  double total_error;
415  ierr = MPI_Reduce (&my_error, &total_error, 1, MPI_DOUBLE,
416  MPI_SUM, master_mpi_rank, mpi_communicator);
417  AssertThrowMPI(ierr);
418 
419  // now adjust the range. if we have to many cells, we take
420  // the upper half of the previous range, otherwise the lower
421  // half. if we have hit the right number, then set the range
422  // to the exact value.
423  // slave nodes also update their own interesting_range, however
424  // their results are not significant since the values will be
425  // overwritten by MPI_Bcast from the master node in next loop.
426  if (total_error > target_error)
427  interesting_range[0] = test_threshold;
428  else if (total_error < target_error)
429  interesting_range[1] = test_threshold;
430  else
431  interesting_range[0] = interesting_range[1] = test_threshold;
432 
433  // terminate the iteration after 25 go-arounds. this is
434  // necessary because oftentimes error indicators on cells
435  // have exactly the same value, and so there may not be a
436  // particular value that cuts the indicators in such a way
437  // that we can achieve the desired number of cells. using a
438  // max of 25 iterations means that we terminate the
439  // iteration after 25 steps if the indicators were perfectly
440  // badly distributed, and we make at most a mistake of
441  // 1/2^25 in the number of cells flagged if indicators are
442  // perfectly equidistributed
443  ++iteration;
444  if (iteration == 25)
445  interesting_range[0] = interesting_range[1] = test_threshold;
446  }
447  while (true);
448 
449  Assert (false, ExcInternalError());
450  return -1;
451  }
452  }
453 }
454 
455 
456 
457 namespace parallel
458 {
459  namespace distributed
460  {
461  namespace GridRefinement
462  {
463  template <int dim, typename VectorType, int spacedim>
464  void
467  const VectorType &criteria,
468  const double top_fraction_of_cells,
469  const double bottom_fraction_of_cells,
470  const unsigned int max_n_cells)
471  {
472  Assert (criteria.size() == tria.n_active_cells(),
473  ExcDimensionMismatch (criteria.size(), tria.n_active_cells()));
474  Assert ((top_fraction_of_cells>=0) && (top_fraction_of_cells<=1),
476  Assert ((bottom_fraction_of_cells>=0) && (bottom_fraction_of_cells<=1),
478  Assert (top_fraction_of_cells+bottom_fraction_of_cells <= 1,
480  Assert (criteria.is_non_negative (),
482 
483  const std::pair<double, double> adjusted_fractions =
484  ::GridRefinement::adjust_refine_and_coarsen_number_fraction<dim> (
485  tria.n_global_active_cells(),
486  max_n_cells,
487  top_fraction_of_cells,
488  bottom_fraction_of_cells);
489 
490  // first extract from the
491  // vector of indicators the
492  // ones that correspond to
493  // cells that we locally own
495  locally_owned_indicators (tria.n_locally_owned_active_cells());
496  get_locally_owned_indicators (tria,
497  criteria,
498  locally_owned_indicators);
499 
500  MPI_Comm mpi_communicator = tria.get_communicator ();
501 
502  // figure out the global
503  // max and min of the
504  // indicators. we don't
505  // need it here, but it's a
506  // collective communication
507  // call
508  const std::pair<typename VectorType::value_type,typename VectorType::value_type> global_min_and_max
509  = compute_global_min_and_max_at_root (locally_owned_indicators,
510  mpi_communicator);
511 
512 
513  double top_threshold, bottom_threshold;
514  top_threshold =
515  RefineAndCoarsenFixedNumber::
516  compute_threshold (locally_owned_indicators,
517  global_min_and_max,
518  static_cast<unsigned int>
519  (adjusted_fractions.first *
520  tria.n_global_active_cells()),
521  mpi_communicator);
522 
523  // compute bottom
524  // threshold only if
525  // necessary. otherwise
526  // use a threshold lower
527  // than the smallest
528  // value we have locally
529  if (adjusted_fractions.second > 0)
530  bottom_threshold =
531  RefineAndCoarsenFixedNumber::
532  compute_threshold (locally_owned_indicators,
533  global_min_and_max,
534  static_cast<unsigned int>
535  ((1-adjusted_fractions.second) *
536  tria.n_global_active_cells()),
537  mpi_communicator);
538  else
539  {
540  bottom_threshold = *std::min_element (criteria.begin(),
541  criteria.end());
542  bottom_threshold -= std::fabs(bottom_threshold);
543  }
544 
545  // now refine the mesh
546  mark_cells (tria, criteria, top_threshold, bottom_threshold);
547  }
548 
549 
550  template <int dim, typename VectorType, int spacedim>
551  void
554  const VectorType &criteria,
555  const double top_fraction_of_error,
556  const double bottom_fraction_of_error)
557  {
558  Assert (criteria.size() == tria.n_active_cells(),
559  ExcDimensionMismatch (criteria.size(), tria.n_active_cells()));
560  Assert ((top_fraction_of_error>=0) && (top_fraction_of_error<=1),
562  Assert ((bottom_fraction_of_error>=0) && (bottom_fraction_of_error<=1),
564  Assert (top_fraction_of_error+bottom_fraction_of_error <= 1,
566  Assert (criteria.is_non_negative (),
568 
569  // first extract from the
570  // vector of indicators the
571  // ones that correspond to
572  // cells that we locally own
574  locally_owned_indicators (tria.n_locally_owned_active_cells());
575  get_locally_owned_indicators (tria,
576  criteria,
577  locally_owned_indicators);
578 
579  MPI_Comm mpi_communicator = tria.get_communicator ();
580 
581  // figure out the global
582  // max and min of the
583  // indicators. we don't
584  // need it here, but it's a
585  // collective communication
586  // call
587  const std::pair<double,double> global_min_and_max
588  = compute_global_min_and_max_at_root (locally_owned_indicators,
589  mpi_communicator);
590 
591  const double total_error
592  = compute_global_sum (locally_owned_indicators,
593  mpi_communicator);
594  double top_threshold, bottom_threshold;
595  top_threshold =
596  RefineAndCoarsenFixedFraction::
597  compute_threshold (locally_owned_indicators,
598  global_min_and_max,
599  top_fraction_of_error *
600  total_error,
601  mpi_communicator);
602  // compute bottom
603  // threshold only if
604  // necessary. otherwise
605  // use a threshold lower
606  // than the smallest
607  // value we have locally
608  if (bottom_fraction_of_error > 0)
609  bottom_threshold =
610  RefineAndCoarsenFixedFraction::
611  compute_threshold (locally_owned_indicators,
612  global_min_and_max,
613  (1-bottom_fraction_of_error) *
614  total_error,
615  mpi_communicator);
616  else
617  {
618  bottom_threshold = *std::min_element (criteria.begin(),
619  criteria.end());
620  bottom_threshold -= std::fabs(bottom_threshold);
621  }
622 
623  // now refine the mesh
624  mark_cells (tria, criteria, top_threshold, bottom_threshold);
625  }
626  }
627  }
628 }
629 
630 
631 // explicit instantiations
632 #include "grid_refinement.inst"
633 
634 DEAL_II_NAMESPACE_CLOSE
635 
636 #endif
unsigned int n_active_cells() const
Definition: tria.cc:11244
active_cell_iterator begin_active(const unsigned int level=0) const
Definition: tria.cc:10668
iterator end()
cell_iterator end() const
Definition: tria.cc:10736
static ::ExceptionBase & ExcNegativeCriteria()
#define Assert(cond, exc)
Definition: exceptions.h:313
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
std::size_t size() const
virtual MPI_Comm get_communicator() const
Definition: tria_base.cc:146
virtual types::global_dof_index n_global_active_cells() const
Definition: tria_base.cc:132
iterator begin()
unsigned int n_locally_owned_active_cells() const
Definition: tria_base.cc:118
#define AssertThrowMPI(error_code)
Definition: exceptions.h:1211
void refine_and_coarsen_fixed_fraction(parallel::distributed::Triangulation< dim, spacedim > &tria, const VectorType &criteria, const double top_fraction_of_error, const double bottom_fraction_of_error)
void refine_and_coarsen_fixed_number(parallel::distributed::Triangulation< dim, spacedim > &tria, const VectorType &criteria, const double top_fraction_of_cells, const double bottom_fraction_of_cells, const unsigned int max_n_cells=std::numeric_limits< unsigned int >::max())
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:73
types::subdomain_id locally_owned_subdomain() const
Definition: tria_base.cc:230
static ::ExceptionBase & ExcInvalidParameterValue()
static ::ExceptionBase & ExcInternalError()