Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_LUSolver.H
Go to the documentation of this file.
1#ifndef AMREX_LU_SOLVER_H_
2#define AMREX_LU_SOLVER_H_
3#include <AMReX_Config.H>
4
5#include <AMReX_Algorithm.H>
6#include <AMReX_Array.H>
7#include <cmath>
8#include <limits>
9
10namespace amrex {
11
12// https://en.wikipedia.org/wiki/LU_decomposition
13
14template <int N, typename T>
16{
17public:
18
19 static constexpr int size = N;
20
21 LUSolver () = default;
22
25
27
29 void operator() (T* AMREX_RESTRICT x, T const* AMREX_RESTRICT b) const
30 {
31 for (int i = 0; i < N; ++i) {
32 x[i] = b[m_piv(i)];
33 for (int k = 0; k < i; ++k) {
34 x[i] -= m_mat(i,k) * x[k];
35 }
36 }
37
38 for (int i = N-1; i >= 0; --i) {
39 for (int k = i+1; k < N; ++k) {
40 x[i] -= m_mat(i,k) * x[k];
41 }
42 x[i] *= m_mat(i,i);
43 }
44 }
45
46 [[nodiscard]] AMREX_GPU_HOST_DEVICE
47 Array2D<T,0,N-1,0,N-1,Order::C> invert () const
48 {
49 Array2D<T,0,N-1,0,N-1,Order::C> IA;
50 for (int j = 0; j < N; ++j) {
51 for (int i = 0; i < N; ++i) {
52 IA(i,j) = (m_piv(i) == j) ? T(1.0) : T(0.0);
53 for (int k = 0; k < i; ++k) {
54 IA(i,j) -= m_mat(i,k) * IA(k,j);
55 }
56 }
57 for (int i = N-1; i >= 0; --i) {
58 for (int k = i+1; k < N; ++k) {
59 IA(i,j) -= m_mat(i,k) * IA(k,j);
60 }
61 IA(i,j) *= m_mat(i,i);
62 }
63 }
64 return IA;
65 }
66
67 [[nodiscard]] AMREX_GPU_HOST_DEVICE
68 T determinant () const
69 {
70 T det = m_mat(0,0);
71 for (int i = 1; i < N; ++i) {
72 det *= m_mat(i,i);
73 }
74 det = T(1.0) / det;
75 return (m_npivs % 2 == 0) ? det : -det;
76 }
77
78private:
79
81 void define_innard ();
82
83 Array2D<T, 0, N-1, 0, N-1, Order::C> m_mat;
84 Array1D<int, 0, N-1> m_piv;
85 int m_npivs = 0;
86};
87
88template <int N, typename T>
91 : m_mat(a_mat)
92{
93 define_innard();
94}
95
96template <int N, typename T>
98{
99 m_mat = a_mat;
100 define_innard();
101}
102
103template <int N, typename T>
106{
107 static_assert(N > 1);
108 static_assert(std::is_floating_point_v<T>);
109
110 for (int i = 0; i < N; ++i) { m_piv(i) = i; }
111 m_npivs = 0;
112
113 for (int i = 0; i < N; ++i) {
114 T maxA = 0;
115 int imax = i;
116
117 for (int k = i; k < N; ++k) {
118 auto const absA = std::abs(m_mat(k,i));
119 if (absA > maxA) {
120 maxA = absA;
121 imax = k;
122 }
123 }
124
125 if (maxA < std::numeric_limits<T>::min()) {
126 amrex::Abort("LUSolver: matrix is degenerate");
127 }
128
129 if (imax != i) {
130 amrex::Swap(m_piv(i), m_piv(imax));
131 for (int j = 0; j < N; ++j) {
132 amrex::Swap(m_mat(i,j), m_mat(imax,j));
133 }
134 ++m_npivs;
135 }
136
137 for (int j = i+1; j < N; ++j) {
138 m_mat(j,i) /= m_mat(i,i);
139 for (int k = i+1; k < N; ++k) {
140 m_mat(j,k) -= m_mat(j,i) * m_mat(i,k);
141 }
142 }
143 }
144
145 for (int i = 0; i < N; ++i) {
146 m_mat(i,i) = T(1) / m_mat(i,i);
147 }
148}
149
150}
151
152#endif
#define AMREX_FORCE_INLINE
Definition AMReX_Extension.H:119
#define AMREX_RESTRICT
Definition AMReX_Extension.H:32
#define AMREX_GPU_HOST_DEVICE
Definition AMReX_GpuQualifiers.H:20
Definition AMReX_LUSolver.H:16
static constexpr int size
Definition AMReX_LUSolver.H:19
__host__ __device__ LUSolver(Array2D< T, 0, N-1, 0, N-1, Order::C > const &a_mat)
Definition AMReX_LUSolver.H:90
__host__ __device__ void operator()(T *__restrict__ x, T const *__restrict__ b) const
Definition AMReX_LUSolver.H:29
void define(Array2D< T, 0, N-1, 0, N-1, Order::C > const &a_mat)
Definition AMReX_LUSolver.H:97
__host__ __device__ Array2D< T, 0, N-1, 0, N-1, Order::C > invert() const
Definition AMReX_LUSolver.H:47
__host__ __device__ T determinant() const
Definition AMReX_LUSolver.H:68
LUSolver()=default
Definition AMReX_Amr.cpp:50
__host__ __device__ void Swap(T &t1, T &t2) noexcept
Definition AMReX_Algorithm.H:94
void Abort(const std::string &msg)
Print out message to cerr and exit via abort().
Definition AMReX.cpp:241
const int[]
Definition AMReX_BLProfiler.cpp:1664
A GPU-compatible one-dimensional array.
Definition AMReX_Array.H:204
A GPU-compatible two-dimensional array.
Definition AMReX_Array.H:357