MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_FilteredAFactory_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 #ifndef MUELU_FILTEREDAFACTORY_DEF_HPP
47 #define MUELU_FILTEREDAFACTORY_DEF_HPP
48 
49 #include <Xpetra_Matrix.hpp>
50 #include <Xpetra_MatrixFactory.hpp>
51 
53 
54 #include "MueLu_FactoryManager.hpp"
55 #include "MueLu_Level.hpp"
56 #include "MueLu_MasterList.hpp"
57 #include "MueLu_Monitor.hpp"
58 
59 namespace MueLu {
60 
61  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
63  RCP<ParameterList> validParamList = rcp(new ParameterList());
64 
65 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
66  SET_VALID_ENTRY("filtered matrix: use lumping");
67  SET_VALID_ENTRY("filtered matrix: reuse graph");
68  SET_VALID_ENTRY("filtered matrix: reuse eigenvalue");
69 #undef SET_VALID_ENTRY
70 
71  validParamList->set< RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory of the matrix A used for filtering");
72  validParamList->set< RCP<const FactoryBase> >("Graph", Teuchos::null, "Generating factory for coalesced filtered graph");
73  validParamList->set< RCP<const FactoryBase> >("Filtering", Teuchos::null, "Generating factory for filtering boolean");
74 
75  return validParamList;
76  }
77 
78  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
80  Input(currentLevel, "A");
81  Input(currentLevel, "Filtering");
82  Input(currentLevel, "Graph");
83  }
84 
85  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
87  FactoryMonitor m(*this, "Matrix filtering", currentLevel);
88 
89  RCP<Matrix> A = Get< RCP<Matrix> >(currentLevel, "A");
90  if (Get<bool>(currentLevel, "Filtering") == false) {
91  GetOStream(Runtime0) << "Filtered matrix is not being constructed as no filtering is being done" << std::endl;
92  Set(currentLevel, "A", A);
93  return;
94  }
95 
96  const ParameterList& pL = GetParameterList();
97  bool lumping = pL.get<bool>("filtered matrix: use lumping");
98  if (lumping)
99  GetOStream(Runtime0) << "Lumping dropped entries" << std::endl;
100 
101  RCP<GraphBase> G = Get< RCP<GraphBase> >(currentLevel, "Graph");
102 
103  RCP<ParameterList> fillCompleteParams(new ParameterList);
104  fillCompleteParams->set("No Nonlocal Changes", true);
105 
106  RCP<Matrix> filteredA;
107  if (pL.get<bool>("filtered matrix: reuse graph")) {
108  filteredA = MatrixFactory::Build(A->getCrsGraph());
109  filteredA->resumeFill();
110 
111  BuildReuse(*A, *G, lumping, *filteredA);
112 
113  filteredA->fillComplete(fillCompleteParams);
114 
115  } else {
116  filteredA = MatrixFactory::Build(A->getRowMap(), A->getColMap(), A->getNodeMaxNumRowEntries());
117 
118  BuildNew(*A, *G, lumping, *filteredA);
119 
120  filteredA->fillComplete(A->getDomainMap(), A->getRangeMap(), fillCompleteParams);
121  }
122 
123  filteredA->SetFixedBlockSize(A->GetFixedBlockSize());
124 
125  if (pL.get<bool>("filtered matrix: reuse eigenvalue")) {
126  // Reuse max eigenvalue from A
127  // It is unclear what eigenvalue is the best for the smoothing, but we already may have
128  // the D^{-1}A estimate in A, may as well use it.
129  // NOTE: ML does that too
130  filteredA->SetMaxEigenvalueEstimate(A->GetMaxEigenvalueEstimate());
131  }
132 
133  Set(currentLevel, "A", filteredA);
134  }
135 
136 // Epetra's API allows direct access to row array.
137 // Tpetra's API does not, providing only ArrayView<const .>
138 // But in most situations we are currently interested in, it is safe to assume
139 // that the view is to the actual data. So this macro directs the code to do
140 // const_cast, and modify the entries directly. This allows us to avoid
141 // replaceLocalValues() call which is quite expensive due to all the searches.
142 #define ASSUME_DIRECT_ACCESS_TO_ROW
143 
144  // Both Epetra and Tpetra matrix-matrix multiply use the following trick:
145  // if an entry of the left matrix is zero, it does not compute or store the
146  // zero value.
147  //
148  // This trick allows us to bypass constructing a new matrix. Instead, we
149  // make a deep copy of the original one, and fill it in with zeros, which
150  // are ignored during the prolongator smoothing.
151  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
153  BuildReuse(const Matrix& A, const GraphBase& G, const bool lumping, Matrix& filteredA) const {
155 
156  size_t blkSize = A.GetFixedBlockSize();
157 
158  ArrayView<const LO> inds;
159  ArrayView<const SC> valsA;
160 #ifdef ASSUME_DIRECT_ACCESS_TO_ROW
161  ArrayView<SC> vals;
162 #else
163  Array<SC> vals;
164 #endif
165 
166  Array<char> filter( A.getColMap()->getNodeNumElements(), 0);
167 
168  size_t numGRows = G.GetNodeNumVertices();
169  for (size_t i = 0; i < numGRows; i++) {
170  // Set up filtering array
172  for (size_t j = 0; j < as<size_t>(indsG.size()); j++)
173  for (size_t k = 0; k < blkSize; k++)
174  filter[indsG[j]*blkSize+k] = 1;
175 
176  for (size_t k = 0; k < blkSize; k++) {
177  LO row = i*blkSize + k;
178 
179  A.getLocalRowView(row, inds, valsA);
180 
181  size_t nnz = inds.size();
182  if (nnz == 0)
183  continue;
184 
185 #ifdef ASSUME_DIRECT_ACCESS_TO_ROW
186  // Transform ArrayView<const SC> into ArrayView<SC>
187  ArrayView<const SC> vals1;
188  filteredA.getLocalRowView(row, inds, vals1);
189  vals = ArrayView<SC>(const_cast<SC*>(vals1.getRawPtr()), nnz);
190 
191  memcpy(vals.getRawPtr(), valsA.getRawPtr(), nnz*sizeof(SC));
192 #else
193  vals = Array<SC>(valsA);
194 #endif
195 
196  if (lumping == false) {
197  for (size_t j = 0; j < nnz; j++)
198  if (!filter[inds[j]])
199  vals[j] = zero;
200 
201  } else {
202  LO diagIndex = -1;
203  SC diagExtra = zero;
204 
205  for (size_t j = 0; j < nnz; j++) {
206  if (filter[inds[j]]) {
207  if (inds[j] == row) {
208  // Remember diagonal position
209  diagIndex = j;
210  }
211  continue;
212  }
213 
214  diagExtra += vals[j];
215 
216  vals[j] = zero;
217  }
218 
219  // Lump dropped entries
220  // NOTE
221  // * Does it make sense to lump for elasticity?
222  // * Is it different for diffusion and elasticity?
223  if (diagIndex != -1)
224  vals[diagIndex] += diagExtra;
225  }
226 
227 #ifndef ASSUME_DIRECT_ACCESS_TO_ROW
228  // Because we used a column map in the construction of the matrix
229  // we can just use insertLocalValues here instead of insertGlobalValues
230  filteredA.replaceLocalValues(row, inds, vals);
231 #endif
232  }
233 
234  // Reset filtering array
235  for (size_t j = 0; j < as<size_t> (indsG.size()); j++)
236  for (size_t k = 0; k < blkSize; k++)
237  filter[indsG[j]*blkSize+k] = 0;
238  }
239  }
240 
241  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
243  BuildNew(const Matrix& A, const GraphBase& G, const bool lumping, Matrix& filteredA) const {
245 
246  size_t blkSize = A.GetFixedBlockSize();
247 
248  ArrayView<const LO> indsA;
249  ArrayView<const SC> valsA;
250  Array<LO> inds;
251  Array<SC> vals;
252 
253  Array<char> filter(blkSize * G.GetImportMap()->getNodeNumElements(), 0);
254 
255  size_t numGRows = G.GetNodeNumVertices();
256  for (size_t i = 0; i < numGRows; i++) {
257  // Set up filtering array
259  for (size_t j = 0; j < as<size_t>(indsG.size()); j++)
260  for (size_t k = 0; k < blkSize; k++)
261  filter[indsG[j]*blkSize+k] = 1;
262 
263  for (size_t k = 0; k < blkSize; k++) {
264  LO row = i*blkSize + k;
265 
266  A.getLocalRowView(row, indsA, valsA);
267 
268  size_t nnz = indsA.size();
269  if (nnz == 0)
270  continue;
271 
272  inds.resize(indsA.size());
273  vals.resize(valsA.size());
274 
275  size_t numInds = 0;
276  if (lumping == false) {
277  for (size_t j = 0; j < nnz; j++)
278  if (filter[indsA[j]]) {
279  inds[numInds] = indsA[j];
280  vals[numInds] = valsA[j];
281  numInds++;
282  }
283 
284  } else {
285  LO diagIndex = -1;
286  SC diagExtra = zero;
287 
288  for (size_t j = 0; j < nnz; j++) {
289  if (filter[indsA[j]]) {
290  inds[numInds] = indsA[j];
291  vals[numInds] = valsA[j];
292 
293  // Remember diagonal position
294  if (inds[numInds] == row)
295  diagIndex = numInds;
296 
297  numInds++;
298 
299  } else {
300  diagExtra += valsA[j];
301  }
302  }
303 
304  // Lump dropped entries
305  // NOTE
306  // * Does it make sense to lump for elasticity?
307  // * Is it different for diffusion and elasticity?
308  if (diagIndex != -1)
309  vals[diagIndex] += diagExtra;
310  }
311  inds.resize(numInds);
312  vals.resize(numInds);
313 
314  // Because we used a column map in the construction of the matrix
315  // we can just use insertLocalValues here instead of insertGlobalValues
316  filteredA.insertLocalValues(row, inds, vals);
317  }
318 
319  // Reset filtering array
320  for (size_t j = 0; j < as<size_t> (indsG.size()); j++)
321  for (size_t k = 0; k < blkSize; k++)
322  filter[indsG[j]*blkSize+k] = 0;
323  }
324  }
325 
326 } //namespace MueLu
327 
328 #endif // MUELU_FILTEREDAFACTORY_DEF_HPP
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
T & get(const std::string &name, T def_value)
virtual size_t GetNodeNumVertices() const =0
Return number of vertices owned by the calling node.
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
Timer to be used in factories. Similar to Monitor but with additional timers.
size_type size() const
One-liner description of what is happening.
void Build(Level &currentLevel) const
Build method.
void BuildNew(const Matrix &A, const GraphBase &G, const bool lumping, Matrix &filteredA) const
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:99
void resize(size_type new_size, const value_type &x=value_type())
T * getRawPtr() const
MueLu representation of a graph.
#define SET_VALID_ENTRY(name)
virtual const RCP< const Map > GetImportMap() const =0
void BuildReuse(const Matrix &A, const GraphBase &G, const bool lumping, Matrix &filteredA) const
void DeclareInput(Level &currentLevel) const
Input.
virtual Teuchos::ArrayView< const LocalOrdinal > getNeighborVertices(LocalOrdinal v) const =0
Return the list of vertices adjacent to the vertex &#39;v&#39;.