Discontinuous Galerkin Library
#include "dg/algorithm.h"
precond.h
Go to the documentation of this file.
1#pragma once
2
3#include <vector>
4
5namespace dg
6{
7
8namespace create
9{
10
12namespace detail
13{
14template<class T>
15void sparsify( cusp::array1d<int, cusp::host_memory>& row_offsets,
16 cusp::array1d<int, cusp::host_memory>& column_indices,
17 cusp::array1d<T, cusp::host_memory>& values,
18 const int i,
19 const thrust::host_vector<T>& zw,
20 const std::vector<int>& iz_zw,
21 unsigned nnzmax, T threshold)
22{
23 //std::cout << "Entries in zw\n";
24 //for( auto idx : iz_zw)
25 // std::cout << "[ "<<idx << " "<<zw[idx]<<"]\n";
26
27 // Take zw and write it into z modulo the drop rules
28 std::vector<std::pair<double, int>> pairs;
29 std::vector<std::pair<int, double>> accept;
30 // 1. Always take the diagonal element
31 accept.push_back( {i, zw[i]});
32 for( auto idx : iz_zw)
33 if( idx != i) //we already have diagonal
34 pairs.push_back( { zw[idx], idx});
35 //std::cout << "Pairs \n";
36 //for( auto pair : pairs)
37 // std::cout << pair.first << " "<<pair.second<<std::endl;
38 std::sort( pairs.begin(), pairs.end(), std::greater<>());
39 //std::cout << "Pairs after sort\n";
40 // 2. Take nnzmax-1 largest values of zw: sort zw by size
41 // but 3. only if entry is greater than threshold
42 for( int k=0; k<(int)nnzmax-1; k++)
43 {
44 if( k < (int)pairs.size() && fabs(pairs[k].first) > threshold)
45 {
46 //std::cout << pairs[k].first << " "<<pairs[k].second<<std::endl;
47 accept.push_back({pairs[k].second, pairs[k].first});
48 }
49 }
50 // sort by index
51 std::sort( accept.begin(), accept.end());
52 //std::cout << "Accepted entries in zw\n";
53 //for( auto pair : accept)
54 // std::cout << "[ "<<pair.first << " "<<pair.second<<"]\n";
55
56
57 //write into matrix
58 row_offsets.push_back(row_offsets[i]);
59 for( auto pair : accept)
60 {
61 //std::cout<< "Entry "<<pair.first<<" "<<pair.second<<"\n";
62 column_indices.push_back( pair.first);
63 values.push_back( pair.second);
64 row_offsets[i+1]++;
65 }
66}
67}
69
92template<class T>
94 const cusp::csr_matrix<int, T, cusp::host_memory>& a,
95 cusp::csr_matrix<int, T, cusp::host_memory>& s,
96 thrust::host_vector<T>& d,
97 const thrust::host_vector<T>& weights,
98 unsigned nnzmax,
99 T threshold)
100{
101 unsigned n = a.num_rows;
102 //assert( a.num_rows == a.num_cols);
103
104 d.resize( n, 0.);
105
106 // Init z_0 = e_0 and p_0 = a_{11}
107 for( int j = a.row_offsets[0]; j<a.row_offsets[1]; j++)
108 {
109 if( a.column_indices[j] == 0)
110 d[0] = a.values[j]*weights[0];
111 }
112 if( fabs( d[0] ) < threshold)
113 d[0] = threshold;
114 //std::cout << "first diagonal "<<d[0]<<"\n";
115 cusp::array1d<int, cusp::host_memory> row_offsets, column_indices;
116 cusp::array1d<T, cusp::host_memory> values;
117
118 row_offsets.push_back(0);
119 row_offsets.push_back(1);
120 column_indices.push_back( 0);
121 values.push_back( 1.0);
122
123 // Main loop
124 for( int i = 1; i<(int)n; i++)
125 {
126 thrust::host_vector<T> zw( n, 0.);
127 std::vector<int> iz_zw; // flags nonzeros in zw
128 //zw = e_i
129 zw[i] = 1.0;
130 iz_zw.push_back(i);
131 std::vector<int> s;
132 // get column indices of row i that are smaller than i
133 for( int k = a.row_offsets[i]; k<a.row_offsets[i+1]; k++)
134 {
135 if( a.column_indices[k] < i )
136 s.push_back( a.column_indices[k]);
137 }
138 //std::cout << "Loop i = "<<i<<"\n";
139 //std::cout<< "s\n";
140 //for( auto idx : s)
141 // std::cout << idx << " \n";
142 while( !s.empty())
143 {
144 auto it = std::min_element( s.begin(), s.end());
145 int j = *it; // j < i in all cases
146 s.erase( it);
147 // A_j * zw
148 d[i] = 0.0;
149 for( int k = a.row_offsets[j]; k<a.row_offsets[j+1]; k++)
150 {
151 //std::cout << "Multiply k " << k<<" "<<a.column_indices[k]<<" "<< a.values[k]<<" j = "<< j << " weights "<<weights[j]<<" zw "<<zw[a.column_indices[k]]<<"\n";
152 d[i] += weights[j]*a.values[k]*zw[ a.column_indices[k]];
153 }
154 //std::cout << "d[i] "<<d[i]<<"\n";
155 T alpha = d[i]/d[j];
156 //std::cout << "alpha ij "<< i <<" "<<j<<" "<<alpha<<"\n";
157 if( fabs( alpha) > threshold)
158 {
159 for( int k = row_offsets[j]; k<row_offsets[j+1]; k++)
160 {
161 int zkk = column_indices[k];
162 //std::cout << "col = "<<zkk<<std::endl;
163 zw[ zkk] -= alpha * values[k];
164 // flag a new nonzero in zw if necessary
165 if (std::find(iz_zw.begin(), iz_zw.end(), zkk) == iz_zw.end()) {
166 iz_zw.push_back( zkk);
167 }
168 //std::cout << "col = "<<zkk<<std::endl;
169 // add indices to set of dot products to compute
170 for( int l = a.row_offsets[zkk]; l < a.row_offsets[zkk+1]; l++)
171 {
172 //std::cout << "l = "<<l<<" "<<a.row_offsets[zkk]<< " "<<a.row_offsets[zkk+1]<<std::endl;
173 if ( (std::find(s.begin(), s.end(), l) == s.end()) && (j<l) && (l < i) ) {
174 s.push_back( l);
175 }
176 }
177 //std::cout << "col = "<<zkk<<std::endl;
178 }
179 }
180 }
181 d[i] = 0.0;
182 for( int k = a.row_offsets[i]; k<a.row_offsets[i+1]; k++)
183 d[i] += a.values[k]*zw[ a.column_indices[k]]*weights[i];
184 if( fabs(d[i]) < threshold)
185 d[i] = threshold;
186 //std::cout << "d[i] "<<d[i]<<"\n";
187 //std::cout << "zw \n";
188 //for(unsigned i=0; i<zw.size(); i++)
189 // std::cout << zw[i]<<"\n";
190 // Apply drop rule to zw:
191 detail::sparsify( row_offsets, column_indices, values, i, zw, iz_zw, nnzmax, threshold);
192 }
193 s.resize( n, n, values.size());
194 s.column_indices = column_indices;
195 s.row_offsets = row_offsets;
196 s.values = values;
197
198
199}
200} //namespace create
201
202}//namespace dg
MPI_Vector< thrust::host_vector< real_type > > weights(const aRealMPITopology2d< real_type > &g)
Nodal weight coefficients.
Definition: mpi_weights.h:22
void sainv_precond(const cusp::csr_matrix< int, T, cusp::host_memory > &a, cusp::csr_matrix< int, T, cusp::host_memory > &s, thrust::host_vector< T > &d, const thrust::host_vector< T > &weights, unsigned nnzmax, T threshold)
Left looking sparse inverse preconditioner for self-adjoint positive definit matrices.
Definition: precond.h:93
This is the namespace for all functions and classes defined and used by the discontinuous Galerkin li...