dune-pdelab  2.7-git
checklopinterface.hh
Go to the documentation of this file.
1 // -*- tab-width: 2; indent-tabs-mode: nil -*-
2 // vi: set et ts=2 sw=2 sts=2:
3 
4 #ifndef DUNE_PDELAB_BACKEND_ISTL_MATRIXFREE_CHECKLOPINTERFACE_HH
5 #define DUNE_PDELAB_BACKEND_ISTL_MATRIXFREE_CHECKLOPINTERFACE_HH
6 
7 
8 namespace Dune {
9  namespace PDELab {
10  namespace impl{
11  // Some of the matrix free solvers require that the local operator describing
12  // the model uses the new interface for nonlinear Jacobian apply methods where
13  // the current solution and the linearization point may have different
14  // type. This is best explained by an example:
15  //
16  //
17  // old: void jacobian_apply_volume (const EG& eg, const LFSU& lfsu, const X& x, const X& z, const LFSV& lfsv, Y& y) const {}
18  // new: void jacobian_apply_volume (const EG& eg, const LFSU& lfsu, const X& x, const Z& z, const LFSV& lfsv, Y& y) const {}
19  //
20  // In the new interface the coefficient z has type Z which may be different
21  // than X.
22  //
23  // The purpose of this file is to provide a helper function to check whether a
24  // local operator complies to the new interface. I'm all in favor of removing
25  // this code as soon as possible.
26  //
27  // The current implementation is based on C++-14 SFINAE. It is entirely
28  // possible that this could be replaced with features from the current
29  // concepts implementation in dune-common.
30 
31  // SFINAE Infrastructure
32  template <typename T>
33  struct Result
34  {
35  private:
36  template <typename A> constexpr auto test(int)
37  -> decltype(std::declval<T>()(std::declval<A>()), std::true_type())
38  {
39  return std::true_type();
40  }
41  template <typename A> constexpr std::false_type test(...)
42  {
43  return std::false_type();
44  }
45 
46  public:
47  template <typename A> constexpr auto operator()(const A& p)
48  {
49  return test<A>(int());
50  }
51  };
52 
53  template <typename T> constexpr auto lambdaToTemplate(const T& t)
54  {
55  return Result<T>();
56  }
57 
58  // The actual tests if the new method exists
59  //
60  // Note: The types in the declval don't really matter. The important part
61  // is that they are all different. This way we check that we have the new
62  // interface since it would not be valid to pass this to the old one.
63  //
64  // Note: Don't forget the & for the last argument. This is necessary
65  // since the last argument of jacobian_apply_volume is passed by
66  // reference (without being const).
68  lambdaToTemplate([](auto&& lop) -> decltype(lop.jacobian_apply_volume(std::declval<bool>(),
69  std::declval<int>(),
70  std::declval<double>(),
71  std::declval<short int>(),
72  std::declval<long int>(),
73  std::declval<long long int&>()
74  )) {});
76  lambdaToTemplate([](auto&& lop) -> decltype(lop.jacobian_apply_volume_post_skeleton(std::declval<bool>(),
77  std::declval<int>(),
78  std::declval<double>(),
79  std::declval<short int>(),
80  std::declval<long int>(),
81  std::declval<long long int&>()
82  )) {});
84  lambdaToTemplate([](auto&& lop) -> decltype(lop.jacobian_apply_skeleton(std::declval<bool>(),
85  std::declval<int>(),
86  std::declval<double>(),
87  std::declval<short int>(),
88  std::declval<long int>(),
89  std::declval<int>(),
90  std::declval<double>(),
91  std::declval<short int>(),
92  std::declval<long int>(),
93  std::declval<long long int&>(),
94  std::declval<long long int&>()
95  )) {});
97  lambdaToTemplate([](auto&& lop) -> decltype(lop.jacobian_apply_boundary(std::declval<bool>(),
98  std::declval<int>(),
99  std::declval<double>(),
100  std::declval<short int>(),
101  std::declval<long int>(),
102  std::declval<long long int&>()
103  )) {});
104 
105  // Similar tests that show if the old or the new methods exist
106  //
107  // Note: Since the calls to the old interface are also valid in the new
108  // interface we only get the information if the method exists in one of
109  // the two implementations.
111  lambdaToTemplate([](auto&& lop) -> decltype(lop.jacobian_apply_volume(std::declval<bool>(),
112  std::declval<int>(),
113  std::declval<double>(),
114  std::declval<double>(),
115  std::declval<long int>(),
116  std::declval<long long int&>()
117  )) {});
119  lambdaToTemplate([](auto&& lop) -> decltype(lop.jacobian_apply_volume_post_skeleton(std::declval<bool>(),
120  std::declval<int>(),
121  std::declval<double>(),
122  std::declval<double>(),
123  std::declval<long int>(),
124  std::declval<long long int&>()
125  )) {});
127  lambdaToTemplate([](auto&& lop) -> decltype(lop.jacobian_apply_skeleton(std::declval<bool>(),
128  std::declval<int>(),
129  std::declval<double>(),
130  std::declval<double>(),
131  std::declval<long int>(),
132  std::declval<int>(),
133  std::declval<double>(),
134  std::declval<double>(),
135  std::declval<long int>(),
136  std::declval<long long int&>(),
137  std::declval<long long int&>()
138  )) {});
140  lambdaToTemplate([](auto&& lop) -> decltype(lop.jacobian_apply_boundary(std::declval<bool>(),
141  std::declval<int>(),
142  std::declval<double>(),
143  std::declval<double>(),
144  std::declval<long int>(),
145  std::declval<long long int&>()
146  )) {});
147 
148  // Now comes the test that should actually be called. If a localoperator
149  // implements the OldOrNew interface for one of the nonlinear jacobian
150  // apply methods but not the new interface we can conlude that only the
151  // old one is implemented.
152  template <typename T>
153  constexpr auto hasOldLOPInterface(T& t) -> typename std::enable_if<
154  (decltype(hasOldOrNewJacobianApplyVolume(t))::value && !decltype(hasNewJacobianApplyVolume(t))::value)
156  || (decltype(hasOldOrNewJacobianApplySkeleton(t))::value && !decltype(hasNewJacobianApplySkeleton(t))::value)
157  || (decltype(hasOldOrNewJacobianApplyBoundary(t))::value && !decltype(hasNewJacobianApplyBoundary(t))::value),
158  std::true_type>::type
159  {
160  return std::true_type();
161  }
162  template <typename T>
163  constexpr auto hasOldLOPInterface(T& t) -> typename std::enable_if<
164  !((decltype(hasOldOrNewJacobianApplyVolume(t))::value && !decltype(hasNewJacobianApplyVolume(t))::value)
166  || (decltype(hasOldOrNewJacobianApplySkeleton(t))::value && !decltype(hasNewJacobianApplySkeleton(t))::value)
167  || (decltype(hasOldOrNewJacobianApplyBoundary(t))::value && !decltype(hasNewJacobianApplyBoundary(t))::value)),
168  std::false_type>::type
169  {
170  return std::false_type();
171  }
172  }
173  }
174 }
175 
176 
177 #endif
const P & p
Definition: constraints.hh:148
For backward compatibility – Do not use this!
Definition: adaptivity.hh:28
auto hasNewJacobianApplySkeleton
Definition: checklopinterface.hh:83
auto hasOldOrNewJacobianApplyBoundary
Definition: checklopinterface.hh:139
auto hasNewJacobianApplyBoundary
Definition: checklopinterface.hh:96
auto hasNewJacobianApplyVolumePostSkeleton
Definition: checklopinterface.hh:75
auto hasOldOrNewJacobianApplyVolume
Definition: checklopinterface.hh:110
auto hasNewJacobianApplyVolume
Definition: checklopinterface.hh:67
auto hasOldOrNewJacobianApplyVolumePostSkeleton
Definition: checklopinterface.hh:118
constexpr auto hasOldLOPInterface(T &t) -> typename std::enable_if<(decltype(hasOldOrNewJacobianApplyVolume(t))::value &&!decltype(hasNewJacobianApplyVolume(t))::value)||(decltype(hasOldOrNewJacobianApplyVolumePostSkeleton(t))::value &&!decltype(hasNewJacobianApplyVolumePostSkeleton(t))::value)||(decltype(hasOldOrNewJacobianApplySkeleton(t))::value &&!decltype(hasNewJacobianApplySkeleton(t))::value)||(decltype(hasOldOrNewJacobianApplyBoundary(t))::value &&!decltype(hasNewJacobianApplyBoundary(t))::value), std::true_type >::type
Definition: checklopinterface.hh:153
constexpr auto lambdaToTemplate(const T &t)
Definition: checklopinterface.hh:53
auto hasOldOrNewJacobianApplySkeleton
Definition: checklopinterface.hh:126
Definition: checklopinterface.hh:34
constexpr auto operator()(const A &p)
Definition: checklopinterface.hh:47
static const unsigned int value
Definition: gridfunctionspace/tags.hh:139