FieldMatVec.hpp 12 KB
Newer Older
1
2
#pragma once

3
4
#include <algorithm>

5
#include <dune/common/diagonalmatrix.hh>
6
7
8
#include <dune/common/fmatrix.hh>
#include <dune/common/fvector.hh>

9
#include <dune/amdis/common/Math.hpp>
10
11
#include <dune/amdis/common/Concepts.hpp>
#include <dune/amdis/common/ScalarTypes.hpp>
12
13
#include <dune/amdis/operations/Arithmetic.hpp>
#include <dune/amdis/operations/MaxMin.hpp>
14
15
16

namespace AMDiS
{
Praetorius, Simon's avatar
Praetorius, Simon committed
17
18
19
20
  using Dune::FieldVector;
  using Dune::FieldMatrix;

  // some arithmetic operations with FieldVector
21
22
23

  template <class T, int N, class S,
    REQUIRES(Concepts::Arithmetic<S>) >
Praetorius, Simon's avatar
Praetorius, Simon committed
24
  FieldVector<T,N> operator*(FieldVector<T,N> v, S factor)
25
26
27
28
29
30
  {
    return v *= factor;
  }

  template <class S, class T, int N,
    REQUIRES(Concepts::Arithmetic<S>) >
Praetorius, Simon's avatar
Praetorius, Simon committed
31
  FieldVector<T,N> operator*(S factor, FieldVector<T,N> v)
32
33
34
35
36
37
  {
    return v *= factor;
  }

  template <class T, int N, class S,
    REQUIRES(Concepts::Arithmetic<S>) >
Praetorius, Simon's avatar
Praetorius, Simon committed
38
  FieldVector<T,N> operator/(FieldVector<T,N> v, S factor)
39
40
41
42
  {
    return v /= factor;
  }

43
44
  template <class T>
  FieldVector<T,1> operator*(FieldVector<T,1> const& v, FieldVector<T,1> const& w)
45
  {
46
    return {v[0] * w[0]};
47
48
  }

49
50
  template <class T, int N>
  FieldVector<T,N> operator*(FieldVector<T,1> const& factor, FieldVector<T,N> v)
51
  {
52
    return v *= factor[0];
53
54
  }

55
56
  template <class T, int N>
  FieldVector<T,N> operator*(FieldVector<T,N> v, FieldVector<T,1> const& factor)
57
  {
58
    return v *= factor[0];
59
60
  }

61
62
63
64
  // ----------------------------------------------------------------------------

  /// Cross-product a 2d-vector = orthogonal vector
  template <class T>
Praetorius, Simon's avatar
Praetorius, Simon committed
65
  FieldVector<T, 2> cross(FieldVector<T, 2> const& a)
66
67
68
69
70
71
  {
    return {{ a[1], -a[0] }};
  }

  /// Cross-product of two vectors (in 3d only)
  template <class T>
Praetorius, Simon's avatar
Praetorius, Simon committed
72
  FieldVector<T, 3> cross(FieldVector<T, 3> const& a, FieldVector<T, 3> const& b)
73
74
75
76
77
78
79
80
  {
    return {{ a[1]*b[2] - a[2]*b[1],
              a[2]*b[0] - a[0]*b[2],
              a[0]*b[1] - a[1]*b[0] }};
  }

  /// Dot product (vec1^T * vec2)
  template <class T, class S, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
81
  auto dot(FieldVector<T,N> const& vec1, FieldVector<S,N> const& vec2)
82
83
84
85
  {
    return vec1.dot(vec2);
  }

86
87
88
89
90
91
92
93
  template <class T, int N, int M,
    REQUIRES( N!=1 && M!=1 )>
  auto operator*(FieldVector<T,N> v, FieldVector<T,M> const& w)
  {
    static_assert(M == N, "Requires vectors of the same type!");
    return v.dot(w);
  }

94
95
96
97
98
  // ----------------------------------------------------------------------------

  namespace Impl
  {
    template <class T, int N, class Operation>
Praetorius, Simon's avatar
Praetorius, Simon committed
99
    T accumulate(FieldVector<T, N> const& x, Operation op)
100
101
102
103
104
105
106
    {
      T result = 0;
      for (int i = 0; i < N; ++i)
        result = op(result, x[i]);
      return result;
    }

107
108
109
110
111
112
113
114
115
    template <class T, int N, class Operation>
    T accumulate(FieldMatrix<T, 1, N> const& x, Operation op)
    {
      T result = 0;
      for (int i = 0; i < N; ++i)
        result = op(result, x[0][i]);
      return result;
    }

116
117
118
119
  } // end namespace Impl

  /// Sum of vector entires.
  template <class T, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
120
  T sum(FieldVector<T, N> const& x)
121
  {
122
    return Impl::accumulate(x, Operation::Plus{});
123
124
  }

125
126
127
128
129
130
  template <class T, int N>
  T sum(FieldMatrix<T, 1, N> const& x)
  {
    return Impl::accumulate(x, Operation::Plus{});
  }

131
132
133

  /// Dot-product with the vector itself
  template <class T, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
134
  auto unary_dot(FieldVector<T, N> const& x)
135
  {
136
    auto op = [](auto const& a, auto const& b) { return a + Math::sqr(std::abs(b)); };
137
138
139
    return Impl::accumulate(x, op);
  }

140
141
142
143
144
145
146
  template <class T, int N>
  auto unary_dot(FieldMatrix<T, 1, N> const& x)
  {
    auto op = [](auto const& a, auto const& b) { return a + Math::sqr(std::abs(b)); };
    return Impl::accumulate(x, op);
  }

147
148
  /// Maximum over all vector entries
  template <class T, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
149
  auto max(FieldVector<T, N> const& x)
150
  {
151
    return Impl::accumulate(x, Operation::Max{});
152
153
  }

154
155
156
157
158
159
  template <class T, int N>
  auto max(FieldMatrix<T, 1, N> const& x)
  {
    return Impl::accumulate(x, Operation::Max{});
  }

160
161
  /// Minimum over all vector entries
  template <class T, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
162
  auto min(FieldVector<T, N> const& x)
163
  {
164
    return Impl::accumulate(x, Operation::Min{});
165
166
  }

167
168
169
170
171
172
  template <class T, int N>
  auto min(FieldMatrix<T, 1, N> const& x)
  {
    return Impl::accumulate(x, Operation::Min{});
  }

173
174
  /// Maximum of the absolute values of vector entries
  template <class T, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
175
  auto abs_max(FieldVector<T, N> const& x)
176
  {
177
    return Impl::accumulate(x, Operation::AbsMax{});
178
179
  }

180
181
182
183
184
185
  template <class T, int N>
  auto abs_max(FieldMatrix<T, 1, N> const& x)
  {
    return Impl::accumulate(x, Operation::AbsMax{});
  }

186
187
  /// Minimum of the absolute values of vector entries
  template <class T, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
188
  auto abs_min(FieldVector<T, N> const& x)
189
  {
190
    return Impl::accumulate(x, Operation::AbsMin{});
191
192
  }

193
194
195
196
197
198
  template <class T, int N>
  auto abs_min(FieldMatrix<T, 1, N> const& x)
  {
    return Impl::accumulate(x, Operation::AbsMin{});
  }

199
200
201
202
203
204
  // ----------------------------------------------------------------------------

  /** \ingroup vector_norms
   *  \brief The 1-norm of a vector = sum_i |x_i|
   **/
  template <class T, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
205
  auto one_norm(FieldVector<T, N> const& x)
206
207
208
209
210
  {
    auto op = [](auto const& a, auto const& b) { return a + std::abs(b); };
    return Impl::accumulate(x, op);
  }

211
212
213
214
215
216
217
  template <class T, int N>
  auto one_norm(FieldMatrix<T, 1, N> const& x)
  {
    auto op = [](auto const& a, auto const& b) { return a + std::abs(b); };
    return Impl::accumulate(x, op);
  }

218
219
220
221
  /** \ingroup vector_norms
   *  \brief The euklidean 2-norm of a vector = sqrt( sum_i |x_i|^2 )
   **/
  template <class T, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
222
  auto two_norm(FieldVector<T, N> const& x)
223
224
225
226
  {
    return std::sqrt(unary_dot(x));
  }

227
228
229
230
231
232
  template <class T, int N>
  auto two_norm(FieldMatrix<T, 1, N> const& x)
  {
    return std::sqrt(unary_dot(x));
  }

233
234
235
236
  /** \ingroup vector_norms
   *  \brief The p-norm of a vector = ( sum_i |x_i|^p )^(1/p)
   **/
  template <int p, class T, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
237
  auto p_norm(FieldVector<T, N> const& x)
238
239
240
241
242
  {
    auto op = [](auto const& a, auto const& b) { return a + Math::pow<p>(std::abs(b)); };
    return std::pow( Impl::accumulate(x, op), 1.0/p );
  }

243
244
245
246
247
248
249
  template <int p, class T, int N>
  auto p_norm(FieldMatrix<T, 1, N> const& x)
  {
    auto op = [](auto const& a, auto const& b) { return a + Math::pow<p>(std::abs(b)); };
    return std::pow( Impl::accumulate(x, op), 1.0/p );
  }

250
251
252
253
  /** \ingroup vector_norms
   *  \brief The infty-norm of a vector = max_i |x_i| = alias for \ref abs_max
   **/
  template <class T, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
254
  auto infty_norm(FieldVector<T, N> const& x)
255
256
257
258
  {
    return abs_max(x);
  }

259
260
261
262
263
264
  template <class T, int N>
  auto infty_norm(FieldMatrix<T, 1, N> const& x)
  {
    return abs_max(x);
  }

265
266
267
268
  // ----------------------------------------------------------------------------

  /// The euklidean distance between two vectors = |lhs-rhs|_2
  template <class T, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
269
  T distance(FieldVector<T, N> const& lhs, FieldVector<T, N> const& rhs)
270
271
272
  {
    T result = 0;
    for (int i = 0; i < N; ++i)
273
      result += Math::sqr(lhs[i] - rhs[i]);
274
275
276
277
278
279
280
    return std::sqrt(result);
  }

  // ----------------------------------------------------------------------------

  /// Outer product (vec1 * vec2^T)
  template <class T, class S, int N, int M, int K>
Praetorius, Simon's avatar
Praetorius, Simon committed
281
  auto outer(FieldMatrix<T,N,K> const& vec1, FieldMatrix<S,M,K> const& vec2)
282
  {
Praetorius, Simon's avatar
Praetorius, Simon committed
283
    using result_type = FieldMatrix<decltype( std::declval<T>() * std::declval<S>() ), N, M>;
284
285
286
287
288
289
290
291
292
293
    result_type mat;
    for (int i = 0; i < N; ++i)
      for (int j = 0; j < M; ++j)
        mat[i][j] = vec1[i].dot(vec2[j]);
    return mat;
  }

  // ----------------------------------------------------------------------------

  template <class T>
Praetorius, Simon's avatar
Praetorius, Simon committed
294
  T det(FieldMatrix<T, 0, 0> const& /*mat*/)
295
296
297
298
299
300
  {
    return 0;
  }

  /// Determinant of a 1x1 matrix
  template <class T>
Praetorius, Simon's avatar
Praetorius, Simon committed
301
  T det(FieldMatrix<T, 1, 1> const& mat)
302
303
304
305
306
307
  {
    return mat[0][0];
  }

  /// Determinant of a 2x2 matrix
  template <class T>
Praetorius, Simon's avatar
Praetorius, Simon committed
308
  T det(FieldMatrix<T, 2, 2> const& mat)
309
310
311
312
313
314
  {
    return mat[0][0]*mat[1][1] - mat[0][1]*mat[1][0];
  }

  /// Determinant of a 3x3 matrix
  template <class T>
Praetorius, Simon's avatar
Praetorius, Simon committed
315
  T det(FieldMatrix<T, 3, 3> const& mat)
316
317
318
319
320
321
322
  {
    return mat[0][0]*mat[1][1]*mat[2][2] + mat[0][1]*mat[1][2]*mat[2][0] + mat[0][2]*mat[1][0]*mat[2][1]
        - (mat[0][2]*mat[1][1]*mat[2][0] + mat[0][1]*mat[1][0]*mat[2][2] + mat[0][0]*mat[1][2]*mat[2][1]);
  }

  /// Determinant of a NxN matrix
  template <class T,  int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
323
  T det(FieldMatrix<T, N, N> const& mat)
324
325
326
327
328
329
  {
    return mat.determinant();
  }

  /// Return the inverse of the matrix `mat`
  template <class T, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
330
  auto inv(FieldMatrix<T, N, N> mat)
331
332
333
334
335
336
337
  {
    mat.invert();
    return mat;
  }

  /// Solve the linear system A*x = b
  template <class T, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
338
  void solve(FieldMatrix<T, N, N> const& A,  FieldVector<T, N>& x,  FieldVector<T, N> const& b)
339
340
341
342
343
344
345
  {
    A.solve(x, b);
  }


  /// Gramian determinant = sqrt( det( DT^T * DF ) )
  template <class T, int N, int M>
Praetorius, Simon's avatar
Praetorius, Simon committed
346
  T gramian(FieldMatrix<T,N,M> const& DF)
347
348
349
350
351
352
353
  {
    using std::sqrt;
    return sqrt( det(outer(DF, DF)) );
  }

  /// Gramian determinant, specialization for 1 column matrices
  template <class T, int M>
Praetorius, Simon's avatar
Praetorius, Simon committed
354
  T gramian(FieldMatrix<T, 1, M> const& DF)
355
356
357
358
359
  {
    using std::sqrt;
    return sqrt(dot(DF[0], DF[0]));
  }

360
361
362
  // ----------------------------------------------------------------------------
  // some arithmetic operations with FieldMatrix

363
  template <class T, int M, int N>
Praetorius, Simon's avatar
Praetorius, Simon committed
364
  FieldMatrix<T,N,M> trans(FieldMatrix<T, M, N> const& A)
365
  {
Praetorius, Simon's avatar
Praetorius, Simon committed
366
    FieldMatrix<T,N,M> At;
367
368
369
370
371
372
373
374
    for (int i = 0; i < M; ++i)
      for (int j = 0; j < N; ++j)
        At[j][i] = A[i][j];

    return At;
  }


375
376
377
  template <class T, int M, int N, class S,
    REQUIRES(Concepts::Arithmetic<S>) >
  FieldMatrix<T,M,N> operator*(S scalar, FieldMatrix<T, M, N> A)
378
379
380
381
  {
    return A *= scalar;
  }

382
383
384
  template <class T, int M, int N, class S,
    REQUIRES(Concepts::Arithmetic<S>) >
  FieldMatrix<T,M,N> operator*(FieldMatrix<T, M, N> A, S scalar)
385
386
387
388
  {
    return A *= scalar;
  }

389
390
391
  template <class T, int M, int N, class S,
    REQUIRES(Concepts::Arithmetic<S>) >
  FieldMatrix<T,M,N> operator/(FieldMatrix<T, M, N> A, S scalar)
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  {
    return A /= scalar;
  }

  template <class T, int M, int N>
  FieldMatrix<T,M,N> operator+(FieldMatrix<T, M, N> A, FieldMatrix<T, M, N> const& B)
  {
    return A += B;
  }

  template <class T, int M, int N>
  FieldMatrix<T,M,N> operator-(FieldMatrix<T, M, N> A, FieldMatrix<T, M, N> const& B)
  {
    return A -= B;
  }


  template <class T, int N, int M>
  FieldVector<T,N> operator*(FieldMatrix<T,N,M> const& mat, FieldVector<T,M> const& vec)
  {
    return Dune::FMatrixHelp::mult(mat, vec);
  }



417
  template <class T, int M, int N, int L>
Praetorius, Simon's avatar
Praetorius, Simon committed
418
  FieldMatrix<T,M,N> multiplies(FieldMatrix<T, M, L> const& A,  FieldMatrix<T, L, N> const& B)
419
420
421
422
423
424
425
  {
    return A.rightmultiplyany(B);
  }



  template <class T, int M, int N, int L>
Praetorius, Simon's avatar
Praetorius, Simon committed
426
  FieldMatrix<T,M,N> multiplies_AtB(FieldMatrix<T, L, M> const& A,  FieldMatrix<T, N, L> const& B)
427
  {
Praetorius, Simon's avatar
Praetorius, Simon committed
428
    FieldMatrix<T,M,N> C;
429
430
431
432
433
434
435
436
437
438
439
440

    for (int m = 0; m < M; ++m) {
      for (int n = 0; n < N; ++n) {
        C[m][n] = 0;
        for (int l = 0; l < L; ++l)
          C[m][n] += A[l][m] * B[n][l];
      }
    }
    return C;
  }

  template <class T, int M, int N, int L>
Praetorius, Simon's avatar
Praetorius, Simon committed
441
  FieldMatrix<T,M,N> multiplies_ABt(FieldMatrix<T, M, L> const& A,  FieldMatrix<T, N, L> const& B)
442
  {
Praetorius, Simon's avatar
Praetorius, Simon committed
443
    FieldMatrix<T,M,N> C;
444
445
446
447
448
449
450
451
452
453
454
455

    for (int m = 0; m < M; ++m) {
      for (int n = 0; n < N; ++n) {
        C[m][n] = 0;
        for (int l = 0; l < L; ++l)
          C[m][n] += A[m][l] * B[n][l];
      }
    }
    return C;
  }

  template <class T, int M, int N, int L>
Praetorius, Simon's avatar
Praetorius, Simon committed
456
  FieldMatrix<T,M,N>& multiplies_ABt(FieldMatrix<T, M, L> const& A,  FieldMatrix<T, N, L> const& B, FieldMatrix<T,M,N>& C)
457
458
459
460
461
462
463
464
465
466
467
  {
    for (int m = 0; m < M; ++m) {
      for (int n = 0; n < N; ++n) {
        C[m][n] = 0;
        for (int l = 0; l < L; ++l)
          C[m][n] += A[m][l] * B[n][l];
      }
    }
    return C;
  }

468
  template <class T, int M, int N>
469
  FieldMatrix<T,M,N>& multiplies_ABt(FieldMatrix<T, M, N> const& A,  Dune::DiagonalMatrix<T, N> const& B, FieldMatrix<T,M,N>& C)
470
471
472
473
474
475
476
477
478
  {
    for (int m = 0; m < M; ++m) {
      for (int n = 0; n < N; ++n) {
        C[m][n] = A[m][n] * B.diagonal(n);
      }
    }
    return C;
  }

479
} // end namespace AMDiS