WaveBEM: Unsteady Nonlinear Potential Flow Solver for Ship-Wave Interaction.
bem_fma.cc
Go to the documentation of this file.
1 //---------------------------- step-34.cc ---------------------------
2 // $Id: step-34.cc 18734 2009-04-25 13:36:48Z heltai $
3 // Version: $Name$
4 //
5 // Copyright (C) 2009, 2010 by the deal.II authors
6 //
7 // This file is subject to QPL and may not be distributed
8 // without copyright and license information. Please refer
9 // to the file deal.II/doc/license.html for the text and
10 // further information on this license.
11 //
12 // Authors: Luca Heltai, Cataldo Manigrasso, Andrea Mola
13 //
14 //---------------------------- step-34.cc ---------------------------
15 #define TOLL 0.001
16 #define MAXELEMENTSPERBLOCK 1
17 
18 #include "../include/bem_fma.h"
19 #include "../include/laplace_kernel.h"
20 
21 
22 template <int dim>
24  :
25  comp_dom(comp_dom)
26 {}
27 
28 
29 template <int dim>
31 {
32 
33  prm.enter_subsection("FMA Params");
34  {
35  prm.declare_entry("FMA Truncation Order", "3", Patterns::Integer());
36  }
37  prm.leave_subsection();
38 
39 }
40 
41 template <int dim>
43 {
44 
45  prm.enter_subsection("FMA Params");
46  {
47  trunc_order = prm.get_integer("FMA Truncation Order");
48  }
49  prm.leave_subsection();
50 
51 }
52 
53 
54 
55 template <int dim>
57 {
58  std::cout<<"Computing direct integrals..."<<std::endl;
59 
60  // The following function performs
61  // the direct integrals
62  // for the fast multipole algorithm
63  // and saves the results into two
64  // sparse matrices which will be
65  // also used for precondictioning:
66  // the actual preconditioner is a
67  // third sparse matrix
68 
69  // declaration of the 3d singular
70  // quadrature to be used
71 
72  // number of dofs per cell
73 
74  const unsigned int dofs_per_cell = comp_dom.fe.dofs_per_cell;
75 
76  std::vector<QGaussOneOverR<2> > sing_quadratures_3d;
77  for (unsigned int i=0; i<dofs_per_cell; ++i)
78  sing_quadratures_3d.push_back
79  (QGaussOneOverR<2>(comp_dom.singular_quadrature_order,
80  comp_dom.fe.get_unit_support_points()[i], true));
81 
82 
83  // vector containing the ids of the dofs
84  // of each cell: it will be used to transfer
85  // the computed local rows of the matrices
86  // into the global matrices
87 
88  std::vector<unsigned int> local_dof_indices(dofs_per_cell);
89 
90  // vector to store parts of rows of neumann
91  // and dirichlet matrix obtained in local
92  // operations
93 
94  Vector<double> local_neumann_matrix_row_i(comp_dom.fe.dofs_per_cell);
95  Vector<double> local_dirichlet_matrix_row_i(comp_dom.fe.dofs_per_cell);
96 
97  // The index $i$ runs on the
98  // collocation points, which are
99  // the support points of the $i$th
100  // basis function, while $j$ runs
101  // on inner integration points. We
102  // perform the following check to
103  // ensure that we are not trying to
104  // use this code for high order
105  // elements. It will only work with
106  // Q1 elements, that is, for
107  // fe.dofs_per_cell ==
108  // GeometryInfo<dim>::vertices_per_cell.
109 
110  AssertThrow(comp_dom.fe.dofs_per_cell == GeometryInfo<dim-1>::vertices_per_cell,
111  ExcMessage("The code in this function can only be used for "
112  "the usual Q1 elements."));
113 
114  // Now that we have checked that
115  // the number of vertices is equal
116  // to the number of degrees of
117  // freedom, we construct a vector
118  // of support points which will be
119  // used in the local integrations:
120 
121  std::vector<Point<dim> > support_points(comp_dom.dh.n_dofs());
122  DoFTools::map_dofs_to_support_points<dim-1, dim>(*comp_dom.mapping, comp_dom.dh, support_points);
123 
124 
125  // After doing so, we can start the
126  // integration loop over all cells,
127  // where we first initialize the
128  // FEValues object and get the
129  // values of $\mathbf{\tilde v}$ at
130  // the quadrature points (this
131  // vector field should be constant,
132  // but it doesn't hurt to be more
133  // general):
134 
135 
136  cell_it
137  cell = comp_dom.dh.begin_active(),
138  endc = comp_dom.dh.end();
139 
140  // first, we (re)initialize the
141  // preconditioning matricies by
142  // generating the corresponding
143  // sparsity pattern, obtained by
144  // means of the octree blocking
145 
146 
147  // the idea here is that we take
148  // each childless block containing
149  // at least a dof (such dof index is i)
150  // and its interaction list.
151  // for each of the dofs i
152  // we create a set with all the
153  // dofs (this dof index is j) of the
154  // elements having
155  // at least one quad point in the
156  // interaction list blocks: these
157  // dofs will determine the non null
158  // elements ij of the precondition
159  // matrix
160 
161  prec_sparsity_pattern.reinit(comp_dom.dh.n_dofs(),comp_dom.dh.n_dofs(),125*comp_dom.fe.dofs_per_cell);
162 
163  for (unsigned int kk = 0; kk < comp_dom.childlessList.size(); kk++)
164 
165  {
166  // for each block in the childless
167  // list we get the list of nodes and
168  // we check if it contains nodes:
169  // if no nodes are contained there is
170  // nothing to do
171 
172  unsigned int blockId = comp_dom.childlessList[kk];
173 
174  OctreeBlock<dim> *block1 = comp_dom.blocks[blockId];
175 
176  std::vector <unsigned int> block1Nodes = block1->GetBlockNodeList();
177 
178  if (block1Nodes.size() > 0)
179  {
180 
181  // if block1 contains nodes,
182  // we need to get all the quad points
183  // in the intList blocks of block1
184  // (such quad points will be used for
185  // direct integrals)
186 
187  unsigned int intListSubLevs = block1->GetIntListSize();
188  const std::set<unsigned int> &block1IntList = block1->GetIntList(intListSubLevs-1);
189 
190  // in this set we will put all the
191  // dofs of the cell to whom
192  // the quad points belong
193 
194  std::set<unsigned int> directNodes;
195 
196  // start looping on the intList
197  // blocks (block2 here)
198 
199  for (std::set<unsigned int>::iterator pos = block1IntList.begin(); pos != block1IntList.end(); pos++)
200  {
201  OctreeBlock<dim> *block2 = comp_dom.blocks[*pos];
202  std::map <cell_it, std::vector<unsigned int> >
203  blockQuadPointsList = block2->GetBlockQuadPointsList();
204 
205  // get the list of quad points
206  // in block2 and loop on it
207 
208  typename std::map <cell_it, std::vector<unsigned int> >::iterator it;
209  for (it = blockQuadPointsList.begin(); it != blockQuadPointsList.end(); it++)
210  {
211  // the key of the map (*it.first pointer) is
212  // the cell of the quad point: we will
213  // get its dofs and put them in the set
214  // of direct nodes
215 
216  cell_it cell = (*it).first;//std::cout<<cell<<" end "<<(*blockQuadPointsList.end()).first<<std::endl;
217  cell->get_dof_indices(local_dof_indices);
218  for (unsigned int j = 0; j < dofs_per_cell; j++)
219  directNodes.insert(local_dof_indices[j]);
220  }
221  }
222  // the loop over blocks in intList
223  // is over: for all the nodes in
224  // block1, we know nodes in directNodes
225  // list have direct integrals, so
226  // we use them to create the
227  // direct contributions matrices
228  // sparsity pattern
229 
230  for (unsigned int i = 0; i < block1Nodes.size(); i++)
231  for (std::set<unsigned int>::iterator pos = directNodes.begin(); pos != directNodes.end(); pos++)
232  prec_sparsity_pattern.add(block1Nodes[i],*pos);
233  }
234 
235  }
236 
237  // unfortunately, the direct integrals must not be computed only for the
238  // quadPoints in the intList: if a bigger block is in the nonIntList of
239  // another block, the bound for the multipole expansion application does
240  // not hold, and so we must compute direct integrals. Here we scan the
241  // nonIntlists of each block al each level to look for bigger blocks and
242  // initialize the prec matrices sparsity pattern with the corresponding nodes
243 
244  for (unsigned int level = 1; level < comp_dom.num_octree_levels + 1; level++) // loop over levels
245 
246  {
247  std::vector<unsigned int>
248  dofs_filled_blocks = comp_dom.dofs_filled_blocks[level];
249  unsigned int startBlockLevel = comp_dom.startLevel[level];
250 
251  // we loop over blocks of each level
252 
253  for (unsigned int jj = 0; jj < dofs_filled_blocks.size(); jj++)
254  {
255 
256  OctreeBlock<dim> *block1 = comp_dom.blocks[dofs_filled_blocks[jj]];
257  const std::vector <unsigned int> &nodesBlk1Ids = block1->GetBlockNodeList();
258 
259  // again, no need to perform next operations if block has no nodes
260 
261  if (nodesBlk1Ids.size() > 0)
262  {
263  // for each block containing nodes, loop over all sublevels in his NN list (this is because if a
264  // block remains childless BEFORE the last level, at this point we need to compute
265  // all its contributions up to the bottom level)
266 
267 
268  for (unsigned int subLevel = 0; subLevel < block1->NumNearNeighLevels(); subLevel++)
269  {
270 
271  // in this vectors we are saving the nodes needing direct integrals
272 
273  std::set <unsigned int> directNodes;
274  const std::set <unsigned int> &nonIntList = block1->GetNonIntList(subLevel);
275 
276  // loop over well separated blocks of higher size (level): in this case
277  // we must use direct evaluation: for each block we get the quad points
278  // list
279  for (std::set<unsigned int>::iterator pos = nonIntList.begin(); pos !=nonIntList.lower_bound(startBlockLevel); pos++)
280  {
281  OctreeBlock<dim> *block2 = comp_dom.blocks[*pos];
282  std::map <cell_it, std::vector<unsigned int> >
283  blockQuadPointsList = block2->GetBlockQuadPointsList();
284 
285  // we loop on the cells of the quad blocks (*it.first pointer)
286  // and put their dofs in the direct list
287 
288  typename std::map <cell_it, std::vector<unsigned int> >::iterator it;
289  for (it = blockQuadPointsList.begin(); it != blockQuadPointsList.end(); it++)
290  {
291  cell_it cell = (*it).first;
292  cell->get_dof_indices(local_dof_indices);
293  for (unsigned int j = 0; j < dofs_per_cell; j++)
294  directNodes.insert(local_dof_indices[j]);
295  }
296  } // end loop over blocks of a sublevel of nonIntList
297 
298  // we use the nodes in directList, to create the sparsity pattern
299 
300  for (unsigned int i = 0; i < nodesBlk1Ids.size(); i++)
301  for (std::set<unsigned int>::iterator pos = directNodes.begin(); pos != directNodes.end(); pos++)
302  prec_sparsity_pattern.add(nodesBlk1Ids[i],*pos);
303 
304  } // end loop over sublevels
305  } // end if: is there any node in the block?
306  }// end loop over block of a level
307  }//end loop over octree levels
308 
309 
310  // sparsity pattern is ready and can be compressed; the direct matrices
311  // and the preconditioner one are the initialized with the sparsity
312  // pattern just computed
313 
314  prec_sparsity_pattern.compress();
315  double filling_percentage = double(prec_sparsity_pattern.n_nonzero_elements())/double(comp_dom.dh.n_dofs()*comp_dom.dh.n_dofs())*100.;
316  std::cout<<prec_sparsity_pattern.n_nonzero_elements()<<" Nonzeros out of "<<comp_dom.dh.n_dofs()*comp_dom.dh.n_dofs()<<": "<<filling_percentage<<"%"<<std::endl;
317 
318  prec_neumann_matrix.reinit(prec_sparsity_pattern);
319  prec_dirichlet_matrix.reinit(prec_sparsity_pattern);
320  preconditioner.reinit(prec_sparsity_pattern);
321 
322  Point<dim> D;
323  double s;
324 
325  // here we finally start computing the direct integrals: we
326  // first loop among the childless blocks
327 
328  for (unsigned int kk = 0; kk < comp_dom.childlessList.size(); kk++)
329 
330  {
331  //std::cout<<"processing block "<<kk <<" of "<<cMesh->GetNumChildlessBlocks()<<std::endl;
332  //std::cout<<"block "<<cMesh->GetChildlessBlockId(kk) <<" of "<<cMesh->GetNumBlocks()<<" in block list"<<std::endl;
333 
334  // this is the Id of the block
335  unsigned int blockId = comp_dom.childlessList[kk];
336  // and this is the block pointer
337  OctreeBlock<dim> *block1 = comp_dom.blocks[blockId];
338  // we get the block node list
339  const std::vector <unsigned int> &block1Nodes = block1->GetBlockNodeList();
340 
341  // if a block has no nodes (if it only contains quad points), there is nothing to do
342  // if instead there are nodes, we start integrating
343  if (block1Nodes.size() > 0)
344  {
345  // we first get all the blocks in the intList of the current block (block1)
346  // and loop over these blocks, to create a list of ALL the quadrature points that
347  // lie in the interaction list blocks: these quad points have to be integrated
348  // directly. the list of direct quad points has to be a std::map of std::set of
349  // integers, meaning that to each cell, we associate a std::set containing all
350  // the direct quad point ids
351  unsigned int intListNumLevs = block1->GetIntListSize();
352  std::set <unsigned int> block1IntList = block1->GetIntList(intListNumLevs-1);
353 
354  std::map <cell_it,std::set<unsigned int> > directQuadPoints;
355  for (std::set<unsigned int>::iterator pos = block1IntList.begin(); pos != block1IntList.end(); pos++)
356  {
357  // now for each block block2 we get the list of quad points
358  OctreeBlock<dim> *block2 = comp_dom.blocks[*pos];
359  std::map <cell_it, std::vector<unsigned int> >
360  blockQuadPointsList = block2->GetBlockQuadPointsList();
361 
362  // we now loop among the cells of the list and for each cell we loop
363  // among its quad points, to copy them into the direct quad points list
364  typename std::map <cell_it, std::vector<unsigned int> >::iterator it;
365  for (it = blockQuadPointsList.begin(); it != blockQuadPointsList.end(); it++)
366  {
367  for (unsigned int i=0; i<(*it).second.size(); i++)
368  {
369  directQuadPoints[(*it).first].insert((*it).second[i]);
370 
371  /*//////////this is for a check///////////////////
372  for (unsigned int kk=0; kk<block1Nodes.size(); kk++)
373  comp_dom.integralCheck[block1Nodes[kk]][(*it).first] += 1;
375  }
376  }
377  }
378  // we are now ready to go: for each node, we know which quad points are to be
379  // treated directly, and for each node, we will now perform the integral.
380  // we then start looping on the nodes of the block
381  for (unsigned int i=0; i<block1Nodes.size(); i++)
382  {
383  unsigned int nodeIndex = block1Nodes[i];
384  typename std::map <cell_it, std::set<unsigned int> >::iterator it;
385  // we loop on the list of quad points to be treated directly
386  for (it = directQuadPoints.begin(); it != directQuadPoints.end(); it++)
387  {
388  // the vectors with the local integrals for the cell must first
389  // be zeroed
390  local_neumann_matrix_row_i = 0;
391  local_dirichlet_matrix_row_i = 0;
392 
393  // we get the first entry of the map, i.e. the cell pointer
394  // and we check if the cell contains the current node, to
395  // decide if singular of regular quadrature is to be used
396  cell_it cell = (*it).first;
397  cell->get_dof_indices(local_dof_indices);
398 
399  // we copy the cell quad points in this set
400  std::set<unsigned int> &cellQuadPoints = (*it).second;
401  bool is_singular = false;
402  unsigned int singular_index = numbers::invalid_unsigned_int;
403 
404  for (unsigned int j=0; j<comp_dom.fe.dofs_per_cell; ++j)
405  if (comp_dom.double_nodes_set[nodeIndex].count(local_dof_indices[j]) > 0)
406  {
407  singular_index = j;
408  is_singular = true;
409  break;
410  }
411  // first case: the current node does not belong to the current cell:
412  // we use regular quadrature
413  if (is_singular == false)
414  {
415  //std::cout<<"Node "<<i<<" Elem "<<cell<<" (Direct) Nodes: ";
416  //for(unsigned int j=0; j<fe.dofs_per_cell; ++j) std::cout<<" "<<local_dof_indices[j];
417  //std::cout<<std::endl;
418 
419  // we start looping on the quad points of the cell: *pos will be the
420  // index of the quad point
421  for (std::set<unsigned int>::iterator pos=cellQuadPoints.begin(); pos!=cellQuadPoints.end(); pos++)
422  {
423  // here we compute the distance R between the node and the quad point
424  const Point<dim> R = comp_dom.quadPoints[cell][*pos] + -1.0*support_points[nodeIndex];
425  LaplaceKernel::kernels(R, D, s);
426 
427  // and here are the integrals for each of the degrees of freedom of the cell: note
428  // how the quadrature values (position, normals, jacobianXweight, shape functions)
429  // are taken from the precomputed ones in ComputationalDomain class
430  for (unsigned int j=0; j<comp_dom.fe.dofs_per_cell; ++j)
431  {
432  local_neumann_matrix_row_i(j) += ( ( D *
433  comp_dom.quadNormals[cell][*pos] ) *
434  comp_dom.quadShapeFunValues[cell][*pos][j] *
435  comp_dom.quadJxW[cell][*pos] );
436  local_dirichlet_matrix_row_i(j) += ( s *
437  comp_dom.quadShapeFunValues[cell][*pos][j] *
438  comp_dom.quadJxW[cell][*pos] );
439  //std::cout<<D<<" "<<comp_dom.quadNormals[cell][*pos]<<" ";
440  //std::cout<<comp_dom.quadShapeFunValues[cell][*pos][j]<<" ";
441  //std::cout<<comp_dom.quadJxW[cell][*pos]<<std::endl;
442  }
443  }
444  } // end if
445  else
446  {
447  // after some checks, we have to create the singular quadrature:
448  // here the quadrature points of the cell will be IGNORED,
449  // and the singular quadrature points are instead used.
450  // the 3d and 2d quadrature rules are different
451  Assert(singular_index != numbers::invalid_unsigned_int,
452  ExcInternalError());
453 
454  const Quadrature<dim-1> *
455  singular_quadrature
456  = (dim == 2
457  ?
458  dynamic_cast<Quadrature<dim-1>*>(
459  new QGaussLogR<1>(comp_dom.singular_quadrature_order,
460  Point<1>((double)singular_index),
461  1./cell->measure(), true))
462  :
463  (dim == 3
464  ?
465  dynamic_cast<Quadrature<dim-1>*>(
466  &sing_quadratures_3d[singular_index])
467  :
468  0));
469  Assert(singular_quadrature, ExcInternalError());
470 
471  // once the singular quadrature has been created, we employ it
472  // to create the corresponding fe_values
473 
474  FEValues<dim-1,dim> fe_v_singular (*comp_dom.mapping, comp_dom.fe, *singular_quadrature,
475  update_jacobians |
476  update_values |
477  update_cell_normal_vectors |
478  update_quadrature_points );
479 
480  fe_v_singular.reinit(cell);
481 
482  // here are the vectors of the quad points and normals vectors
483 
484  const std::vector<Point<dim> > &singular_normals = fe_v_singular.get_normal_vectors();
485  const std::vector<Point<dim> > &singular_q_points = fe_v_singular.get_quadrature_points();
486 
487 
488  // and here is the integrals computation: note how in this case the
489  // values for shape functions & co. are not taken from the precomputed
490  // ones in ComputationalDomain class
491 
492  for (unsigned int q=0; q<singular_quadrature->size(); ++q)
493  {
494  const Point<dim> R = singular_q_points[q] + -1.0*support_points[nodeIndex];
495  LaplaceKernel::kernels(R, D, s);
496  for (unsigned int j=0; j<comp_dom.fe.dofs_per_cell; ++j)
497  {
498  local_neumann_matrix_row_i(j) += (( D *
499  singular_normals[q]) *
500  fe_v_singular.shape_value(j,q) *
501  fe_v_singular.JxW(q) );
502 
503  local_dirichlet_matrix_row_i(j) += ( s *
504  fe_v_singular.shape_value(j,q) *
505  fe_v_singular.JxW(q) );
506  }
507  }
508  if (dim==2)
509  delete singular_quadrature;
510 
511  } // end else
512 
513  // Finally, we need to add
514  // the contributions of the
515  // current cell to the
516  // global matrix.
517 
518  for (unsigned int j=0; j<comp_dom.fe.dofs_per_cell; ++j)
519  {
520  prec_neumann_matrix.add(nodeIndex,local_dof_indices[j],local_neumann_matrix_row_i(j));
521  prec_dirichlet_matrix.add(nodeIndex,local_dof_indices[j],local_dirichlet_matrix_row_i(j));
522  if (cell->material_id() == comp_dom.free_sur_ID1 ||
523  cell->material_id() == comp_dom.free_sur_ID2 ||
524  cell->material_id() == comp_dom.free_sur_ID3 )
525  preconditioner.add(nodeIndex,local_dof_indices[j],-local_dirichlet_matrix_row_i(j));
526  else
527  preconditioner.add(nodeIndex,local_dof_indices[j], local_neumann_matrix_row_i(j));
528  }
529 
530  } // end loop on cells of the intList
531  } // end loop over nodes of block1
532  } // end if (nodes in block > 0)
533  } // end loop over childless blocks
534 
535 
536  // as said, the direct integrals must not be computed only for the
537  // quadPoints in the intList: if a bigger block is in the nonIntList of
538  // another block, the bound for the multipole expansion application does
539  // not hold, and so we must compute direct integrals. Here we scan the
540  // nonIntlists of each block al each level to look for bigger blocks and
541  // compute the direct integral contribution for the quadNodes in such
542  // blocks
543 
544  for (unsigned int level = 1; level < comp_dom.num_octree_levels + 1; level++) // loop over levels
545 
546  {
547  unsigned int startBlockLevel = comp_dom.startLevel[level];
548  for (unsigned int jj = 0; jj < comp_dom.dofs_filled_blocks[level].size(); jj++) // loop over blocks of each level
549  {
550 
551  OctreeBlock<dim> *block1 = comp_dom.blocks[comp_dom.dofs_filled_blocks[level][jj]];
552  const std::vector <unsigned int> &nodesBlk1Ids = block1->GetBlockNodeList();
553 
554  for (unsigned int i = 0; i < nodesBlk1Ids.size(); i++)
555  {
556  // for each block containing nodes, loop over all sublevels in his NN list (this is because if a
557  // block remains childless BEFORE the last level, at this point we need to compute
558  // all its contributions up to the bottom level)
559  unsigned int nodeIndex = nodesBlk1Ids[i];
560  std::map <cell_it,std::set<unsigned int> > directQuadPoints;
561  for (unsigned int subLevel = 0; subLevel < block1->NumNearNeighLevels(); subLevel++)
562  {
563  const std::set <unsigned int> &nonIntList = block1->GetNonIntList(subLevel);
564 
565  // loop over well separated blocks of higher size (level)-----> in this case
566  //we must use direct evaluation (luckily being childless they only contain 1 element)
567  for (std::set<unsigned int>::iterator pos = nonIntList.begin(); pos !=nonIntList.lower_bound(startBlockLevel); pos++)
568  {
569  OctreeBlock<dim> *block2 = comp_dom.blocks[*pos];
570  std::map <cell_it, std::vector<unsigned int> >
571  blockQuadPointsList = block2->GetBlockQuadPointsList();
572  typename std::map <cell_it, std::vector<unsigned int> >::iterator it;
573  for (it = blockQuadPointsList.begin(); it != blockQuadPointsList.end(); it++)
574  {
575  for (unsigned int ii=0; ii<(*it).second.size(); ii++)
576  {
577  directQuadPoints[(*it).first].insert((*it).second[ii]);
578 
579  /*////////this is for a check/////////////////////
580  comp_dom.integralCheck[nodesBlk1Ids[i]][(*it).first] += 1;
582  }
583  }
584  } // end loop over blocks of a sublevel of nonIntList
585  } // end loop over sublevels
586 
587  typename std::map <cell_it, std::set<unsigned int> >::iterator it;
588  for (it = directQuadPoints.begin(); it != directQuadPoints.end(); it++)
589  {
590  // the vectors with the local integrals for the cell must first
591  // be zeroed
592  local_neumann_matrix_row_i = 0;
593  local_dirichlet_matrix_row_i = 0;
594 
595  // we get the first entry of the map, i.e. the cell pointer
596  // here the quadrature is regular as the cell is well
597  // separated
598  cell_it cell = (*it).first;
599  cell->get_dof_indices(local_dof_indices);
600  // we copy the cell quad points in this set
601  std::set<unsigned int> &cellQuadPoints = (*it).second;
602 
603  //std::cout<<"Node "<<i<<" Elem "<<cell<<" (Direct) Nodes: ";
604  //for(unsigned int j=0; j<fe.dofs_per_cell; ++j) std::cout<<" "<<local_dof_indices[j];
605  //std::cout<<std::endl;
606 
607  // we start looping on the quad points of the cell: *pos will be the
608  // index of the quad point
609  for (std::set<unsigned int>::iterator pos=cellQuadPoints.begin(); pos!=cellQuadPoints.end(); pos++)
610  {
611  // here we compute the distance R between the node and the quad point
612  const Point<dim> R = comp_dom.quadPoints[cell][*pos] + -1.0*support_points[nodeIndex];
613  LaplaceKernel::kernels(R, D, s);
614 
615  // and here are the integrals for each of the degrees of freedom of the cell: note
616  // how the quadrature values (position, normals, jacobianXweight, shape functions)
617  // are taken from the precomputed ones in ComputationalDomain class
618 
619  for (unsigned int j=0; j<comp_dom.fe.dofs_per_cell; ++j)
620  {
621  local_neumann_matrix_row_i(j) += ( ( D *
622  comp_dom.quadNormals[cell][*pos] ) *
623  comp_dom.quadShapeFunValues[cell][*pos][j] *
624  comp_dom.quadJxW[cell][*pos] );
625  local_dirichlet_matrix_row_i(j) += ( s *
626  comp_dom.quadShapeFunValues[cell][*pos][j] *
627  comp_dom.quadJxW[cell][*pos] );
628 
629  } // end loop over the dofs in the cell
630  } // end loop over the quad points in a cell
631 
632  // Finally, we need to add
633  // the contributions of the
634  // current cell to the
635  // global matrix.
636 
637  for (unsigned int j=0; j<comp_dom.fe.dofs_per_cell; ++j)
638  {
639  prec_neumann_matrix.add(nodeIndex,local_dof_indices[j],local_neumann_matrix_row_i(j));
640  prec_dirichlet_matrix.add(nodeIndex,local_dof_indices[j],local_dirichlet_matrix_row_i(j));
641  if (cell->material_id() == comp_dom.free_sur_ID1 ||
642  cell->material_id() == comp_dom.free_sur_ID2 ||
643  cell->material_id() == comp_dom.free_sur_ID3 )
644  preconditioner.add(nodeIndex,local_dof_indices[j],-local_dirichlet_matrix_row_i(j));
645  else
646  preconditioner.add(nodeIndex,local_dof_indices[j], local_neumann_matrix_row_i(j));
647  }
648 
649 
650  } // end loop over quad points in the direct quad points list
651  } // end loop over nodes in a block
652  }// end loop over block of a level
653  }//end loop over octree levels
654 
655 
656 
657  std::cout<<"...done computing direct integrals"<<std::endl;
658 }
659 
660 
661 
662 template <int dim>
663 void BEMFMA<dim>::multipole_integrals()
664 {
665 
666  std::cout<<"Computing multipole integrals..."<<std::endl;
667 
668  // we start clearing the two structures in which we will
669  // store the integrals. these objects are quite complicated:
670  // for each block we are going to get the portion of
671  // the cells contained in it, and by means if their
672  // quad points in the block, perform the integrals
673  // (but remember that there is going to be one integral
674  // for each shape function/cell dof, and that the integral
675  // will be stored in a multipole expansion).
676  // thus, this structure is a map associating the
677  // blockId (an unsigned int) to the dofs_per_cell integrals
678  // for each cell, i.e. to a map associating cells
679  // to vectors of multipole expansions (vectors of size
680  // dofs_per_cell)
681 
682  elemMultipoleExpansionsKer1.clear();
683  elemMultipoleExpansionsKer2.clear();
684 
685  // we set a useful integer variable and perform some check
686 
687  const unsigned int dofs_per_cell = comp_dom.fe.dofs_per_cell;
688 
689 
690  AssertThrow(dofs_per_cell == GeometryInfo<dim-1>::vertices_per_cell,
691  ExcMessage("The code in this function can only be used for "
692  "the usual Q1 elements."));
693 
694  // now we start looping on the childless blocks to perform the integrals
695  for (unsigned int kk = 0; kk < comp_dom.childlessList.size(); kk++)
696 
697  {
698  //std::cout<<"processing block "<<kk <<" of "<<cMesh->GetNumChildlessBlocks()<<std::endl;
699  //std::cout<<"block "<<cMesh->GetChildlessBlockId(kk) <<" of "<<cMesh->GetNumBlocks()<<" in block list"<<std::endl;
700 
701  // we get the current block and its Id, and then we
702  // compute its center, which is needed to construct the
703  // multipole expansion in which we store the integrals
704 
705  unsigned int blockId = comp_dom.childlessList[kk];
706  OctreeBlock<dim> *block = comp_dom.blocks[blockId];
707  double delta = block->GetDelta();
708  Point<dim> deltaHalf;
709  for (unsigned int i=0; i<dim; i++)
710  deltaHalf(i) = delta/2.;
711  Point<dim> blockCenter = block->GetPMin()+deltaHalf;
712 
713  // at this point, we get the list of quad nodes for the current block,
714  // and loop over it
715  std::map <cell_it, std::vector <unsigned int> > blockQuadPointsList = block->GetBlockQuadPointsList();
716 
717  typename std::map <cell_it, std::vector<unsigned int> >::iterator it;
718  for (it = blockQuadPointsList.begin(); it != blockQuadPointsList.end(); it++)
719  {
720  // for each cell in the list, we get the list of its quad nodes
721  // present in the current block
722  cell_it cell = (*it).first;
723  std::vector <unsigned int> &cellQuadPoints = (*it).second;
724 
725  // the vectors in the structures that we have previously cleared
726  // neet to be resized
727  elemMultipoleExpansionsKer1[blockId][cell].resize(dofs_per_cell);
728  elemMultipoleExpansionsKer2[blockId][cell].resize(dofs_per_cell);
729 
730  // the vectors are now initialized with an empty multipole expansion
731  // centered in the current block center
732  for (unsigned int j=0; j<comp_dom.fe.dofs_per_cell; ++j)
733  {
734  elemMultipoleExpansionsKer1[blockId][cell][j] =
735  MultipoleExpansion(trunc_order, blockCenter, &assLegFunction);
736  elemMultipoleExpansionsKer2[blockId][cell][j] =
737  MultipoleExpansion(trunc_order, blockCenter, &assLegFunction);
738  }
739 
740  // the contribution of each quadrature node (which can be seen as a
741  // source with a certain strength) is introduced in the
742  // multipole expansion with the appropriate methods (AddNormDer
743  // for neumann matrix integrals, Add for dirichlet matrix
744  // integrals)
745  for (unsigned int k=0; k<cellQuadPoints.size(); ++k)
746  {
747  unsigned int q = cellQuadPoints[k];
748  for (unsigned int j=0; j<comp_dom.fe.dofs_per_cell; ++j)
749  {
750  elemMultipoleExpansionsKer1[blockId][cell][j].AddNormDer(comp_dom.quadShapeFunValues[cell][q][j]*comp_dom.quadJxW[cell][q]/4/numbers::PI,comp_dom.quadPoints[cell][q],comp_dom.quadNormals[cell][q]);
751  elemMultipoleExpansionsKer2[blockId][cell][j].Add(comp_dom.quadShapeFunValues[cell][q][j]*comp_dom.quadJxW[cell][q]/4/numbers::PI,comp_dom.quadPoints[cell][q]);
752  }
753  } // end loop on cell quadrature points in the block
754 
755  } // end loop over cells in the block
756 
757  } // fine loop sui blocchi childless
758 
759 
760 
761  std::cout<<"...done computing multipole integrals"<<std::endl;
762 }
763 
764 
765 
766 template <int dim>
767 void BEMFMA<dim>::generate_multipole_expansions(const Vector<double> &phi_values, const Vector<double> &dphi_dn_values) const
768 {
769  std::cout<<"Generating multipole expansions..."<<std::endl;
770 
771 
772 // also here we clear the structures storing the multipole
773 // expansions for Dirichlet and Neumann matrices
774 
775 
776  blockMultipoleExpansionsKer1.clear();
777  blockMultipoleExpansionsKer2.clear();
778 
779 // we reisze them: there's going to be an expansion per block
780 
781  blockMultipoleExpansionsKer1.resize(comp_dom.num_blocks);
782  blockMultipoleExpansionsKer2.resize(comp_dom.num_blocks);
783 
784 // these two variables will be handy in the following
785 
786  std::vector<unsigned int> local_dof_indices(comp_dom.fe.dofs_per_cell);
787  double delta;
788 
789 // we loop on blocks and for each of them we create an empty multipole expansion
790 // centered in the block center
791 
792  for (unsigned int ii = 0; ii < comp_dom.num_blocks ; ii++)
793 
794  {
795  delta = comp_dom.blocks[ii]->GetDelta();
796  Point<dim> deltaHalf;
797  for (unsigned int i=0; i<dim; i++)
798  deltaHalf(i) = delta/2.;
799 
800  Point<dim> blockCenter = comp_dom.blocks[ii]->GetPMin()+deltaHalf;
801 
802  blockMultipoleExpansionsKer1[ii] = MultipoleExpansion(trunc_order, blockCenter, &assLegFunction);
803  blockMultipoleExpansionsKer2[ii] = MultipoleExpansion(trunc_order, blockCenter, &assLegFunction);
804  }
805 
806 // we now begin the rising phase of the algorithm: starting from the lowest block levels (childless blocks)
807 // we get all the values of the multipole integrals and aggregate them in the multipole expansion for
808 // each blocks
809 
810  for (unsigned int kk = 0; kk < comp_dom.childlessList.size(); kk++)
811 
812  {
813 
814  // for each block we get the center and the quad points
815 
816  unsigned int blockId = comp_dom.childlessList[kk];
817  OctreeBlock<dim> *block = comp_dom.blocks[blockId];
818 
819  delta = comp_dom.blocks[blockId]->GetDelta();
820  Point<dim> deltaHalf;
821  for (unsigned int i=0; i<dim; i++)
822  deltaHalf(i) = delta/2.;
823  Point<dim> blockCenter = comp_dom.blocks[blockId]->GetPMin()+deltaHalf;
824 
825  std::map <cell_it, std::vector <unsigned int> > blockQuadPointsList = block->GetBlockQuadPointsList();
826 
827  // we loop on the cells of the quad points in the block: remember that for each cell with a node in the
828  // block, we had created a set of dofs_per_cell multipole expansion, representing
829  // the (partial) integral on each cell
830 
831  typename std::map <cell_it, std::vector<unsigned int> >::iterator it;
832  for (it = blockQuadPointsList.begin(); it != blockQuadPointsList.end(); it++)
833  {
834  cell_it cell = (*it).first;
835  cell->get_dof_indices(local_dof_indices);
836 
837  // for each cell we get the dof_indices, and add to the block multipole expansion,
838  // the integral previously computed, multiplied by the phi or dphi_dn value at the
839  // corresponding dof of the cell. A suitable MultipoleExpansion class method has been
840  // created for this purpose
841 
842  for (unsigned int jj=0; jj < comp_dom.fe.dofs_per_cell; ++jj)
843  {
844  blockMultipoleExpansionsKer2.at(blockId).Add(elemMultipoleExpansionsKer2[blockId][cell][jj],dphi_dn_values(local_dof_indices[jj]));
845  blockMultipoleExpansionsKer1.at(blockId).Add(elemMultipoleExpansionsKer1[blockId][cell][jj],phi_values(local_dof_indices[jj]));
846  }
847  } //end loop ond block elements
848  } // end loop on childless blocks
849 
850 
851 // now all the lower level blocks have a multipole expansion containing the contribution to the integrals
852 // of all the quad points in them: we now begin summing the child multipole expansion to the the parents
853 // expansions: to do that we need to translate che children expansions to the parent block center: there
854 // is a MultipoleExpansion clas for this too
855 
856 // we loop the levels starting from the bottom one
857 
858  for (unsigned int level = comp_dom.num_octree_levels; level > 0; level--)
859 
860  {
861 
862  // for each block we add the (translated) multipole expansion to the the parent expansion
863 
864  std::cout<<"processing level "<<level <<" of "<<comp_dom.num_octree_levels<<std::endl;
865 
866  for (unsigned int kk = comp_dom.startLevel[level]; kk < comp_dom.endLevel[level]+1; kk++)
867 
868  {
869  unsigned int parentId = comp_dom.blocks[kk]->GetParentId();
870 
871  blockMultipoleExpansionsKer1.at(parentId).Add(blockMultipoleExpansionsKer1.at(kk));
872  blockMultipoleExpansionsKer2.at(parentId).Add(blockMultipoleExpansionsKer2.at(kk));
873 
874  } // end loop over blocks of a level
875 
876  } // end loop over levels
877 
878 
879  std::cout<<"...done generating multipole expansions"<<std::endl;
880 
881 }
882 
883 
884 
885 template <int dim>
886 void BEMFMA<dim>::multipole_matr_vect_products(const Vector<double> &phi_values, const Vector<double> &dphi_dn_values,
887  Vector<double> &matrVectProdN, Vector<double> &matrVectProdD) const
888 {
889  std::cout<<"Computing multipole matrix-vector products... "<<std::endl;
890 
891  // we start re-initializing matrix-vector-product vectors
892  matrVectProdN = 0;
893  matrVectProdD = 0;
894 
895  //and here we compute the direct integral contributions (stored in two sparse matrices)
896  prec_neumann_matrix.vmult(matrVectProdN, phi_values);
897  prec_dirichlet_matrix.vmult(matrVectProdD, dphi_dn_values);
898 
899  //from here on, we compute the multipole expansions contributions
900 
901  // we start cleaning past sessions
902  blockLocalExpansionsKer1.clear();
903  blockLocalExpansionsKer2.clear();
904 
905  blockLocalExpansionsKer1.resize(comp_dom.num_blocks);
906  blockLocalExpansionsKer2.resize(comp_dom.num_blocks);
907 
908  // we declare some familiar variables that will be useful in the method
909  std::vector<Point<dim> > support_points(comp_dom.dh.n_dofs());
910  DoFTools::map_dofs_to_support_points<dim-1, dim>( *comp_dom.mapping,
911  comp_dom.dh, support_points);
912  std::vector<unsigned int> local_dof_indices(comp_dom.fe.dofs_per_cell);
913  double delta;
914 
915 
916  // here we loop on all the blocks and build an empty local expansion for
917  // each of them
918  for (unsigned int ii = 0; ii < comp_dom.num_blocks ; ii++)
919 
920  {
921  delta = comp_dom.blocks[ii]->GetDelta();
922  Point<dim> deltaHalf;
923  for (unsigned int i=0; i<dim; i++)
924  deltaHalf(i) = delta/2.;
925  Point<dim> blockCenter = comp_dom.blocks[ii]->GetPMin()+deltaHalf;
926 
927  blockLocalExpansionsKer1[ii] = LocalExpansion(trunc_order, blockCenter, &assLegFunction);
928  blockLocalExpansionsKer2[ii] = LocalExpansion(trunc_order, blockCenter, &assLegFunction);
929  }
930 
931 
932  // here the descending phase of the algorithm begins: we will start from the top level, and loop
933  // on each block of each level: all the needed multipole integrals contributions must be
934  // introduced in each specific block local expansion. to do this, for each block, we first need to
935  // translate into the block center the parent block local expansion (it accounts for all far blocks
936  // contribution of the parent, and all blocks that are far from the parent, are far from its
937  // children); then, we have to consider all the blocks in the current block's nonIntList,
938  // and convert their multipole expansions to the local expansion of the current block
939  // (there is only one exception to this procedure, and we'll comment it in the following)
940 
941  // so, here we loop over levels, starting form lower levels (bigger blocks)
942  for (unsigned int level = 1; level < comp_dom.num_octree_levels + 1; level++)
943 
944  {
945  std::cout<<"processing level "<<level <<" of "<<comp_dom.num_octree_levels<<std::endl;
946 
947  // we get the ids of the first and last block of the level
948  unsigned int startBlockLevel = comp_dom.startLevel[level];
949  unsigned int endBlockLevel = comp_dom.endLevel[level];
950 
951  // to reduce computational cost, we decide to loop on the list of blocks which
952  // contain at least one node (the local and multipole expansion will be finally evaluated
953  // at the nodes positions)
954 
955  for (unsigned int k = 0; k < comp_dom.dofs_filled_blocks[level].size(); k++) // loop over blocks of each level
956  {
957  //std::cout<<"Block "<<jj<<std::endl;
958  unsigned int jj = comp_dom.dofs_filled_blocks[level][k];
959  OctreeBlock<dim> *block1 = comp_dom.blocks[jj];
960  unsigned int block1Parent = block1->GetParentId();
961  std::vector <unsigned int> nodesBlk1Ids = block1->GetBlockNodeList();
962 
963 
964  // here we get parent contribution to local expansion and transfer it in current
965  // block: this operation requires a local expansion translation, implemented
966  // in a specific LocalExpansion class member
967 
968  blockLocalExpansionsKer1[jj].Add(blockLocalExpansionsKer1[block1Parent]);
969  blockLocalExpansionsKer2[jj].Add(blockLocalExpansionsKer2[block1Parent]);
970 
971  // for each block, loop over all sublevels in his NN list (this is because if a
972  // block remains childless BEFORE the last level, at this point we need to compute
973  // all its contributions up to the bottom level)
974 
975  for (unsigned int subLevel = 0; subLevel < block1->NumNearNeighLevels(); subLevel++)
976  {
977  // we get the nonIntList of each block
978 
979  std::set <unsigned int> nonIntList = block1->GetNonIntList(subLevel);
980  std::set <cell_it> nonIntListElemsBlk1;
981 
982  // we start converting into local expansions, all the multipole expansions
983  // of all the blocks in nonIntList, that are of the same size (level) of the
984  // current block. To perform the conversion, we use another member of the
985  // LocalExpansion class. Note that all the contributions to the integrals
986  // of blocks bigger than current block had already been considered in
987  // the direct integrals method (the bounds of the local and multipole
988  // expansion do not hold in such case)
989 
990  for (std::set <unsigned int>::iterator pos1 = nonIntList.lower_bound(startBlockLevel); pos1 != nonIntList.upper_bound(endBlockLevel); pos1++) // loop over NNs of NNs and add them to intList
991  {
992  //std::cout<<"NonIntListPart2 Blocks: "<<*pos1<<" ";
993  unsigned int block2Id = *pos1;
994  blockLocalExpansionsKer1[jj].Add(blockMultipoleExpansionsKer1[block2Id]);
995  blockLocalExpansionsKer2[jj].Add(blockMultipoleExpansionsKer2[block2Id]);
996 
997  /*////////this is for a check///////////////////////
998  OctreeBlock<dim>* block2 = comp_dom.blocks[block2Id];
999  std::vector<unsigned int> nodesBlk1Ids = block1->GetBlockNodeList();
1000  std::map <cell_it, std::vector<unsigned int> >
1001  blockQuadPointsList = block2->GetBlockQuadPointsList();
1002  typename std::map <cell_it, std::vector<unsigned int> >::iterator it;
1003  for (it = blockQuadPointsList.begin(); it != blockQuadPointsList.end(); it++)
1004  {
1005  for (unsigned int i=0; i<(*it).second.size(); i++)
1006  {
1007  for (unsigned int kk=0; kk<nodesBlk1Ids.size(); kk++)
1008  comp_dom.integralCheck[nodesBlk1Ids[kk]][(*it).first] += 1;
1009  }
1010  }
1012  } // end loop over well separated blocks of the same size (level)
1013 
1014 
1015  // loop over well separated blocks of the smaller size (level)-----> use multipoles without local expansions
1016 
1017  // we now have to loop over blocks in the nonIntList that are smaller than the current
1018  // blocks: in this case the bound for the conversion of a multipole into local expansion
1019  // do not hold, but the bound for the evaluation of the multipole expansions does hold:
1020  // thus, we will simply evaluate the multipole expansions of such blocks for each node in
1021  // the clock
1022 
1023  for (std::set <unsigned int>::iterator pos1 = nonIntList.upper_bound(endBlockLevel); pos1 != nonIntList.end(); pos1++)
1024  {
1025  //std::cout<<"NonIntListPart3 Blocks: "<<*pos1<<" ";
1026  unsigned int block2Id = *pos1;
1027  //std::vector <cell_it> elemBlk2Ids = block2.GetBlockElementsList();
1028  for (unsigned int ii = 0; ii < nodesBlk1Ids.size(); ii++) //loop over each node of block1
1029  {
1030  Point<dim> &nodeBlk1 = support_points[nodesBlk1Ids.at(ii)];
1031  matrVectProdD(nodesBlk1Ids[ii]) += blockMultipoleExpansionsKer2[block2Id].Evaluate(nodeBlk1);
1032  matrVectProdN(nodesBlk1Ids[ii]) += blockMultipoleExpansionsKer1[block2Id].Evaluate(nodeBlk1);
1033 
1034  /*//////this is for a check/////////////////////////
1035  OctreeBlock<dim>* block2 = comp_dom.blocks[block2Id];
1036  std::map <cell_it, std::vector<unsigned int> >
1037  blockQuadPointsList = block2->GetBlockQuadPointsList();
1038  typename std::map <cell_it, std::vector<unsigned int> >::iterator it;
1039  for (it = blockQuadPointsList.begin(); it != blockQuadPointsList.end(); it++)
1040  {
1041  for (unsigned int i=0; i<(*it).second.size(); i++)
1042  {
1043  comp_dom.integralCheck[nodesBlk1Ids[ii]][(*it).first] += 1;
1044  }
1045  }
1047  }
1048  } // end loop over well separated blocks of smaller size (level)
1049 
1050 
1051  } // end loop over all sublevels in nonIntlist
1052 
1053  } // end loop over blocks of each level
1054 
1055  } // end loop over levels
1056 
1057 
1058  // finally, when the loop over levels is done, we need to evaluate local expansions of all
1059  // childless blocks, at each block node(s)
1060  for (unsigned int kk = 0; kk < comp_dom.childlessList.size(); kk++)
1061 
1062  {
1063  unsigned int block1Id = comp_dom.childlessList[kk];
1064  OctreeBlock<dim> *block1 = comp_dom.blocks[block1Id];
1065  std::vector <unsigned int> nodesBlk1Ids = block1->GetBlockNodeList();
1066 
1067  // loop over nodes of block
1068  for (unsigned int ii = 0; ii < nodesBlk1Ids.size(); ii++) //loop over each node of block1
1069  {
1070  Point<dim> &nodeBlk1 = support_points[nodesBlk1Ids.at(ii)];
1071  matrVectProdD(nodesBlk1Ids[ii]) += (blockLocalExpansionsKer2[block1Id]).Evaluate(nodeBlk1);
1072  matrVectProdN(nodesBlk1Ids[ii]) += (blockLocalExpansionsKer1[block1Id]).Evaluate(nodeBlk1);
1073  } // end loop over nodes
1074 
1075  } // end loop over childless blocks
1076 
1077  /*////////this is for a check//////////////////////
1078  for (unsigned int i = 0; i < comp_dom.dh.n_dofs(); i++)
1079  {
1080  for (cell_it cell = comp_dom.dh.begin_active(); cell != comp_dom.dh.end(); ++cell)
1081  {
1082  std::cout<<i<<" "<<cell<<" "<<comp_dom.integralCheck[i][cell]<<std::endl;
1083  comp_dom.integralCheck[i][cell] = 0;
1084  }
1085  }
1087 
1088 
1089 
1090 
1091  std::cout<<"...done computing multipole matrix-vector products"<<std::endl;
1092 
1093 }
1094 
1095 // this method computes the preconditioner needed for the GMRES:
1096 // to do it, it needs to receive the alpha vector from the bem_problem
1097 // class
1098 
1099 template <int dim>
1100 SparseDirectUMFPACK &BEMFMA<dim>::FMA_preconditioner(const Vector<double> &alpha)
1101 {
1102 
1103  // first step: for each node in which a Neumann boundary condition is applied
1104  // (in such nodes the potential phi is an unknown), we must add the alpha values
1105  // to the diagonal terms of the preconditioner
1106 
1107  for (unsigned int i=0; i < comp_dom.dh.n_dofs(); i++)
1108  if (comp_dom.surface_nodes(i) == 0)
1109  preconditioner.add(i,i,alpha(i));
1110 
1111  // this part is more complicated, and has to do with the presence of double and
1112  // triple nodes in our mesh, and with the corresponding correction we perform on the
1113  // matrix vector products for the lhs and rhs of the system
1114  // here we correct the right hand side so as to account for the presence of double and
1115  // triple dofs
1116 
1117  // we start looping on the dofs
1118  for (unsigned int i=0; i <comp_dom.dh.n_dofs(); i++)
1119  {
1120  // in the next line we compute the "first" among the set of double nodes: this node
1121  // is the first dirichlet node in the set, and if no dirichlet node is there, we get the
1122  // first neumann node
1123 
1124  std::set<unsigned int> doubles = comp_dom.double_nodes_set[i];
1125  unsigned int firstOfDoubles = *doubles.begin();
1126  for (std::set<unsigned int>::iterator it = doubles.begin() ; it != doubles.end(); it++ )
1127  {
1128  if (comp_dom.surface_nodes(*it) == 1)
1129  {
1130  firstOfDoubles = *it;
1131  break;
1132  }
1133  }
1134 
1135  // for each set of double nodes, we will perform the correction only once, and precisely
1136  // when the current node is the first of the set
1137  if (i == firstOfDoubles)
1138  {
1139  // the vector entry corresponding to the first node of the set does not need modification,
1140  // thus we erase ti form the set
1141  doubles.erase(i);
1142 
1143  // if the current (first) node is a dirichlet node, for all its neumann doubles we will
1144  // impose that the potential is equal to that of the first node: this means that in the
1145  // rhs we will put the potential value of the first node (which is prescribed by bc),
1146  // while here in the matrix we will fill the line with zeros and set the diagonal term to 1
1147  if (comp_dom.surface_nodes(i) == 1)
1148  {
1149  for (std::set<unsigned int>::iterator it = doubles.begin() ; it != doubles.end(); it++ )
1150  {
1151 
1152  if (comp_dom.surface_nodes(*it) == 1)
1153  {
1154 
1155  }
1156  else
1157  {
1158  for (unsigned int k = 0; k < prec_sparsity_pattern.row_length(i); k++)
1159  {
1160  unsigned int j = prec_sparsity_pattern.column_number(*it,k);
1161  preconditioner.set(*it,j,0);
1162  }
1163  preconditioner.set(*it,*it,1);
1164  }
1165  }
1166  }
1167 
1168  // if the current (first) node is a neumann node, for all its doubles we will impose that
1169  // the potential is equal to that of the first node: this means that in the rhs we will
1170  // put 0, while here in the matrix we will fill the line with zeros, set the diagonal
1171  // term to 1, and the term corresponding to the "first" node of the set to -1
1172  if (comp_dom.surface_nodes(i) == 0)
1173  {
1174  for (std::set<unsigned int>::iterator it = doubles.begin() ; it != doubles.end(); it++ )
1175  {
1176  for (unsigned int k = 0; k < prec_sparsity_pattern.row_length(i); k++)
1177  {
1178  unsigned int j = prec_sparsity_pattern.column_number(*it,k);
1179  preconditioner.set(*it,j,0);
1180  }
1181  preconditioner.set(*it,*it,1);
1182  preconditioner.set(*it,i,-1);
1183  }
1184  }
1185 
1186 
1187  }
1188  }
1189 
1190 
1191  //preconditioner.print_formatted(std::cout,4,true,0," 0 ",1.);
1192  inv.initialize(preconditioner);
1193 
1194  return inv;
1195 }
1196 
1197 template class BEMFMA<3>;
void parse_parameters(ParameterHandler &prm)
Definition: bem_fma.cc:42
std::map< cell_it, std::vector< unsigned int > > GetBlockQuadPointsList() const
void map_dofs_to_support_points(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof_handler, std::vector< Point< spacedim > > &support_points)
#define AssertThrow(cond, exc)
unsigned int NumNearNeighLevels() const
std::set< unsigned int > GetIntList(unsigned int sublevel) const
void enter_subsection(const std::string &subsection)
void declare_parameters(ParameterHandler &prm)
Definition: bem_fma.cc:30
static::ExceptionBase & ExcMessage(std::string arg1)
BEMFMA(ComputationalDomain< dim > &comp_dom)
Definition: bem_fma.cc:23
std::vector< unsigned int > GetBlockNodeList() const
Definition: octree_block.cc:98
DoFHandler< dim-1, dim >::active_cell_iterator cell_it
Definition: bem_fma.h:50
std::set< unsigned int > GetNonIntList(unsigned int sublevel) const
unsigned int GetIntListSize() const
void leave_subsection()
void direct_integrals()
Definition: bem_fma.cc:56
void declare_entry(const std::string &entry, const std::string &default_value, const Patterns::PatternBase &pattern=Patterns::Anything(), const std::string &documentation=std::string())
long int get_integer(const std::string &entry_string) const