HyperHDG
mass_approx_eigenvalue.hxx
Go to the documentation of this file.
1 #pragma once // Ensure that file is included only once in a single compilation.
2 
5 #include <HyperHDG/hy_assert.hxx>
6 #include <HyperHDG/plot.hxx>
7 #include <algorithm>
8 #include <array>
9 #include <cmath>
10 
11 namespace GlobalLoop
12 {
13 /*!*************************************************************************************************
14  * \brief Combine local solver and global information for eigenvalue problems with mass matrix
15  * approximation.
16  *
17  * \tparam TopologyT Class type containing topological information.
18  * \tparam GeometryT Class type containing geometrical information.
19  * \tparam NodeDescriptorT Class type containing the information of nodes of hyperedges.
20  * \tparam LocalSolverT Class type of the local solver.
21  * \tparam LargeVecT Clas type of large, global vector.
22  * \tparam dof_index_t Index type of hyperedges. Default is \c unsigned \c int.
23  *
24  * \authors Guido Kanschat, Heidelberg University, 2019--2020.
25  * \authors Andreas Rupp, Heidelberg University, 2019--2020.
26  **************************************************************************************************/
27 template <class TopologyT,
28  class GeometryT,
29  class NodeDescriptorT,
30  class LocalSolverT,
31  typename LargeVecT = std::vector<double>,
32  typename dof_index_t = unsigned int>
34 {
35  /*!***********************************************************************************************
36  * \brief Prepare struct to check for function to exist (cf. compile_time_tricks.hxx).
37  ************************************************************************************************/
38  HAS_MEMBER_FUNCTION(trace_to_flux, has_trace_to_flux);
39  /*!***********************************************************************************************
40  * \brief Prepare struct to check for function to exist (cf. compile_time_tricks.hxx).
41  ************************************************************************************************/
42  HAS_MEMBER_FUNCTION(trace_to_mass_flux, has_trace_to_mass_flux);
43 
44  /*!***********************************************************************************************
45  * \brief Floating type is determined by floating type of large vector's entries.
46  ************************************************************************************************/
47  using dof_value_t = typename LargeVecT::value_type;
48 
49  private:
50  /*!***********************************************************************************************
51  * \brief Instantiation of a hypergraph.
52  ************************************************************************************************/
53  HDGHyperGraph<LocalSolverT::n_glob_dofs_per_node(),
54  TopologyT,
55  GeometryT,
56  NodeDescriptorT,
57  typename LocalSolverT::data_type>
59  /*!***********************************************************************************************
60  * \brief Vector containing the indices of Dirichlet type nodes.
61  ************************************************************************************************/
62  std::vector<dof_index_t> dirichlet_indices_;
63  /*!***********************************************************************************************
64  * \brief Instantiation of a local solver.
65  ************************************************************************************************/
66  const LocalSolverT local_solver_;
67  /*!***********************************************************************************************
68  * \brief Struct encoding the options for plotting.
69  ************************************************************************************************/
71 
72  public:
73  /*!***********************************************************************************************
74  * \brief Abstract problem constructor.
75  *
76  * Constructor for class containing a HyperGraph and a local solver that solve a PDE on a
77  * hyperedge.
78  *
79  * \param construct_topo Information to construct a topology.
80  * \param construct_geom Information to construct a geometry.
81  * \param construct_loc_sol Information to construct a local solver.
82  ************************************************************************************************/
83  MassApproxEigenvalue(const typename TopologyT::constructor_value_type& construct_topo,
84  const typename GeometryT::constructor_value_type& construct_geom,
85  const typename LocalSolverT::constructor_value_type& construct_loc_sol)
86  : hyper_graph_(construct_topo, construct_geom), local_solver_(construct_loc_sol)
87  {
88  static_assert(TopologyT::hyEdge_dim() == GeometryT::hyEdge_dim(),
89  "Hyperedge dimension of topology and geometry must be equal!");
90  static_assert(TopologyT::space_dim() == GeometryT::space_dim(),
91  "Space dimension of topology and geometry must be equal!");
92  static_assert(TopologyT::hyEdge_dim() == LocalSolverT::hyEdge_dim(),
93  "Hyperedge dimension of hypergraph and local solver must be equal!");
94  }
95  /*!***********************************************************************************************
96  * \brief Abstract problem constructor.
97  *
98  * Constructor for class containing a HyperGraph and a local solver that solve a PDE on a
99  * hyperedge.
100  *
101  * \param construct_topo Information to construct a topology.
102  * \param construct_loc_sol Information to construct a local solver.
103  ************************************************************************************************/
104  MassApproxEigenvalue(const typename TopologyT::constructor_value_type& construct_topo,
105  const typename LocalSolverT::constructor_value_type& construct_loc_sol)
106  : hyper_graph_(construct_topo), local_solver_(construct_loc_sol)
107  {
108  static_assert(TopologyT::hyEdge_dim() == GeometryT::hyEdge_dim(),
109  "Hyperedge dimension of topology and geometry must be equal!");
110  static_assert(TopologyT::space_dim() == GeometryT::space_dim(),
111  "Space dimension of topology and geometry must be equal!");
112  static_assert(TopologyT::hyEdge_dim() == LocalSolverT::hyEdge_dim(),
113  "Hyperedge dimension of hypergraph and local solver must be equal!");
114  }
115  /*!***********************************************************************************************
116  * \brief Abstract problem constructor.
117  *
118  * Constructor for class containing a HyperGraph and a local solver that solve a PDE on a
119  * hyperedge.
120  *
121  * \param construct_topo Information to construct a topology.
122  ************************************************************************************************/
123  MassApproxEigenvalue(const typename TopologyT::constructor_value_type& construct_topo)
124  : hyper_graph_(construct_topo)
125  {
126  static_assert(TopologyT::hyEdge_dim() == GeometryT::hyEdge_dim(),
127  "Hyperedge dimension of topology and geometry must be equal!");
128  static_assert(TopologyT::space_dim() == GeometryT::space_dim(),
129  "Space dimension of topology and geometry must be equal!");
130  static_assert(TopologyT::hyEdge_dim() == LocalSolverT::hyEdge_dim(),
131  "Hyperedge dimension of hypergraph and local solver must be equal!");
132  }
133  /*!***********************************************************************************************
134  * \brief Return indices of Dirichlet degrees of freedom.
135  *
136  * \tparam hyNode_index_t Typename of the index type for hypernodes.
137  * \retval dirichlet_indices_ Vector containing all dirichlet dof indices.
138  ************************************************************************************************/
139  template <typename hyNode_index_t = dof_index_t>
140  std::vector<unsigned int> dirichlet_indices()
141  {
142  constexpr unsigned int hyEdge_dim = TopologyT::hyEdge_dim();
143 
144  std::array<dof_index_t, LocalSolverT::n_glob_dofs_per_node()> dof_indices;
146  std::array<unsigned int, 2 * hyEdge_dim> hyNode_types;
147 
148  std::for_each(hyper_graph_.begin(), hyper_graph_.end(), [&](auto hyper_edge) {
149  hyNode_types = local_solver_.node_types(hyper_edge);
150  hyEdge_hyNodes = hyper_edge.topology.get_hyNode_indices();
151 
152  for (unsigned int i = 0; i < hyNode_types.size(); ++i)
153  if (hyNode_types[i] == 1)
154  {
155  hyper_graph_.hyNode_factory().get_dof_indices(hyEdge_hyNodes[i], dof_indices);
156  for (unsigned int j = 0; j < dof_indices.size(); ++j)
157  dirichlet_indices_.push_back(dof_indices[j]);
158  }
159  });
160 
161  std::sort(dirichlet_indices_.begin(), dirichlet_indices_.end());
162  auto last = std::unique(dirichlet_indices_.begin(), dirichlet_indices_.end());
163  dirichlet_indices_.erase(last, dirichlet_indices_.end());
164 
165  return dirichlet_indices_;
166  }
167  /*!***********************************************************************************************
168  * \brief Evaluate condensed matrix-vector product.
169  *
170  * Function that evaluates the condensed, matrix-free version of the matrix-vector product
171  * \f$A x = y\f$, where \f$A\f$ is the condensed matrix of the LDG-H method, \f$x\f$ is the
172  * vector of parameters to define the skeletal variable \f$\lambda\f$, and \f$y\f$ is the
173  * resulting vector, which has the same size as the input vector \f$x\f$.
174  *
175  * \tparam hyNode_index_t Typename of the hypernode index. Defaults to \c unsigned \c int.
176  * \param x_vec A vector containing the input vector \f$x\f$.
177  * \param time Time at which given analyitic functions will be evaluated.
178  * \retval y_vec A vector containing the product \f$y = Ax\f$.
179  ************************************************************************************************/
180  template <typename hyNode_index_t = dof_index_t>
181  LargeVecT trace_to_flux(const LargeVecT& x_vec, const dof_value_t time = 0.)
182  {
183  constexpr unsigned int hyEdge_dim = TopologyT::hyEdge_dim();
184  constexpr unsigned int n_dofs_per_node = LocalSolverT::n_glob_dofs_per_node();
185 
186  LargeVecT vec_Ax(x_vec.size(), 0.);
188  std::array<std::array<dof_value_t, n_dofs_per_node>, 2 * hyEdge_dim> hyEdge_dofs_old,
189  hyEdge_dofs_new;
190 
191  // Do matrix--vector multiplication by iterating over all hyperedges.
192  std::for_each(hyper_graph_.begin(), hyper_graph_.end(), [&](auto hyper_edge) {
193  // Fill x_vec's degrees of freedom of a hyperedge into hyEdge_dofs array.
194  hyEdge_hyNodes = hyper_edge.topology.get_hyNode_indices();
195  for (unsigned int hyNode = 0; hyNode < hyEdge_hyNodes.size(); ++hyNode)
196  {
197  hyper_graph_.hyNode_factory().get_dof_values(hyEdge_hyNodes[hyNode], x_vec,
198  hyEdge_dofs_old[hyNode]);
199  hyEdge_dofs_new[hyNode].fill(0.);
200  }
201 
202  // Turn degrees of freedom of x_vec that have been stored locally into those of vec_Ax.
203  if constexpr (
204  has_trace_to_flux<
205  LocalSolverT,
206  std::array<std::array<dof_value_t, n_dofs_per_node>, 2 * TopologyT::hyEdge_dim()>&(
207  std::array<std::array<dof_value_t, n_dofs_per_node>, 2 * TopologyT::hyEdge_dim()>&,
208  std::array<std::array<dof_value_t, n_dofs_per_node>, 2 * TopologyT::hyEdge_dim()>&,
209  dof_value_t)>::value)
210  local_solver_.trace_to_flux(hyEdge_dofs_old, hyEdge_dofs_new, time);
211  else if constexpr (
212  has_trace_to_flux<
213  LocalSolverT,
214  std::array<std::array<dof_value_t, n_dofs_per_node>, 2 * TopologyT::hyEdge_dim()>&(
215  std::array<std::array<dof_value_t, n_dofs_per_node>, 2 * TopologyT::hyEdge_dim()>&,
216  std::array<std::array<dof_value_t, n_dofs_per_node>, 2 * TopologyT::hyEdge_dim()>&,
217  decltype(hyper_edge)&, dof_value_t)>::value)
218  local_solver_.trace_to_flux(hyEdge_dofs_old, hyEdge_dofs_new, hyper_edge, time);
219  else
220  hy_assert(false, "Function seems not to be implemented!");
221 
222  // Fill hyEdge_dofs array degrees of freedom into vec_Ax.
223  for (unsigned int hyNode = 0; hyNode < hyEdge_hyNodes.size(); ++hyNode)
224  hyper_graph_.hyNode_factory().add_to_dof_values(hyEdge_hyNodes[hyNode], vec_Ax,
225  hyEdge_dofs_new[hyNode]);
226  });
227 
228  return vec_Ax;
229  }
230  /*!***********************************************************************************************
231  * \brief Evaluate condensed matrix-vector product of approximated mass matrix.
232  *
233  * Similar to the standard matrix-vector product, but using the approxmiated mass matrix instead
234  * of the Laplacian.
235  *
236  * \tparam hyNode_index_t Typename of the hypernode index. Defaults to \c unsigned \c int.
237  * \param x_vec A vector containing the input vector \f$x\f$.
238  * \param time Time at which given analyitic functions will be evaluated.
239  * \retval y_vec A vector containing the product \f$y = Ax\f$.
240  ************************************************************************************************/
241  template <typename hyNode_index_t = dof_index_t>
242  LargeVecT trace_to_mass_flux(const LargeVecT& x_vec, const dof_value_t time = 0.)
243  {
244  constexpr unsigned int hyEdge_dim = TopologyT::hyEdge_dim();
245  constexpr unsigned int n_dofs_per_node = LocalSolverT::n_glob_dofs_per_node();
246 
247  LargeVecT vec_Ax(x_vec.size(), 0.);
249  std::array<std::array<dof_value_t, n_dofs_per_node>, 2 * hyEdge_dim> hyEdge_dofs_old,
250  hyEdge_dofs_new;
251 
252  // Do matrix--vector multiplication by iterating over all hyperedges.
253  std::for_each(hyper_graph_.begin(), hyper_graph_.end(), [&](auto hyper_edge) {
254  // Fill x_vec's degrees of freedom of a hyperedge into hyEdge_dofs array.
255  hyEdge_hyNodes = hyper_edge.topology.get_hyNode_indices();
256  for (unsigned int hyNode = 0; hyNode < hyEdge_hyNodes.size(); ++hyNode)
257  {
258  hyper_graph_.hyNode_factory().get_dof_values(hyEdge_hyNodes[hyNode], x_vec,
259  hyEdge_dofs_old[hyNode]);
260  hyEdge_dofs_new[hyNode].fill(0.);
261  }
262 
263  // Turn degrees of freedom of x_vec that have been stored locally into those of vec_Ax.
264  if constexpr (
265  has_trace_to_mass_flux<
266  LocalSolverT,
267  std::array<std::array<dof_value_t, n_dofs_per_node>, 2 * TopologyT::hyEdge_dim()>&(
268  std::array<std::array<dof_value_t, n_dofs_per_node>, 2 * TopologyT::hyEdge_dim()>&,
269  std::array<std::array<dof_value_t, n_dofs_per_node>, 2 * TopologyT::hyEdge_dim()>&,
270  dof_value_t)>::value)
271  {
272  local_solver_.trace_to_mass_flux(hyEdge_dofs_old, hyEdge_dofs_new, time);
273  }
274  else if constexpr (
275  has_trace_to_mass_flux<
276  LocalSolverT,
277  std::array<std::array<dof_value_t, n_dofs_per_node>, 2 * TopologyT::hyEdge_dim()>&(
278  std::array<std::array<dof_value_t, n_dofs_per_node>, 2 * TopologyT::hyEdge_dim()>&,
279  std::array<std::array<dof_value_t, n_dofs_per_node>, 2 * TopologyT::hyEdge_dim()>&,
280  decltype(hyper_edge)&, dof_value_t)>::value)
281  {
282  local_solver_.trace_to_mass_flux(hyEdge_dofs_old, hyEdge_dofs_new, hyper_edge, time);
283  }
284  else
285  hy_assert(false, "Function seems not to be implemented!");
286 
287  // Fill hyEdge_dofs array degrees of freedom into vec_Ax.
288  for (unsigned int hyNode = 0; hyNode < hyEdge_hyNodes.size(); ++hyNode)
289  hyper_graph_.hyNode_factory().add_to_dof_values(hyEdge_hyNodes[hyNode], vec_Ax,
290  hyEdge_dofs_new[hyNode]);
291  });
292 
293  return vec_Ax;
294  }
295  /*!***********************************************************************************************
296  * \brief Determine size of condensed system for the skeletal unknowns.
297  *
298  * Function that returns the size \f$n\f$ of the \f$n \times n\f$ linear, sparse system
299  * \f$Ax = b\f$ that is solved by the program in a matrix-free fashion.
300  *
301  * This function is needed to define a \c LinearOperator from Python's \c scipy.sparse.linalg
302  * package which can be used to define iterative solvers for sparse systems.
303  *
304  * \retval n Size of condensed global system of equations.
305  ************************************************************************************************/
306  dof_index_t size_of_system() const { return hyper_graph_.n_global_dofs(); }
307  /*!***********************************************************************************************
308  * \brief Set plot option and return old plot option.
309  *
310  * Function to set and / or read the current plot option.
311  *
312  * \param option A \c std::string containing the plot option to be considered.
313  * \param value A \c std::string containing the new value of the considered option.
314  * If empty, the old value is kept.
315  * \retval opt_value A \c std::string containing the value of the plot option.
316  ************************************************************************************************/
317  std::string plot_option(const std::string& option, std::string value = "")
318  {
319  return set_plot_option(plot_options, option, value);
320  }
321  /*!***********************************************************************************************
322  * \brief Plot solution in vtu format.
323  *
324  * Function that plots the solution of the problem to a predefined file.
325  *
326  * \param lambda A vector of unknowns containing the data vector.
327  * \param time Time at which analytic functions are evaluated.
328  * \retval file A file in the output directory.
329  ************************************************************************************************/
330  void plot_solution(const std::vector<dof_value_t>& lambda, const dof_value_t time = 0.)
331  {
332  plot(hyper_graph_, local_solver_, lambda, plot_options, time);
333  }
334  /*!***********************************************************************************************
335  * \brief Return refinement level.
336  ************************************************************************************************/
337  unsigned int get_refinement() { return hyper_graph_.get_refinement(); }
338  /*!***********************************************************************************************
339  * \brief Set refinement level.
340  ************************************************************************************************/
341  void set_refinement(unsigned int level) { hyper_graph_.set_refinement(level); }
342 }; // end of class MassApproxEigenvalue
343 
344 } // end of namespace GlobalLoop
compile_time_tricks.hxx
GlobalLoop::MassApproxEigenvalue::MassApproxEigenvalue
MassApproxEigenvalue(const typename TopologyT::constructor_value_type &construct_topo)
Abstract problem constructor.
Definition: mass_approx_eigenvalue.hxx:123
GlobalLoop::MassApproxEigenvalue::plot_options
PlotOptions plot_options
Struct encoding the options for plotting.
Definition: mass_approx_eigenvalue.hxx:70
hy_assert.hxx
This file provides the function hy_assert.
GlobalLoop::MassApproxEigenvalue::MassApproxEigenvalue
MassApproxEigenvalue(const typename TopologyT::constructor_value_type &construct_topo, const typename LocalSolverT::constructor_value_type &construct_loc_sol)
Abstract problem constructor.
Definition: mass_approx_eigenvalue.hxx:104
plot.hxx
GlobalLoop::MassApproxEigenvalue::plot_solution
void plot_solution(const std::vector< dof_value_t > &lambda, const dof_value_t time=0.)
Plot solution in vtu format.
Definition: mass_approx_eigenvalue.hxx:330
GlobalLoop::MassApproxEigenvalue::MassApproxEigenvalue
MassApproxEigenvalue(const typename TopologyT::constructor_value_type &construct_topo, const typename GeometryT::constructor_value_type &construct_geom, const typename LocalSolverT::constructor_value_type &construct_loc_sol)
Abstract problem constructor.
Definition: mass_approx_eigenvalue.hxx:83
PlotOptions
A class storing options for plotting.
Definition: plot.hxx:20
GlobalLoop::MassApproxEigenvalue::trace_to_mass_flux
LargeVecT trace_to_mass_flux(const LargeVecT &x_vec, const dof_value_t time=0.)
Evaluate condensed matrix-vector product of approximated mass matrix.
Definition: mass_approx_eigenvalue.hxx:242
HDGHyperGraph::end
HDGHyperGraph< n_dofs_per_nodeT, TopoT, GeomT, NodeT, DataT, hyEdge_index_t >::iterator end()
Return iterator to the end of hyEdge list.
Definition: hdg_hypergraph.hxx:433
HDGHyperGraph
The class template uniting topology and geometry of a hypergraph with the topology of the skeleton sp...
Definition: hdg_hypergraph.hxx:51
GlobalLoop::MassApproxEigenvalue::local_solver_
const LocalSolverT local_solver_
Instantiation of a local solver.
Definition: mass_approx_eigenvalue.hxx:66
SmallMat::size
static constexpr unsigned int size()
Return size a SmallMat.
Definition: dense_la.hxx:54
GlobalLoop::MassApproxEigenvalue
Combine local solver and global information for eigenvalue problems with mass matrix approximation.
Definition: mass_approx_eigenvalue.hxx:33
GlobalLoop::MassApproxEigenvalue::hyper_graph_
HDGHyperGraph< LocalSolverT::n_glob_dofs_per_node(), TopologyT, GeometryT, NodeDescriptorT, typename LocalSolverT::data_type > hyper_graph_
Instantiation of a hypergraph.
Definition: mass_approx_eigenvalue.hxx:58
GlobalLoop::MassApproxEigenvalue::set_refinement
void set_refinement(unsigned int level)
Set refinement level.
Definition: mass_approx_eigenvalue.hxx:341
GlobalLoop::MassApproxEigenvalue::dirichlet_indices
std::vector< unsigned int > dirichlet_indices()
Return indices of Dirichlet degrees of freedom.
Definition: mass_approx_eigenvalue.hxx:140
GlobalLoop::MassApproxEigenvalue::dof_value_t
typename LargeVecT::value_type dof_value_t
Floating type is determined by floating type of large vector's entries.
Definition: mass_approx_eigenvalue.hxx:47
GlobalLoop::MassApproxEigenvalue::HAS_MEMBER_FUNCTION
HAS_MEMBER_FUNCTION(trace_to_flux, has_trace_to_flux)
Prepare struct to check for function to exist (cf. compile_time_tricks.hxx).
GlobalLoop::MassApproxEigenvalue::get_refinement
unsigned int get_refinement()
Return refinement level.
Definition: mass_approx_eigenvalue.hxx:337
GlobalLoop::MassApproxEigenvalue::trace_to_flux
LargeVecT trace_to_flux(const LargeVecT &x_vec, const dof_value_t time=0.)
Evaluate condensed matrix-vector product.
Definition: mass_approx_eigenvalue.hxx:181
GlobalLoop::MassApproxEigenvalue::plot_option
std::string plot_option(const std::string &option, std::string value="")
Set plot option and return old plot option.
Definition: mass_approx_eigenvalue.hxx:317
plot
void plot(HyperGraphT &hyper_graph, const LocalSolverT &local_solver, const LargeVecT &lambda, PlotOptions &plot_options, const floatT time=0.)
Function plotting the solution of an equation on a hypergraph in vtu format.
Definition: plot.hxx:778
hy_assert
#define hy_assert(Expr, Msg)
The assertion to be used within HyperHDG — deactivate using -DNDEBUG compile flag.
Definition: hy_assert.hxx:38
HDGHyperGraph::begin
HDGHyperGraph< n_dofs_per_nodeT, TopoT, GeomT, NodeT, DataT, hyEdge_index_t >::iterator begin()
Return iterator to first hyEdge of HDGHyperGraph.
Definition: hdg_hypergraph.hxx:417
set_plot_option
std::string set_plot_option(PlotOptions &plot_options, const std::string &option, std::string value="")
Set a plot option and return the new value of this option as std::string.
Definition: plot.hxx:122
hdg_hypergraph.hxx
GlobalLoop::MassApproxEigenvalue::size_of_system
dof_index_t size_of_system() const
Determine size of condensed system for the skeletal unknowns.
Definition: mass_approx_eigenvalue.hxx:306
GlobalLoop
A namespace for global loops.
Definition: elliptic.hxx:14
SmallMat
This class implements a small/dense matrix.
Definition: dense_la.hxx:34
GlobalLoop::MassApproxEigenvalue::dirichlet_indices_
std::vector< dof_index_t > dirichlet_indices_
Vector containing the indices of Dirichlet type nodes.
Definition: mass_approx_eigenvalue.hxx:62