Reference documentation for deal.II version 8.4.2
constraint_matrix.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2015 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 #include <deal.II/lac/constraint_matrix.h>
17 #include <deal.II/lac/constraint_matrix.templates.h>
18 
19 #include <deal.II/base/memory_consumption.h>
20 #include <deal.II/lac/dynamic_sparsity_pattern.h>
21 #include <deal.II/lac/block_vector.h>
22 #include <deal.II/lac/block_sparse_matrix.h>
23 #include <deal.II/lac/sparse_matrix_ez.h>
24 #include <deal.II/lac/chunk_sparse_matrix.h>
25 #include <deal.II/lac/block_sparse_matrix_ez.h>
26 #include <deal.II/lac/parallel_vector.h>
27 #include <deal.II/lac/parallel_block_vector.h>
28 #include <deal.II/lac/petsc_vector.h>
29 #include <deal.II/lac/petsc_block_vector.h>
30 #include <deal.II/lac/petsc_sparse_matrix.h>
31 #include <deal.II/lac/petsc_block_sparse_matrix.h>
32 #include <deal.II/lac/petsc_parallel_vector.h>
33 #include <deal.II/lac/petsc_parallel_block_vector.h>
34 #include <deal.II/lac/petsc_parallel_sparse_matrix.h>
35 #include <deal.II/lac/petsc_parallel_block_sparse_matrix.h>
36 #include <deal.II/lac/trilinos_vector.h>
37 #include <deal.II/lac/trilinos_block_vector.h>
38 #include <deal.II/lac/trilinos_sparse_matrix.h>
39 #include <deal.II/lac/trilinos_block_sparse_matrix.h>
40 #include <deal.II/lac/matrix_block.h>
41 
42 #include <algorithm>
43 #include <numeric>
44 #include <set>
45 #include <ostream>
46 
47 DEAL_II_NAMESPACE_OPEN
48 
49 
50 
51 // Static member variable
53 
54 
55 
56 bool
57 ConstraintMatrix::check_zero_weight (const std::pair<size_type, double> &p)
58 {
59  return (p.second == 0);
60 }
61 
62 
63 
64 bool
66 {
67  return line < a.line;
68 }
69 
70 
71 
72 bool
74 {
75  return line == a.line;
76 }
77 
78 
79 
80 std::size_t
82 {
86 }
87 
88 
89 
90 void
91 ConstraintMatrix::add_lines (const std::set<size_type> &lines)
92 {
93  for (std::set<size_type>::const_iterator
94  i = lines.begin(); i != lines.end(); ++i)
95  add_line (*i);
96 }
97 
98 
99 
100 void
101 ConstraintMatrix::add_lines (const std::vector<bool> &lines)
102 {
103  for (size_type i=0; i<lines.size(); ++i)
104  if (lines[i] == true)
105  add_line (i);
106 }
107 
108 
109 
110 void
112 {
113  for (size_type i=0; i<lines.n_elements(); ++i)
114  add_line (lines.nth_index_in_set(i));
115 }
116 
117 
118 
119 void
121 (const size_type line,
122  const std::vector<std::pair<size_type,double> > &col_val_pairs)
123 {
124  Assert (sorted==false, ExcMatrixIsClosed());
125  Assert (is_constrained(line), ExcLineInexistant(line));
126 
128  Assert (line_ptr->line == line, ExcInternalError());
129 
130  // if in debug mode, check whether an entry for this column already
131  // exists and if its the same as the one entered at present
132  //
133  // in any case: skip this entry if an entry for this column already
134  // exists, since we don't want to enter it twice
135  for (std::vector<std::pair<size_type,double> >::const_iterator
136  col_val_pair = col_val_pairs.begin();
137  col_val_pair!=col_val_pairs.end(); ++col_val_pair)
138  {
139  Assert (line != col_val_pair->first,
140  ExcMessage ("Can't constrain a degree of freedom to itself"));
141 
142  for (ConstraintLine::Entries::const_iterator
143  p=line_ptr->entries.begin();
144  p != line_ptr->entries.end(); ++p)
145  if (p->first == col_val_pair->first)
146  {
147  // entry exists, break innermost loop
148  Assert (p->second == col_val_pair->second,
149  ExcEntryAlreadyExists(line, col_val_pair->first,
150  p->second, col_val_pair->second));
151  break;
152  }
153 
154  line_ptr->entries.push_back (*col_val_pair);
155  }
156 }
157 
158 
159 
161 (const ConstraintMatrix &constraints,
162  const IndexSet &filter)
163 {
164  if (constraints.n_constraints() == 0)
165  return;
166 
167  Assert (filter.size() > constraints.lines.back().line,
168  ExcMessage ("Filter needs to be larger than constraint matrix size."));
169  for (std::vector<ConstraintLine>::const_iterator line=constraints.lines.begin();
170  line!=constraints.lines.end(); ++line)
171  if (filter.is_element(line->line))
172  {
173  const size_type row = filter.index_within_set (line->line);
174  add_line (row);
175  set_inhomogeneity (row, line->inhomogeneity);
176  for (size_type i=0; i<line->entries.size(); ++i)
177  if (filter.is_element(line->entries[i].first))
178  add_entry (row, filter.index_within_set (line->entries[i].first),
179  line->entries[i].second);
180  }
181 }
182 
183 
184 
186 {
187  if (sorted == true)
188  return;
189 
190  // sort the lines
191  std::sort (lines.begin(), lines.end());
192 
193  // update list of pointers and give the vector a sharp size since we
194  // won't modify the size any more after this point.
195  {
196  std::vector<size_type> new_lines (lines_cache.size(),
198  size_type counter = 0;
199  for (std::vector<ConstraintLine>::const_iterator line=lines.begin();
200  line!=lines.end(); ++line, ++counter)
201  new_lines[calculate_line_index(line->line)] = counter;
202  std::swap (lines_cache, new_lines);
203  }
204 
205  // in debug mode: check whether we really set the pointers correctly.
206  for (size_type i=0; i<lines_cache.size(); ++i)
209  ExcInternalError());
210 
211  // first, strip zero entries, as we have to do that only once
212  for (std::vector<ConstraintLine>::iterator line = lines.begin();
213  line!=lines.end(); ++line)
214  // first remove zero entries. that would mean that in the linear
215  // constraint for a node, x_i = ax_1 + bx_2 + ..., another node times 0
216  // appears. obviously, 0*something can be omitted
217  line->entries.erase (std::remove_if (line->entries.begin(),
218  line->entries.end(),
220  line->entries.end());
221 
222 
223 
224 #ifdef DEBUG
225  // In debug mode we are computing an estimate for the maximum number
226  // of constraints so that we can bail out if there is a cycle in the
227  // constraints (which is easier than searching for cycles in the graph).
228  //
229  // Let us figure out the largest dof index. This is an upper bound for the
230  // number of constraints because it is an approximation for the number of dofs
231  // in our system.
232  size_type largest_idx = 0;
233  for (std::vector<ConstraintLine>::iterator line = lines.begin();
234  line!=lines.end(); ++line)
235  {
236  for (ConstraintLine::Entries::iterator it = line->entries.begin(); it!=line->entries.end(); ++it)
237  {
238  largest_idx=std::max(largest_idx, it->first);
239  }
240  }
241 #endif
242 
243  // replace references to dofs that are themselves constrained. note that
244  // because we may replace references to other dofs that may themselves be
245  // constrained to third ones, we have to iterate over all this until we
246  // replace no chains of constraints any more
247  //
248  // the iteration replaces references to constrained degrees of freedom by
249  // second-order references. for example if x3=x0/2+x2/2 and x2=x0/2+x1/2,
250  // then the new list will be x3=x0/2+x0/4+x1/4. note that x0 appear
251  // twice. we will throw this duplicate out in the following step, where
252  // we sort the list so that throwing out duplicates becomes much more
253  // efficient. also, we have to do it only once, rather than in each
254  // iteration
255  size_type iteration = 0;
256  while (true)
257  {
258  bool chained_constraint_replaced = false;
259 
260  for (std::vector<ConstraintLine>::iterator line = lines.begin();
261  line!=lines.end(); ++line)
262  {
263 #ifdef DEBUG
264  // we need to keep track of how many replacements we do in this line, because we can
265  // end up in a cycle A->B->C->A without the number of entries growing.
266  size_type n_replacements = 0;
267 #endif
268 
269  // loop over all entries of this line (including ones that we
270  // have appended in this go around) and see whether they are
271  // further constrained. ignore elements that we don't store on
272  // the current processor
273  size_type entry = 0;
274  while (entry < line->entries.size())
275  if (((local_lines.size() == 0)
276  ||
277  (local_lines.is_element(line->entries[entry].first)))
278  &&
279  is_constrained (line->entries[entry].first))
280  {
281  // ok, this entry is further constrained:
282  chained_constraint_replaced = true;
283 
284  // look up the chain of constraints for this entry
285  const size_type dof_index = line->entries[entry].first;
286  const double weight = line->entries[entry].second;
287 
288  Assert (dof_index != line->line,
289  ExcMessage ("Cycle in constraints detected!"));
290 
291  const ConstraintLine *constrained_line =
292  &lines[lines_cache[calculate_line_index(dof_index)]];
293  Assert (constrained_line->line == dof_index,
294  ExcInternalError());
295 
296  // now we have to replace an entry by its expansion. we do
297  // that by overwriting the entry by the first entry of the
298  // expansion and adding the remaining ones to the end,
299  // where we will later process them once more
300  //
301  // we can of course only do that if the DoF that we are
302  // currently handle is constrained by a linear combination
303  // of other dofs:
304  if (constrained_line->entries.size() > 0)
305  {
306  for (size_type i=0; i<constrained_line->entries.size(); ++i)
307  Assert (dof_index != constrained_line->entries[i].first,
308  ExcMessage ("Cycle in constraints detected!"));
309 
310  // replace first entry, then tack the rest to the end
311  // of the list
312  line->entries[entry] =
313  std::make_pair (constrained_line->entries[0].first,
314  constrained_line->entries[0].second *
315  weight);
316 
317  for (size_type i=1; i<constrained_line->entries.size(); ++i)
318  line->entries
319  .push_back (std::make_pair (constrained_line->entries[i].first,
320  constrained_line->entries[i].second *
321  weight));
322 
323 #ifdef DEBUG
324  // keep track of how many entries we replace in this
325  // line. If we do more than there are constraints or
326  // dofs in our system, we must have a cycle.
327  ++n_replacements;
328  Assert(n_replacements/2<largest_idx, ExcMessage("Cycle in constraints detected!"));
329  if (n_replacements/2>=largest_idx)
330  return; // this enables us to test for this Exception.
331 #endif
332  }
333  else
334  // the DoF that we encountered is not constrained by a
335  // linear combination of other dofs but is equal to just
336  // the inhomogeneity (i.e. its chain of entries is
337  // empty). in that case, we can't just overwrite the
338  // current entry, but we have to actually eliminate it
339  {
340  line->entries.erase (line->entries.begin()+entry);
341  }
342 
343  line->inhomogeneity += constrained_line->inhomogeneity *
344  weight;
345 
346  // now that we're here, do not increase index by one but
347  // rather make another pass for the present entry because
348  // we have replaced the present entry by another one, or
349  // because we have deleted it and shifted all following
350  // ones one forward
351  }
352  else
353  // entry not further constrained. just move ahead by one
354  ++entry;
355  }
356 
357  // if we didn't do anything in this round, then quit the loop
358  if (chained_constraint_replaced == false)
359  break;
360 
361  // increase iteration count. note that we should not iterate more
362  // times than there are constraints, since this puts a natural upper
363  // bound on the length of constraint chains
364  ++iteration;
365  Assert (iteration <= lines.size(), ExcInternalError());
366  }
367 
368  // finally sort the entries and re-scale them if necessary. in this step,
369  // we also throw out duplicates as mentioned above. moreover, as some
370  // entries might have had zero weights, we replace them by a vector with
371  // sharp sizes.
372  for (std::vector<ConstraintLine>::iterator line = lines.begin();
373  line!=lines.end(); ++line)
374  {
375  std::sort (line->entries.begin(), line->entries.end());
376 
377  // loop over the now sorted list and see whether any of the entries
378  // references the same dofs more than once in order to find how many
379  // non-duplicate entries we have. This lets us allocate the correct
380  // amount of memory for the constraint entries.
381  size_type duplicates = 0;
382  for (size_type i=1; i<line->entries.size(); ++i)
383  if (line->entries[i].first == line->entries[i-1].first)
384  duplicates++;
385 
386  if (duplicates > 0 || line->entries.size() < line->entries.capacity())
387  {
388  ConstraintLine::Entries new_entries;
389 
390  // if we have no duplicates, copy verbatim the entries. this way,
391  // the final size is of the vector is correct.
392  if (duplicates == 0)
393  new_entries = line->entries;
394  else
395  {
396  // otherwise, we need to go through the list by and and
397  // resolve the duplicates
398  new_entries.reserve (line->entries.size() - duplicates);
399  new_entries.push_back(line->entries[0]);
400  for (size_type j=1; j<line->entries.size(); ++j)
401  if (line->entries[j].first == line->entries[j-1].first)
402  {
403  Assert (new_entries.back().first == line->entries[j].first,
404  ExcInternalError());
405  new_entries.back().second += line->entries[j].second;
406  }
407  else
408  new_entries.push_back (line->entries[j]);
409 
410  Assert (new_entries.size() == line->entries.size() - duplicates,
411  ExcInternalError());
412 
413  // make sure there are really no duplicates left and that the
414  // list is still sorted
415  for (size_type j=1; j<new_entries.size(); ++j)
416  {
417  Assert (new_entries[j].first != new_entries[j-1].first,
418  ExcInternalError());
419  Assert (new_entries[j].first > new_entries[j-1].first,
420  ExcInternalError());
421  }
422  }
423 
424  // replace old list of constraints for this dof by the new one
425  line->entries.swap (new_entries);
426  }
427 
428  // finally do the following check: if the sum of weights for the
429  // constraints is close to one, but not exactly one, then rescale all
430  // the weights so that they sum up to 1. this adds a little numerical
431  // stability and avoids all sorts of problems where the actual value
432  // is close to, but not quite what we expected
433  //
434  // the case where the weights don't quite sum up happens when we
435  // compute the interpolation weights "on the fly", i.e. not from
436  // precomputed tables. in this case, the interpolation weights are
437  // also subject to round-off
438  double sum = 0;
439  for (size_type i=0; i<line->entries.size(); ++i)
440  sum += line->entries[i].second;
441  if ((sum != 1.0) && (std::fabs (sum-1.) < 1.e-13))
442  {
443  for (size_type i=0; i<line->entries.size(); ++i)
444  line->entries[i].second /= sum;
445  line->inhomogeneity /= sum;
446  }
447  } // end of loop over all constraint lines
448 
449 #ifdef DEBUG
450  // if in debug mode: check that no dof is constrained to another dof that
451  // is also constrained. exclude dofs from this check whose constraint
452  // lines are not stored on the local processor
453  for (std::vector<ConstraintLine>::const_iterator line=lines.begin();
454  line!=lines.end(); ++line)
455  for (ConstraintLine::Entries::const_iterator
456  entry=line->entries.begin();
457  entry!=line->entries.end(); ++entry)
458  if ((local_lines.size() == 0)
459  ||
460  (local_lines.is_element(entry->first)))
461  {
462  // make sure that entry->first is not the index of a line itself
463  const bool is_circle = is_constrained(entry->first);
464  Assert (is_circle == false,
465  ExcDoFConstrainedToConstrainedDoF(line->line, entry->first));
466  }
467 #endif
468 
469  sorted = true;
470 }
471 
472 
473 
474 void
475 ConstraintMatrix::merge (const ConstraintMatrix &other_constraints,
476  const MergeConflictBehavior merge_conflict_behavior)
477 {
478  AssertThrow(local_lines == other_constraints.local_lines,
479  ExcNotImplemented());
480 
481  // store the previous state with respect to sorting
482  const bool object_was_sorted = sorted;
483  sorted = false;
484 
485  if (other_constraints.lines_cache.size() > lines_cache.size())
486  lines_cache.resize(other_constraints.lines_cache.size(),
488 
489  // first action is to fold into the present object possible constraints
490  // in the second object. we don't strictly need to do this any more since
491  // the ConstraintMatrix has learned to deal with chains of constraints in
492  // the close() function, but we have traditionally done this and it's not
493  // overly hard to do.
494  //
495  // for this, loop over all constraints and replace the constraint lines
496  // with a new one where constraints are replaced if necessary.
498  for (std::vector<ConstraintLine>::iterator line=lines.begin();
499  line!=lines.end(); ++line)
500  {
501  tmp.clear ();
502  for (size_type i=0; i<line->entries.size(); ++i)
503  {
504  // if the present dof is not constrained, or if we won't take the
505  // constraint from the other object, then simply copy it over
506  if (other_constraints.is_constrained(line->entries[i].first) == false
507  ||
508  ((merge_conflict_behavior != right_object_wins)
509  &&
510  other_constraints.is_constrained(line->entries[i].first)
511  &&
512  this->is_constrained(line->entries[i].first)))
513  tmp.push_back(line->entries[i]);
514  else
515  // otherwise resolve further constraints by replacing the old
516  // entry by a sequence of new entries taken from the other
517  // object, but with multiplied weights
518  {
519  const ConstraintLine::Entries *other_line
520  = other_constraints.get_constraint_entries (line->entries[i].first);
521  Assert (other_line != 0,
522  ExcInternalError());
523 
524  const double weight = line->entries[i].second;
525 
526  for (ConstraintLine::Entries::const_iterator j=other_line->begin();
527  j!=other_line->end(); ++j)
528  tmp.push_back (std::pair<size_type,double>(j->first,
529  j->second*weight));
530 
531  line->inhomogeneity += other_constraints.get_inhomogeneity(line->entries[i].first) *
532  weight;
533  }
534  }
535  // finally exchange old and newly resolved line
536  line->entries.swap (tmp);
537  }
538 
539 
540 
541  // next action: append those lines at the end that we want to add
542  for (std::vector<ConstraintLine>::const_iterator
543  line=other_constraints.lines.begin();
544  line!=other_constraints.lines.end(); ++line)
545  if (is_constrained(line->line) == false)
546  lines.push_back (*line);
547  else
548  {
549  // the constrained dof we want to copy from the other object is
550  // also constrained here. let's see what we should do with that
551  switch (merge_conflict_behavior)
552  {
554  AssertThrow (false,
555  ExcDoFIsConstrainedFromBothObjects (line->line));
556  break;
557 
558  case left_object_wins:
559  // ignore this constraint
560  break;
561 
562  case right_object_wins:
563  // we need to replace the existing constraint by the one from
564  // the other object
565  lines[lines_cache[calculate_line_index(line->line)]].entries
566  = line->entries;
567  lines[lines_cache[calculate_line_index(line->line)]].inhomogeneity
568  = line->inhomogeneity;
569  break;
570 
571  default:
572  Assert (false, ExcNotImplemented());
573  }
574  }
575 
576  // update the lines cache
577  size_type counter = 0;
578  for (std::vector<ConstraintLine>::const_iterator line=lines.begin();
579  line!=lines.end(); ++line, ++counter)
581 
582  // if the object was sorted before, then make sure it is so afterward as
583  // well. otherwise leave everything in the unsorted state
584  if (object_was_sorted == true)
585  close ();
586 }
587 
588 
589 
591 {
592  //TODO: this doesn't work with IndexSets yet. [TH]
593  AssertThrow(local_lines.size()==0, ExcNotImplemented());
594 
595  lines_cache.insert (lines_cache.begin(), offset,
597 
598  for (std::vector<ConstraintLine>::iterator i = lines.begin();
599  i != lines.end(); ++i)
600  {
601  i->line += offset;
602  for (ConstraintLine::Entries::iterator
603  j = i->entries.begin();
604  j != i->entries.end(); ++j)
605  j->first += offset;
606  }
607 }
608 
609 
610 
612 {
613  {
614  std::vector<ConstraintLine> tmp;
615  lines.swap (tmp);
616  }
617 
618  {
619  std::vector<size_type> tmp;
620  lines_cache.swap (tmp);
621  }
622 
623  sorted = false;
624 }
625 
626 
627 
628 void ConstraintMatrix::reinit (const IndexSet &local_constraints)
629 {
630  local_lines = local_constraints;
631 
632  // make sure the IndexSet is compressed. Otherwise this can lead to crashes
633  // that are hard to find (only happen in release mode).
634  // see tests/mpi/constraint_matrix_crash_01
636 
637  clear();
638 }
639 
640 
641 
643 {
644  Assert (sorted == true, ExcMatrixNotClosed());
645  Assert (sparsity.is_compressed() == false, ExcMatrixIsClosed());
646  Assert (sparsity.n_rows() == sparsity.n_cols(), ExcNotQuadratic());
647 
648  // store for each index whether it must be distributed or not. If entry
649  // is numbers::invalid_unsigned_int, no distribution is necessary.
650  // otherwise, the number states which line in the constraint matrix
651  // handles this index
652  std::vector<size_type> distribute(sparsity.n_rows(),
654 
655  for (size_type c=0; c<lines.size(); ++c)
656  distribute[lines[c].line] = c;
657 
658  const size_type n_rows = sparsity.n_rows();
659  for (size_type row=0; row<n_rows; ++row)
660  {
662  {
663  // regular line. loop over cols all valid cols. note that this
664  // changes the line we are presently working on: we add additional
665  // entries. these are put to the end of the row. however, as
666  // constrained nodes cannot be constrained to other constrained
667  // nodes, nothing will happen if we run into these added nodes, as
668  // they can't be distributed further. we might store the position of
669  // the last old entry and stop work there, but since operating on
670  // the newly added ones only takes two comparisons (column index
671  // valid, distribute[column] necessarily
672  // ==numbers::invalid_size_type), it is cheaper to not do so and
673  // run right until the end of the line
674  for (SparsityPattern::iterator entry = sparsity.begin(row);
675  ((entry != sparsity.end(row)) &&
676  entry->is_valid_entry());
677  ++entry)
678  {
679  const size_type column = entry->column();
680 
681  if (distribute[column] != numbers::invalid_size_type)
682  {
683  // distribute entry at regular row @p{row} and irregular
684  // column sparsity.colnums[j]
685  for (size_type q=0;
686  q!=lines[distribute[column]].entries.size();
687  ++q)
688  sparsity.add (row,
689  lines[distribute[column]].entries[q].first);
690  }
691  }
692  }
693  else
694  // row must be distributed. note that here the present row is not
695  // touched (unlike above)
696  {
697  for (SparsityPattern::iterator entry = sparsity.begin(row);
698  (entry != sparsity.end(row)) && entry->is_valid_entry(); ++entry)
699  {
700  const size_type column = entry->column();
701  if (distribute[column] == numbers::invalid_size_type)
702  // distribute entry at irregular row @p{row} and regular
703  // column sparsity.colnums[j]
704  for (size_type q=0;
705  q!=lines[distribute[row]].entries.size(); ++q)
706  sparsity.add (lines[distribute[row]].entries[q].first,
707  column);
708  else
709  // distribute entry at irregular row @p{row} and irregular
710  // column sparsity.get_column_numbers()[j]
711  for (size_type p=0; p!=lines[distribute[row]].entries.size(); ++p)
712  for (size_type q=0;
713  q!=lines[distribute[column]].entries.size(); ++q)
714  sparsity.add (lines[distribute[row]].entries[p].first,
715  lines[distribute[column]].entries[q].first);
716  }
717  }
718  }
719 
720  sparsity.compress();
721 }
722 
723 
724 
725 
727 {
728  Assert (sorted == true, ExcMatrixNotClosed());
729  Assert (sparsity.n_rows() == sparsity.n_cols(),
730  ExcNotQuadratic());
731 
732  // store for each index whether it must be distributed or not. If entry
733  // is numbers::invalid_unsigned_int, no distribution is necessary.
734  // otherwise, the number states which line in the constraint matrix
735  // handles this index
736  std::vector<size_type> distribute(sparsity.n_rows(),
738 
739  for (size_type c=0; c<lines.size(); ++c)
740  distribute[lines[c].line] = c;
741 
742  const size_type n_rows = sparsity.n_rows();
743  for (size_type row=0; row<n_rows; ++row)
744  {
746  // regular line. loop over cols. note that as we proceed to
747  // distribute cols, the loop may get longer
748  for (size_type j=0; j<sparsity.row_length(row); ++j)
749  {
750  const size_type column = sparsity.column_number(row,j);
751 
752  if (distribute[column] != numbers::invalid_size_type)
753  {
754  // distribute entry at regular row @p{row} and irregular
755  // column column. note that this changes the line we are
756  // presently working on: we add additional entries. if we
757  // add another entry at a column behind the present one, we
758  // will encounter it later on (but since it can't be
759  // further constrained, won't have to do anything about
760  // it). if we add it up front of the present column, we
761  // will find the present column later on again as it was
762  // shifted back (again nothing happens, in particular no
763  // endless loop, as when we encounter it the second time we
764  // won't be able to add more entries as they all already
765  // exist, but we do the same work more often than
766  // necessary, and the loop gets longer), so move the cursor
767  // one to the right in the case that we add an entry up
768  // front that did not exist before. check whether it
769  // existed before by tracking the length of this row
770  size_type old_rowlength = sparsity.row_length(row);
771  for (size_type q=0;
772  q!=lines[distribute[column]].entries.size();
773  ++q)
774  {
775  const size_type
776  new_col = lines[distribute[column]].entries[q].first;
777 
778  sparsity.add (row, new_col);
779 
780  const size_type new_rowlength = sparsity.row_length(row);
781  if ((new_col < column) && (old_rowlength != new_rowlength))
782  ++j;
783  old_rowlength = new_rowlength;
784  };
785  };
786  }
787  else
788  // row must be distributed
789  for (size_type j=0; j<sparsity.row_length(row); ++j)
790  {
791  const size_type column = sparsity.column_number(row,j);
792 
793  if (distribute[column] == numbers::invalid_size_type)
794  // distribute entry at irregular row @p{row} and regular
795  // column sparsity.colnums[j]
796  for (size_type q=0;
797  q!=lines[distribute[row]].entries.size(); ++q)
798  sparsity.add (lines[distribute[row]].entries[q].first,
799  column);
800  else
801  // distribute entry at irregular row @p{row} and irregular
802  // column sparsity.get_column_numbers()[j]
803  for (size_type p=0; p!=lines[distribute[row]].entries.size(); ++p)
804  for (size_type q=0;
805  q!=lines[distribute[sparsity.column_number(row,j)]]
806  .entries.size(); ++q)
807  sparsity.add (lines[distribute[row]].entries[p].first,
808  lines[distribute[sparsity.column_number(row,j)]]
809  .entries[q].first);
810  };
811  };
812 }
813 
814 
815 
817 {
818  Assert (sorted == true, ExcMatrixNotClosed());
819  Assert (sparsity.is_compressed() == false, ExcMatrixIsClosed());
820  Assert (sparsity.n_rows() == sparsity.n_cols(),
821  ExcNotQuadratic());
822  Assert (sparsity.n_block_rows() == sparsity.n_block_cols(),
823  ExcNotQuadratic());
824  Assert (sparsity.get_column_indices() == sparsity.get_row_indices(),
825  ExcNotQuadratic());
826 
827  const BlockIndices &
828  index_mapping = sparsity.get_column_indices();
829 
830  const size_type n_blocks = sparsity.n_block_rows();
831 
832  // store for each index whether it must be distributed or not. If entry
833  // is numbers::invalid_unsigned_int, no distribution is necessary.
834  // otherwise, the number states which line in the constraint matrix
835  // handles this index
836  std::vector<size_type> distribute (sparsity.n_rows(),
838 
839  for (size_type c=0; c<lines.size(); ++c)
840  distribute[lines[c].line] = c;
841 
842  const size_type n_rows = sparsity.n_rows();
843  for (size_type row=0; row<n_rows; ++row)
844  {
845  // get index of this row within the blocks
846  const std::pair<size_type,size_type>
847  block_index = index_mapping.global_to_local(row);
848  const size_type block_row = block_index.first;
849 
851  // regular line. loop over all columns and see whether this column
852  // must be distributed
853  {
854 
855  // to loop over all entries in this row, we have to loop over all
856  // blocks in this blockrow and the corresponding row therein
857  for (size_type block_col=0; block_col<n_blocks; ++block_col)
858  {
859  const SparsityPattern &
860  block_sparsity = sparsity.block(block_row, block_col);
861 
863  entry = block_sparsity.begin(block_index.second);
864  (entry != block_sparsity.end(block_index.second)) &&
865  entry->is_valid_entry();
866  ++entry)
867  {
868  const size_type global_col
869  = index_mapping.local_to_global(block_col, entry->column());
870 
871  if (distribute[global_col] != numbers::invalid_size_type)
872  // distribute entry at regular row @p{row} and
873  // irregular column global_col
874  {
875  for (size_type q=0;
876  q!=lines[distribute[global_col]].entries.size(); ++q)
877  sparsity.add (row,
878  lines[distribute[global_col]].entries[q].first);
879  }
880  }
881  }
882  }
883  else
884  {
885  // row must be distributed. split the whole row into the chunks
886  // defined by the blocks
887  for (size_type block_col=0; block_col<n_blocks; ++block_col)
888  {
889  const SparsityPattern &
890  block_sparsity = sparsity.block(block_row,block_col);
891 
893  entry = block_sparsity.begin(block_index.second);
894  (entry != block_sparsity.end(block_index.second)) &&
895  entry->is_valid_entry();
896  ++entry)
897  {
898  const size_type global_col
899  = index_mapping.local_to_global (block_col, entry->column());
900 
901  if (distribute[global_col] == numbers::invalid_size_type)
902  // distribute entry at irregular row @p{row} and
903  // regular column global_col.
904  {
905  for (size_type q=0; q!=lines[distribute[row]].entries.size(); ++q)
906  sparsity.add (lines[distribute[row]].entries[q].first, global_col);
907  }
908  else
909  // distribute entry at irregular row @p{row} and
910  // irregular column @p{global_col}
911  {
912  for (size_type p=0; p!=lines[distribute[row]].entries.size(); ++p)
913  for (size_type q=0; q!=lines[distribute[global_col]].entries.size(); ++q)
914  sparsity.add (lines[distribute[row]].entries[p].first,
915  lines[distribute[global_col]].entries[q].first);
916  }
917  }
918  }
919  }
920  }
921 
922  sparsity.compress();
923 }
924 
925 
926 
927 
929 {
930  Assert (sorted == true, ExcMatrixNotClosed());
931  Assert (sparsity.n_rows() == sparsity.n_cols(),
932  ExcNotQuadratic());
933  Assert (sparsity.n_block_rows() == sparsity.n_block_cols(),
934  ExcNotQuadratic());
935  Assert (sparsity.get_column_indices() == sparsity.get_row_indices(),
936  ExcNotQuadratic());
937 
938  const BlockIndices &
939  index_mapping = sparsity.get_column_indices();
940 
941  const size_type n_blocks = sparsity.n_block_rows();
942 
943  // store for each index whether it must be distributed or not. If entry
944  // is numbers::invalid_unsigned_int, no distribution is necessary.
945  // otherwise, the number states which line in the constraint matrix
946  // handles this index
947  std::vector<size_type> distribute (sparsity.n_rows(),
949 
950  for (size_type c=0; c<lines.size(); ++c)
951  distribute[lines[c].line] = static_cast<signed int>(c);
952 
953  const size_type n_rows = sparsity.n_rows();
954  for (size_type row=0; row<n_rows; ++row)
955  {
956  // get index of this row within the blocks
957  const std::pair<size_type,size_type>
958  block_index = index_mapping.global_to_local(row);
959  const size_type block_row = block_index.first;
960  const size_type local_row = block_index.second;
961 
963  // regular line. loop over all columns and see whether this column
964  // must be distributed. note that as we proceed to distribute cols,
965  // the loop over cols may get longer.
966  //
967  // don't try to be clever here as in the algorithm for the
968  // DynamicSparsityPattern, as that would be much more
969  // complicated here. after all, we know that compressed patterns
970  // are inefficient...
971  {
972 
973  // to loop over all entries in this row, we have to loop over all
974  // blocks in this blockrow and the corresponding row therein
975  for (size_type block_col=0; block_col<n_blocks; ++block_col)
976  {
977  const DynamicSparsityPattern &
978  block_sparsity = sparsity.block(block_row, block_col);
979 
980  for (size_type j=0; j<block_sparsity.row_length(local_row); ++j)
981  {
982  const size_type global_col
983  = index_mapping.local_to_global(block_col,
984  block_sparsity.column_number(local_row,j));
985 
986  if (distribute[global_col] != numbers::invalid_size_type)
987  // distribute entry at regular row @p{row} and
988  // irregular column global_col
989  {
990  for (size_type q=0;
991  q!=lines[distribute[global_col]]
992  .entries.size(); ++q)
993  sparsity.add (row,
994  lines[distribute[global_col]].entries[q].first);
995  };
996  };
997  };
998  }
999  else
1000  {
1001  // row must be distributed. split the whole row into the chunks
1002  // defined by the blocks
1003  for (size_type block_col=0; block_col<n_blocks; ++block_col)
1004  {
1005  const DynamicSparsityPattern &
1006  block_sparsity = sparsity.block(block_row,block_col);
1007 
1008  for (size_type j=0; j<block_sparsity.row_length(local_row); ++j)
1009  {
1010  const size_type global_col
1011  = index_mapping.local_to_global (block_col,
1012  block_sparsity.column_number(local_row,j));
1013 
1014  if (distribute[global_col] == numbers::invalid_size_type)
1015  // distribute entry at irregular row @p{row} and
1016  // regular column global_col.
1017  {
1018  for (size_type q=0;
1019  q!=lines[distribute[row]].entries.size(); ++q)
1020  sparsity.add (lines[distribute[row]].entries[q].first,
1021  global_col);
1022  }
1023  else
1024  // distribute entry at irregular row @p{row} and
1025  // irregular column @p{global_col}
1026  {
1027  for (size_type p=0;
1028  p!=lines[distribute[row]].entries.size(); ++p)
1029  for (size_type q=0; q!=lines[distribute[global_col]].entries.size(); ++q)
1030  sparsity.add (lines[distribute[row]].entries[p].first,
1031  lines[distribute[global_col]].entries[q].first);
1032  };
1033  };
1034  };
1035  };
1036  };
1037 }
1038 
1039 
1040 
1042 {
1043  if (is_constrained(index) == false)
1044  return false;
1045 
1047  Assert (p.line == index, ExcInternalError());
1048 
1049  // return if an entry for this line was found and if it has only one
1050  // entry equal to 1.0
1051  return ((p.entries.size() == 1) &&
1052  (p.entries[0].second == 1.0));
1053 }
1054 
1055 
1057  const size_type index2) const
1058 {
1059  if (is_constrained(index1) == true)
1060  {
1062  Assert (p.line == index1, ExcInternalError());
1063 
1064  // return if an entry for this line was found and if it has only one
1065  // entry equal to 1.0 and that one is index2
1066  return ((p.entries.size() == 1) &&
1067  (p.entries[0].first == index2) &&
1068  (p.entries[0].second == 1.0));
1069  }
1070  else if (is_constrained(index2) == true)
1071  {
1073  Assert (p.line == index2, ExcInternalError());
1074 
1075  // return if an entry for this line was found and if it has only one
1076  // entry equal to 1.0 and that one is index1
1077  return ((p.entries.size() == 1) &&
1078  (p.entries[0].first == index1) &&
1079  (p.entries[0].second == 1.0));
1080  }
1081  else
1082  return false;
1083 }
1084 
1085 
1086 
1089 {
1090  size_type return_value = 0;
1091  for (std::vector<ConstraintLine>::const_iterator i=lines.begin();
1092  i!=lines.end(); ++i)
1093  // use static cast, since typeof(size)==std::size_t, which is !=
1094  // size_type on AIX
1095  return_value = std::max(return_value,
1096  static_cast<size_type>(i->entries.size()));
1097 
1098  return return_value;
1099 }
1100 
1101 
1102 
1104 {
1105  for (std::vector<ConstraintLine>::const_iterator i=lines.begin();
1106  i!=lines.end(); ++i)
1107  if (i->inhomogeneity != 0.)
1108  return true;
1109 
1110  return false;
1111 }
1112 
1113 
1114 void ConstraintMatrix::print (std::ostream &out) const
1115 {
1116  for (size_type i=0; i!=lines.size(); ++i)
1117  {
1118  // output the list of constraints as pairs of dofs and their weights
1119  if (lines[i].entries.size() > 0)
1120  {
1121  for (size_type j=0; j<lines[i].entries.size(); ++j)
1122  out << " " << lines[i].line
1123  << " " << lines[i].entries[j].first
1124  << ": " << lines[i].entries[j].second << "\n";
1125 
1126  // print out inhomogeneity.
1127  if (lines[i].inhomogeneity != 0)
1128  out << " " << lines[i].line
1129  << ": " << lines[i].inhomogeneity << "\n";
1130  }
1131  else
1132  // but also output something if the constraint simply reads
1133  // x[13]=0, i.e. where the right hand side is not a linear
1134  // combination of other dofs
1135  {
1136  if (lines[i].inhomogeneity != 0)
1137  out << " " << lines[i].line
1138  << " = " << lines[i].inhomogeneity
1139  << "\n";
1140  else
1141  out << " " << lines[i].line << " = 0\n";
1142  }
1143  }
1144 
1145  AssertThrow (out, ExcIO());
1146 }
1147 
1148 
1149 
1150 void
1151 ConstraintMatrix::write_dot (std::ostream &out) const
1152 {
1153  out << "digraph constraints {"
1154  << std::endl;
1155  for (size_type i=0; i!=lines.size(); ++i)
1156  {
1157  // same concept as in the previous function
1158  if (lines[i].entries.size() > 0)
1159  for (size_type j=0; j<lines[i].entries.size(); ++j)
1160  out << " " << lines[i].line << "->" << lines[i].entries[j].first
1161  << "; // weight: "
1162  << lines[i].entries[j].second
1163  << "\n";
1164  else
1165  out << " " << lines[i].line << "\n";
1166  }
1167  out << "}" << std::endl;
1168 }
1169 
1170 
1171 
1172 std::size_t
1174 {
1179 }
1180 
1181 
1182 
1183 void
1184 ConstraintMatrix::resolve_indices (std::vector<types::global_dof_index> &indices) const
1185 {
1186  const unsigned int indices_size = indices.size();
1187  const std::vector<std::pair<types::global_dof_index,double> > *line_ptr;
1188  for (unsigned int i=0; i<indices_size; ++i)
1189  {
1190  line_ptr = get_constraint_entries(indices[i]);
1191  // if the index is constraint, the constraints indices are added to the
1192  // indices vector
1193  if (line_ptr!=NULL)
1194  {
1195  const unsigned int line_size = line_ptr->size();
1196  for (unsigned int j=0; j<line_size; ++j)
1197  indices.push_back((*line_ptr)[j].first);
1198  }
1199  }
1200 
1201  // keep only the unique elements
1202  std::sort(indices.begin(),indices.end());
1203  std::vector<types::global_dof_index>::iterator it;
1204  it = std::unique(indices.begin(),indices.end());
1205  indices.resize(it-indices.begin());
1206 }
1207 
1208 
1209 
1210 // explicit instantiations
1211 //
1212 // define a list of functions for vectors and matrices, respectively, where
1213 // the vector/matrix can be replaced using a preprocessor variable
1214 // VectorType/MatrixType. note that we need a space between "VectorType" and
1215 // ">" to disambiguate ">>" when VectorType trails in an angle bracket
1216 
1217 // TODO: The way we define all the instantiations is probably not the very
1218 // best one. Try to find a better description.
1219 
1220 #define VECTOR_FUNCTIONS(VectorType) \
1221  template void ConstraintMatrix::condense<VectorType >(const VectorType &uncondensed,\
1222  VectorType &condensed) const;\
1223  template void ConstraintMatrix::condense<VectorType >(VectorType &vec) const;\
1224  template void ConstraintMatrix:: \
1225  distribute_local_to_global<VectorType > (const Vector<double> &, \
1226  const std::vector<ConstraintMatrix::size_type> &, \
1227  VectorType &, \
1228  const FullMatrix<double> &) const
1229 
1230 #define PARALLEL_VECTOR_FUNCTIONS(VectorType) \
1231  template void ConstraintMatrix:: \
1232  distribute_local_to_global<VectorType > (const Vector<double> &, \
1233  const std::vector<ConstraintMatrix::size_type> &, \
1234  VectorType &, \
1235  const FullMatrix<double> &) const
1236 
1237 
1238 #ifdef DEAL_II_WITH_PETSC
1239 VECTOR_FUNCTIONS(PETScWrappers::MPI::Vector);
1240 VECTOR_FUNCTIONS(PETScWrappers::MPI::BlockVector);
1241 #endif
1242 
1243 #ifdef DEAL_II_WITH_TRILINOS
1244 PARALLEL_VECTOR_FUNCTIONS(TrilinosWrappers::MPI::Vector);
1245 PARALLEL_VECTOR_FUNCTIONS(TrilinosWrappers::MPI::BlockVector);
1246 #endif
1247 
1248 #define MATRIX_VECTOR_FUNCTIONS(MatrixType, VectorType) \
1249  template void ConstraintMatrix:: \
1250  distribute_local_to_global<MatrixType,VectorType > (const FullMatrix<MatrixType::value_type> &, \
1251  const Vector<VectorType::value_type> &, \
1252  const std::vector<ConstraintMatrix::size_type> &, \
1253  MatrixType &, \
1254  VectorType &, \
1255  bool , \
1256  internal::bool2type<false>) const
1257 #define MATRIX_FUNCTIONS(MatrixType) \
1258  template void ConstraintMatrix:: \
1259  distribute_local_to_global<MatrixType,Vector<MatrixType::value_type> > (const FullMatrix<MatrixType::value_type> &, \
1260  const Vector<MatrixType::value_type> &, \
1261  const std::vector<ConstraintMatrix::size_type> &, \
1262  MatrixType &, \
1263  Vector<MatrixType::value_type> &, \
1264  bool , \
1265  internal::bool2type<false>) const
1266 #define BLOCK_MATRIX_VECTOR_FUNCTIONS(MatrixType, VectorType) \
1267  template void ConstraintMatrix:: \
1268  distribute_local_to_global<MatrixType,VectorType > (const FullMatrix<MatrixType::value_type> &, \
1269  const Vector<VectorType::value_type> &, \
1270  const std::vector<ConstraintMatrix::size_type> &, \
1271  MatrixType &, \
1272  VectorType &, \
1273  bool , \
1274  internal::bool2type<true>) const
1275 #define BLOCK_MATRIX_FUNCTIONS(MatrixType) \
1276  template void ConstraintMatrix:: \
1277  distribute_local_to_global<MatrixType,Vector<MatrixType::value_type> > (const FullMatrix<MatrixType::value_type> &, \
1278  const Vector<MatrixType::value_type> &, \
1279  const std::vector<ConstraintMatrix::size_type> &, \
1280  MatrixType &, \
1281  Vector<MatrixType::value_type> &, \
1282  bool , \
1283  internal::bool2type<true>) const
1284 
1285 MATRIX_FUNCTIONS(SparseMatrix<double>);
1286 MATRIX_FUNCTIONS(SparseMatrix<float>);
1287 MATRIX_FUNCTIONS(FullMatrix<double>);
1288 MATRIX_FUNCTIONS(FullMatrix<float>);
1289 MATRIX_FUNCTIONS(FullMatrix<std::complex<double> >);
1290 
1291 BLOCK_MATRIX_FUNCTIONS(BlockSparseMatrix<double>);
1292 BLOCK_MATRIX_FUNCTIONS(BlockSparseMatrix<float>);
1293 BLOCK_MATRIX_VECTOR_FUNCTIONS(BlockSparseMatrix<double>, BlockVector<double>);
1294 BLOCK_MATRIX_VECTOR_FUNCTIONS(BlockSparseMatrix<float>, BlockVector<float>);
1295 
1296 MATRIX_FUNCTIONS(SparseMatrixEZ<double>);
1297 MATRIX_FUNCTIONS(SparseMatrixEZ<float>);
1298 MATRIX_FUNCTIONS(ChunkSparseMatrix<double>);
1299 MATRIX_FUNCTIONS(ChunkSparseMatrix<float>);
1300 
1301 // BLOCK_MATRIX_FUNCTIONS(BlockSparseMatrixEZ<double>);
1302 // BLOCK_MATRIX_VECTOR_FUNCTIONS(BlockSparseMatrixEZ<float>, Vector<float>);
1303 
1304 #ifdef DEAL_II_WITH_PETSC
1305 MATRIX_FUNCTIONS(PETScWrappers::SparseMatrix);
1306 BLOCK_MATRIX_FUNCTIONS(PETScWrappers::BlockSparseMatrix);
1307 MATRIX_FUNCTIONS(PETScWrappers::MPI::SparseMatrix);
1308 BLOCK_MATRIX_FUNCTIONS(PETScWrappers::MPI::BlockSparseMatrix);
1309 MATRIX_VECTOR_FUNCTIONS(PETScWrappers::SparseMatrix, PETScWrappers::Vector);
1310 BLOCK_MATRIX_VECTOR_FUNCTIONS(PETScWrappers::BlockSparseMatrix, PETScWrappers::BlockVector);
1313 #endif
1314 
1315 #ifdef DEAL_II_WITH_TRILINOS
1316 MATRIX_FUNCTIONS(TrilinosWrappers::SparseMatrix);
1317 BLOCK_MATRIX_FUNCTIONS(TrilinosWrappers::BlockSparseMatrix);
1322 #endif
1323 
1324 
1325 #define SPARSITY_FUNCTIONS(SparsityPatternType) \
1326  template void ConstraintMatrix::add_entries_local_to_global<SparsityPatternType> ( \
1327  const std::vector<ConstraintMatrix::size_type> &, \
1328  SparsityPatternType &, \
1329  const bool, \
1330  const Table<2,bool> &, \
1331  internal::bool2type<false>) const; \
1332  template void ConstraintMatrix::add_entries_local_to_global<SparsityPatternType> ( \
1333  const std::vector<ConstraintMatrix::size_type> &, \
1334  const std::vector<ConstraintMatrix::size_type> &, \
1335  SparsityPatternType &, \
1336  const bool, \
1337  const Table<2,bool> &) const
1338 #define BLOCK_SPARSITY_FUNCTIONS(SparsityPatternType) \
1339  template void ConstraintMatrix::add_entries_local_to_global<SparsityPatternType> ( \
1340  const std::vector<ConstraintMatrix::size_type> &, \
1341  SparsityPatternType &, \
1342  const bool, \
1343  const Table<2,bool> &, \
1344  internal::bool2type<true>) const; \
1345  template void ConstraintMatrix::add_entries_local_to_global<SparsityPatternType> ( \
1346  const std::vector<ConstraintMatrix::size_type> &, \
1347  const std::vector<ConstraintMatrix::size_type> &, \
1348  SparsityPatternType &, \
1349  const bool, \
1350  const Table<2,bool> &) const
1351 
1352 SPARSITY_FUNCTIONS(SparsityPattern);
1353 SPARSITY_FUNCTIONS(DynamicSparsityPattern);
1354 BLOCK_SPARSITY_FUNCTIONS(BlockSparsityPattern);
1355 BLOCK_SPARSITY_FUNCTIONS(BlockDynamicSparsityPattern);
1356 
1357 #ifdef DEAL_II_WITH_TRILINOS
1358 SPARSITY_FUNCTIONS(TrilinosWrappers::SparsityPattern);
1359 BLOCK_SPARSITY_FUNCTIONS(TrilinosWrappers::BlockSparsityPattern);
1360 #endif
1361 
1362 
1363 #define ONLY_MATRIX_FUNCTIONS(MatrixType) \
1364  template void ConstraintMatrix::distribute_local_to_global<MatrixType > (\
1365  const FullMatrix<MatrixType::value_type> &, \
1366  const std::vector<ConstraintMatrix::size_type> &, \
1367  const std::vector<ConstraintMatrix::size_type> &, \
1368  MatrixType &) const
1369 
1370 ONLY_MATRIX_FUNCTIONS(FullMatrix<float>);
1371 ONLY_MATRIX_FUNCTIONS(FullMatrix<double>);
1372 ONLY_MATRIX_FUNCTIONS(SparseMatrix<float>);
1373 ONLY_MATRIX_FUNCTIONS(SparseMatrix<double>);
1374 ONLY_MATRIX_FUNCTIONS(MatrixBlock<SparseMatrix<float> >);
1375 ONLY_MATRIX_FUNCTIONS(MatrixBlock<SparseMatrix<double> >);
1376 ONLY_MATRIX_FUNCTIONS(BlockSparseMatrix<float>);
1377 ONLY_MATRIX_FUNCTIONS(BlockSparseMatrix<double>);
1378 
1379 #ifdef DEAL_II_WITH_TRILINOS
1380 ONLY_MATRIX_FUNCTIONS(TrilinosWrappers::SparseMatrix);
1381 ONLY_MATRIX_FUNCTIONS(TrilinosWrappers::BlockSparseMatrix);
1382 #endif
1383 
1384 #ifdef DEAL_II_WITH_PETSC
1385 ONLY_MATRIX_FUNCTIONS(PETScWrappers::SparseMatrix);
1386 ONLY_MATRIX_FUNCTIONS(PETScWrappers::BlockSparseMatrix);
1387 ONLY_MATRIX_FUNCTIONS(PETScWrappers::MPI::SparseMatrix);
1388 ONLY_MATRIX_FUNCTIONS(PETScWrappers::MPI::BlockSparseMatrix);
1389 #endif
1390 
1391 #include "constraint_matrix.inst"
1392 
1393 // allocate scratch data. Cannot use the generic template instantiation
1394 // because we need to provide an initializer object of type
1395 // internals::ConstraintMatrixData<Number> that can be passed to the
1396 // constructor of scratch_data (it won't allow one to be constructed in place).
1397 namespace internals
1398 {
1399 #define SCRATCH_INITIALIZER(Number,Name) \
1400  ConstraintMatrixData<Number>::ScratchData scratch_data_initializer_##Name; \
1401  template<> Threads::ThreadLocalStorage<ConstraintMatrixData<Number>::ScratchData> \
1402  ConstraintMatrixData<Number>::scratch_data(scratch_data_initializer_##Name)
1403 
1404  SCRATCH_INITIALIZER(double,double);
1405  SCRATCH_INITIALIZER(float,float);
1406  SCRATCH_INITIALIZER(long double,ldouble);
1407  SCRATCH_INITIALIZER(std::complex<double>,cdouble);
1408  SCRATCH_INITIALIZER(std::complex<float>,cfloat);
1409  SCRATCH_INITIALIZER(std::complex<long double>,cldouble);
1410 #undef SCRATCH_INITIALIZER
1411 }
1412 
1413 
1414 DEAL_II_NAMESPACE_CLOSE
const types::global_dof_index invalid_size_type
Definition: types.h:173
bool operator<(const ConstraintLine &) const
std::vector< size_type > lines_cache
void print(std::ostream &) const
static bool check_zero_weight(const std::pair< size_type, double > &p)
size_type nth_index_in_set(const unsigned int local_index) const
Definition: index_set.h:1432
std::size_t memory_consumption() const
size_type column_number(const size_type row, const size_type index) const
DEAL_VOLATILE unsigned int counter
Definition: subscriptor.h:184
void add(const size_type i, const size_type j)
::ExceptionBase & ExcMessage(std::string arg1)
Auxiliary class aiding in the handling of block structures like in BlockVector or FESystem...
Definition: block_indices.h:54
void add_entries(const size_type line, const std::vector< std::pair< size_type, double > > &col_val_pairs)
iterator end() const
#define AssertThrow(cond, exc)
Definition: exceptions.h:358
types::global_dof_index size_type
std::vector< std::pair< size_type, double > > Entries
size_type n_cols() const
bool is_compressed() const
SparsityPatternType & block(const size_type row, const size_type column)
size_type size() const
Definition: index_set.h:1247
size_type n_rows() const
void add_line(const size_type line)
bool operator==(const ConstraintLine &) const
void add_entry(const size_type line, const size_type column, const double value)
void add(const size_type i, const size_type j)
void add(const size_type i, const size_type j)
#define Assert(cond, exc)
Definition: exceptions.h:294
size_type index_within_set(const size_type global_index) const
Definition: index_set.h:1475
void condense(SparsityPattern &sparsity) const
size_type n_constraints() const
const BlockIndices & get_row_indices() const
void resolve_indices(std::vector< types::global_dof_index > &indices) const
bool has_inhomogeneities() const
static const Table< 2, bool > default_empty_table
std::size_t memory_consumption() const
void add_lines(const std::vector< bool > &lines)
size_type max_constraint_indirections() const
size_type calculate_line_index(const size_type line) const
void distribute(VectorType &vec) const
std_cxx11::enable_if< std_cxx11::is_fundamental< T >::value, std::size_t >::type memory_consumption(const T &t)
void merge(const ConstraintMatrix &other_constraints, const MergeConflictBehavior merge_conflict_behavior=no_conflicts_allowed)
void compress() const
Definition: index_set.h:1256
void write_dot(std::ostream &) const
size_type row_length(const size_type row) const
bool is_identity_constrained(const size_type index) const
void shift(const size_type offset)
bool are_identity_constrained(const size_type index1, const size_type index2) const
bool is_element(const size_type index) const
Definition: index_set.h:1317
void reinit(const IndexSet &local_constraints=IndexSet())
void add_selected_constraints(const ConstraintMatrix &constraints_in, const IndexSet &filter)
const std::vector< std::pair< size_type, double > > * get_constraint_entries(const size_type line) const
double get_inhomogeneity(const size_type line) const
void set_inhomogeneity(const size_type line, const double value)
iterator begin() const
std::vector< ConstraintLine > lines
bool is_constrained(const size_type index) const
size_type n_elements() const
Definition: index_set.h:1380
const BlockIndices & get_column_indices() const