Plugins
nedelec_source_impl.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2014: G-CSC, Goethe University Frankfurt
3  * Author: Dmitry Logashenko
4  *
5  * This file is part of UG4.
6  *
7  * UG4 is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License version 3 (as published by the
9  * Free Software Foundation) with the following additional attribution
10  * requirements (according to LGPL/GPL v3 §7):
11  *
12  * (1) The following notice must be displayed in the Appropriate Legal Notices
13  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14  *
15  * (2) The following notice must be displayed at a prominent place in the
16  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17  *
18  * (3) The following bibliography is recommended for citation and must be
19  * preserved in all covered files:
20  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21  * parallel geometric multigrid solver on hierarchically distributed grids.
22  * Computing and visualization in science 16, 4 (2013), 151-164"
23  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24  * flexible software system for simulating pde based models on high performance
25  * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30  * GNU Lesser General Public License for more details.
31  */
32 
41 
42 #include "nedelec_local_ass.h"
43 
44 namespace ug{
45 namespace Electromagnetism{
46 
50 template <typename TDomain, typename TAlgebra>
52 (
53  const char * ssNames,
54  const char * posSsNames,
55  const char * cutSsNames,
56  SmartPtr<ApproximationSpace<TDomain> > vertApproxSpace,
58 )
59 : m_allSsNames ((std::string (ssNames) + ',') + posSsNames), m_posSsNames (posSsNames), m_cutSsNames (cutSsNames),
60  m_spVertApproxSpace (vertApproxSpace),
61  m_auxLocLaplace (new AuxLaplaceLocAss (*this)),
62  m_outOfSource (new OutOfSource (*this)),
63  m_zeroAverage (new ZeroAverage (m_outOfSource)),
64  m_auxLaplaceAss (new DomainDiscretization<TDomain, TPotAlgebra> (vertApproxSpace)),
65  m_auxLaplaceOp (new AssembledLinearOperator<TPotAlgebra> (SmartPtr<IAssemble<TPotAlgebra> >(m_auxLaplaceAss))),
66  m_potSolver (potSolver)
67 {
68 // Check the parameters:
70  UG_THROW ("NedelecLoopCurrent: Illegal vert.-centered approx. space.");
71  if (m_spVertApproxSpace->num_fct () != 1)
72  UG_THROW ("NedelecLoopCurrent: Exactly one function should be defined in the vert.-centered approx. space.");
73  if (! m_spVertApproxSpace->is_def_everywhere (0))
74  UG_THROW ("NedelecLoopCurrent: The function in the vert.-centered approx. space must be defined everywhere.");
75  if (m_potSolver.invalid ())
76  UG_THROW ("NedelecLoopCurrent: Illegal solver for the auxiliary problems.");
77 
78 // Fill the subset groups:
79  std::vector<std::string> vssNames;
80  ConstSmartPtr<subset_handler_type> spIsh = vertApproxSpace->subset_handler ();
81 
82  TokenizeString (m_allSsNames, vssNames);
83  for (size_t i = 0; i < vssNames.size(); i++)
84  RemoveWhitespaceFromString (vssNames [i]);
85  m_allSsGrp.set_subset_handler (spIsh); m_allSsGrp.add (vssNames);
86 
87  TokenizeString (m_posSsNames, vssNames);
88  for (size_t i = 0; i < vssNames.size(); i++)
89  RemoveWhitespaceFromString (vssNames [i]);
90  m_posSsGrp.set_subset_handler (spIsh); m_posSsGrp.add (vssNames);
91 
92  TokenizeString (m_cutSsNames, vssNames);
93  for (size_t i = 0; i < vssNames.size(); i++)
94  RemoveWhitespaceFromString (vssNames [i]);
95  m_cutSsGrp.set_subset_handler (spIsh); m_cutSsGrp.add (vssNames);
96 
97 // Compose the global discretization of the auxiliary equations:
99  m_auxLaplaceAss->add
101 }
102 
106 template <typename TDomain, typename TAlgebra>
108 (
109  const char * fctNames,
110  number I
111 )
112 {
113  m_vSrcData.push_back (TSrcData (fctNames, I));
114 }
115 
119 template <typename TDomain, typename TAlgebra>
121 (
123 )
124 {
125  typedef typename domain_traits<WDim>::DimElemList ElemList;
126 
127 // Do we have data to compute?
128  if (m_vSrcData.size () == 0)
129  UG_THROW ("NedelecLoopCurrent: No electric currents specified.");
130 
131 // Check the grid function:
132  if (sp_u.invalid ())
133  UG_THROW ("NedelecLoopCurrent: Illegal grid function specification.");
134 
135 // Get the DoF distributions:
136  GridFunction<TDomain, TAlgebra> & u = * sp_u.get ();
138  const GridLevel g_lev (u.grid_level ());
139  SmartPtr<DoFDistribution> vertDD = m_spVertApproxSpace->dof_distribution (g_lev);
140 
141 // Compute the potential of the source:
142  pot_gf_type pot_u (m_spVertApproxSpace, g_lev);
143 # ifdef UG_PARALLEL
144  pot_u.set_storage_type (PST_CONSISTENT);
145 # endif
146  compute_potential (pot_u);
147 
148 // Compute the normalization factor of the potential (to scale the current to 1)
149  number pot_scaling;
150  boost::mpl::for_each<ElemList>
151  (GetFluxOfPotential (this, * m_spVertApproxSpace->domain().get (), pot_u,
152  * vertDD.get (), pot_scaling));
153 # ifdef UG_PARALLEL
154  {
155  pcl::ProcessCommunicator proc_comm;
156  pot_scaling = proc_comm.allreduce (pot_scaling, PCL_RO_SUM);
157  }
158 # endif
159  pot_scaling = - pot_scaling;
160 
161 // Loop over the source data
162  for (size_t i_data = 0; i_data < m_vSrcData.size (); i_data++)
163  {
164  // Get the component indices:
165  FunctionGroup fctGrp;
166  try
167  {
168  fctGrp = u.fct_grp_by_name (m_vSrcData[i_data].fctNames.c_str ());
169  }
170  UG_CATCH_THROW ("NedelecLoopCurrent: Functions '" << m_vSrcData[i_data].fctNames <<
171  "' not all contained in the edge approximation space.");
172 
173  // Check the functions
174  for (size_t i_fct = 0; i_fct < fctGrp.size (); i_fct++)
175  if (u.local_finite_element_id(fctGrp[i_fct]).type () != LFEID::NEDELEC)
176  UG_THROW ("NedelecLoopCurrent: Not a Nedelec-element-based grid function specified for the source.");
177 
178  // Compute the gradients of the potential
179  number value = m_vSrcData[i_data].I / pot_scaling;
180  for (size_t i_fct = 0; i_fct < fctGrp.size (); i_fct++)
181  distribute_source_potential (* vertDD.get (), pot_u, * edgeDD.get (),
182  fctGrp[i_fct], value, u);
183  }
184 }
185 
196 template <typename TDomain, typename TAlgebra>
197 template <typename TElem>
199 (
200  const DoFDistribution & edgeDD,
201  aa_edge_flag_type & in_source
202 )
203 {
204  typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type;
205  typedef typename DoFDistribution::traits<TElem>::const_iterator iterator;
206 
207  const ISubsetHandler * pIsh = edgeDD.subset_handler().get ();
209 
210 // Loop over the source subsets:
211  for (size_t i = 0; i < m_allSsGrp.size (); i++)
212  {
213  int si = m_allSsGrp [i];
214  bool in_pos = m_posSsGrp.contains (si);
215  // Loop over all the elements of the given type in the subset
216  iterator e_end = edgeDD.template end<TElem> (si);
217  for (iterator elem_iter = edgeDD.template begin<TElem> (si);
218  elem_iter != e_end; ++elem_iter)
219  {
220  TElem * pElem = *elem_iter;
221  pIsh->grid()->associated_elements (edge_list, pElem);
222  UG_ASSERT ((edge_list.size () == (size_t) ref_elem_type::numEdges),
223  "Mismatch of numbers of corners and vertices of an element");
224  for (size_t e = 0; e < (size_t) ref_elem_type::numEdges; e++)
225  {
226  Edge * pEdge = edge_list[e];
227  char flag = 1;
228  if (in_pos)
229  {
230  if (m_cutSsGrp.contains (pIsh->get_subset_index (pEdge->vertex (0))))
231  flag |= 2;
232  if (m_cutSsGrp.contains (pIsh->get_subset_index (pEdge->vertex (1))))
233  flag |= 4;
234  }
235  in_source [pEdge] = flag;
236  }
237  }
238  }
239 }
240 
244 template <typename TDomain, typename TAlgebra>
246 (
247  pot_gf_type & pot_u
248 )
249 {
250  pot_gf_type pot_rhs (pot_u.approx_space (), pot_u.dof_distribution ());
251 
252 // Prepare the attachment for the flags:
253  MultiGrid * mg = pot_u.dd()->multi_grid().get ();
254  a_vert_flag_type a_in_source;
255  mg->attach_to_vertices (a_in_source);
256  m_outOfSource->init (pot_u.domain().get (), a_in_source);
257 
258 // Assemble the matrix of the auxiliary problem:
259  pot_u.set (0.0);
260  m_auxLaplaceOp->set_level (pot_u.grid_level ());
261  m_auxLaplaceOp->init_op_and_rhs (pot_rhs);
262 
263 // Initizlize the solver:
264  m_potSolver->init (m_auxLaplaceOp);
265 
266 // Assemble and solve the Laplace equation:
267  m_potSolver->apply (pot_u, pot_rhs);
268 
269 // Release the attachment:
270  mg->detach_from_vertices (a_in_source);
271 }
272 
279 template <typename TDomain, typename TAlgebra>
281 (
282  const DoFDistribution & vertDD,
283  pot_vector_type & src_pot,
284  DoFDistribution & edgeDD,
285  size_t func,
286  number value,
287  vector_type & src_field
288 )
289 {
291 
292 // The full-dim. grid element types for this dimension:
293  typedef typename domain_traits<WDim>::DimElemList ElemList;
294 
295 // Multigrid and iterators:
296  SmartPtr<MultiGrid> sp_mg = edgeDD.multi_grid ();
297  t_edge_iter edgeIterBeg = edgeDD.begin<Edge> ();
298  t_edge_iter edgeIterEnd = edgeDD.end<Edge> ();
299 
300 // Mark the edges in the source:
301  a_edge_flag_type a_in_source;
302  sp_mg->attach_to_edges (a_in_source);
303  aa_edge_flag_type aa_in_source (*sp_mg, a_in_source);
304  SetAttachmentValues (aa_in_source, edgeIterBeg, edgeIterEnd, 0);
305  boost::mpl::for_each<ElemList> (MarkSourceEdges (this, edgeDD, aa_in_source));
306 # ifdef UG_PARALLEL
307  AttachmentAllReduce<Edge> (*sp_mg, a_in_source, PCL_RO_BOR);
308 # endif
309 
310 // Compute the gradient:
311  std::vector<size_t> vVertInd (1);
312  std::vector<DoFIndex> vEdgeInd (1);
313  for (t_edge_iter edgeIter = edgeIterBeg; edgeIter != edgeIterEnd; ++edgeIter)
314  {
315  Edge * pEdge = *edgeIter;
316  char edge_flag;
317  number nd_pot [2];
318 
319  // Get the edge DoF and check whether the edge is in the source:
320  if (edgeDD.inner_dof_indices (pEdge, func, vEdgeInd) != 1)
321  UG_THROW ("NedelecLoopCurrent: Edge DoF distribution mismatch. Not the Nedelec-Type-1 element?");
322  if ((edge_flag = aa_in_source [pEdge]) == 0)
323  { // we are not in the source
324  DoFRef (src_field, vEdgeInd [0]) = 0;
325  continue;
326  }
327 
328  // Get the values at the ends:
329  for (size_t i = 0; i < 2; i++)
330  {
331  Vertex * pVertex = pEdge->vertex (i);
332  if (vertDD.inner_algebra_indices (pVertex, vVertInd) != 1)
333  UG_THROW ("NedelecLoopCurrent: Vertex DoF distribution mismatch. Not the Lagrange-Order-1 element?");
334  nd_pot [i] = src_pot [vVertInd [0]];
335  if ((edge_flag & (2 << i)) != 0)
336  nd_pot [i] += 1.0; // the jump of the potential at the cut
337  }
338 
339  // Compute the gradient:
340  DoFRef (src_field, vEdgeInd [0]) = value * (nd_pot [1] - nd_pot [0]);
341  }
342 
343 // Release the attachment:
344  sp_mg->detach_from_edges (a_in_source);
345 }
346 
347 /*----- Assembling the auxiliary Poisson problems 1: class AuxLaplaceLocAss -----*/
348 
352 template <typename TDomain, typename TAlgebra>
353 template <typename TElem>
355 (
356  GridObject * elem,
357  const position_type vCornerCoords [],
358  number loc_A [numCorners] [numCorners]
359 )
360 {
362 
363 // request the finite element geometry
364  TFEGeom & geo = GeomProvider<TFEGeom>::get ();
365  // we assume that this is the simplest discretization:
366  UG_ASSERT (geo.num_ip () == 1, "Only the simplest quadrature is supported here.");
367 
368 // initialize the fe geometry
369  geo.update (elem, vCornerCoords);
370 
371 // compute the upper triangle of the local stiffness matrix
372  for (size_t from_co = 0; from_co < (size_t) numCorners; from_co++)
373  for (size_t to_co = from_co; to_co < (size_t) numCorners; to_co++)
374  loc_A [from_co] [to_co]
375  = VecDot (geo.global_grad (0, from_co), geo.global_grad (0, to_co))
376  * geo.weight (0);
377 // use the symmetry
378  for (size_t from_co = 1; from_co < (size_t) numCorners; from_co++)
379  for (size_t to_co = 0; to_co < from_co; to_co++)
380  loc_A [from_co] [to_co] = loc_A [to_co] [from_co];
381 }
382 
386 template <typename TDomain, typename TAlgebra>
387 template <typename TElem>
389 (
390  GridObject * elem,
391  const SubsetGroup & bndGrp,
392  bool bnd_flag [numCorners]
393 )
394 {
395  TElem * pElem = (TElem *) elem;
396  const ISubsetHandler * pIsh = bndGrp.subset_handler().get ();
397  bool bnd = false;
398 
399  for (size_t i = 0; i < (size_t) numCorners; i++)
400  if ((bnd_flag [i] = bndGrp.contains (pIsh->get_subset_index (pElem->vertex (i)))))
401  bnd = true;
402  return bnd;
403 }
404 
409 template <typename TDomain, typename TAlgebra>
411 (
412  NedelecLoopCurrent & master
413 )
414 : IElemDisc<TDomain> (master.m_spVertApproxSpace->name(0).c_str(), master.m_allSsNames.c_str()),
415  m_master (master),
416  m_posSsGrp (master.m_spVertApproxSpace->subset_handler (), master.m_posSsNames),
417  m_cutSsGrp (master.m_spVertApproxSpace->subset_handler (), master.m_cutSsNames),
418  m_in_pos_subset (false)
419 {
420 // check the data
421  if (m_posSsGrp.empty ())
422  UG_THROW ("NedelecLoopCurrent: No positive direction subsets specified");
423  if (m_cutSsGrp.empty ())
424  UG_THROW ("NedelecLoopCurrent: No cut specified");
425 // register assemble functions
427 }
428 
429 // check the basis and the grid
430 template<typename TDomain, typename TAlgebra>
432 (
433  const std::vector<LFEID> & vLfeID,
434  bool bNonRegular
435 )
436 {
437  if (bNonRegular)
438  UG_THROW ("NedelecLoopCurrent:"
439  " The discretization of the auxiliary systems does not support hanging nodes.\n");
440 
441  if (vLfeID.size () != 1)
442  UG_THROW ("NedelecLoopCurrent:"
443  " Only scalar grid functions are supported for the potential");
444 
445  if (vLfeID[0].type() != LFEID::LAGRANGE || vLfeID[0].order() != 1)
446  UG_THROW ("NedelecLoopCurrent:"
447  " Only Largange-1 functions are supported for the potential");
448 }
449 
450 // register the local assembler functions for all the elements and dimensions
451 template<typename TDomain, typename TAlgebra>
453 {
454 // get all grid element types in this dimension and below
455  typedef typename domain_traits<WDim>::DimElemList ElemList;
456 
457 // switch assemble functions
458  boost::mpl::for_each<ElemList> (RegisterLocalDiscr (this));
459 }
460 
461 // register the local assembler functions for a given element
462 template<typename TDomain, typename TAlgebra>
463 template<typename TElem> // the element to register for
465 {
467 
468  this->clear_add_fct(id);
469 
470  this->set_prep_elem_loop_fct(id, & AuxLaplaceLocAss::template prepare_element_loop<TElem>);
471  this->set_prep_elem_fct (id, & AuxLaplaceLocAss::template prepare_element<TElem>);
472  this->set_fsh_elem_loop_fct (id, & AuxLaplaceLocAss::template finish_element_loop<TElem>);
473  this->set_add_jac_A_elem_fct(id, & AuxLaplaceLocAss::template ass_JA_elem<TElem>);
474  this->set_add_jac_M_elem_fct(id, & AuxLaplaceLocAss::template ass_JM_elem<TElem>);
475  this->set_add_def_A_elem_fct(id, & AuxLaplaceLocAss::template ass_dA_elem<TElem>);
476  this->set_add_def_M_elem_fct(id, & AuxLaplaceLocAss::template ass_dM_elem<TElem>);
477  this->set_add_rhs_elem_fct (id, & AuxLaplaceLocAss::template ass_rhs_elem<TElem>);
478 }
479 
480 // prepares the loop over the elements: check whether we are in the positive subset
481 template<typename TDomain, typename TAlgebra>
482 template<typename TElem>
484 (
485  ReferenceObjectID roid, // [in] only elements with this roid are looped over
486  int si // [in] and only in this subdomain
487 )
488 {
489  m_in_pos_subset = m_posSsGrp.contains (si);
490 }
491 
493 template<typename TDomain, typename TAlgebra>
494 template<typename TElem>
496 (
497  LocalMatrix & J,
498  const LocalVector & u,
499  GridObject * elem,
500  const position_type vCornerCoords []
501 )
502 {
503  typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type;
504 
505 // assemble the local matrix
506  number loc_A [ref_elem_type::numCorners] [ref_elem_type::numCorners];
508 
509 // add the local matrix to the global one
510  for (size_t from_co = 0; from_co < (size_t) ref_elem_type::numCorners; from_co++)
511  for (size_t to_co = 0; to_co < (size_t) ref_elem_type::numCorners; to_co++)
512  J (_C_, from_co, _C_, to_co) += loc_A [from_co] [to_co];
513 }
514 
515 // computes the local right-hand side
516 template<typename TDomain, typename TAlgebra>
517 template <typename TElem>
519 (
520  LocalVector & d,
521  GridObject * elem,
522  const position_type vCornerCoords []
523 )
524 {
525  typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type;
526 
527  if (! m_in_pos_subset) return; // rhs is nonzero only in one subset
528 
529 // assemble the local matrix
530  bool at_cut [ref_elem_type::numCorners];
532  (elem, m_master.m_cutSsGrp, at_cut))
533  return; // no corners on the cut
534 
535 // assemble the local matrix and compose the right-hand side of it
536  number loc_A [ref_elem_type::numCorners] [ref_elem_type::numCorners];
538  (elem, vCornerCoords, loc_A);
539  for (size_t i = 0; i < (size_t) ref_elem_type::numCorners; i++)
540  for (size_t j = 0; j < (size_t) ref_elem_type::numCorners; j++)
541  if (at_cut [j])
542  d (_C_, i) -= loc_A [i] [j]; // to simulate the jump of the potential
543 }
544 
545 /*----- Assembling the auxiliary Poisson problems 2: class OutOfSource -----*/
546 
550 template <typename TDomain, typename TAlgebra>
552 (
553  NedelecLoopCurrent & master
554 )
555 : m_master (master)
556 {}
557 
561 template <typename TDomain, typename TAlgebra>
562 template <typename TElem>
564 (
565  const TDomain * dom
566 )
567 {
568  typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type;
569  typedef typename geometry_traits<TElem>::const_iterator iterator;
570 
571 // Get the multigrid and the subset handler:
572  const MultiGrid * mg = dom->grid().get ();
573  const MGSubsetHandler * ssh = dom->subset_handler().get ();
574  size_t n_levels = mg->num_levels ();
575 
576 // Loop over the source subsets:
577  for (size_t i = 0; i < m_master.m_allSsGrp.size (); i++)
578  {
579  int si = m_master.m_allSsGrp [i];
580  for (size_t lev = 0; lev < n_levels; lev++)
581  {
582  // Loop over all the elements of the given type in the subset
583  iterator e_end = ssh->template end<TElem> (si, lev);
584  for (iterator elem_iter = ssh->template begin<TElem> (si, lev);
585  elem_iter != e_end; ++elem_iter)
586  {
587  TElem * pElem = *elem_iter;
588  for (size_t i = 0; i < (size_t) ref_elem_type::numCorners; i++)
589  m_in_source [pElem->vertex (i)] = true;
590  }
591  }
592  }
593 }
594 
598 template <typename TDomain, typename TAlgebra>
600 (
601  const TDomain * dom
602 )
603 {
604 // The full-dim. grid element types for this dimension:
605  typedef typename domain_traits<WDim>::DimElemList ElemList;
606 
607 // Reset the flags:
608  const MultiGrid * mg = dom->grid().get ();
609  SetAttachmentValues (m_in_source, mg->begin<Vertex> (), mg->end<Vertex> (), false);
610 
611 // Mark the vertices:
612  boost::mpl::for_each<ElemList> (MarkSourceVertices (this, dom));
613 }
614 
619 template <typename TDomain, typename TAlgebra>
621 (
622  const DoFDistribution & vertDD,
623  pot_matrix_type & A
624 )
625 {
627  std::vector<size_t> vVertInd (1);
628 
629 // Loop over all the vertices out of the source
630  iterator vert_end = vertDD.end<Vertex> ();
631  for (iterator vert_iter = vertDD.begin<Vertex> (); vert_iter != vert_end; ++vert_iter)
632  {
633  Vertex * pVertex = *vert_iter;
634  if (m_in_source [pVertex])
635  continue; // the vertex is in the source
636 
637  if (vertDD.inner_algebra_indices (pVertex, vVertInd) != 1)
638  UG_THROW ("NedelecLoopCurrent: Vertex DoF distribution mismatch. Not the Lagrange-Order-1 element?");
639 
640  SetDirichletRow (A, vVertInd[0]);
641  }
642 }
643 
648 template <typename TDomain, typename TAlgebra>
650 (
651  const DoFDistribution & vertDD,
652  pot_vector_type & u
653 )
654 {
656  std::vector<size_t> vVertInd (1);
657 
658 // Loop over all the vertices out of the source
659  iterator vert_end = vertDD.end<Vertex> ();
660  for (iterator vert_iter = vertDD.begin<Vertex> (); vert_iter != vert_end; ++vert_iter)
661  {
662  Vertex * pVertex = *vert_iter;
663  if (m_in_source [pVertex])
664  continue; // the vertex is in the source
665 
666  if (vertDD.inner_algebra_indices (pVertex, vVertInd) != 1)
667  UG_THROW ("NedelecLoopCurrent: Vertex DoF distribution mismatch. Not the Lagrange-Order-1 element?");
668 
669  u [vVertInd[0]] = 0;
670  }
671 }
672 
676 template <typename TDomain, typename TAlgebra>
678 (
679  const DoFDistribution & vertDD,
680  pot_vector_type & u
681 )
682 {
684  iterator vert_end = vertDD.end<Vertex> ();
685  std::vector<size_t> vVertInd (1);
686  size_t n_values;
687  number ave;
688 
689 // Loop over all the vertices in the source and compute the average
690  n_values = 0; ave = 0;
691  for (iterator vert_iter = vertDD.begin<Vertex> (); vert_iter != vert_end; ++vert_iter)
692  {
693  Vertex * pVertex = *vert_iter;
694  if (! m_in_source [pVertex])
695  continue; // the vertex is out of the source
696 
697  if (vertDD.inner_algebra_indices (pVertex, vVertInd) != 1)
698  UG_THROW ("NedelecLoopCurrent: Vertex DoF distribution mismatch. Not the Lagrange-Order-1 element?");
699 
700  ave += u [vVertInd[0]];
701  n_values++;
702  }
703 # ifdef UG_PARALLEL
704  {
705  pcl::ProcessCommunicator proc_comm;
706  ave = proc_comm.allreduce (ave, PCL_RO_SUM);
707  n_values = proc_comm.allreduce (n_values, PCL_RO_SUM);
708  }
709 # endif
710  ave /= n_values;
711 
712 // Subtract the average from the components
713  for (iterator vert_iter = vertDD.begin<Vertex> (); vert_iter != vert_end; ++vert_iter)
714  {
715  Vertex * pVertex = *vert_iter;
716  if (! m_in_source [pVertex])
717  continue; // the vertex is out of the source
718 
719  vertDD.inner_algebra_indices (pVertex, vVertInd);
720  u [vVertInd[0]] -= ave;
721  }
722 }
723 
724 /*----- Computation of the flux of the potential over the cut -----*/
725 
730 template <typename TDomain, typename TAlgebra>
731 template <typename TElem>
733 (
734  const domain_type & domain,
735  const pot_vector_type & pot,
736  const DoFDistribution & vertDD,
737  number & flux
738 )
739 {
740  typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type;
741  typedef typename DoFDistribution::traits<TElem>::const_iterator iterator;
742 
743 // Get the positions of the grid points:
744  const typename TDomain::position_accessor_type & aaPos = domain.position_accessor ();
745 
746 // Get the 'negative' subset indices
747  SubsetGroup negSsGrp (m_allSsGrp);
748  negSsGrp.remove (m_posSsGrp);
749 
750 // Loop the elements in the subset group:
751  for (size_t i = 0; i < negSsGrp.size (); i++)
752  {
753  int si = negSsGrp [i];
754  iterator e_end = vertDD.template end<TElem> (si);
755  for (iterator elem_iter = vertDD.template begin<TElem> (si);
756  elem_iter != e_end; ++elem_iter)
757  {
758  TElem * pElem = *elem_iter;
759  bool bnd_flag [ref_elem_type::numCorners];
760 
761  // Check whether we are at the cut
762  if (! LocLaplaceA<TElem>::bnd_corners (pElem, m_cutSsGrp, bnd_flag))
763  continue; // this is not the case
764 
765  // Get the corner positions:
766  position_type aCorners [ref_elem_type::numCorners];
767  for (size_t co = 0; co < (size_t) ref_elem_type::numCorners; co++)
768  aCorners [co] = aaPos [pElem->vertex (co)];
769 
770  // Assemble the local Laplacian:
771  number loc_A [ref_elem_type::numCorners] [ref_elem_type::numCorners];
772  LocLaplaceA<TElem>::stiffness (pElem, aCorners, loc_A);
773 
774  // Compute the local contributions to the flux:
775  std::vector<size_t> vVertInd (1);
776  for (size_t i = 0; i < (size_t) ref_elem_type::numCorners; i++)
777  if (bnd_flag [i]) // consider only the corners at the cut
778  for (size_t j = 0; j < (size_t) ref_elem_type::numCorners; j++)
779  {
780  if (vertDD.inner_algebra_indices (pElem->vertex (j), vVertInd) != 1)
781  UG_THROW ("NedelecLoopCurrent: Illegal vertex-centered DoF distribution");
782  flux += loc_A [i] [j] * pot [vVertInd [0]];
783  }
784  }
785  }
786 }
787 
788 } // end namespace Electromagnetism
789 } // end namespace ug
790 
791 /* End of File */
T * get()
bool invalid() const
size_t allreduce(const size_t &t, pcl::ReduceOperation op) const
traits< TElem >::iterator begin()
size_t inner_algebra_indices(GridObject *elem, std::vector< size_t > &ind, bool bClear=true) const
size_t inner_dof_indices(GridObject *elem, size_t fct, std::vector< DoFIndex > &ind, bool bClear=true) const
traits< TElem >::iterator end()
SmartPtr< MultiGrid > multi_grid()
FunctionGroup fct_grp_by_name(const char *names) const
const LFEID & local_finite_element_id(size_t fct) const
ConstSmartPtr< ISubsetHandler > subset_handler() const
virtual Vertex * vertex(size_t index) const
Class for local assembling of the auxiliary Laplace operator.
Definition: nedelec_source.h:280
SubsetGroup m_posSsGrp
group of the positive direction subsets
Definition: nedelec_source.h:358
void ass_JA_elem(LocalMatrix &J, const LocalVector &u, GridObject *elem, const position_type vCornerCoords[])
transfer the local stiffness matrix to the global discretization
Definition: nedelec_source_impl.h:496
void register_loc_discr_func()
Definition: nedelec_source_impl.h:464
void register_all_loc_discr_funcs()
Definition: nedelec_source_impl.h:452
SubsetGroup m_cutSsGrp
group of the surfaces at the cut
Definition: nedelec_source.h:360
virtual void prepare_setting(const std::vector< LFEID > &vLfeID, bool bNonRegular)
switches between non-regular and regular grids
Definition: nedelec_source_impl.h:432
void prepare_element_loop(ReferenceObjectID roid, int si)
Definition: nedelec_source_impl.h:484
void ass_rhs_elem(LocalVector &d, GridObject *elem, const position_type vCornerCoords[])
Definition: nedelec_source_impl.h:519
AuxLaplaceLocAss(NedelecLoopCurrent &master)
constructor
Definition: nedelec_source_impl.h:411
Helper class for assembling the local stiffness matrix of Laplacian in various routines.
Definition: nedelec_source.h:251
static void stiffness(GridObject *elem, const position_type vCornerCoords[], number loc_A[numCorners][numCorners])
Computes the local discretization of the Laplace operator.
Definition: nedelec_source_impl.h:355
Constraint that sets the problem to 0-identity out of the source.
Definition: nedelec_source.h:374
void adjust_vector(const DoFDistribution &vertDD, pot_vector_type &u)
sets to 0 all the entries of a vector that do not belong to the closure of the source subdomain
Definition: nedelec_source_impl.h:650
void adjust_matrix(const DoFDistribution &vertDD, pot_matrix_type &A)
sets to identity all the matrix rows that do not belong to the closure of the source subdomain
Definition: nedelec_source_impl.h:621
OutOfSource(NedelecLoopCurrent &master)
constructor
Definition: nedelec_source_impl.h:552
void mark_source_vertices_elem_type(const TDomain *dom)
marks the vertices belonging to elements in the source (for one element type)
Definition: nedelec_source_impl.h:564
void mark_source_vertices(const TDomain *dom)
marks the vertices belonging to elements in the source (for all element types)
Definition: nedelec_source_impl.h:600
void set_zero_average(const DoFDistribution &vertDD, pot_vector_type &u)
sets the arithmetic average of the solution vector to zero
Definition: nedelec_source_impl.h:678
Postprocessor to eliminate the kernel parts in the solution.
Definition: nedelec_source.h:547
Class for computation of loop currents.
Definition: nedelec_source.h:123
void compute(SmartPtr< GridFunction< TDomain, TAlgebra > > sp_u)
Computation of the source (only if 'init'ialized): distributes the potential.
Definition: nedelec_source_impl.h:121
SmartPtr< OutOfSource > m_outOfSource
Extension of the matrices and vectors to the whole domain.
Definition: nedelec_source.h:638
SubsetGroup m_posSsGrp
Group of the subsets of the positive direction.
Definition: nedelec_source.h:628
SubsetGroup m_cutSsGrp
Group of the surfaces of the cut of the loop.
Definition: nedelec_source.h:630
void distribute_source_potential(const DoFDistribution &vertDD, pot_vector_type &src_pot, DoFDistribution &edgeDD, size_t func, number value, vector_type &src_field)
Computes the gradient of the potential.
Definition: nedelec_source_impl.h:281
std::string m_allSsNames
Names of all the subsets of the source.
Definition: nedelec_source.h:619
std::string m_cutSsNames
Names of the surfaces of the cut of the loop.
Definition: nedelec_source.h:623
TAlgebra::vector_type vector_type
Type of Vector (for the Nedelec-element-based grid functions)
Definition: nedelec_source.h:140
void compute_potential(pot_gf_type &pot_u)
Computes the potential of the source.
Definition: nedelec_source_impl.h:246
TDomain domain_type
Type of Domain.
Definition: nedelec_source.h:129
TDomain::position_type position_type
position type
Definition: nedelec_source.h:157
std::string m_posSsNames
Names of the subsets of the positive direction.
Definition: nedelec_source.h:621
SmartPtr< AuxLaplaceLocAss > m_auxLocLaplace
Local discretization of the auxiliary equations.
Definition: nedelec_source.h:636
void set(const char *fctNames, number I)
Setting the electric current value.
Definition: nedelec_source_impl.h:108
SmartPtr< DomainDiscretization< TDomain, TPotAlgebra > > m_auxLaplaceAss
Global discretization of the auxiliary equations.
Definition: nedelec_source.h:648
NedelecLoopCurrent(const char *ssNames, const char *posSsNames, const char *cutSsNames, SmartPtr< ApproximationSpace< TDomain > > vertApproxSpace, SmartPtr< ILinearOperatorInverse< pot_vector_type > > potSolver)
Constructor.
Definition: nedelec_source_impl.h:52
void get_flux_of_pot(const TDomain &domain, const pot_vector_type &pot, const DoFDistribution &vertDD, number &flux)
Computes the flux of of the gradient of the potential over the cut (for one type of elements)
Definition: nedelec_source_impl.h:733
void mark_source_edges(const DoFDistribution &edgeDD, aa_edge_flag_type &in_source)
Marks edges that belong to the loop source domain (for one type of elements)
Definition: nedelec_source_impl.h:199
Grid::EdgeAttachmentAccessor< a_edge_flag_type > aa_edge_flag_type
Definition: nedelec_source.h:163
SmartPtr< ApproximationSpace< TDomain > > m_spVertApproxSpace
Vertex-centered approximation space.
Definition: nedelec_source.h:633
SubsetGroup m_allSsGrp
Group of all the subsets of the source.
Definition: nedelec_source.h:626
SmartPtr< ILinearOperatorInverse< pot_vector_type > > m_potSolver
Solver for the auxliliary equations.
Definition: nedelec_source.h:652
size_t size() const
static TGeom & get()
SmartPtr< TDomain > domain()
SmartPtr< DoFDistribution > dof_distribution()
SmartPtr< ApproximationSpace< TDomain > > approx_space()
const GridLevel & grid_level() const
SmartPtr< DoFDistribution > dd()
void init(SmartPtr< ApproximationSpace< TDomain > > spApproxSpace, SmartPtr< DoFDistribution > spDoFDistr, bool bManage)
void attach_to_vertices(IAttachment &attachment)
void detach_from_vertices(IAttachment &attachment)
void associated_elements(traits< Vertex >::secure_container &elemsOut, TElem *e)
TDomain::position_type position_type
int get_subset_index(const char *name) const
Grid * grid() const
SpaceType type() const
size_t num_levels() const
geometry_traits< TGeomObj >::iterator begin()
geometry_traits< TGeomObj >::iterator end()
size_t size() const
bool contains(const char *name) const
void remove(const char *name)
bool empty() const
void add(const char *name)
size_t size() const
ConstSmartPtr< ISubsetHandler > subset_handler() const
void set_subset_handler(ConstSmartPtr< ISubsetHandler > sh)
PST_CONSISTENT
Grid::VertexAttachmentAccessor< position_attachment_type > position_accessor_type
SmartPtr< TSubsetHandler > subset_handler()
void SetAttachmentValues(TAttachmentAccessor &aaVal, TIter elemsBegin, TIter elemsEnd, const TVal &val)
#define PCL_RO_SUM
#define PCL_RO_BOR
Variant::Type type()
vector< string > TokenizeString(const char *str, const char delimiter=',')
void RemoveWhitespaceFromString(std::string &string)
#define UG_ASSERT(expr, msg)
#define UG_CATCH_THROW(msg)
#define UG_THROW(msg)
double number
vector_t::value_type VecDot(const vector_t &v1, const vector_t &v2)
const number & DoFRef(const TMatrix &mat, const DoFIndex &iInd, const DoFIndex &jInd)
ReferenceObjectID
void SetDirichletRow(TMatrix &mat, const DoFIndex &ind)
SurfaceView::traits< TElem >::const_iterator const_iterator
Helper class for computation of the flux of potential over the cut.
Definition: nedelec_source.h:576
Helper class for marking the edges in the source.
Definition: nedelec_source.h:212
Helper class for marking the vertices in the closure of the source subdomain.
Definition: nedelec_source.h:392
Structure for keeping electric current data.
Definition: nedelec_source.h:606
function ProblemDisc new(problemDesc, dom)