HyperHDG
diffusion_ldgh.hxx
Go to the documentation of this file.
1 #pragma once // Ensure that file is included only once in a single compilation.
2 
3 #include <HyperHDG/dense_la.hxx>
4 #include <HyperHDG/hypercube.hxx>
7 
8 #include <algorithm>
9 #include <tuple>
10 
11 namespace LocalSolver
12 {
13 /*!*************************************************************************************************
14  * \brief Default parameters for the diffusion equation, cf. below.
15  *
16  * \authors Guido Kanschat, Heidelberg University, 2019--2020.
17  * \authors Andreas Rupp, Heidelberg University, 2019--2020.
18  **************************************************************************************************/
19 template <unsigned int space_dimT, typename param_float_t = double>
20 struct DiffusionParametersDefault
21 {
22  /*!***********************************************************************************************
23  * \brief Array containing hypernode types corresponding to Dirichlet boundary.
24  ************************************************************************************************/
25  static constexpr std::array<unsigned int, 0U> dirichlet_nodes{};
26  /*!***********************************************************************************************
27  * \brief Array containing hypernode types corresponding to Neumann boundary.
28  ************************************************************************************************/
29  static constexpr std::array<unsigned int, 0U> neumann_nodes{};
30  /*!***********************************************************************************************
31  * \brief Inverse diffusion coefficient in PDE as analytic function.
32  ************************************************************************************************/
34  const param_float_t = 0.)
35  {
36  return 1.;
37  }
38  /*!***********************************************************************************************
39  * \brief Right-hand side in PDE as analytic function.
40  ************************************************************************************************/
42  const param_float_t = 0.)
43  {
44  return 0.;
45  }
46  /*!***********************************************************************************************
47  * \brief Dirichlet values of solution as analytic function.
48  ************************************************************************************************/
50  const param_float_t = 0.)
51  {
52  return 0.;
53  }
54  /*!***********************************************************************************************
55  * \brief Neumann values of solution as analytic function.
56  ************************************************************************************************/
57  static param_float_t neumann_value(const Point<space_dimT, param_float_t>&,
58  const param_float_t = 0.)
59  {
60  return 0.;
61  }
62  /*!***********************************************************************************************
63  * \brief Analytic result of PDE (for convergence tests).
64  ************************************************************************************************/
66  const param_float_t = 0.)
67  {
68  return 0.;
69  }
70 }; // end of struct DiffusionParametersDefault
71 
72 /*!*************************************************************************************************
73  * \brief Local solver diffusion equation on hypergraph.
74  *
75  * This class contains the local solver for an isotropic diffusion equation, i.e.,
76  * \f[
77  * - \nabla \cdot ( d \nabla u ) = f \quad \text{ in } \Omega, \qquad
78  * u = u_\text D \quad \text{ on } \partial \Omega_\text D, \qquad
79  * - d \nabla u \cdot \nu = g_\text N \quad \text{ on } \partial \Omega_\text N
80  * \f]
81  * in a spatial domain \f$\Omega \subset \mathbb R^d\f$. Here, \f$d\f$ is the spatial dimension
82  * \c space_dim, \f$\Omega\f$ is a regular graph (\c hyEdge_dimT = 1) or hypergraph whose
83  * hyperedges are surfaces (\c hyEdge_dimT = 2) or volumes (\c hyEdge_dimT = 3) or hypervolumes (in
84  * case of \c hyEdge_dimT > 3). \f$f\f$ and \f$d\f$ are scalars defined in the whole domain, the
85  * Dirichlet and Neumann boundary data needs to be defined on their respective hypernodes.
86  *
87  * Moreover, this class provides the functions that approximate the condensed mass matrix. By this,
88  * it is possible to approximate parabolic problems (in a very bad way) and to find good starting
89  * values for the nonlinear eigenvalue problem.
90  *
91  * \tparam hyEdge_dimT Dimension of a hyperedge, i.e., 1 is for PDEs defined on graphs, 2 is for
92  * PDEs defined on surfaces, and 3 is for PDEs defined on volumes.
93  * \tparam poly_deg The polynomial degree of test and trial functions.
94  * \tparam quad_deg The order of the quadrature rule.
95  * \tparam parametersT Struct depending on templates \c space_dimTP and \c lSol_float_TP that
96  * contains static parameter functions.
97  * Defaults to above functions included in \c DiffusionParametersDefault.
98  * \tparam lSol_float_t The floating point type calculations are executed in. Defaults to double.
99  *
100  * \authors Guido Kanschat, Heidelberg University, 2019--2020.
101  * \authors Andreas Rupp, Heidelberg University, 2019--2020.
102  **************************************************************************************************/
103 template <unsigned int hyEdge_dimT,
104  unsigned int poly_deg,
105  unsigned int quad_deg,
106  template <unsigned int, typename> typename parametersT = DiffusionParametersDefault,
107  typename lSol_float_t = double>
109 {
110  public:
111  /*!***********************************************************************************************
112  * \brief Define type of (hyperedge related) data that is stored in HyDataContainer.
113  ************************************************************************************************/
114  struct data_type
115  {
116  };
117  /*!***********************************************************************************************
118  * \brief Define type of node elements, especially with respect to nodal shape functions.
119  ************************************************************************************************/
121  {
122  typedef std::tuple<TPP::ShapeFunction<
125  };
126  /*!***********************************************************************************************
127  * \brief Define how errors are evaluated.
128  ************************************************************************************************/
129  struct error_def
130  {
131  /*!*********************************************************************************************
132  * \brief Define the typename returned by function errors.
133  **********************************************************************************************/
134  typedef std::array<lSol_float_t, 1U> error_t;
135  /*!*********************************************************************************************
136  * \brief Define how initial error is generated.
137  **********************************************************************************************/
139  {
140  std::array<lSol_float_t, 1U> summed_error;
141  summed_error.fill(0.);
142  return summed_error;
143  }
144  /*!*********************************************************************************************
145  * \brief Define how local errors should be accumulated.
146  **********************************************************************************************/
147  static error_t sum_error(error_t& summed_error, const error_t& new_error)
148  {
149  for (unsigned int k = 0; k < summed_error.size(); ++k)
150  summed_error[k] += new_error[k];
151  return summed_error;
152  }
153  /*!*********************************************************************************************
154  * \brief Define how global errors should be postprocessed.
155  **********************************************************************************************/
156  static error_t postprocess_error(error_t& summed_error)
157  {
158  for (unsigned int k = 0; k < summed_error.size(); ++k)
159  summed_error[k] = std::sqrt(summed_error[k]);
160  return summed_error;
161  }
162  };
163 
164  // -----------------------------------------------------------------------------------------------
165  // Public, static constexpr functions
166  // -----------------------------------------------------------------------------------------------
167 
168  /*!***********************************************************************************************
169  * \brief Dimension of hyper edge type that this object solves on.
170  ************************************************************************************************/
171  static constexpr unsigned int hyEdge_dim() { return hyEdge_dimT; }
172  /*!***********************************************************************************************
173  * \brief Evaluate amount of global degrees of freedom per hypernode.
174  *
175  * This number must be equal to HyperNodeFactory::n_dofs_per_node() of the HyperNodeFactory
176  * cooperating with this object.
177  *
178  * \retval n_dofs Number of global degrees of freedom per hypernode.
179  ************************************************************************************************/
180  static constexpr unsigned int n_glob_dofs_per_node()
181  {
182  return Hypercube<hyEdge_dimT - 1>::pow(poly_deg + 1);
183  }
184  /*!***********************************************************************************************
185  * \brief Dimension of of the solution evaluated with respect to a hyperedge.
186  ************************************************************************************************/
187  static constexpr unsigned int system_dimension() { return hyEdge_dimT + 1; }
188  /*!***********************************************************************************************
189  * \brief Dimension of of the solution evaluated with respect to a hypernode.
190  ************************************************************************************************/
191  static constexpr unsigned int node_system_dimension() { return 1; }
192 
193  private:
194  // -----------------------------------------------------------------------------------------------
195  // Private, static constexpr functions
196  // -----------------------------------------------------------------------------------------------
197 
198  /*!***********************************************************************************************
199  * \brief Number of local shape functions (with respect to all spatial dimensions).
200  ************************************************************************************************/
201  static constexpr unsigned int n_shape_fct_ = n_glob_dofs_per_node() * (poly_deg + 1);
202  /*!***********************************************************************************************
203  * \brief Number oflocal shape functions (with respect to a face / hypernode).
204  ************************************************************************************************/
205  static constexpr unsigned int n_shape_bdr_ = n_glob_dofs_per_node();
206  /*!***********************************************************************************************
207  * \brief Number of (local) degrees of freedom per hyperedge.
208  ************************************************************************************************/
209  static constexpr unsigned int n_loc_dofs_ = (hyEdge_dimT + 1) * n_shape_fct_;
210  /*!***********************************************************************************************
211  * \brief Dimension of of the solution evaluated with respect to a hypernode.
212  *
213  * This allows to the use of this quantity as template parameter in member functions.
214  ************************************************************************************************/
215  static constexpr unsigned int system_dim = system_dimension();
216  /*!***********************************************************************************************
217  * \brief Dimension of of the solution evaluated with respect to a hypernode.
218  *
219  * This allows to the use of this quantity as template parameter in member functions.
220  ************************************************************************************************/
221  static constexpr unsigned int node_system_dim = node_system_dimension();
222  /*!***********************************************************************************************
223  * \brief Find out whether a node is of Dirichlet type.
224  ************************************************************************************************/
225  template <typename parameters>
226  static constexpr bool is_dirichlet(const unsigned int node_type)
227  {
228  return std::find(parameters::dirichlet_nodes.begin(), parameters::dirichlet_nodes.end(),
229  node_type) != parameters::dirichlet_nodes.end();
230  }
231 
232  // -----------------------------------------------------------------------------------------------
233  // Private, const members: Parameters and auxiliaries that help assembling matrices, etc.
234  // -----------------------------------------------------------------------------------------------
235 
236  /*!***********************************************************************************************
237  * \brief (Globally constant) penalty parameter for HDG scheme.
238  ************************************************************************************************/
239  const lSol_float_t tau_;
240  /*!***********************************************************************************************
241  * \brief An integrator helps to easily evaluate integrals (e.g. via quadrature).
242  ************************************************************************************************/
246  lSol_float_t>
248 
249  // -----------------------------------------------------------------------------------------------
250  // Private, internal functions for the local solver
251  // -----------------------------------------------------------------------------------------------
252 
253  /*!***********************************************************************************************
254  * \brief Assemble local matrix for the local solver.
255  *
256  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
257  * \param tau Penalty parameter.
258  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
259  * \param time Time, when the local matrix is evaluated.
260  * \retval loc_mat Matrix of the local solver.
261  ************************************************************************************************/
262  template <typename hyEdgeT>
264  assemble_loc_matrix(const lSol_float_t tau, hyEdgeT& hyper_edge, const lSol_float_t time) const;
265  /*!***********************************************************************************************
266  * \brief Assemble local right-hand for the local solver (from skeletal).
267  *
268  * The right hand side needs the values of the global degrees of freedom. Note that we basically
269  * follow the lines of
270  *
271  * B. Cockburn, J. Gopalakrishnan, and R. Lazarov.
272  * Unified hybridization of discontinuous Galerkin, mixed, and continuous Galerkin methods for
273  * second order elliptic problems. SIAM Journal on Numerical Analysis, 47(2):1319–1365, 2009
274  *
275  * and discriminate between local solvers with respect to the skeletal variable and with respect
276  * to the global right-hand side. This assembles the local right-hand side with respect to the
277  * skeletal variable.
278  *
279  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
280  * \tparam SmallMatT The data type of the \c lambda values.
281  * \param lambda_values Global degrees of freedom associated to the hyperedge.
282  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
283  * \retval loc_rhs Local right hand side of the locasl solver.
284  ************************************************************************************************/
285  template <typename hyEdgeT, typename SmallMatT>
287  const SmallMatT& lambda_values,
288  hyEdgeT& hyper_edge) const;
289  /*!***********************************************************************************************
290  * \brief Assemble local right-hand for the local solver (from global right-hand side).
291  *
292  * Note that we basically follow the lines of
293  *
294  * B. Cockburn, J. Gopalakrishnan, and R. Lazarov.
295  * Unified hybridization of discontinuous Galerkin, mixed, and continuous Galerkin methods for
296  * second order elliptic problems. SIAM Journal on Numerical Analysis, 47(2):1319–1365, 2009
297  *
298  * and discriminate between local solvers with respect to the skeletal variable and with respect
299  * to the global right-hand side. This assembles the local right-hand side with respect to the
300  * global right-hand side. This function implicitly uses the parameters.
301  *
302  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
303  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
304  * \param time Point of time, rhs is evaluated at
305  * \retval loc_rhs Local right hand side of the locasl solver.
306  ************************************************************************************************/
307  template <typename hyEdgeT>
309  hyEdgeT& hyper_edge,
310  const lSol_float_t time) const;
311  /*!***********************************************************************************************
312  * \brief Assemble local right-hand for the local solver (from volume function coefficients).
313  *
314  * Note that we basically follow the lines of
315  *
316  * B. Cockburn, J. Gopalakrishnan, and R. Lazarov.
317  * Unified hybridization of discontinuous Galerkin, mixed, and continuous Galerkin methods for
318  * second order elliptic problems. SIAM Journal on Numerical Analysis, 47(2):1319–1365, 2009
319  *
320  * and discriminate between local solvers with respect to the skeletal variable and with respect
321  * to the global right-hand side. This assembles the local right-hand side with respect to the
322  * global right-hand side. This function implicitly uses the parameters.
323  *
324  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
325  * \tparam SmallVecT The data type of the coefficients.
326  * \param coeffs Local coefficients of bulk variable u.
327  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
328  * \retval loc_rhs Local right hand side of the locasl solver.
329  ************************************************************************************************/
330  template <typename hyEdgeT, typename SmallVecT>
331  inline SmallVec<n_loc_dofs_, lSol_float_t> assemble_rhs_from_coeffs(const SmallVecT& coeffs,
332  hyEdgeT& hyper_edge) const;
333  /*!***********************************************************************************************
334  * \brief Solve local problem (with right-hand side from skeletal).
335  *
336  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
337  * \tparam SmallMatT The data type of \c lambda_values.
338  * \param lambda_values Global degrees of freedom associated to the hyperedge.
339  * \param solution_type Type of local problem that is to be solved.
340  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
341  * \param time Point of time the problem is solved.
342  * \retval loc_sol Solution of the local problem.
343  ************************************************************************************************/
344  template <typename hyEdgeT, typename SmallMatT>
345  inline SmallVec<n_loc_dofs_, lSol_float_t> solve_local_problem(const SmallMatT& lambda_values,
346  const unsigned int solution_type,
347  hyEdgeT& hyper_edge,
348  const lSol_float_t time) const
349  {
350  try
351  {
353  if (solution_type == 0)
354  rhs = assemble_rhs_from_lambda(lambda_values, hyper_edge);
355  else if (solution_type == 1)
356  rhs = assemble_rhs_from_lambda(lambda_values, hyper_edge) +
357  assemble_rhs_from_global_rhs(hyper_edge, time);
358  else
359  hy_assert(0 == 1, "This has not been implemented!");
360  return rhs / assemble_loc_matrix(tau_, hyper_edge, time);
361  }
362  catch (Wrapper::LAPACKexception& exc)
363  {
364  hy_assert(0 == 1, exc.what() << std::endl
365  << "This can happen if quadrature is too inaccurate!");
366  throw exc;
367  }
368  }
369  /*!***********************************************************************************************
370  * \brief Solve local problem for mass matrix approximation.
371  *
372  * \note This function is not use for elliptic problems.
373  *
374  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
375  * \tparam SmallMatT The data type for the lambda_values.
376  * \param lambda_values Global degrees of freedom associated to the hyperedge.
377  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
378  * \param time Point of time the local problem is solved at.
379  * \retval loc_sol Solution of the local problem.
380  ************************************************************************************************/
381  template <typename hyEdgeT, typename SmallMatT>
382  inline SmallVec<n_loc_dofs_, lSol_float_t> solve_mass_problem(const SmallMatT& lambda_values,
383  hyEdgeT& hyper_edge,
384  const lSol_float_t time) const
385  {
386  try
387  {
388  SmallVec<n_loc_dofs_, lSol_float_t> rhs = assemble_rhs_from_coeffs(lambda_values, hyper_edge);
389  return rhs / assemble_loc_matrix(tau_, hyper_edge, time);
390  }
391  catch (Wrapper::LAPACKexception& exc)
392  {
393  hy_assert(0 == 1, exc.what() << std::endl
394  << "This can happen if quadrature is too inaccurate!");
395  throw exc;
396  }
397  }
398  /*!***********************************************************************************************
399  * \brief Solve local problem for parabolic approximations.
400  *
401  * \note This function is not use for elliptic problems.
402  ************************************************************************************************/
403  template <typename hyEdgeT, typename SmallMatT, typename SmallVecT>
405  const SmallMatT& lambda_values,
406  const SmallVecT& coeffs,
407  hyEdgeT& hyper_edge,
408  const lSol_float_t UNUSED(delta_time),
409  const lSol_float_t time) const
410  {
411  try
412  {
414  rhs = assemble_rhs_from_lambda(lambda_values, hyper_edge) +
415  assemble_rhs_from_global_rhs(hyper_edge, time) +
416  assemble_rhs_from_coeffs(coeffs, hyper_edge);
417  return (rhs / assemble_loc_matrix(tau_, hyper_edge, time));
418  }
419  catch (Wrapper::LAPACKexception& exc)
420  {
421  hy_assert(0 == 1, exc.what() << std::endl
422  << "This can happen if quadrature is too inaccurate!");
423  throw exc;
424  }
425  }
426  /*!***********************************************************************************************
427  * \brief Evaluate primal variable at boundary.
428  *
429  * Function to evaluate primal variable of the solution. This function is needed to calculate
430  * the local numerical fluxes.
431  *
432  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
433  * \param coeffs Coefficients of the local solution.
434  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
435  * \retval bdr_coeffs Coefficients of respective (dim-1) dimensional function at boundaries.
436  ************************************************************************************************/
437  template <typename hyEdgeT>
440  hyEdgeT& hyper_edge) const;
441  /*!***********************************************************************************************
442  * \brief Evaluate dual variable at boundary.
443  *
444  * Function to evaluate dual variable of the solution. This function is needed to calculate the
445  * local numerical fluxes.
446  *
447  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
448  * \param coeffs Coefficients of the local solution.
449  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
450  * \retval bdr_coeffs Coefficients of respective (dim-1) dimensional function at boundaries.
451  ************************************************************************************************/
452  template <typename hyEdgeT>
455  hyEdgeT& hyper_edge) const;
456 
457  public:
458  // -----------------------------------------------------------------------------------------------
459  // Public functions (and one typedef) to be utilized by external functions.
460  // -----------------------------------------------------------------------------------------------
461 
462  /*!***********************************************************************************************
463  * \brief Class is constructed using a single double indicating the penalty parameter.
464  ************************************************************************************************/
465  typedef lSol_float_t constructor_value_type;
466  /*!***********************************************************************************************
467  * \brief Constructor for local solver.
468  *
469  * \param tau Penalty parameter of HDG scheme.
470  ************************************************************************************************/
471  Diffusion(const constructor_value_type& tau = 1.) : tau_(tau) {}
472  /*!***********************************************************************************************
473  * \brief Evaluate local contribution to matrix--vector multiplication.
474  *
475  * Execute matrix--vector multiplication y = A * x, where x represents the vector containing the
476  * skeletal variable (adjacent to one hyperedge), and A is the condensed matrix arising from the
477  * HDG discretization. This function does this multiplication (locally) for one hyperedge. The
478  * hyperedge is no parameter, since all hyperedges are assumed to have the same properties.
479  *
480  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
481  * \tparam SmallMatInT Data type of \c lambda_values_in.
482  * \tparam SmallMatOutT Data type of \c lambda_values_out.
483  * \param lambda_values_in Local part of vector x.
484  * \param lambda_values_out Local part that will be added to A * x.
485  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
486  * \param time Time.
487  * \retval vecAx Local part of vector A * x.
488  ************************************************************************************************/
489  template <typename hyEdgeT, typename SmallMatInT, typename SmallMatOutT>
490  SmallMatOutT& trace_to_flux(const SmallMatInT& lambda_values_in,
491  SmallMatOutT& lambda_values_out,
492  hyEdgeT& hyper_edge,
493  const lSol_float_t time = 0.) const
494  {
495  hy_assert(lambda_values_in.size() == lambda_values_out.size() &&
496  lambda_values_in.size() == 2 * hyEdge_dimT,
497  "Both matrices must be of same size which corresponds to the number of faces!");
498  for (unsigned int i = 0; i < lambda_values_in.size(); ++i)
499  hy_assert(
500  lambda_values_in[i].size() == lambda_values_out[i].size() &&
501  lambda_values_in[i].size() == n_glob_dofs_per_node(),
502  "Both matrices must be of same size which corresponds to the number of dofs per face!");
503 
504  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
506  solve_local_problem(lambda_values_in, 0U, hyper_edge, time);
507 
509  primal_at_boundary(coeffs, hyper_edge)),
510  duals(dual_at_boundary(coeffs, hyper_edge));
511 
512  for (unsigned int i = 0; i < lambda_values_out.size(); ++i)
513  if (is_dirichlet<parameters>(hyper_edge.node_descriptor[i]))
514  for (unsigned int j = 0; j < lambda_values_out[i].size(); ++j)
515  lambda_values_out[i][j] = 0.;
516  else
517  for (unsigned int j = 0; j < lambda_values_out[i].size(); ++j)
518  lambda_values_out[i][j] =
519  duals(i, j) + tau_ * primals(i, j) -
520  tau_ * lambda_values_in[i][j] * hyper_edge.geometry.face_area(i);
521 
522  return lambda_values_out;
523  }
524  /*!***********************************************************************************************
525  * \brief Fill an array with 1 if the node is Dirichlet and 0 otherwise.
526  ************************************************************************************************/
527  template <typename hyEdgeT>
528  std::array<unsigned int, 2 * hyEdge_dimT> node_types(hyEdgeT& hyper_edge) const
529  {
530  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
531 
532  std::array<unsigned int, 2 * hyEdge_dimT> result;
533  result.fill(0);
534 
535  for (unsigned int i = 0; i < 2 * hyEdge_dimT; ++i)
536  if (is_dirichlet<parameters>(hyper_edge.node_descriptor[i]))
537  result[i] = 1;
538 
539  return result;
540  }
541  /*!***********************************************************************************************
542  * \brief Evaluate local contribution to residual \f$ A x - b \f$.
543  *
544  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
545  * \tparam SmallMatInT Data type of \c lambda_values_in.
546  * \tparam SmallMatOutT Data type of \c lambda_values_out.
547  * \param lambda_values_in Local part of vector x.
548  * \param lambda_values_out Local part that will be added to A * x.
549  * \param hyper_edge The geometry of the considered hyperedge (of typename hyEdgeT).
550  * \param time Time at which analytic functions are evaluated.
551  * \retval vecAx Local part of vector A * x - b.
552  ************************************************************************************************/
553  template <typename hyEdgeT, typename SmallMatInT, typename SmallMatOutT>
554  SmallMatOutT& residual_flux(const SmallMatInT& lambda_values_in,
555  SmallMatOutT& lambda_values_out,
556  hyEdgeT& hyper_edge,
557  const lSol_float_t time = 0.) const
558  {
559  hy_assert(lambda_values_in.size() == lambda_values_out.size() &&
560  lambda_values_in.size() == 2 * hyEdge_dimT,
561  "Both matrices must be of same size which corresponds to the number of faces!");
562  for (unsigned int i = 0; i < lambda_values_in.size(); ++i)
563  hy_assert(
564  lambda_values_in[i].size() == lambda_values_out[i].size() &&
565  lambda_values_in[i].size() == n_glob_dofs_per_node(),
566  "Both matrices must be of same size which corresponds to the number of dofs per face!");
567 
568  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
570  solve_local_problem(lambda_values_in, 1U, hyper_edge, time);
571 
573  primal_at_boundary(coeffs, hyper_edge)),
574  duals(dual_at_boundary(coeffs, hyper_edge));
575 
576  for (unsigned int i = 0; i < lambda_values_out.size(); ++i)
577  {
578  if (is_dirichlet<parameters>(hyper_edge.node_descriptor[i]))
579  for (unsigned int j = 0; j < lambda_values_out[i].size(); ++j)
580  lambda_values_out[i][j] = 0.;
581  else
582  for (unsigned int j = 0; j < lambda_values_out[i].size(); ++j)
583  lambda_values_out[i][j] =
584  duals(i, j) + tau_ * primals(i, j) -
585  tau_ * lambda_values_in[i][j] * hyper_edge.geometry.face_area(i);
586  }
587 
588  return lambda_values_out;
589  }
590  /*!***********************************************************************************************
591  * \brief Evaluate L2 projected lambda values at initial state.
592  *
593  * \note This function is not used for elliptic problems.
594  *
595  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
596  * \tparam SmallMatT Data type of \c lambda_values.
597  * \param lambda_values Local part of vector x.
598  * \param hyper_edge The geometry of the considered hyperedge (of typename hyEdgeT).
599  * \param time Initial time.
600  * \retval lambda_vakues L2 projected lambda ar initial state.
601  ************************************************************************************************/
602  template <typename hyEdgeT, typename SmallMatT>
603  SmallMatT& make_initial(SmallMatT& lambda_values,
604  hyEdgeT& hyper_edge,
605  const lSol_float_t time = 0.) const
606  {
607  hy_assert(lambda_values.size() == 2 * hyEdge_dimT, "Matrix must have appropriate size!");
608  for (unsigned int i = 0; i < lambda_values.size(); ++i)
609  hy_assert(lambda_values[i].size() == n_glob_dofs_per_node(),
610  "Matrix must have appropriate size!");
611 
612  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
613  for (unsigned int i = 0; i < lambda_values.size(); ++i)
614  {
615  if (is_dirichlet<parameters>(hyper_edge.node_descriptor[i]))
616  for (unsigned int j = 0; j < lambda_values[i].size(); ++j)
617  lambda_values[i][j] = 0.;
618  else
619  for (unsigned int j = 0; j < lambda_values[i].size(); ++j)
620  lambda_values[i][j] =
621  integrator ::template integrate_bdrUni_psifunc<decltype(hyEdgeT::geometry),
622  parameters::initial>(
623  j, i, hyper_edge.geometry, time);
624  }
625 
626  return lambda_values;
627  }
628 
629  /*template < class hyEdgeT >
630  std::array< std::array<lSol_float_t, n_shape_bdr_>, 2*hyEdge_dimT > trace_to_mass_flux
631  (
632  const std::array< std::array<lSol_float_t, n_shape_bdr_>, 2*hyEdge_dimT > & lambda_values,
633  hyEdgeT & hyper_edge,
634  const lSol_float_t time = 0.
635  ) const
636  {
637  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
638 
639  std::array<lSol_float_t, n_loc_dofs_> coeffs
640  = solve_local_problem(lambda_values, 0U, hyper_edge, time);
641  std::array< std::array<lSol_float_t, n_shape_bdr_> , 2 * hyEdge_dimT > bdr_values;
642 
643  SmallVec<n_shape_fct_, lSol_float_t> u_coeffs, test_coeffs;
644  for (unsigned int i = 0; i < n_shape_fct_; ++i)
645  u_coeffs[i] = coeffs[hyEdge_dimT*n_shape_fct_+i];
646 
647  std::array< std::array<lSol_float_t, n_shape_bdr_>, 2*hyEdge_dimT > lambda_values_uni;
648  for (unsigned int i = 0; i < lambda_values.size(); ++i) lambda_values_uni[i].fill(0.);
649  for (unsigned int i = 0; i < lambda_values.size(); ++i)
650  if ( is_dirichlet<parameters>(hyper_edge.node_descriptor[i]) )
651  for (unsigned int j = 0; j < lambda_values[i].size(); ++j) bdr_values[i][j] = 0.;
652  else
653  for (unsigned int j = 0; j < lambda_values[i].size(); ++j)
654  {
655  lambda_values_uni[i][j] = 1.;
656  coeffs = solve_local_problem(lambda_values_uni, 0U, hyper_edge, time);
657  for (unsigned int k = 0; k < n_shape_fct_; ++k)
658  test_coeffs[k] = coeffs[hyEdge_dimT*n_shape_fct_+k];
659  bdr_values[i][j] = integrator::integrate_vol_phiphi
660  (u_coeffs.data(), test_coeffs.data(), hyper_edge.geometry);
661  lambda_values_uni[i][j] = 0.;
662  }
663 
664  return bdr_values;
665  }
666  template < class hyEdgeT >
667  std::array< std::array<lSol_float_t, n_shape_bdr_>, 2*hyEdge_dimT > total_numerical_flux_mass
668  (
669  const std::array< std::array<lSol_float_t, n_shape_bdr_>, 2*hyEdge_dimT > & lambda_values,
670  hyEdgeT & hyper_edge,
671  const lSol_float_t time = 0.
672  ) const
673  {
674  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
675 
676  std::array<lSol_float_t, n_loc_dofs_> coeffs
677  = solve_local_problem(lambda_values, 1U, hyper_edge, time);
678  std::array< std::array<lSol_float_t, n_shape_bdr_> , 2 * hyEdge_dimT > bdr_values;
679 
680  SmallVec<n_shape_fct_, lSol_float_t> u_coeffs, test_coeffs;
681  for (unsigned int i = 0; i < n_shape_fct_; ++i)
682  u_coeffs[i] = coeffs[hyEdge_dimT*n_shape_fct_+i];
683 
684  std::array< std::array<lSol_float_t, n_shape_bdr_>, 2*hyEdge_dimT > lambda_values_uni;
685  for (unsigned int i = 0; i < lambda_values.size(); ++i) lambda_values_uni[i].fill(0.);
686  for (unsigned int i = 0; i < lambda_values.size(); ++i)
687  if ( is_dirichlet<parameters>(hyper_edge.node_descriptor[i]) )
688  for (unsigned int j = 0; j < lambda_values[i].size(); ++j) bdr_values[i][j] = 0.;
689  else
690  for (unsigned int j = 0; j < lambda_values[i].size(); ++j)
691  {
692  lambda_values_uni[i][j] = 1.;
693  coeffs = solve_local_problem(lambda_values_uni, 0U, hyper_edge, time);
694  for (unsigned int k = 0; k < n_shape_fct_; ++k)
695  test_coeffs[k] = coeffs[hyEdge_dimT*n_shape_fct_+k];
696  bdr_values[i][j] = integrator::integrate_vol_phiphi
697  (u_coeffs.data(), test_coeffs.data(), hyper_edge.geometry);
698  lambda_values_uni[i][j] = 0.;
699  }
700 
701  return bdr_values;
702  }*/
703 
704  /*!***********************************************************************************************
705  * \brief Evaluate local contribution to mass matrix--vector multiplication.
706  *
707  * \note This function is not used for elliptic problems.
708  *
709  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
710  * \tparam SmallMatInT Data type of \c lambda_values_in.
711  * \tparam SmallMatOutT Data type of \c lambda_values_out.
712  * \param lambda_values_in Local part of vector x.
713  * \param lambda_values_out Local part that will be added to A * x-
714  * \param hyper_edge The geometry of the considered hyperedge (of typename hyEdgeT).
715  * \param time Time at which analytic functions are evaluated.
716  * \retval vecAx Local part of vector A * x.
717  ************************************************************************************************/
718  template <typename hyEdgeT, typename SmallMatInT, typename SmallMatOutT>
719  SmallMatOutT& trace_to_mass_flux(const SmallMatInT& lambda_values_in,
720  SmallMatOutT& lambda_values_out,
721  hyEdgeT& hyper_edge,
722  const lSol_float_t time = 0.) const
723  {
724  hy_assert(lambda_values_in.size() == lambda_values_out.size() &&
725  lambda_values_in.size() == 2 * hyEdge_dimT,
726  "Both matrices must be of same size which corresponds to the number of faces!");
727  for (unsigned int i = 0; i < lambda_values_in.size(); ++i)
728  hy_assert(
729  lambda_values_in[i].size() == lambda_values_out[i].size() &&
730  lambda_values_in[i].size() == n_glob_dofs_per_node(),
731  "Both matrices must be of same size which corresponds to the number of dofs per face!");
732 
733  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
735  solve_local_problem(lambda_values_in, 0U, hyper_edge, time);
736  coeffs = solve_mass_problem(coeffs, hyper_edge, time);
737 
739  primal_at_boundary(coeffs, hyper_edge)),
740  duals(dual_at_boundary(coeffs, hyper_edge));
741 
742  for (unsigned int i = 0; i < lambda_values_out.size(); ++i)
743  {
744  if (is_dirichlet<parameters>(hyper_edge.node_descriptor[i]))
745  for (unsigned int j = 0; j < lambda_values_out[i].size(); ++j)
746  lambda_values_out[i][j] = 0.;
747  else
748  for (unsigned int j = 0; j < lambda_values_out[i].size(); ++j)
749  lambda_values_out[i][j] = duals(i, j) + tau_ * primals(i, j);
750  }
751 
752  return lambda_values_out;
753  }
754  /*!***********************************************************************************************
755  * \brief Evaluate local contribution to mass matrix--vector residual.
756  *
757  * \note This function is not used for elliptic problems.
758  *
759  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
760  * \tparam SmallMatInT Data type of \c lambda_values_in.
761  * \tparam SmallMatOutT Data type of \¢ lambda_values_out
762  * \param lambda_values_in Local part of vector x.
763  * \param lambda_values_out Local part that will be added to A * x.
764  * \param hyper_edge The geometry of the considered hyperedge (of typename hyEdgeT).
765  * \param time Time.
766  * \retval vecAx Local part of mass matrix residual.
767  ************************************************************************************************/
768  template <typename hyEdgeT, typename SmallMatInT, typename SmallMatOutT>
769  SmallMatOutT& total_numerical_flux_mass(const SmallMatInT& lambda_values_in,
770  SmallMatOutT& lambda_values_out,
771  hyEdgeT& hyper_edge,
772  const lSol_float_t time = 0.) const
773  {
774  hy_assert(lambda_values_in.size() == lambda_values_out.size() &&
775  lambda_values_in.size() == 2 * hyEdge_dimT,
776  "Both matrices must be of same size which corresponds to the number of faces!");
777  for (unsigned int i = 0; i < lambda_values_in.size(); ++i)
778  hy_assert(
779  lambda_values_in[i].size() == lambda_values_out[i].size() &&
780  lambda_values_in[i].size() == n_glob_dofs_per_node(),
781  "Both matrices must be of same size which corresponds to the number of dofs per face!");
782 
783  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
785  solve_local_problem(lambda_values_in, 1U, hyper_edge, time);
786  coeffs = solve_mass_problem(coeffs, hyper_edge, time);
787 
789  primal_at_boundary(coeffs, hyper_edge)),
790  duals(dual_at_boundary(coeffs, hyper_edge));
791 
792  for (unsigned int i = 0; i < lambda_values_out.size(); ++i)
793  {
794  if (is_dirichlet<parameters>(hyper_edge.node_descriptor[i]))
795  for (unsigned int j = 0; j < lambda_values_out[i].size(); ++j)
796  lambda_values_out[i][j] = 0.;
797  else
798  for (unsigned int j = 0; j < lambda_values_out[i].size(); ++j)
799  lambda_values_out[i][j] = duals(i, j) + tau_ * primals(i, j);
800  }
801 
802  return lambda_values_out;
803  }
804  /*!***********************************************************************************************
805  * \brief Calculate squared local contribution of L2 error.
806  *
807  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
808  * \tparam SmallMatT Data type of \c lambda_values.
809  * \param lambda_values The values of the skeletal variable's coefficients.
810  * \param hy_edge The geometry of the considered hyperedge (of typename GeomT).
811  * \param time Time at which anaytic functions are evaluated.
812  * \retval vec_b Local part of vector b.
813  ************************************************************************************************/
814  template <typename hyEdgeT, typename SmallMatT>
815  std::array<lSol_float_t, 1U> errors(const SmallMatT& lambda_values,
816  hyEdgeT& hy_edge,
817  const lSol_float_t time = 0.) const
818  {
819  hy_assert(lambda_values.size() == 2 * hyEdge_dimT, "Matrix must have appropriate size!");
820  for (unsigned int i = 0; i < lambda_values.size(); ++i)
821  hy_assert(lambda_values[i].size() == n_glob_dofs_per_node(),
822  "Matrix must have appropriate size!");
823 
824  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
826  solve_local_problem(lambda_values, 1U, hy_edge, time);
827  std::array<lSol_float_t, n_shape_fct_> coeffs;
828  for (unsigned int i = 0; i < coeffs.size(); ++i)
829  coeffs[i] = coefficients[i + hyEdge_dimT * n_shape_fct_];
830 
831  return std::array<lSol_float_t, 1U>({integrator::template integrate_vol_diffsquare_discana<
832  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>, decltype(hyEdgeT::geometry),
833  parameters::analytic_result, Point<hyEdge_dimT, lSol_float_t> >(coeffs, hy_edge.geometry,
834  time)});
835  }
836  /*!***********************************************************************************************
837  * \brief Parabolic approximation version of local squared L2 error.
838  *
839  * \note This function is not used for elliptic problems.
840  *
841  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
842  * \tparam SmallMatT Data type of \c lambda_values.
843  * \param lambda_values_new Abscissas of the supporting points.
844  * \param lambda_values_old The values of the skeletal variable's coefficients.
845  * \param hy_edge The geometry of the considered hyperedge (of typename GeomT).
846  * \param delta_t Time step size.
847  * \param time Time.
848  * \retval vec_b Local part of vector b.
849  ************************************************************************************************/
850  template <typename hyEdgeT, typename SmallMatT>
851  lSol_float_t errors_temp(const SmallMatT& lambda_values_new,
852  const SmallMatT& lambda_values_old,
853  hyEdgeT& hy_edge,
854  const lSol_float_t delta_t,
855  const lSol_float_t time) const
856  {
857  hy_assert(lambda_values_new.size() == lambda_values_old.size() &&
858  lambda_values_new.size() == 2 * hyEdge_dimT,
859  "Both matrices must be of same size which corresponds to the number of faces!");
860  for (unsigned int i = 0; i < lambda_values_new.size(); ++i)
861  hy_assert(
862  lambda_values_new[i].size() == lambda_values_old[i].size() &&
863  lambda_values_new[i].size() == n_glob_dofs_per_node(),
864  "Both matrices must be of same size which corresponds to the number of dofs per face!");
865 
866  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
867 
869  solve_local_problem(lambda_values_new, 1U, hy_edge, time);
871  solve_local_problem(lambda_values_old, 1U, hy_edge, time - delta_t);
872  for (unsigned int i = 0; i < coeffs_old.size(); ++i)
873  coeffs_old[i] = (coeffs_old[i] - coeffs_new[i]) / delta_t;
874 
876  solve_loc_prob_cor(lambda_values_new, coeffs_old, hy_edge, delta_t, time);
877  std::array<lSol_float_t, n_shape_fct_> coeffs;
878  for (unsigned int i = 0; i < coeffs.size(); ++i)
879  coeffs[i] = coefficients[i + hyEdge_dimT * n_shape_fct_];
880  return integrator::template integrate_vol_diffsquare_discana<decltype(hyEdgeT::geometry),
881  parameters::analytic_result>(
882  coeffs, hy_edge.geometry, time);
883  }
884  /*!***********************************************************************************************
885  * \brief Evaluate local reconstruction at tensorial products of abscissas.
886  *
887  * \tparam absc_float_t Floating type for the abscissa values.
888  * \tparam abscissas_sizeT Size of the array of array of abscissas.
889  * \tparam input_array_t Type of input array.
890  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
891  * \param abscissas Abscissas of the supporting points.
892  * \param lambda_values The values of the skeletal variable's coefficients.
893  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
894  * \param time Time at which analytic functions are evaluated.
895  * \retval function_values Function values at quadrature points.
896  ************************************************************************************************/
897  template <typename abscissa_float_t,
898  std::size_t abscissas_sizeT,
899  class input_array_t,
900  class hyEdgeT>
901  std::array<std::array<lSol_float_t, Hypercube<hyEdge_dimT>::pow(abscissas_sizeT)>, system_dim>
902  bulk_values(const std::array<abscissa_float_t, abscissas_sizeT>& abscissas,
903  const input_array_t& lambda_values,
904  hyEdgeT& hyper_edge,
905  const lSol_float_t time = 0.) const;
906 }; // end of class Diffusion
907 
908 // -------------------------------------------------------------------------------------------------
910 // -------------------------------------------------------------------------------------------------
911 
912 // -------------------------------------------------------------------------------------------------
913 // -------------------------------------------------------------------------------------------------
914 //
915 // IMPLEMENTATION OF MEMBER FUNCTIONS OF Diffusion
916 //
917 // -------------------------------------------------------------------------------------------------
918 // -------------------------------------------------------------------------------------------------
919 
920 // -------------------------------------------------------------------------------------------------
921 // assemble_loc_matrix
922 // -------------------------------------------------------------------------------------------------
923 
924 template <unsigned int hyEdge_dimT,
925  unsigned int poly_deg,
926  unsigned int quad_deg,
927  template <unsigned int, typename>
928  typename parametersT,
929  typename lSol_float_t>
930 template <typename hyEdgeT>
931 inline SmallSquareMat<
933  lSol_float_t>
935  const lSol_float_t tau,
936  hyEdgeT& hyper_edge,
937  const lSol_float_t time) const
938 {
939  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
941  lSol_float_t vol_integral, face_integral, helper;
942  SmallVec<hyEdge_dimT, lSol_float_t> grad_int_vec, normal_int_vec;
943 
944  for (unsigned int i = 0; i < n_shape_fct_; ++i)
945  {
946  for (unsigned int j = 0; j < n_shape_fct_; ++j)
947  {
948  // Integral_element phi_i phi_j dx in diagonal blocks
949  vol_integral = integrator::template integrate_vol_phiphifunc<
950  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>, decltype(hyEdgeT::geometry),
951  parameters::inverse_diffusion_coeff, Point<hyEdge_dimT, lSol_float_t> >(
952  i, j, hyper_edge.geometry, time);
953  // Integral_element - nabla phi_i \vec phi_j dx
954  // = Integral_element - div \vec phi_i phi_j dx in right upper and left lower blocks
955  grad_int_vec =
956  integrator::template integrate_vol_nablaphiphi<SmallVec<hyEdge_dimT, lSol_float_t>,
957  decltype(hyEdgeT::geometry)>(
958  i, j, hyper_edge.geometry);
959 
960  face_integral = 0.;
961  normal_int_vec = 0.;
962  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
963  {
964  helper = integrator::template integrate_bdr_phiphi<decltype(hyEdgeT::geometry)>(
965  i, j, face, hyper_edge.geometry);
966  face_integral += helper;
967  normal_int_vec += helper * hyper_edge.geometry.local_normal(face);
968  }
969 
970  local_mat(hyEdge_dimT * n_shape_fct_ + i, hyEdge_dimT * n_shape_fct_ + j) +=
971  tau * face_integral;
972  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
973  {
974  local_mat(dim * n_shape_fct_ + i, dim * n_shape_fct_ + j) += vol_integral;
975  local_mat(hyEdge_dimT * n_shape_fct_ + i, dim * n_shape_fct_ + j) -= grad_int_vec[dim];
976  local_mat(dim * n_shape_fct_ + i, hyEdge_dimT * n_shape_fct_ + j) -= grad_int_vec[dim];
977  local_mat(hyEdge_dimT * n_shape_fct_ + i, dim * n_shape_fct_ + j) += normal_int_vec[dim];
978  }
979  }
980  }
981 
982  return local_mat;
983 } // end of Diffusion::assemble_loc_matrix
984 
985 // -------------------------------------------------------------------------------------------------
986 // assemble_rhs_from_lambda
987 // -------------------------------------------------------------------------------------------------
988 
989 template <unsigned int hyEdge_dimT,
990  unsigned int poly_deg,
991  unsigned int quad_deg,
992  template <unsigned int, typename>
993  typename parametersT,
994  typename lSol_float_t>
995 template <typename hyEdgeT, typename SmallMatT>
997  lSol_float_t>
999  const SmallMatT& lambda_values,
1000  hyEdgeT& hyper_edge) const
1001 {
1002  static_assert(std::is_same<typename SmallMatT::value_type::value_type, lSol_float_t>::value,
1003  "Lambda values should have same floating point arithmetics as local solver!");
1004  hy_assert(lambda_values.size() == 2 * hyEdge_dimT,
1005  "The size of the lambda values should be twice the dimension of a hyperedge.");
1006  for (unsigned int i = 0; i < 2 * hyEdge_dimT; ++i)
1007  hy_assert(lambda_values[i].size() == n_shape_bdr_,
1008  "The size of lambda should be the amount of ansatz functions at boundary.");
1009 
1010  SmallVec<n_loc_dofs_, lSol_float_t> right_hand_side;
1011  lSol_float_t integral;
1012 
1013  for (unsigned int i = 0; i < n_shape_fct_; ++i)
1014  for (unsigned int j = 0; j < n_shape_bdr_; ++j)
1015  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
1016  {
1017  integral = integrator::template integrate_bdr_phipsi<decltype(hyEdgeT::geometry)>(
1018  i, j, face, hyper_edge.geometry);
1019  right_hand_side[hyEdge_dimT * n_shape_fct_ + i] += tau_ * lambda_values[face][j] * integral;
1020  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
1021  right_hand_side[dim * n_shape_fct_ + i] -=
1022  hyper_edge.geometry.local_normal(face).operator[](dim) * lambda_values[face][j] *
1023  integral;
1024  }
1025 
1026  return right_hand_side;
1027 } // end of Diffusion::assemble_rhs_from_lambda
1028 
1029 // -------------------------------------------------------------------------------------------------
1030 // assemble_rhs_from_global_rhs
1031 // -------------------------------------------------------------------------------------------------
1032 
1033 template <unsigned int hyEdge_dimT,
1034  unsigned int poly_deg,
1035  unsigned int quad_deg,
1036  template <unsigned int, typename>
1037  typename parametersT,
1038  typename lSol_float_t>
1039 template <typename hyEdgeT>
1041  lSol_float_t>
1043  hyEdgeT& hyper_edge,
1044  const lSol_float_t time) const
1045 {
1046  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
1047  SmallVec<n_loc_dofs_, lSol_float_t> right_hand_side;
1048  lSol_float_t integral;
1049  for (unsigned int i = 0; i < n_shape_fct_; ++i)
1050  {
1051  right_hand_side[hyEdge_dimT * n_shape_fct_ + i] = integrator::template integrate_vol_phifunc<
1052  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>, decltype(hyEdgeT::geometry),
1053  parameters::right_hand_side, Point<hyEdge_dimT, lSol_float_t> >(i, hyper_edge.geometry, time);
1054  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
1055  {
1056  if (!is_dirichlet<parameters>(hyper_edge.node_descriptor[face]))
1057  continue;
1058  integral = integrator::template integrate_bdr_phifunc<
1059  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>, decltype(hyEdgeT::geometry),
1060  parameters::dirichlet_value, Point<hyEdge_dimT, lSol_float_t> >(i, face,
1061  hyper_edge.geometry, time);
1062  right_hand_side[hyEdge_dimT * n_shape_fct_ + i] += tau_ * integral;
1063  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
1064  right_hand_side[dim * n_shape_fct_ + i] -=
1065  hyper_edge.geometry.local_normal(face).operator[](dim) * integral;
1066  }
1067  }
1068 
1069  return right_hand_side;
1070 } // end of Diffusion::assemble_rhs_from_global_rhs
1071 
1072 // -------------------------------------------------------------------------------------------------
1073 // assemble_rhs_from_coeffs
1074 // -------------------------------------------------------------------------------------------------
1075 
1076 template <unsigned int hyEdge_dimT,
1077  unsigned int poly_deg,
1078  unsigned int quad_deg,
1079  template <unsigned int, typename>
1080  typename parametersT,
1081  typename lSol_float_t>
1082 template <typename hyEdgeT, typename SmallVecT>
1084  lSol_float_t>
1086  const SmallVecT& coeffs,
1087  hyEdgeT& hyper_edge) const
1088 {
1089  SmallVec<n_loc_dofs_, lSol_float_t> right_hand_side;
1090  for (unsigned int i = 0; i < n_shape_fct_; ++i)
1091  for (unsigned int j = 0; j < n_shape_fct_; ++j)
1092  right_hand_side[hyEdge_dimT * n_shape_fct_ + i] +=
1093  coeffs[hyEdge_dimT * n_shape_fct_ + j] *
1094  integrator::template integrate_vol_phiphi(i, j, hyper_edge.geometry);
1095 
1096  return right_hand_side;
1097 } // end of Diffusion::assemble_rhs_from_coeffs
1098 
1099 // -------------------------------------------------------------------------------------------------
1100 // primal_at_boundary
1101 // -------------------------------------------------------------------------------------------------
1102 
1103 template <unsigned int hyEdge_dimT,
1104  unsigned int poly_deg,
1105  unsigned int quad_deg,
1106  template <unsigned int, typename>
1107  typename parametersT,
1108  typename lSol_float_t>
1109 template <typename hyEdgeT>
1110 inline SmallMat<2 * hyEdge_dimT,
1112  lSol_float_t>
1115  hyEdgeT& hyper_edge) const
1116 {
1118 
1119  for (unsigned int i = 0; i < n_shape_fct_; ++i)
1120  for (unsigned int j = 0; j < n_shape_bdr_; ++j)
1121  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
1122  bdr_values(face, j) +=
1123  coeffs[hyEdge_dimT * n_shape_fct_ + i] *
1124  integrator::template integrate_bdr_phipsi<decltype(hyEdgeT::geometry)>(
1125  i, j, face, hyper_edge.geometry);
1126 
1127  return bdr_values;
1128 } // end of Diffusion::primal_at_boundary
1129 
1130 // -------------------------------------------------------------------------------------------------
1131 // dual_at_boundary
1132 // -------------------------------------------------------------------------------------------------
1133 
1134 template <unsigned int hyEdge_dimT,
1135  unsigned int poly_deg,
1136  unsigned int quad_deg,
1137  template <unsigned int, typename>
1138  typename parametersT,
1139  typename lSol_float_t>
1140 template <typename hyEdgeT>
1141 inline SmallMat<2 * hyEdge_dimT,
1143  lSol_float_t>
1146  hyEdgeT& hyper_edge) const
1147 {
1149  lSol_float_t integral;
1150 
1151  for (unsigned int i = 0; i < n_shape_fct_; ++i)
1152  for (unsigned int j = 0; j < n_shape_bdr_; ++j)
1153  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
1154  {
1155  integral = integrator::template integrate_bdr_phipsi<decltype(hyEdgeT::geometry)>(
1156  i, j, face, hyper_edge.geometry);
1157  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
1158  bdr_values(face, j) += hyper_edge.geometry.local_normal(face).operator[](dim) * integral *
1159  coeffs[dim * n_shape_fct_ + i];
1160  }
1161 
1162  return bdr_values;
1163 } // end of Diffusion::dual_at_boundary
1164 
1165 // -------------------------------------------------------------------------------------------------
1166 // bulk_values
1167 // -------------------------------------------------------------------------------------------------
1168 
1169 template <unsigned int hyEdge_dimT,
1170  unsigned int poly_deg,
1171  unsigned int quad_deg,
1172  template <unsigned int, typename>
1173  typename parametersT,
1174  typename lSol_float_t>
1175 template <typename abscissa_float_t,
1176  std::size_t abscissas_sizeT,
1177  class input_array_t,
1178  typename hyEdgeT>
1179 std::array<std::array<lSol_float_t, Hypercube<hyEdge_dimT>::pow(abscissas_sizeT)>,
1182  const std::array<abscissa_float_t, abscissas_sizeT>& abscissas,
1183  const input_array_t& lambda_values,
1184  hyEdgeT& hyper_edge,
1185  const lSol_float_t time) const
1186 {
1188  solve_local_problem(lambda_values, 1U, hyper_edge, time);
1190  SmallVec<static_cast<unsigned int>(abscissas_sizeT), abscissa_float_t> helper(abscissas);
1191 
1192  std::array<std::array<lSol_float_t, Hypercube<hyEdge_dimT>::pow(abscissas_sizeT)>,
1194  point_vals;
1195 
1196  for (unsigned int d = 0; d < system_dim; ++d)
1197  {
1198  for (unsigned int i = 0; i < coeffs.size(); ++i)
1199  coeffs[i] = coefficients[d * n_shape_fct_ + i];
1200  for (unsigned int pt = 0; pt < Hypercube<hyEdge_dimT>::pow(abscissas_sizeT); ++pt)
1201  point_vals[d][pt] = integrator::shape_fun_t::template lin_comb_fct_val<float>(
1202  coeffs, Hypercube<hyEdge_dimT>::template tensorial_pt<Point<hyEdge_dimT> >(pt, helper));
1203  }
1204 
1205  return point_vals;
1206 }
1207 // end of Diffusion::bulk_values
1208 
1209 // -------------------------------------------------------------------------------------------------
1211 // -------------------------------------------------------------------------------------------------
1212 
1213 } // namespace LocalSolver
LocalSolver::Diffusion::bulk_values
std::array< std::array< lSol_float_t, Hypercube< hyEdge_dimT >::pow(abscissas_sizeT)>, system_dim > bulk_values(const std::array< abscissa_float_t, abscissas_sizeT > &abscissas, const input_array_t &lambda_values, hyEdgeT &hyper_edge, const lSol_float_t time=0.) const
Evaluate local reconstruction at tensorial products of abscissas.
LocalSolver::Diffusion::assemble_rhs_from_global_rhs
SmallVec< n_loc_dofs_, lSol_float_t > assemble_rhs_from_global_rhs(hyEdgeT &hyper_edge, const lSol_float_t time) const
Assemble local right-hand for the local solver (from global right-hand side).
LocalSolver::Diffusion::system_dimension
static constexpr unsigned int system_dimension()
Dimension of of the solution evaluated with respect to a hyperedge.
Definition: diffusion_ldgh.hxx:187
LocalSolver::Diffusion::n_shape_fct_
static constexpr unsigned int n_shape_fct_
Number of local shape functions (with respect to all spatial dimensions).
Definition: diffusion_ldgh.hxx:201
shape_function.hxx
LocalSolver::Diffusion::n_glob_dofs_per_node
static constexpr unsigned int n_glob_dofs_per_node()
Evaluate amount of global degrees of freedom per hypernode.
Definition: diffusion_ldgh.hxx:180
LocalSolver::Diffusion::assemble_loc_matrix
SmallSquareMat< n_loc_dofs_, lSol_float_t > assemble_loc_matrix(const lSol_float_t tau, hyEdgeT &hyper_edge, const lSol_float_t time) const
Assemble local matrix for the local solver.
LocalSolver::Diffusion::assemble_rhs_from_coeffs
SmallVec< n_loc_dofs_, lSol_float_t > assemble_rhs_from_coeffs(const SmallVecT &coeffs, hyEdgeT &hyper_edge) const
Assemble local right-hand for the local solver (from volume function coefficients).
LocalSolver::Diffusion::node_system_dimension
static constexpr unsigned int node_system_dimension()
Dimension of of the solution evaluated with respect to a hypernode.
Definition: diffusion_ldgh.hxx:191
LocalSolver::Diffusion::dual_at_boundary
SmallMat< 2 *hyEdge_dimT, n_shape_bdr_, lSol_float_t > dual_at_boundary(const SmallVec< n_loc_dofs_, lSol_float_t > &coeffs, hyEdgeT &hyper_edge) const
Evaluate dual variable at boundary.
LocalSolver::Diffusion::errors_temp
lSol_float_t errors_temp(const SmallMatT &lambda_values_new, const SmallMatT &lambda_values_old, hyEdgeT &hy_edge, const lSol_float_t delta_t, const lSol_float_t time) const
Parabolic approximation version of local squared L2 error.
Definition: diffusion_ldgh.hxx:851
LocalSolver::Diffusion::make_initial
SmallMatT & make_initial(SmallMatT &lambda_values, hyEdgeT &hyper_edge, const lSol_float_t time=0.) const
Evaluate L2 projected lambda values at initial state.
Definition: diffusion_ldgh.hxx:603
Wrapper::LAPACKexception::what
const char * what() const
Definition: lapack.hxx:27
LocalSolver
A namespace for local solvers.
Definition: advection_parab_ldgh.hxx:11
tensorial.hxx
diffusion_uniform.geometry
geometry
Definition: diffusion_uniform.py:19
LocalSolver::Diffusion::error_def::initial_error
static error_t initial_error()
Define how initial error is generated.
Definition: diffusion_ldgh.hxx:138
LocalSolver::Diffusion::error_def
Define how errors are evaluated.
Definition: diffusion_ldgh.hxx:129
LocalSolver::Diffusion::error_def::sum_error
static error_t sum_error(error_t &summed_error, const error_t &new_error)
Define how local errors should be accumulated.
Definition: diffusion_ldgh.hxx:147
LocalSolver::Diffusion::hyEdge_dim
static constexpr unsigned int hyEdge_dim()
Dimension of hyper edge type that this object solves on.
Definition: diffusion_ldgh.hxx:171
LocalSolver::Diffusion::integrator
TPP::Quadrature::Tensorial< TPP::Quadrature::GaussLegendre< quad_deg >, TPP::ShapeFunction< TPP::ShapeType::Tensorial< TPP::ShapeType::Legendre< poly_deg >, hyEdge_dimT > >, lSol_float_t > integrator
An integrator helps to easily evaluate integrals (e.g. via quadrature).
Definition: diffusion_ldgh.hxx:247
LocalSolver::DiffusionParametersDefault::dirichlet_value
static param_float_t dirichlet_value(const Point< space_dimT, param_float_t > &, const param_float_t=0.)
Dirichlet values of solution as analytic function.
Definition: diffusion_ldgh.hxx:49
LocalSolver::DiffusionParametersDefault::neumann_value
static param_float_t neumann_value(const Point< space_dimT, param_float_t > &, const param_float_t=0.)
Neumann values of solution as analytic function.
Definition: diffusion_ldgh.hxx:57
LocalSolver::Diffusion::assemble_rhs_from_lambda
SmallVec< n_loc_dofs_, lSol_float_t > assemble_rhs_from_lambda(const SmallMatT &lambda_values, hyEdgeT &hyper_edge) const
Assemble local right-hand for the local solver (from skeletal).
TPP::Quadrature::GaussLegendre
Gauss–Legendre quadrature points and weights in one spatial dimension.
Definition: one_dimensional.hxx:19
SmallMat::size
static constexpr unsigned int size()
Return size a SmallMat.
Definition: dense_la.hxx:54
LocalSolver::Diffusion::node_element::functions
std::tuple< TPP::ShapeFunction< TPP::ShapeType::Tensorial< TPP::ShapeType::Legendre< poly_deg >, hyEdge_dimT - 1 > > > functions
Definition: diffusion_ldgh.hxx:124
LocalSolver::Diffusion::trace_to_mass_flux
SmallMatOutT & trace_to_mass_flux(const SmallMatInT &lambda_values_in, SmallMatOutT &lambda_values_out, hyEdgeT &hyper_edge, const lSol_float_t time=0.) const
Evaluate local contribution to mass matrix–vector multiplication.
Definition: diffusion_ldgh.hxx:719
TPP::ShapeType::Tensorial
Struct that handles the evaluation of tensorial shape functions.
Definition: tensorial.hxx:22
LocalSolver::Diffusion::is_dirichlet
static constexpr bool is_dirichlet(const unsigned int node_type)
Find out whether a node is of Dirichlet type.
Definition: diffusion_ldgh.hxx:226
LocalSolver::Diffusion::error_def::error_t
std::array< lSol_float_t, 1U > error_t
Define the typename returned by function errors.
Definition: diffusion_ldgh.hxx:134
LocalSolver::Diffusion::node_element
Define type of node elements, especially with respect to nodal shape functions.
Definition: diffusion_ldgh.hxx:120
LocalSolver::Diffusion::solve_mass_problem
SmallVec< n_loc_dofs_, lSol_float_t > solve_mass_problem(const SmallMatT &lambda_values, hyEdgeT &hyper_edge, const lSol_float_t time) const
Solve local problem for mass matrix approximation.
Definition: diffusion_ldgh.hxx:382
LocalSolver::Diffusion::Diffusion
Diffusion(const constructor_value_type &tau=1.)
Constructor for local solver.
Definition: diffusion_ldgh.hxx:471
LocalSolver::Diffusion
Local solver diffusion equation on hypergraph.
Definition: diffusion_ldgh.hxx:108
TPP::ShapeFunction
Struct that handles different types of evaluation of shape functions.
Definition: shape_function.hxx:15
LocalSolver::Diffusion::errors
std::array< lSol_float_t, 1U > errors(const SmallMatT &lambda_values, hyEdgeT &hy_edge, const lSol_float_t time=0.) const
Calculate squared local contribution of L2 error.
Definition: diffusion_ldgh.hxx:815
LocalSolver::DiffusionParametersDefault::analytic_result
static param_float_t analytic_result(const Point< space_dimT, param_float_t > &, const param_float_t=0.)
Analytic result of PDE (for convergence tests).
Definition: diffusion_ldgh.hxx:65
LocalSolver::Diffusion::solve_local_problem
SmallVec< n_loc_dofs_, lSol_float_t > solve_local_problem(const SmallMatT &lambda_values, const unsigned int solution_type, hyEdgeT &hyper_edge, const lSol_float_t time) const
Solve local problem (with right-hand side from skeletal).
Definition: diffusion_ldgh.hxx:345
TPP::Quadrature::Tensorial
General integrator class on tensorial hypergraphs.
Definition: tensorial.hxx:24
LocalSolver::Diffusion::total_numerical_flux_mass
SmallMatOutT & total_numerical_flux_mass(const SmallMatInT &lambda_values_in, SmallMatOutT &lambda_values_out, hyEdgeT &hyper_edge, const lSol_float_t time=0.) const
Evaluate local contribution to mass matrix–vector residual.
Definition: diffusion_ldgh.hxx:769
LocalSolver::DiffusionParametersDefault::right_hand_side
static param_float_t right_hand_side(const Point< space_dimT, param_float_t > &, const param_float_t=0.)
Right-hand side in PDE as analytic function.
Definition: diffusion_ldgh.hxx:41
LocalSolver::DiffusionParametersDefault::neumann_nodes
static constexpr std::array< unsigned int, 0U > neumann_nodes
Array containing hypernode types corresponding to Neumann boundary.
Definition: advection_parab_ldgh.hxx:29
LocalSolver::Diffusion::residual_flux
SmallMatOutT & residual_flux(const SmallMatInT &lambda_values_in, SmallMatOutT &lambda_values_out, hyEdgeT &hyper_edge, const lSol_float_t time=0.) const
Evaluate local contribution to residual .
Definition: diffusion_ldgh.hxx:554
LocalSolver::Diffusion::data_type
Define type of (hyperedge related) data that is stored in HyDataContainer.
Definition: diffusion_ldgh.hxx:114
LocalSolver::Diffusion::trace_to_flux
SmallMatOutT & trace_to_flux(const SmallMatInT &lambda_values_in, SmallMatOutT &lambda_values_out, hyEdgeT &hyper_edge, const lSol_float_t time=0.) const
Evaluate local contribution to matrix–vector multiplication.
Definition: diffusion_ldgh.hxx:490
hypercube.hxx
LocalSolver::Diffusion::tau_
const lSol_float_t tau_
(Globally constant) penalty parameter for HDG scheme.
Definition: diffusion_ldgh.hxx:239
LocalSolver::Diffusion::primal_at_boundary
SmallMat< 2 *hyEdge_dimT, n_shape_bdr_, lSol_float_t > primal_at_boundary(const SmallVec< n_loc_dofs_, lSol_float_t > &coeffs, hyEdgeT &hyper_edge) const
Evaluate primal variable at boundary.
Wrapper::LAPACKexception
Exception to be thrown if LAPACK's solve fails.
Definition: lapack.hxx:25
LocalSolver::DiffusionParametersDefault::dirichlet_nodes
static constexpr std::array< unsigned int, 0U > dirichlet_nodes
Array containing hypernode types corresponding to Dirichlet boundary.
Definition: advection_parab_ldgh.hxx:25
LocalSolver::Diffusion::n_shape_bdr_
static constexpr unsigned int n_shape_bdr_
Number oflocal shape functions (with respect to a face / hypernode).
Definition: diffusion_ldgh.hxx:205
Hypercube::pow
static constexpr unsigned int pow(unsigned int base)
Return n to the power dim.
Definition: hypercube.hxx:25
LocalSolver::Diffusion::node_types
std::array< unsigned int, 2 *hyEdge_dimT > node_types(hyEdgeT &hyper_edge) const
Fill an array with 1 if the node is Dirichlet and 0 otherwise.
Definition: diffusion_ldgh.hxx:528
LocalSolver::Diffusion::solve_loc_prob_cor
SmallVec< n_loc_dofs_, lSol_float_t > solve_loc_prob_cor(const SmallMatT &lambda_values, const SmallVecT &coeffs, hyEdgeT &hyper_edge, const lSol_float_t UNUSED(delta_time), const lSol_float_t time) const
Solve local problem for parabolic approximations.
Definition: diffusion_ldgh.hxx:404
parameters
the intent is to exercise the right to control the distribution of derivative or collective works based on the Library In mere aggregation of another work not based on the Library with the you must alter all the notices that refer to this so that they refer to the ordinary GNU General Public instead of to this it is irreversible for that so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy This option is useful when you wish to copy part of the code of the Library into a program that is not a library You may copy and distribute the which must be distributed under the terms of Sections and above on a medium customarily used for software interchange If distribution of object code is made by offering access to copy from a designated then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source even though third parties are not compelled to copy the source along with the object code A program that contains no derivative of any portion of the but is designed to work with the Library by being compiled or linked with is called a work that uses the Library Such a in is not a derivative work of the and therefore falls outside the scope of this License linking a work that uses the Library with the Library creates an executable that is a derivative of the rather than a work that uses the library The executable is therefore covered by this License Section states terms for distribution of such executables When a work that uses the Library uses material from a header file that is part of the the object code for the work may be a derivative work of the Library even though the source code is not Whether this is true is especially significant if the work can be linked without the or if the work is itself a library The threshold for this to be true is not precisely defined by law If such an object file uses only numerical parameters
Definition: License.txt:259
hy_assert
#define hy_assert(Expr, Msg)
The assertion to be used within HyperHDG — deactivate using -DNDEBUG compile flag.
Definition: hy_assert.hxx:38
dense_la.hxx
LocalSolver::DiffusionParametersDefault::inverse_diffusion_coeff
static param_float_t inverse_diffusion_coeff(const Point< space_dimT, param_float_t > &, const param_float_t=0.)
Inverse diffusion coefficient in PDE as analytic function.
Definition: diffusion_ldgh.hxx:33
LocalSolver::Diffusion::error_def::postprocess_error
static error_t postprocess_error(error_t &summed_error)
Define how global errors should be postprocessed.
Definition: diffusion_ldgh.hxx:156
LocalSolver::Diffusion::node_system_dim
static constexpr unsigned int node_system_dim
Dimension of of the solution evaluated with respect to a hypernode.
Definition: diffusion_ldgh.hxx:221
UNUSED
#define UNUSED(x)
Unused parametes will neither result in g++, nor in doxygen warnings if wrapped by this.
Definition: compile_time_tricks.hxx:10
LocalSolver::Diffusion::constructor_value_type
lSol_float_t constructor_value_type
Class is constructed using a single double indicating the penalty parameter.
Definition: diffusion_ldgh.hxx:465
LocalSolver::Diffusion::system_dim
static constexpr unsigned int system_dim
Dimension of of the solution evaluated with respect to a hypernode.
Definition: diffusion_ldgh.hxx:215
LocalSolver::Diffusion::n_loc_dofs_
static constexpr unsigned int n_loc_dofs_
Number of (local) degrees of freedom per hyperedge.
Definition: diffusion_ldgh.hxx:209
SmallMat
This class implements a small/dense matrix.
Definition: dense_la.hxx:34
Hypercube
Helper class containing numbers and functions related to hypercubes.
Definition: hypercube.hxx:12