HyperHDG
diffusion_parab_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 for parabolic diffusion equation on hypergraph.
74  *
75  * \note Theta must be one, since only implicit Euler has been implemented at the moment.
76  *
77  * This class contains the local solver for an isotropic diffusion equation, i.e.,
78  * \f[
79  * \partial_t u - \nabla \cdot ( d \nabla u ) = f \quad \text{ in } \Omega, \qquad
80  * u = u_\text D \quad \text{ on } \partial \Omega_\text D, \qquad
81  * - d \nabla u \cdot \nu = g_\text N \quad \text{ on } \partial \Omega_\text N
82  * \f]
83  * in a spatial domain \f$\Omega \subset \mathbb R^d\f$. Here, \f$d\f$ is the spatial dimension
84  * \c space_dim, \f$\Omega\f$ is a regular graph (\c hyEdge_dimT = 1) or hypergraph whose
85  * hyperedges are surfaces (\c hyEdge_dimT = 2) or volumes (\c hyEdge_dimT = 3) or hypervolumes (in
86  * case of \c hyEdge_dimT > 3). \f$f\f$ and \f$d\f$ are scalars defined in the whole domain, the
87  * Dirichlet and Neumann boundary data needs to be defined on their respective hypernodes.
88  *
89  * \tparam hyEdge_dimT Dimension of a hyperedge, i.e., 1 is for PDEs defined on graphs, 2 is for
90  * PDEs defined on surfaces, and 3 is for PDEs defined on volumes.
91  * \tparam poly_deg The polynomial degree of test and trial functions.
92  * \tparam quad_deg The order of the quadrature rule.
93  * \tparam parametersT Struct depending on templates \c space_dimTP and \c lSol_float_TP that
94  * contains static parameter functions.
95  * Defaults to above functions included in \c DiffusionParametersDefault.
96  * \tparam lSol_float_t The floating point type calculations are executed in. Defaults to double.
97  *
98  * \authors Guido Kanschat, Heidelberg University, 2019--2020.
99  * \authors Andreas Rupp, Heidelberg University, 2019--2020.
100  **************************************************************************************************/
101 template <unsigned int hyEdge_dimT,
102  unsigned int poly_deg,
103  unsigned int quad_deg,
104  template <unsigned int, typename> typename parametersT = DiffusionParametersDefault,
105  typename lSol_float_t = double>
107 {
108  public:
109  // -----------------------------------------------------------------------------------------------
110  // Public, static constexpr functions
111  // -----------------------------------------------------------------------------------------------
112 
113  /*!***********************************************************************************************
114  * \brief Dimension of hyper edge type that this object solves on.
115  ************************************************************************************************/
116  static constexpr unsigned int hyEdge_dim() { return hyEdge_dimT; }
117  /*!***********************************************************************************************
118  * \brief Evaluate amount of global degrees of freedom per hypernode.
119  *
120  * This number must be equal to HyperNodeFactory::n_dofs_per_node() of the HyperNodeFactory
121  * cooperating with this object.
122  *
123  * \retval n_dofs Number of global degrees of freedom per hypernode.
124  ************************************************************************************************/
125  static constexpr unsigned int n_glob_dofs_per_node()
126  {
127  return Hypercube<hyEdge_dimT - 1>::pow(poly_deg + 1);
128  }
129  /*!***********************************************************************************************
130  * \brief Dimension of of the solution evaluated with respect to a hyperedge.
131  ************************************************************************************************/
132  static constexpr unsigned int system_dimension() { return hyEdge_dimT + 1; }
133  /*!***********************************************************************************************
134  * \brief Dimension of of the solution evaluated with respect to a hypernode.
135  ************************************************************************************************/
136  static constexpr unsigned int node_system_dimension() { return 1; }
137 
138  private:
139  // -----------------------------------------------------------------------------------------------
140  // Private, static constexpr functions
141  // -----------------------------------------------------------------------------------------------
142 
143  /*!***********************************************************************************************
144  * \brief Number of local shape functions (with respect to all spatial dimensions).
145  ************************************************************************************************/
146  static constexpr unsigned int n_shape_fct_ = n_glob_dofs_per_node() * (poly_deg + 1);
147  /*!***********************************************************************************************
148  * \brief Number oflocal shape functions (with respect to a face / hypernode).
149  ************************************************************************************************/
150  static constexpr unsigned int n_shape_bdr_ = n_glob_dofs_per_node();
151  /*!***********************************************************************************************
152  * \brief Number of (local) degrees of freedom per hyperedge.
153  ************************************************************************************************/
154  static constexpr unsigned int n_loc_dofs_ = (hyEdge_dimT + 1) * n_shape_fct_;
155  /*!***********************************************************************************************
156  * \brief Dimension of of the solution evaluated with respect to a hypernode.
157  *
158  * This allows to the use of this quantity as template parameter in member functions.
159  ************************************************************************************************/
160  static constexpr unsigned int system_dim = system_dimension();
161  /*!***********************************************************************************************
162  * \brief Dimension of of the solution evaluated with respect to a hypernode.
163  *
164  * This allows to the use of this quantity as template parameter in member functions.
165  ************************************************************************************************/
166  static constexpr unsigned int node_system_dim = node_system_dimension();
167  /*!***********************************************************************************************
168  * \brief Find out whether a node is of Dirichlet type.
169  ************************************************************************************************/
170  template <typename parameters>
171  static constexpr bool is_dirichlet(const unsigned int node_type)
172  {
173  return std::find(parameters::dirichlet_nodes.begin(), parameters::dirichlet_nodes.end(),
174  node_type) != parameters::dirichlet_nodes.end();
175  }
176 
177  // -----------------------------------------------------------------------------------------------
178  // Private, const members: Parameters and auxiliaries that help assembling matrices, etc.
179  // -----------------------------------------------------------------------------------------------
180 
181  /*!***********************************************************************************************
182  * \brief (Globally constant) penalty parameter for HDG scheme.
183  ************************************************************************************************/
184  const lSol_float_t tau_;
185  /*!***********************************************************************************************
186  * \brief Parameter theta that defines the one-step theta scheme.
187  ************************************************************************************************/
188  const lSol_float_t theta_;
189  /*!***********************************************************************************************
190  * \brief Time step size.
191  ************************************************************************************************/
192  const lSol_float_t delta_t_;
193  /*!***********************************************************************************************
194  * \brief An integrator helps to easily evaluate integrals (e.g. via quadrature).
195  ************************************************************************************************/
199  lSol_float_t>
201 
202  // -----------------------------------------------------------------------------------------------
203  // Private, internal functions for the local solver
204  // -----------------------------------------------------------------------------------------------
205 
206  /*!***********************************************************************************************
207  * \brief Assemble local matrix for the local solver.
208  *
209  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
210  * \param tau Penalty parameter.
211  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
212  * \param time Time, when the local matrix is evaluated.
213  * \retval loc_mat Matrix of the local solver.
214  ************************************************************************************************/
215  template <typename hyEdgeT>
217  assemble_loc_matrix(const lSol_float_t tau, hyEdgeT& hyper_edge, const lSol_float_t time) const;
218  /*!***********************************************************************************************
219  * \brief Assemble local right-hand for the local solver (from skeletal).
220  *
221  * The right hand side needs the values of the global degrees of freedom. Note that we basically
222  * follow the lines of
223  *
224  * B. Cockburn, J. Gopalakrishnan, and R. Lazarov.
225  * Unified hybridization of discontinuous Galerkin, mixed, and continuous Galerkin methods for
226  * second order elliptic problems. SIAM Journal on Numerical Analysis, 47(2):1319–1365, 2009
227  *
228  * and discriminate between local solvers with respect to the skeletal variable and with respect
229  * to the global right-hand side. This assembles the local right-hand side with respect to the
230  * skeletal variable.
231  *
232  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
233  * \tparam SmallMatT The data type of the \¢ lambda_values.
234  * \param lambda_values Global degrees of freedom associated to the hyperedge.
235  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
236  * \retval loc_rhs Local right hand side of the locasl solver.
237  ************************************************************************************************/
238  template <typename hyEdgeT, typename SmallMatT>
240  const SmallMatT& lambda_values,
241  hyEdgeT& hyper_edge) const;
242  /*!***********************************************************************************************
243  * \brief Assemble local right-hand for the local solver (from global right-hand side).
244  *
245  * Note that we basically follow the lines of
246  *
247  * B. Cockburn, J. Gopalakrishnan, and R. Lazarov.
248  * Unified hybridization of discontinuous Galerkin, mixed, and continuous Galerkin methods for
249  * second order elliptic problems. SIAM Journal on Numerical Analysis, 47(2):1319–1365, 2009
250  *
251  * and discriminate between local solvers with respect to the skeletal variable and with respect
252  * to the global right-hand side. This assembles the local right-hand side with respect to the
253  * global right-hand side. This function implicitly uses the parameters.
254  *
255  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
256  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
257  * \param time Point of time, rhs is evaluated at
258  * \retval loc_rhs Local right hand side of the locasl solver.
259  ************************************************************************************************/
260  template <typename hyEdgeT>
262  hyEdgeT& hyper_edge,
263  const lSol_float_t time) const;
264  /*!***********************************************************************************************
265  * \brief Assemble local right-hand for the local solver (from function coefficients).
266  *
267  * Note that we basically follow the lines of
268  *
269  * B. Cockburn, J. Gopalakrishnan, and R. Lazarov.
270  * Unified hybridization of discontinuous Galerkin, mixed, and continuous Galerkin methods for
271  * second order elliptic problems. SIAM Journal on Numerical Analysis, 47(2):1319–1365, 2009
272  *
273  * and discriminate between local solvers with respect to the skeletal variable and with respect
274  * to the global right-hand side. This assembles the local right-hand side with respect to the
275  * global right-hand side. This function implicitly uses the parameters.
276  *
277  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
278  * \param coeffs Local coefficients of bulk variable u.
279  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
280  * \retval loc_rhs Local right hand side of the locasl solver.
281  ************************************************************************************************/
282  template <typename hyEdgeT>
284  const std::array<lSol_float_t, n_loc_dofs_>& coeffs,
285  hyEdgeT& hyper_edge) const;
286  /*!***********************************************************************************************
287  * \brief Solve local problem (with right-hand side from skeletal).
288  *
289  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
290  * \tparam SmallMatT The data type of the \c lambda_values.
291  * \param lambda_values Global degrees of freedom associated to the hyperedge.
292  * \param solution_type Type of local problem that is to be solved.
293  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
294  * \param time Point of time the problem is solved.
295  * \retval loc_sol Solution of the local problem.
296  ************************************************************************************************/
297  template <typename hyEdgeT, typename SmallMatT>
298  inline std::array<lSol_float_t, n_loc_dofs_> solve_local_problem(const SmallMatT& lambda_values,
299  const unsigned int solution_type,
300  hyEdgeT& hyper_edge,
301  const lSol_float_t time) const
302  {
303  try
304  {
306  if (solution_type == 0)
307  rhs = assemble_rhs_from_lambda(lambda_values, hyper_edge);
308  else if (solution_type == 1)
309  rhs = assemble_rhs_from_lambda(lambda_values, hyper_edge) +
310  assemble_rhs_from_global_rhs(hyper_edge, time);
311  else
312  hy_assert(0 == 1, "This has not been implemented!");
313  return (rhs / assemble_loc_matrix(tau_, hyper_edge, time)).data();
314  }
315  catch (Wrapper::LAPACKexception& exc)
316  {
317  hy_assert(0 == 1, exc.what() << std::endl
318  << "This can happen if quadrature is too inaccurate!");
319  throw exc;
320  }
321  }
322  /*!***********************************************************************************************
323  * \brief Evaluate primal variable at boundary.
324  *
325  * Function to evaluate primal variable of the solution. This function is needed to calculate
326  * the local numerical fluxes.
327  *
328  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
329  * \param coeffs Coefficients of the local solution.
330  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
331  * \retval bdr_coeffs Coefficients of respective (dim-1) dimensional function at boundaries.
332  ************************************************************************************************/
333  template <typename hyEdgeT>
334  inline std::array<std::array<lSol_float_t, n_shape_bdr_>, 2 * hyEdge_dimT> primal_at_boundary(
335  const std::array<lSol_float_t, n_loc_dofs_>& coeffs,
336  hyEdgeT& hyper_edge) const;
337  /*!***********************************************************************************************
338  * \brief Evaluate dual variable at boundary.
339  *
340  * Function to evaluate dual variable of the solution. This function is needed to calculate the
341  * local numerical fluxes.
342  *
343  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
344  * \param coeffs Coefficients of the local solution.
345  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
346  * \retval bdr_coeffs Coefficients of respective (dim-1) dimensional function at boundaries.
347  ************************************************************************************************/
348  template <typename hyEdgeT>
349  inline std::array<std::array<lSol_float_t, n_shape_bdr_>, 2 * hyEdge_dimT> dual_at_boundary(
350  const std::array<lSol_float_t, (hyEdge_dimT + 1) * n_shape_fct_>& coeffs,
351  hyEdgeT& hyper_edge) const;
352 
353  public:
354  // -----------------------------------------------------------------------------------------------
355  // Public functions (and one typedef) to be utilized by external functions.
356  // -----------------------------------------------------------------------------------------------
357 
358  /*!***********************************************************************************************
359  * \brief Define type of (hyperedge related) data that is stored in HyDataContainer.
360  ************************************************************************************************/
361  struct data_type
362  {
365  };
366  /*!***********************************************************************************************
367  * \brief Define type of node elements, especially with respect to nodal shape functions.
368  ************************************************************************************************/
370  {
371  typedef std::tuple<TPP::ShapeFunction<
374  };
375  /*!***********************************************************************************************
376  * \brief Define how errors are evaluated.
377  ************************************************************************************************/
378  struct error_def
379  {
380  /*!*********************************************************************************************
381  * \brief Define the typename returned by function errors.
382  **********************************************************************************************/
383  typedef std::array<lSol_float_t, 1U> error_t;
384  /*!*********************************************************************************************
385  * \brief Define how initial error is generated.
386  **********************************************************************************************/
388  {
389  std::array<lSol_float_t, 1U> summed_error;
390  summed_error.fill(0.);
391  return summed_error;
392  }
393  /*!*********************************************************************************************
394  * \brief Define how local errors should be accumulated.
395  **********************************************************************************************/
396  static error_t sum_error(error_t& summed_error, const error_t& new_error)
397  {
398  for (unsigned int k = 0; k < summed_error.size(); ++k)
399  summed_error[k] += new_error[k];
400  return summed_error;
401  }
402  /*!*********************************************************************************************
403  * \brief Define how global errors should be postprocessed.
404  **********************************************************************************************/
405  static error_t postprocess_error(error_t& summed_error)
406  {
407  for (unsigned int k = 0; k < summed_error.size(); ++k)
408  summed_error[k] = std::sqrt(summed_error[k]);
409  return summed_error;
410  }
411  };
412  /*!***********************************************************************************************
413  * \brief Class is constructed using a single double indicating the penalty parameter.
414  ************************************************************************************************/
415  typedef std::vector<lSol_float_t> constructor_value_type;
416  /*!***********************************************************************************************
417  * \brief Constructor for local solver.
418  *
419  * \param constru Constructor object.
420  ************************************************************************************************/
421  DiffusionParab(const constructor_value_type& constru = std::vector(3, 1.))
422  : tau_(constru[0]), theta_(constru[1]), delta_t_(constru[2])
423  {
424  }
425  /*!***********************************************************************************************
426  * \brief Evaluate local contribution to matrix--vector multiplication.
427  *
428  * Execute matrix--vector multiplication y = A * x, where x represents the vector containing the
429  * skeletal variable (adjacent to one hyperedge), and A is the condensed matrix arising from the
430  * HDG discretization. This function does this multiplication (locally) for one hyperedge. The
431  * hyperedge is no parameter, since all hyperedges are assumed to have the same properties.
432  *
433  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
434  * \tparam SmallMatInT Data type of \c lambda_values_in.
435  * \tparam SmallMatOutT Data type of \c lambda_values_out
436  * \param lambda_values_in Local part of vector x.
437  * \param lambda_values_out Local part that will be added to A * x.
438  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
439  * \param time Time at which time step ends.
440  * \retval vecAx Local part of vector A * x.
441  ************************************************************************************************/
442  template <typename hyEdgeT, typename SmallMatInT, typename SmallMatOutT>
443  SmallMatOutT& trace_to_flux(const SmallMatInT& lambda_values_in,
444  SmallMatOutT& lambda_values_out,
445  hyEdgeT& hyper_edge,
446  const lSol_float_t time = 0.) const
447  {
448  hy_assert(lambda_values_in.size() == lambda_values_out.size() &&
449  lambda_values_in.size() == 2 * hyEdge_dimT,
450  "Both matrices must be of same size which corresponds to the number of faces!");
451  for (unsigned int i = 0; i < lambda_values_in.size(); ++i)
452  hy_assert(
453  lambda_values_in[i].size() == lambda_values_out[i].size() &&
454  lambda_values_in[i].size() == n_glob_dofs_per_node(),
455  "Both matrices must be of same size which corresponds to the number of dofs per face!");
456 
457  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
458  std::array<lSol_float_t, n_loc_dofs_> coeffs =
459  solve_local_problem(lambda_values_in, 0U, hyper_edge, time);
460 
461  std::array<std::array<lSol_float_t, n_shape_bdr_>, 2 * hyEdge_dimT> primals(
462  primal_at_boundary(coeffs, hyper_edge)),
463  duals(dual_at_boundary(coeffs, hyper_edge));
464 
465  for (unsigned int i = 0; i < lambda_values_out.size(); ++i)
466  if (is_dirichlet<parameters>(hyper_edge.node_descriptor[i]))
467  for (unsigned int j = 0; j < lambda_values_out[i].size(); ++j)
468  lambda_values_out[i][j] = 0.;
469  else
470  for (unsigned int j = 0; j < lambda_values_out[i].size(); ++j)
471  {
472  lambda_values_out[i][j] =
473  duals[i][j] + tau_ * primals[i][j] -
474  tau_ * lambda_values_in[i][j] * hyper_edge.geometry.face_area(i);
475  lambda_values_out[i][j] *= theta_;
476  }
477 
478  return lambda_values_out;
479  }
480  /*!***********************************************************************************************
481  * \brief Evaluate local contribution to residual.
482  *
483  * Execute residual evaluation y = A * x - b, where x represents the vector containing the
484  * skeletal variable (adjacent to one hyperedge), and A is the condensed matrix arising from the
485  * HDG discretization. This function does this multiplication (locally) for one hyperedge. The
486  * hyperedge is no parameter, since all hyperedges are assumed to have the same properties.
487  *
488  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
489  * \tparam SmallMatInT Data type of \c lambda_values_in.
490  * \tparam SmallMatOutT Data type of \c lambda_values_out.
491  * \param lambda_values_in Local part of vector x.
492  * \param lambda_values_out Local part that will be added to A * x.
493  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
494  * \param time Time at which time step ends.
495  * \retval vecAx Local part of vector A * x.
496  ************************************************************************************************/
497  template <typename hyEdgeT, typename SmallMatInT, typename SmallMatOutT>
498  SmallMatOutT& residual_flux(const SmallMatInT& lambda_values_in,
499  SmallMatOutT& lambda_values_out,
500  hyEdgeT& hyper_edge,
501  const lSol_float_t time = 0.) const
502  {
503  hy_assert(lambda_values_in.size() == lambda_values_out.size() &&
504  lambda_values_in.size() == 2 * hyEdge_dimT,
505  "Both matrices must be of same size which corresponds to the number of faces!");
506  for (unsigned int i = 0; i < lambda_values_in.size(); ++i)
507  hy_assert(
508  lambda_values_in[i].size() == lambda_values_out[i].size() &&
509  lambda_values_in[i].size() == n_glob_dofs_per_node(),
510  "Both matrices must be of same size which corresponds to the number of dofs per face!");
511 
512  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
513  std::array<lSol_float_t, n_loc_dofs_> coeffs =
514  solve_local_problem(lambda_values_in, 1U, hyper_edge, time);
515 
516  std::array<std::array<lSol_float_t, n_shape_bdr_>, 2 * hyEdge_dimT> primals(
517  primal_at_boundary(coeffs, hyper_edge)),
518  duals(dual_at_boundary(coeffs, hyper_edge));
519 
520  for (unsigned int i = 0; i < lambda_values_out.size(); ++i)
521  {
522  if (is_dirichlet<parameters>(hyper_edge.node_descriptor[i]))
523  for (unsigned int j = 0; j < lambda_values_out[i].size(); ++j)
524  lambda_values_out[i][j] = 0.;
525  else
526  for (unsigned int j = 0; j < lambda_values_out[i].size(); ++j)
527  {
528  lambda_values_out[i][j] =
529  duals[i][j] + tau_ * primals[i][j] -
530  tau_ * lambda_values_in[i][j] * hyper_edge.geometry.face_area(i);
531  lambda_values_out[i][j] *= theta_;
532  lambda_values_out[i][j] += (1. - theta_) * hyper_edge.data.boundary_flux_old(j, i);
533  }
534  }
535 
536  return lambda_values_out;
537  }
538  /*!***********************************************************************************************
539  * \brief Set data into data container to be used for next time step.
540  *
541  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
542  * \param lambda_values Local part of vector x.
543  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
544  * \param time Time at which the old time step ended.
545  ************************************************************************************************/
546  template <class hyEdgeT>
547  void set_data(
548  const std::array<std::array<lSol_float_t, n_shape_bdr_>, 2 * hyEdge_dimT>& lambda_values,
549  hyEdgeT& hyper_edge,
550  const lSol_float_t time = 0.) const
551  {
552  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
553 
554  std::array<lSol_float_t, n_loc_dofs_> coeffs =
555  solve_local_problem(lambda_values, 1U, hyper_edge, time);
556 
557  for (unsigned int i = 0; i < n_shape_fct_; ++i)
558  hyper_edge.data.u_old[i] = coeffs[hyEdge_dimT * n_shape_fct_ + i];
559 
560  std::array<SmallVec<n_shape_fct_, lSol_float_t>, hyEdge_dimT> q_components;
561  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
562  for (unsigned int i = 0; i < n_shape_fct_; ++i)
563  q_components[dim][i] = coeffs[dim * n_shape_fct_ + i];
564 
565  // Fill flux_old!
566  lSol_float_t helper;
568  for (unsigned int i = 0; i < n_shape_fct_; ++i)
569  {
570  hyper_edge.data.flux_old[i] = integrator::template integrate_vol_phifunc<
571  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>, decltype(hyEdgeT::geometry),
572  parameters::right_hand_side>(i, hyper_edge.geometry, time);
573  for (unsigned int j = 0; j < n_shape_fct_; ++j)
574  {
575  grad_int_vec =
576  integrator::template integrate_vol_nablaphiphi<Point<hyEdge_dimT, lSol_float_t>,
577  decltype(hyEdgeT::geometry)>(
578  i, j, hyper_edge.geometry);
579  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
580  hyper_edge.data.flux_old[i] += q_components[dim][j] * grad_int_vec[dim];
581  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
582  {
583  helper = integrator::template integrate_bdr_phiphi<decltype(hyEdgeT::geometry)>(
584  i, j, face, hyper_edge.geometry);
585  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
586  hyper_edge.data.flux_old[i] -= q_components[dim][j] *
587  hyper_edge.geometry.local_normal(face).operator[](dim) *
588  helper;
589  hyper_edge.data.flux_old[i] -= tau_ * hyper_edge.data.u_old[j] * helper;
590  }
591  }
592  for (unsigned int j = 0; j < n_shape_bdr_; ++j)
593  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
594  hyper_edge.data.flux_old[i] +=
595  tau_ * lambda_values[face][j] *
596  integrator::template integrate_bdr_phipsi<decltype(hyEdgeT::geometry)>(
597  i, j, face, hyper_edge.geometry);
598  }
599 
600  std::array<std::array<lSol_float_t, n_shape_bdr_>, 2 * hyEdge_dimT> primals(
601  primal_at_boundary(coeffs, hyper_edge)),
602  duals(dual_at_boundary(coeffs, hyper_edge));
603 
604  for (unsigned int i = 0; i < lambda_values.size(); ++i)
605  {
606  if (is_dirichlet<parameters>(hyper_edge.node_descriptor[i]))
607  for (unsigned int j = 0; j < lambda_values[i].size(); ++j)
608  hyper_edge.data.boundary_flux_old(j, i) = 0.;
609  else
610  for (unsigned int j = 0; j < lambda_values[i].size(); ++j)
611  hyper_edge.data.boundary_flux_old(j, i) =
612  duals[i][j] + tau_ * primals[i][j] -
613  tau_ * lambda_values[i][j] * hyper_edge.geometry.face_area(i);
614  }
615  }
616  /*!***********************************************************************************************
617  * \brief L2 project initial data to skeletal and fill data container.
618  *
619  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
620  * \tparam SmallMatT The data tyepe of \c lambda_values.
621  * \param lambda_values Local part of vector x.
622  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
623  * \param time Initial time of parabolic problem.
624  * \retval vecAx L2 projected initial datum.
625  ************************************************************************************************/
626  template <class hyEdgeT, typename SmallMatT>
627  SmallMatT& make_initial(SmallMatT& lambda_values,
628  hyEdgeT& hyper_edge,
629  const lSol_float_t time = 0.) const
630  {
631  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
632 
633  // Set skeltal variable!
634  for (unsigned int i = 0; i < lambda_values.size(); ++i)
635  {
636  if (is_dirichlet<parameters>(hyper_edge.node_descriptor[i]))
637  for (unsigned int j = 0; j < lambda_values[i].size(); ++j)
638  lambda_values[i][j] = 0.;
639  else
640  for (unsigned int j = 0; j < lambda_values[i].size(); ++j)
641  lambda_values[i][j] = integrator::template integrate_bdrUni_psifunc<
642  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>,
643  decltype(hyEdgeT::geometry), parameters::initial>(j, i, hyper_edge.geometry, time);
644  }
645 
646  // Define primary as L^2 projection!
647  for (unsigned int i = 0; i < n_shape_fct_; ++i)
648  hyper_edge.data.u_old[i] = integrator::template integrate_volUni_phifunc<
649  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>, decltype(hyEdgeT::geometry),
650  parameters::initial>(i, hyper_edge.geometry, time);
651 
652  // Define dual as H^{1/2} projection!
654  for (unsigned int i = 0; i < n_shape_fct_; ++i)
655  for (unsigned int j = 0; j < n_shape_fct_; ++j)
656  mass_flux(i, j) = integrator::template integrate_vol_phiphifunc<
657  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>,
658  decltype(hyEdgeT::geometry), parameters::inverse_diffusion_coeff>(
659  i, j, hyper_edge.geometry, time);
660  const SmallSquareMat<n_shape_fct_, lSol_float_t>& mass_mat = mass_flux;
661 
662  std::array<SmallVec<n_shape_fct_, lSol_float_t>, hyEdge_dimT> q_components;
664 
665  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
666  {
667  for (unsigned int i = 0; i < n_shape_fct_; ++i)
668  {
669  local_rhs[i] = integrator::template integrate_vol_derphifunc<
670  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>,
671  decltype(hyEdgeT::geometry), parameters::initial, Point<hyEdge_dimT, lSol_float_t> >(
672  i, dim, hyper_edge.geometry, time);
673  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
674  local_rhs[i] -=
675  integrator::template integrate_bdr_phifunc<
676  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>,
677  decltype(hyEdgeT::geometry), parameters::initial, Point<hyEdge_dimT, lSol_float_t> >(
678  i, face, hyper_edge.geometry, time) *
679  hyper_edge.geometry.local_normal(face).operator[](dim);
680  }
681  q_components[dim] = local_rhs / mass_mat;
682  }
683 
684  // Fill flux_old!
685  lSol_float_t helper;
687  for (unsigned int i = 0; i < n_shape_fct_; ++i)
688  {
689  hyper_edge.data.flux_old[i] = integrator::template integrate_vol_phifunc<
690  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>, decltype(hyEdgeT::geometry),
691  parameters::right_hand_side, Point<hyEdge_dimT, lSol_float_t> >(i, hyper_edge.geometry,
692  time);
693  for (unsigned int j = 0; j < n_shape_fct_; ++j)
694  {
695  grad_int_vec =
696  integrator::template integrate_vol_nablaphiphi<Point<hyEdge_dimT, lSol_float_t>,
697  decltype(hyEdgeT::geometry)>(
698  i, j, hyper_edge.geometry);
699  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
700  hyper_edge.data.flux_old[i] += q_components[dim][j] * grad_int_vec[dim];
701  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
702  {
703  helper = integrator::template integrate_bdr_phiphi<decltype(hyEdgeT::geometry)>(
704  i, j, face, hyper_edge.geometry);
705  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
706  hyper_edge.data.flux_old[i] -= q_components[dim][j] *
707  hyper_edge.geometry.local_normal(face).operator[](dim) *
708  helper;
709  hyper_edge.data.flux_old[i] -= tau_ * hyper_edge.data.u_old[j] * helper;
710  }
711  }
712  for (unsigned int j = 0; j < n_shape_bdr_; ++j)
713  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
714  hyper_edge.data.flux_old[i] +=
715  tau_ * lambda_values[face][j] *
716  integrator::template integrate_bdr_phipsi<decltype(hyEdgeT::geometry)>(
717  i, j, face, hyper_edge.geometry);
718  }
719 
720  std::array<lSol_float_t, n_loc_dofs_> coeffs;
721  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
722  for (unsigned int i = 0; i < n_shape_fct_; ++i)
723  coeffs[dim * n_shape_fct_ + i] = q_components[dim][i];
724  for (unsigned int i = 0; i < n_shape_fct_; ++i)
725  coeffs[hyEdge_dimT * n_shape_fct_ + i] = hyper_edge.data.u_old[i];
726  std::array<std::array<lSol_float_t, n_shape_bdr_>, 2 * hyEdge_dimT> primals(
727  primal_at_boundary(coeffs, hyper_edge)),
728  duals(dual_at_boundary(coeffs, hyper_edge));
729 
730  for (unsigned int i = 0; i < lambda_values.size(); ++i)
731  {
732  if (is_dirichlet<parameters>(hyper_edge.node_descriptor[i]))
733  for (unsigned int j = 0; j < lambda_values[i].size(); ++j)
734  hyper_edge.data.boundary_flux_old(j, i) = 0.;
735  else
736  for (unsigned int j = 0; j < lambda_values[i].size(); ++j)
737  hyper_edge.data.boundary_flux_old(j, i) =
738  duals[i][j] + tau_ * primals[i][j] -
739  tau_ * lambda_values[i][j] * hyper_edge.geometry.face_area(i);
740  }
741 
742  return lambda_values;
743  }
744  /*!***********************************************************************************************
745  * \brief Evaluate squared local L2 error.
746  *
747  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
748  * \param lambda_values The values of the skeletal variable's coefficients.
749  * \param hy_edge The geometry of the considered hyperedge (of typename GeomT).
750  * \param time Time at which error is evaluated.
751  * \retval err Local squared L2 error.
752  ************************************************************************************************/
753  template <class hyEdgeT>
754  std::array<lSol_float_t, 1U> errors(const std::array<std::array<lSol_float_t, n_shape_bdr_>,
755  2 * hyEdge_dimT>& UNUSED(lambda_values),
756  hyEdgeT& hy_edge,
757  const lSol_float_t time = 0.) const
758  {
759  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
760 
761  return std::array<lSol_float_t, 1U>({integrator::template integrate_vol_diffsquare_discana<
762  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>, decltype(hyEdgeT::geometry),
763  parameters::analytic_result, Point<hyEdge_dimT, lSol_float_t> >(hy_edge.data.u_old.data(),
764  hy_edge.geometry, time)});
765  }
766  /*!***********************************************************************************************
767  * \brief Evaluate local local reconstruction at tensorial products of abscissas.
768  *
769  * \tparam abscissa_float_t Floating type for the abscissa values.
770  * \tparam abscissas_sizeT Size of the array of array of abscissas.
771  * \tparam input_array_t Input array type.
772  * \tparam hyEdgeT The geometry type / typename of the considered hyEdge's geometry.
773  * \param abscissas Abscissas of the supporting points.
774  * \param lambda_values The values of the skeletal variable's coefficients.
775  * \param hyper_edge The geometry of the considered hyperedge (of typename GeomT).
776  * \param time Time at which function is plotted.
777  * \retval func_vals Array of function values.
778  ************************************************************************************************/
779  template <typename abscissa_float_t,
780  std::size_t abscissas_sizeT,
781  class input_array_t,
782  class hyEdgeT>
783  std::array<std::array<lSol_float_t, Hypercube<hyEdge_dimT>::pow(abscissas_sizeT)>, system_dim>
784  bulk_values(const std::array<abscissa_float_t, abscissas_sizeT>& abscissas,
785  const input_array_t& lambda_values,
786  hyEdgeT& hyper_edge,
787  const lSol_float_t time = 0.) const;
788 
789 }; // namespace LocalSolver
790 
791 // -------------------------------------------------------------------------------------------------
793 // -------------------------------------------------------------------------------------------------
794 
795 // -------------------------------------------------------------------------------------------------
796 // -------------------------------------------------------------------------------------------------
797 //
798 // IMPLEMENTATION OF MEMBER FUNCTIONS OF DiffusionParab
799 //
800 // -------------------------------------------------------------------------------------------------
801 // -------------------------------------------------------------------------------------------------
802 
803 // -------------------------------------------------------------------------------------------------
804 // assemble_loc_matrix
805 // -------------------------------------------------------------------------------------------------
806 
807 template <unsigned int hyEdge_dimT,
808  unsigned int poly_deg,
809  unsigned int quad_deg,
810  template <unsigned int, typename>
811  typename parametersT,
812  typename lSol_float_t>
813 template <typename hyEdgeT>
814 inline SmallSquareMat<
816  lSol_float_t>
818  const lSol_float_t tau,
819  hyEdgeT& hyper_edge,
820  const lSol_float_t time) const
821 {
822  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
824  lSol_float_t vol_integral, face_integral, helper;
825  SmallVec<hyEdge_dimT, lSol_float_t> grad_int_vec, normal_int_vec;
826 
827  for (unsigned int i = 0; i < n_shape_fct_; ++i)
828  {
829  for (unsigned int j = 0; j < n_shape_fct_; ++j)
830  {
831  // Integral_element phi_i phi_j dx in diagonal blocks
832  vol_integral = integrator::template integrate_vol_phiphifunc<
833  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>, decltype(hyEdgeT::geometry),
834  parameters::inverse_diffusion_coeff, Point<hyEdge_dimT, lSol_float_t> >(
835  i, j, hyper_edge.geometry, time);
836  // Integral_element - nabla phi_i \vec phi_j dx
837  // = Integral_element - div \vec phi_i phi_j dx in right upper and left lower blocks
838  grad_int_vec =
839  integrator::template integrate_vol_nablaphiphi<SmallVec<hyEdge_dimT, lSol_float_t>,
840  decltype(hyEdgeT::geometry)>(
841  i, j, hyper_edge.geometry);
842 
843  face_integral = 0.;
844  normal_int_vec = 0.;
845  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
846  {
847  helper = integrator::template integrate_bdr_phiphi<decltype(hyEdgeT::geometry)>(
848  i, j, face, hyper_edge.geometry);
849  face_integral += helper;
850  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
851  normal_int_vec[dim] += hyper_edge.geometry.local_normal(face).operator[](dim) * helper;
852  }
853 
854  local_mat(hyEdge_dimT * n_shape_fct_ + i, hyEdge_dimT * n_shape_fct_ + j) +=
855  tau * theta_ * delta_t_ * face_integral;
856  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
857  {
858  local_mat(dim * n_shape_fct_ + i, dim * n_shape_fct_ + j) += vol_integral;
859  local_mat(dim * n_shape_fct_ + i, hyEdge_dimT * n_shape_fct_ + j) -= grad_int_vec[dim];
860  local_mat(hyEdge_dimT * n_shape_fct_ + i, dim * n_shape_fct_ + j) -=
861  theta_ * delta_t_ * grad_int_vec[dim];
862  local_mat(hyEdge_dimT * n_shape_fct_ + i, dim * n_shape_fct_ + j) +=
863  theta_ * delta_t_ * normal_int_vec[dim];
864  }
865 
866  local_mat(hyEdge_dimT * n_shape_fct_ + i, hyEdge_dimT * n_shape_fct_ + j) +=
867  integrator::template integrate_vol_phiphi<decltype(hyEdgeT::geometry)>(i, j,
868  hyper_edge.geometry);
869  }
870  }
871 
872  return local_mat;
873 } // end of DiffusionParab::assemble_loc_matrix
874 
875 // -------------------------------------------------------------------------------------------------
876 // assemble_rhs_from_lambda
877 // -------------------------------------------------------------------------------------------------
878 
879 template <unsigned int hyEdge_dimT,
880  unsigned int poly_deg,
881  unsigned int quad_deg,
882  template <unsigned int, typename>
883  typename parametersT,
884  typename lSol_float_t>
885 template <typename hyEdgeT, typename SmallMatT>
886 inline SmallVec<
888  lSol_float_t>
890  assemble_rhs_from_lambda(const SmallMatT& lambda_values, hyEdgeT& hyper_edge) const
891 {
892  hy_assert(lambda_values.size() == 2 * hyEdge_dimT,
893  "The size of the lambda values should be twice the dimension of a hyperedge.");
894  for (unsigned int i = 0; i < 2 * hyEdge_dimT; ++i)
895  hy_assert(lambda_values[i].size() == n_shape_bdr_,
896  "The size of lambda should be the amount of ansatz functions at boundary.");
897 
898  SmallVec<n_loc_dofs_, lSol_float_t> right_hand_side;
899  lSol_float_t integral;
900 
901  for (unsigned int i = 0; i < n_shape_fct_; ++i)
902  for (unsigned int j = 0; j < n_shape_bdr_; ++j)
903  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
904  {
905  integral = integrator::template integrate_bdr_phipsi<decltype(hyEdgeT::geometry)>(
906  i, j, face, hyper_edge.geometry);
907  right_hand_side[hyEdge_dimT * n_shape_fct_ + i] +=
908  tau_ * theta_ * delta_t_ * lambda_values[face][j] * integral;
909  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
910  right_hand_side[dim * n_shape_fct_ + i] -=
911  hyper_edge.geometry.local_normal(face).operator[](dim) * lambda_values[face][j] *
912  integral;
913  }
914 
915  return right_hand_side;
916 } // end of DiffusionParab::assemble_rhs_from_lambda
917 
918 // -------------------------------------------------------------------------------------------------
919 // assemble_rhs_from_global_rhs
920 // -------------------------------------------------------------------------------------------------
921 
922 template <unsigned int hyEdge_dimT,
923  unsigned int poly_deg,
924  unsigned int quad_deg,
925  template <unsigned int, typename>
926  typename parametersT,
927  typename lSol_float_t>
928 template <typename hyEdgeT>
929 inline SmallVec<
931  lSol_float_t>
933  assemble_rhs_from_global_rhs(hyEdgeT& hyper_edge, const lSol_float_t time) const
934 {
935  using parameters = parametersT<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>;
936  SmallVec<n_loc_dofs_, lSol_float_t> right_hand_side;
937  lSol_float_t integral;
938  for (unsigned int i = 0; i < n_shape_fct_; ++i)
939  {
940  right_hand_side[hyEdge_dimT * n_shape_fct_ + i] =
941  theta_ * delta_t_ *
942  integrator::template integrate_vol_phifunc<
943  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>, decltype(hyEdgeT::geometry),
944  parameters::right_hand_side, Point<hyEdge_dimT, lSol_float_t> >(i, hyper_edge.geometry,
945  time);
946 
947  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
948  {
949  if (!is_dirichlet<parameters>(hyper_edge.node_descriptor[face]))
950  continue;
951  integral = integrator::template integrate_bdr_phifunc<
952  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>, decltype(hyEdgeT::geometry),
953  parameters::dirichlet_value, Point<hyEdge_dimT, lSol_float_t> >(i, face,
954  hyper_edge.geometry, time);
955  right_hand_side[hyEdge_dimT * n_shape_fct_ + i] +=
956  tau_ * theta_ * delta_t_ * integral +
957  tau_ * (1. - theta_) * delta_t_ *
958  integrator::template integrate_bdr_phifunc<
959  Point<decltype(hyEdgeT::geometry)::space_dim(), lSol_float_t>,
960  decltype(hyEdgeT::geometry), parameters::dirichlet_value,
961  Point<hyEdge_dimT, lSol_float_t> >(i, face, hyper_edge.geometry, time - delta_t_);
962  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
963  right_hand_side[dim * n_shape_fct_ + i] -=
964  hyper_edge.geometry.local_normal(face).operator[](dim) * integral;
965  }
966  }
967 
968  for (unsigned int i = 0; i < n_shape_fct_; ++i)
969  right_hand_side[hyEdge_dimT * n_shape_fct_ + i] +=
970  hyper_edge.data.u_old[i] * hyper_edge.geometry.area() +
971  delta_t_ * (1. - theta_) * hyper_edge.data.flux_old[i];
972 
973  return right_hand_side;
974 } // end of DiffusionParab::assemble_rhs_from_global_rhs
975 
976 // -------------------------------------------------------------------------------------------------
977 // assemble_rhs_from_coeffs
978 // -------------------------------------------------------------------------------------------------
979 
980 template <unsigned int hyEdge_dimT,
981  unsigned int poly_deg,
982  unsigned int quad_deg,
983  template <unsigned int, typename>
984  typename parametersT,
985  typename lSol_float_t>
986 template <typename hyEdgeT>
987 inline SmallVec<
989  lSol_float_t>
992  const std::array<
993  lSol_float_t,
995  coeffs,
996  hyEdgeT& hyper_edge) const
997 {
998  SmallVec<n_loc_dofs_, lSol_float_t> right_hand_side;
999  for (unsigned int i = 0; i < n_shape_fct_; ++i)
1000  for (unsigned int j = 0; j < n_shape_fct_; ++j)
1001  right_hand_side[hyEdge_dimT * n_shape_fct_ + i] +=
1002  coeffs[hyEdge_dimT * n_shape_fct_ + j] *
1003  integrator::template integrate_vol_phiphi(i, j, hyper_edge.geometry);
1004 
1005  return right_hand_side;
1006 } // end of DiffusionParab::assemble_rhs_from_coeffs
1007 
1008 // -------------------------------------------------------------------------------------------------
1009 // primal_at_boundary
1010 // -------------------------------------------------------------------------------------------------
1011 
1012 template <unsigned int hyEdge_dimT,
1013  unsigned int poly_deg,
1014  unsigned int quad_deg,
1015  template <unsigned int, typename>
1016  typename parametersT,
1017  typename lSol_float_t>
1018 template <typename hyEdgeT>
1019 inline std::array<
1020  std::array<
1021  lSol_float_t,
1023  2 * hyEdge_dimT>
1025  const std::array<lSol_float_t, n_loc_dofs_>& coeffs,
1026  hyEdgeT& hyper_edge) const
1027 {
1028  std::array<std::array<lSol_float_t, n_shape_bdr_>, 2 * hyEdge_dimT> bdr_values;
1029 
1030  for (unsigned int dim_n = 0; dim_n < 2 * hyEdge_dimT; ++dim_n)
1031  bdr_values[dim_n].fill(0.);
1032 
1033  for (unsigned int i = 0; i < n_shape_fct_; ++i)
1034  for (unsigned int j = 0; j < n_shape_bdr_; ++j)
1035  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
1036  bdr_values[face][j] +=
1037  coeffs[hyEdge_dimT * n_shape_fct_ + i] *
1038  integrator::template integrate_bdr_phipsi<decltype(hyEdgeT::geometry)>(
1039  i, j, face, hyper_edge.geometry);
1040 
1041  return bdr_values;
1042 } // end of DiffusionParab::primal_at_boundary
1043 
1044 // -------------------------------------------------------------------------------------------------
1045 // dual_at_boundary
1046 // -------------------------------------------------------------------------------------------------
1047 
1048 template <unsigned int hyEdge_dimT,
1049  unsigned int poly_deg,
1050  unsigned int quad_deg,
1051  template <unsigned int, typename>
1052  typename parametersT,
1053  typename lSol_float_t>
1054 template <typename hyEdgeT>
1055 inline std::array<
1056  std::array<
1057  lSol_float_t,
1059  2 * hyEdge_dimT>
1061  const std::array<lSol_float_t, (hyEdge_dimT + 1) * n_shape_fct_>& coeffs,
1062  hyEdgeT& hyper_edge) const
1063 {
1064  std::array<std::array<lSol_float_t, n_shape_bdr_>, 2 * hyEdge_dimT> bdr_values;
1065  lSol_float_t integral;
1066 
1067  for (unsigned int dim_n = 0; dim_n < 2 * hyEdge_dimT; ++dim_n)
1068  bdr_values[dim_n].fill(0.);
1069 
1070  for (unsigned int i = 0; i < n_shape_fct_; ++i)
1071  for (unsigned int j = 0; j < n_shape_bdr_; ++j)
1072  for (unsigned int face = 0; face < 2 * hyEdge_dimT; ++face)
1073  {
1074  integral = integrator::template integrate_bdr_phipsi<decltype(hyEdgeT::geometry)>(
1075  i, j, face, hyper_edge.geometry);
1076  for (unsigned int dim = 0; dim < hyEdge_dimT; ++dim)
1077  bdr_values[face][j] += hyper_edge.geometry.local_normal(face).operator[](dim) * integral *
1078  coeffs[dim * n_shape_fct_ + i];
1079  }
1080 
1081  return bdr_values;
1082 } // end of DiffusionParab::dual_at_boundary
1083 
1084 // -------------------------------------------------------------------------------------------------
1085 // bulk_values
1086 // -------------------------------------------------------------------------------------------------
1087 
1088 template <unsigned int hyEdge_dimT,
1089  unsigned int poly_deg,
1090  unsigned int quad_deg,
1091  template <unsigned int, typename>
1092  typename parametersT,
1093  typename lSol_float_t>
1094 template <typename abscissa_float_t,
1095  std::size_t abscissas_sizeT,
1096  class input_array_t,
1097  typename hyEdgeT>
1098 std::array<std::array<lSol_float_t, Hypercube<hyEdge_dimT>::pow(abscissas_sizeT)>,
1101  const std::array<abscissa_float_t, abscissas_sizeT>& abscissas,
1102  const input_array_t& lambda_values,
1103  hyEdgeT& hyper_edge,
1104  const lSol_float_t time) const
1105 {
1107  solve_local_problem(lambda_values, 1U, hyper_edge, time);
1109  SmallVec<static_cast<unsigned int>(abscissas_sizeT), abscissa_float_t> helper(abscissas);
1110 
1111  std::array<std::array<lSol_float_t, Hypercube<hyEdge_dimT>::pow(abscissas_sizeT)>,
1113  point_vals;
1114 
1115  for (unsigned int d = 0; d < system_dim; ++d)
1116  {
1117  for (unsigned int i = 0; i < coeffs.size(); ++i)
1118  coeffs[i] = coefficients[d * n_shape_fct_ + i];
1119  for (unsigned int pt = 0; pt < Hypercube<hyEdge_dimT>::pow(abscissas_sizeT); ++pt)
1120  point_vals[d][pt] = integrator::shape_fun_t::template lin_comb_fct_val<float>(
1121  coeffs, Hypercube<hyEdge_dimT>::template tensorial_pt<Point<hyEdge_dimT> >(pt, helper));
1122  }
1123 
1124  return point_vals;
1125 }
1126 // end of DiffusionParab::bulk_values
1127 
1128 // -------------------------------------------------------------------------------------------------
1130 // -------------------------------------------------------------------------------------------------
1131 
1132 } // namespace LocalSolver
LocalSolver::DiffusionParab::node_element
Define type of node elements, especially with respect to nodal shape functions.
Definition: diffusion_parab_ldgh.hxx:369
LocalSolver::DiffusionParab::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_parab_ldgh.hxx:396
shape_function.hxx
LocalSolver::DiffusionParab::delta_t_
const lSol_float_t delta_t_
Time step size.
Definition: diffusion_parab_ldgh.hxx:192
LocalSolver::DiffusionParab::primal_at_boundary
std::array< std::array< lSol_float_t, n_shape_bdr_ >, 2 *hyEdge_dimT > primal_at_boundary(const std::array< lSol_float_t, n_loc_dofs_ > &coeffs, hyEdgeT &hyper_edge) const
Evaluate primal variable at boundary.
LocalSolver::DiffusionParab::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_parab_ldgh.hxx:200
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::DiffusionParab::system_dim
static constexpr unsigned int system_dim
Dimension of of the solution evaluated with respect to a hypernode.
Definition: diffusion_parab_ldgh.hxx:160
LocalSolver::DiffusionParab::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 local reconstruction at tensorial products of abscissas.
LocalSolver::DiffusionParab::dual_at_boundary
std::array< std::array< lSol_float_t, n_shape_bdr_ >, 2 *hyEdge_dimT > dual_at_boundary(const std::array< lSol_float_t,(hyEdge_dimT+1) *n_shape_fct_ > &coeffs, hyEdgeT &hyper_edge) const
Evaluate dual variable at boundary.
LocalSolver::DiffusionParab::constructor_value_type
std::vector< lSol_float_t > constructor_value_type
Class is constructed using a single double indicating the penalty parameter.
Definition: diffusion_parab_ldgh.hxx:415
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_parab_ldgh.hxx:49
LocalSolver::DiffusionParab::error_def::initial_error
static error_t initial_error()
Define how initial error is generated.
Definition: diffusion_parab_ldgh.hxx:387
LocalSolver::DiffusionParab::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_parab_ldgh.hxx:498
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_parab_ldgh.hxx:57
LocalSolver::DiffusionParab::n_shape_fct_
static constexpr unsigned int n_shape_fct_
Number of local shape functions (with respect to all spatial dimensions).
Definition: diffusion_parab_ldgh.hxx:146
LocalSolver::DiffusionParab::node_system_dim
static constexpr unsigned int node_system_dim
Dimension of of the solution evaluated with respect to a hypernode.
Definition: diffusion_parab_ldgh.hxx:166
LocalSolver::DiffusionParab::solve_local_problem
std::array< lSol_float_t, n_loc_dofs_ > 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_parab_ldgh.hxx:298
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
TPP::ShapeType::Tensorial
Struct that handles the evaluation of tensorial shape functions.
Definition: tensorial.hxx:22
LocalSolver::DiffusionParab::errors
std::array< lSol_float_t, 1U > errors(const std::array< std::array< lSol_float_t, n_shape_bdr_ >, 2 *hyEdge_dimT > &UNUSED(lambda_values), hyEdgeT &hy_edge, const lSol_float_t time=0.) const
Evaluate squared local L2 error.
Definition: diffusion_parab_ldgh.hxx:754
LocalSolver::DiffusionParab::node_system_dimension
static constexpr unsigned int node_system_dimension()
Dimension of of the solution evaluated with respect to a hypernode.
Definition: diffusion_parab_ldgh.hxx:136
LocalSolver::DiffusionParab::error_def
Define how errors are evaluated.
Definition: diffusion_parab_ldgh.hxx:378
LocalSolver::DiffusionParab::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_parab_ldgh.hxx:443
TPP::ShapeFunction
Struct that handles different types of evaluation of shape functions.
Definition: shape_function.hxx:15
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_parab_ldgh.hxx:65
TPP::Quadrature::Tensorial
General integrator class on tensorial hypergraphs.
Definition: tensorial.hxx:24
LocalSolver::DiffusionParab::error_def::postprocess_error
static error_t postprocess_error(error_t &summed_error)
Define how global errors should be postprocessed.
Definition: diffusion_parab_ldgh.hxx:405
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_parab_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::DiffusionParab::error_def::error_t
std::array< lSol_float_t, 1U > error_t
Define the typename returned by function errors.
Definition: diffusion_parab_ldgh.hxx:383
LocalSolver::DiffusionParab::set_data
void set_data(const std::array< std::array< lSol_float_t, n_shape_bdr_ >, 2 *hyEdge_dimT > &lambda_values, hyEdgeT &hyper_edge, const lSol_float_t time=0.) const
Set data into data container to be used for next time step.
Definition: diffusion_parab_ldgh.hxx:547
SmallMat::data
std::array< mat_entry_t, size()> & data()
Return data array that allows to manipulate the SmallMat.
Definition: dense_la.hxx:190
LocalSolver::DiffusionParab::tau_
const lSol_float_t tau_
(Globally constant) penalty parameter for HDG scheme.
Definition: diffusion_parab_ldgh.hxx:184
LocalSolver::DiffusionParab::system_dimension
static constexpr unsigned int system_dimension()
Dimension of of the solution evaluated with respect to a hyperedge.
Definition: diffusion_parab_ldgh.hxx:132
hypercube.hxx
LocalSolver::DiffusionParab::node_element::functions
std::tuple< TPP::ShapeFunction< TPP::ShapeType::Tensorial< TPP::ShapeType::Legendre< poly_deg >, hyEdge_dimT - 1 > > > functions
Definition: diffusion_parab_ldgh.hxx:373
LocalSolver::DiffusionParab::data_type::flux_old
SmallVec< n_shape_fct_, lSol_float_t > flux_old
Definition: diffusion_parab_ldgh.hxx:363
Wrapper::LAPACKexception
Exception to be thrown if LAPACK's solve fails.
Definition: lapack.hxx:25
LocalSolver::DiffusionParab::n_loc_dofs_
static constexpr unsigned int n_loc_dofs_
Number of (local) degrees of freedom per hyperedge.
Definition: diffusion_parab_ldgh.hxx:154
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::DiffusionParab::data_type::u_old
SmallVec< n_shape_fct_, lSol_float_t > u_old
Definition: diffusion_parab_ldgh.hxx:363
LocalSolver::DiffusionParab::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).
Hypercube::pow
static constexpr unsigned int pow(unsigned int base)
Return n to the power dim.
Definition: hypercube.hxx:25
LocalSolver::DiffusionParab::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::DiffusionParab::data_type::boundary_flux_old
SmallMat< n_shape_bdr_, 2 *hyEdge_dimT, lSol_float_t > boundary_flux_old
Definition: diffusion_parab_ldgh.hxx:364
LocalSolver::DiffusionParab
Local solver for parabolic diffusion equation on hypergraph.
Definition: diffusion_parab_ldgh.hxx:106
LocalSolver::DiffusionParab::make_initial
SmallMatT & make_initial(SmallMatT &lambda_values, hyEdgeT &hyper_edge, const lSol_float_t time=0.) const
L2 project initial data to skeletal and fill data container.
Definition: diffusion_parab_ldgh.hxx:627
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_parab_ldgh.hxx:33
LocalSolver::DiffusionParab::DiffusionParab
DiffusionParab(const constructor_value_type &constru=std::vector(3, 1.))
Constructor for local solver.
Definition: diffusion_parab_ldgh.hxx:421
LocalSolver::DiffusionParab::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_parab_ldgh.hxx:125
LocalSolver::DiffusionParab::n_shape_bdr_
static constexpr unsigned int n_shape_bdr_
Number oflocal shape functions (with respect to a face / hypernode).
Definition: diffusion_parab_ldgh.hxx:150
LocalSolver::DiffusionParab::is_dirichlet
static constexpr bool is_dirichlet(const unsigned int node_type)
Find out whether a node is of Dirichlet type.
Definition: diffusion_parab_ldgh.hxx:171
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::DiffusionParab::theta_
const lSol_float_t theta_
Parameter theta that defines the one-step theta scheme.
Definition: diffusion_parab_ldgh.hxx:188
LocalSolver::DiffusionParab::data_type
Define type of (hyperedge related) data that is stored in HyDataContainer.
Definition: diffusion_parab_ldgh.hxx:361
LocalSolver::DiffusionParab::assemble_rhs_from_coeffs
SmallVec< n_loc_dofs_, lSol_float_t > assemble_rhs_from_coeffs(const std::array< lSol_float_t, n_loc_dofs_ > &coeffs, hyEdgeT &hyper_edge) const
Assemble local right-hand for the local solver (from function coefficients).
LocalSolver::DiffusionParab::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).
SmallMat
This class implements a small/dense matrix.
Definition: dense_la.hxx:34
LocalSolver::DiffusionParab::hyEdge_dim
static constexpr unsigned int hyEdge_dim()
Dimension of hyper edge type that this object solves on.
Definition: diffusion_parab_ldgh.hxx:116
Hypercube
Helper class containing numbers and functions related to hypercubes.
Definition: hypercube.hxx:12