MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_Maxwell_Utils_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_MAXWELL_UTILS_DEF_HPP
47 #define MUELU_MAXWELL_UTILS_DEF_HPP
48 
49 #include <sstream>
50 
51 #include "MueLu_ConfigDefs.hpp"
52 
53 #include "Xpetra_Map.hpp"
55 #include "Xpetra_MatrixUtils.hpp"
56 
58 
59 #include "MueLu_Level.hpp"
60 #include "MueLu_ThresholdAFilterFactory.hpp"
61 #include "MueLu_Utilities.hpp"
62 #include "MueLu_RAPFactory.hpp"
63 
64 namespace MueLu {
65 
66 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
68  RCP<Matrix>& D0_Matrix_,
69  magnitudeType rowSumTol,
70  bool useKokkos_,
71  Kokkos::View<bool*, typename Node::device_type::memory_space>& BCrowsKokkos_,
72  Kokkos::View<bool*, typename Node::device_type::memory_space>& BCcolsKokkos_,
73  Kokkos::View<bool*, typename Node::device_type::memory_space>& BCdomainKokkos_,
74  int& BCedges_,
75  int& BCnodes_,
76  Teuchos::ArrayRCP<bool>& BCrows_,
77  Teuchos::ArrayRCP<bool>& BCcols_,
78  Teuchos::ArrayRCP<bool>& BCdomain_,
79  bool& allEdgesBoundary_,
80  bool& allNodesBoundary_) {
81  // clean rows associated with boundary conditions
82  // Find rows with only 1 or 2 nonzero entries, record them in BCrows_.
83  // BCrows_[i] is true, iff i is a boundary row
84  // BCcols_[i] is true, iff i is a boundary column
85  int BCedgesLocal = 0;
86  int BCnodesLocal = 0;
87  if (useKokkos_) {
88  BCrowsKokkos_ = Utilities::DetectDirichletRows_kokkos(*SM_Matrix_, Teuchos::ScalarTraits<magnitudeType>::eps(), /*count_twos_as_dirichlet=*/true);
89 
90  if (rowSumTol > 0.)
91  Utilities::ApplyRowSumCriterion(*SM_Matrix_, rowSumTol, BCrowsKokkos_);
92 
93  BCcolsKokkos_ = Kokkos::View<bool*, typename Node::device_type>(Kokkos::ViewAllocateWithoutInitializing("dirichletCols"), D0_Matrix_->getColMap()->getLocalNumElements());
94  BCdomainKokkos_ = Kokkos::View<bool*, typename Node::device_type>(Kokkos::ViewAllocateWithoutInitializing("dirichletDomains"), D0_Matrix_->getDomainMap()->getLocalNumElements());
95  Utilities::DetectDirichletColsAndDomains(*D0_Matrix_, BCrowsKokkos_, BCcolsKokkos_, BCdomainKokkos_);
96 
97  auto BCrowsKokkos = BCrowsKokkos_;
98  Kokkos::parallel_reduce(
99  BCrowsKokkos_.size(), KOKKOS_LAMBDA(int i, int& sum) {
100  if (BCrowsKokkos(i))
101  ++sum;
102  },
103  BCedgesLocal);
104 
105  auto BCdomainKokkos = BCdomainKokkos_;
106  Kokkos::parallel_reduce(
107  BCdomainKokkos_.size(), KOKKOS_LAMBDA(int i, int& sum) {
108  if (BCdomainKokkos(i))
109  ++sum;
110  },
111  BCnodesLocal);
112  } else {
113  BCrows_ = Teuchos::arcp_const_cast<bool>(Utilities::DetectDirichletRows(*SM_Matrix_, Teuchos::ScalarTraits<magnitudeType>::eps(), /*count_twos_as_dirichlet=*/true));
114 
115  if (rowSumTol > 0.)
116  Utilities::ApplyRowSumCriterion(*SM_Matrix_, rowSumTol, BCrows_);
117 
118  BCcols_.resize(D0_Matrix_->getColMap()->getLocalNumElements());
119  BCdomain_.resize(D0_Matrix_->getDomainMap()->getLocalNumElements());
120  Utilities::DetectDirichletColsAndDomains(*D0_Matrix_, BCrows_, BCcols_, BCdomain_);
121 
122  for (auto it = BCrows_.begin(); it != BCrows_.end(); ++it)
123  if (*it)
124  BCedgesLocal += 1;
125  for (auto it = BCdomain_.begin(); it != BCdomain_.end(); ++it)
126  if (*it)
127  BCnodesLocal += 1;
128  }
129 
130  MueLu_sumAll(SM_Matrix_->getRowMap()->getComm(), BCedgesLocal, BCedges_);
131  MueLu_sumAll(SM_Matrix_->getRowMap()->getComm(), BCnodesLocal, BCnodes_);
132 
133  allEdgesBoundary_ = Teuchos::as<Xpetra::global_size_t>(BCedges_) >= D0_Matrix_->getRangeMap()->getGlobalNumElements();
134  allNodesBoundary_ = Teuchos::as<Xpetra::global_size_t>(BCnodes_) >= D0_Matrix_->getDomainMap()->getGlobalNumElements();
135 }
136 
137 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
139  RCP<Matrix>& D0_Matrix_,
140  magnitudeType rowSumTol,
141  Kokkos::View<bool*, typename Node::device_type::memory_space>& BCrowsKokkos_,
142  Kokkos::View<bool*, typename Node::device_type::memory_space>& BCcolsKokkos_,
143  Kokkos::View<bool*, typename Node::device_type::memory_space>& BCdomainKokkos_,
144  int& BCedges_,
145  int& BCnodes_,
146  bool& allEdgesBoundary_,
147  bool& allNodesBoundary_) {
148  // clean rows associated with boundary conditions
149  // Find rows with only 1 or 2 nonzero entries, record them in BCrows_.
150  // BCrows_[i] is true, iff i is a boundary row
151  // BCcols_[i] is true, iff i is a boundary column
152  int BCedgesLocal = 0;
153  int BCnodesLocal = 0;
154  {
155  BCrowsKokkos_ = Utilities::DetectDirichletRows_kokkos(*SM_Matrix_, Teuchos::ScalarTraits<magnitudeType>::eps(), /*count_twos_as_dirichlet=*/true);
156 
157  if (rowSumTol > 0.)
158  Utilities::ApplyRowSumCriterion(*SM_Matrix_, rowSumTol, BCrowsKokkos_);
159 
160  BCcolsKokkos_ = Kokkos::View<bool*, typename Node::device_type>(Kokkos::ViewAllocateWithoutInitializing("dirichletCols"), D0_Matrix_->getColMap()->getLocalNumElements());
161  BCdomainKokkos_ = Kokkos::View<bool*, typename Node::device_type>(Kokkos::ViewAllocateWithoutInitializing("dirichletDomains"), D0_Matrix_->getDomainMap()->getLocalNumElements());
162  Utilities::DetectDirichletColsAndDomains(*D0_Matrix_, BCrowsKokkos_, BCcolsKokkos_, BCdomainKokkos_);
163 
164  auto BCrowsKokkos = BCrowsKokkos_;
165  Kokkos::parallel_reduce(
166  BCrowsKokkos_.size(), KOKKOS_LAMBDA(int i, int& sum) {
167  if (BCrowsKokkos(i))
168  ++sum;
169  },
170  BCedgesLocal);
171 
172  auto BCdomainKokkos = BCdomainKokkos_;
173  Kokkos::parallel_reduce(
174  BCdomainKokkos_.size(), KOKKOS_LAMBDA(int i, int& sum) {
175  if (BCdomainKokkos(i))
176  ++sum;
177  },
178  BCnodesLocal);
179  }
180 
181  MueLu_sumAll(SM_Matrix_->getRowMap()->getComm(), BCedgesLocal, BCedges_);
182  MueLu_sumAll(SM_Matrix_->getRowMap()->getComm(), BCnodesLocal, BCnodes_);
183 
184  allEdgesBoundary_ = Teuchos::as<Xpetra::global_size_t>(BCedges_) >= D0_Matrix_->getRangeMap()->getGlobalNumElements();
185  allNodesBoundary_ = Teuchos::as<Xpetra::global_size_t>(BCnodes_) >= D0_Matrix_->getDomainMap()->getGlobalNumElements();
186 }
187 
188 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
191  const magnitudeType tolerance,
192  const bool keepDiagonal,
193  const size_t expectedNNZperRow) {
194  Level fineLevel;
195  fineLevel.SetFactoryManager(null);
196  fineLevel.SetLevelID(0);
197  fineLevel.Set("A", A);
198  fineLevel.setlib(A->getDomainMap()->lib());
199  RCP<ThresholdAFilterFactory> ThreshFact = rcp(new ThresholdAFilterFactory("A", tolerance, keepDiagonal, expectedNNZperRow));
200  fineLevel.Request("A", ThreshFact.get());
201  ThreshFact->Build(fineLevel);
202  return fineLevel.Get<RCP<Matrix> >("A", ThreshFact.get());
203 }
204 
205 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
207  RCP<Matrix>& D0_Matrix_,
208  RCP<Matrix>& SM_Matrix_,
209  RCP<Matrix>& M1_Matrix_,
210  RCP<Matrix>& Ms_Matrix_) {
211  bool defaultFilter = false;
212 
213  // Remove zero entries from D0 if necessary.
214  // In the construction of the prolongator we use the graph of the
215  // matrix, so zero entries mess it up.
216  if (parameterList_.get<bool>("refmaxwell: filter D0", true) && D0_Matrix_->getLocalMaxNumRowEntries() > 2) {
217  D0_Matrix_ = removeExplicitZeros(D0_Matrix_, 1e-8, false, 2);
218 
219  // If D0 has too many zeros, maybe SM and M1 do as well.
220  defaultFilter = true;
221  }
222 
223  if (!M1_Matrix_.is_null() && parameterList_.get<bool>("refmaxwell: filter M1", defaultFilter)) {
224  RCP<Vector> diag = VectorFactory::Build(M1_Matrix_->getRowMap());
225  // find a reasonable absolute value threshold
226  M1_Matrix_->getLocalDiagCopy(*diag);
227  magnitudeType threshold = 1.0e-8 * diag->normInf();
228 
229  M1_Matrix_ = removeExplicitZeros(M1_Matrix_, threshold, true);
230  }
231 
232  if (!Ms_Matrix_.is_null() && parameterList_.get<bool>("refmaxwell: filter Ms", defaultFilter)) {
233  RCP<Vector> diag = VectorFactory::Build(Ms_Matrix_->getRowMap());
234  // find a reasonable absolute value threshold
235  Ms_Matrix_->getLocalDiagCopy(*diag);
236  magnitudeType threshold = 1.0e-8 * diag->normInf();
237 
238  Ms_Matrix_ = removeExplicitZeros(Ms_Matrix_, threshold, true);
239  }
240 
241  if (!SM_Matrix_.is_null() && parameterList_.get<bool>("refmaxwell: filter SM", defaultFilter)) {
242  RCP<Vector> diag = VectorFactory::Build(SM_Matrix_->getRowMap());
243  // find a reasonable absolute value threshold
244  SM_Matrix_->getLocalDiagCopy(*diag);
245  magnitudeType threshold = 1.0e-8 * diag->normInf();
246 
247  SM_Matrix_ = removeExplicitZeros(SM_Matrix_, threshold, true);
248  }
249 }
250 
251 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
254  const magnitudeType threshold) {
255  using ATS = Kokkos::ArithTraits<Scalar>;
256  using impl_Scalar = typename ATS::val_type;
257  using impl_ATS = Kokkos::ArithTraits<impl_Scalar>;
258  using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
259 
260  const impl_Scalar impl_SC_ONE = impl_ATS::one();
261  const impl_Scalar impl_SC_ZERO = impl_ATS::zero();
262 
263  {
264  auto lclMat = A->getLocalMatrixDevice();
265  Kokkos::parallel_for(
266  "thresholdedAbs",
267  range_type(0, lclMat.nnz()),
268  KOKKOS_LAMBDA(const size_t i) {
269  if (impl_ATS::magnitude(lclMat.values(i)) > threshold)
270  lclMat.values(i) = impl_SC_ONE;
271  else
272  lclMat.values(i) = impl_SC_ZERO;
273  });
274  }
275 }
276 
277 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
279  setMatvecParams(Matrix& A, RCP<ParameterList> matvecParams) {
280  RCP<const Import> xpImporter = A.getCrsGraph()->getImporter();
281  if (!xpImporter.is_null())
282  xpImporter->setDistributorParameters(matvecParams);
283  RCP<const Export> xpExporter = A.getCrsGraph()->getExporter();
284  if (!xpExporter.is_null())
285  xpExporter->setDistributorParameters(matvecParams);
286 }
287 
288 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
291  PtAPWrapper(const RCP<Matrix>& A, const RCP<Matrix>& P, ParameterList& params, std::string& label) {
292  Level fineLevel, coarseLevel;
293  fineLevel.SetFactoryManager(null);
294  coarseLevel.SetFactoryManager(null);
295  coarseLevel.SetPreviousLevel(rcpFromRef(fineLevel));
296  fineLevel.SetLevelID(0);
297  coarseLevel.SetLevelID(1);
298  fineLevel.Set("A", A);
299  coarseLevel.Set("P", P);
300  coarseLevel.setlib(A->getDomainMap()->lib());
301  fineLevel.setlib(A->getDomainMap()->lib());
302  coarseLevel.setObjectLabel(label);
303  fineLevel.setObjectLabel(label);
304 
305  RCP<RAPFactory> rapFact = rcp(new RAPFactory());
306  ParameterList rapList = *(rapFact->GetValidParameterList());
307  rapList.set("transpose: use implicit", true);
308  rapList.set("rap: fix zero diagonals", params.get<bool>("rap: fix zero diagonals", true));
309  rapList.set("rap: fix zero diagonals threshold", params.get<double>("rap: fix zero diagonals threshold", Teuchos::ScalarTraits<double>::eps()));
310  rapList.set("rap: triple product", params.get<bool>("rap: triple product", false));
311  rapFact->SetParameterList(rapList);
312 
313  coarseLevel.Request("A", rapFact.get());
314 
315  return coarseLevel.Get<RCP<Matrix> >("A", rapFact.get());
316 }
317 
318 } // namespace MueLu
319 
320 #define MUELU_MAXWELL_UTILS_SHORT
321 #endif // ifdef MUELU_MAXWELL_UTILS_DEF_HPP
static RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > PtAPWrapper(const RCP< Matrix > &A, const RCP< Matrix > &P, Teuchos::ParameterList &params, std::string &label)
Performs an P^T AP.
static void DetectDirichletColsAndDomains(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Teuchos::ArrayRCP< bool > &dirichletRows, Teuchos::ArrayRCP< bool > dirichletCols, Teuchos::ArrayRCP< bool > dirichletDomain)
Detects Dirichlet columns &amp; domains from a list of Dirichlet rows.
#define MueLu_sumAll(rcpComm, in, out)
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access). Usage: Level-&gt;Get&lt; RCP&lt;Matrix&gt; &gt;(&quot;A&quot;, factory) if factory == NULL =&gt; use default factory.
T & get(const std::string &name, T def_value)
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
static void ApplyRowSumCriterion(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Magnitude rowSumTol, Teuchos::ArrayRCP< bool > &dirichletRows)
Apply Rowsum Criterion.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
T * get() const
void SetPreviousLevel(const RCP< Level > &previousLevel)
Definition: MueLu_Level.cpp:85
void SetFactoryManager(const RCP< const FactoryManagerBase > &factoryManager)
Set default factories (used internally by Hierarchy::SetLevel()).
Definition: MueLu_Level.cpp:92
void setlib(Xpetra::UnderlyingLib lib2)
void resize(const size_type n, const T &val=T())
virtual void SetParameterList(const Teuchos::ParameterList &paramList)
Set parameters from a parameter list and return with default values.
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
Teuchos::ScalarTraits< Scalar >::magnitudeType magnitudeType
static void setMatvecParams(Matrix &A, RCP< ParameterList > matvecParams)
Sets matvec params on a matrix.
static Teuchos::ArrayRCP< const bool > DetectDirichletRows(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Magnitude &tol=Teuchos::ScalarTraits< Magnitude >::zero(), bool count_twos_as_dirichlet=false)
Detect Dirichlet rows.
virtual void setObjectLabel(const std::string &objectLabel)
static void detectBoundaryConditionsSM(RCP< Matrix > &SM_Matrix, RCP< Matrix > &D0_Matrix, magnitudeType rowSumTol, bool useKokkos_, Kokkos::View< bool *, typename Node::device_type::memory_space > &BCrowsKokkos, Kokkos::View< bool *, typename Node::device_type::memory_space > &BCcolsKokkos, Kokkos::View< bool *, typename Node::device_type::memory_space > &BCdomainKokkos, int &BCedges, int &BCnodes, Teuchos::ArrayRCP< bool > &BCrows, Teuchos::ArrayRCP< bool > &BCcols, Teuchos::ArrayRCP< bool > &BCdomain, bool &allEdgesBoundary, bool &allNodesBoundary)
Detect Dirichlet boundary conditions.
void Set(const std::string &ename, const T &entry, const FactoryBase *factory=NoFactory::get())
void Build(Level &currentLevel) const
Build an object with this factory.
void SetLevelID(int levelID)
Set level number.
Definition: MueLu_Level.cpp:78
iterator end() const
Factory for building coarse matrices.
static void thresholdedAbs(const RCP< Matrix > &A, const magnitudeType thresholded)
static Kokkos::View< bool *, typename NO::device_type::memory_space > DetectDirichletRows_kokkos(const Matrix &A, const Magnitude &tol=Teuchos::ScalarTraits< typename Teuchos::ScalarTraits< SC >::magnitudeType >::zero(), const bool count_twos_as_dirichlet=false)
Detect Dirichlet rows.
Factory for building a thresholded operator.
static RCP< Matrix > removeExplicitZeros(const RCP< Matrix > &A, const magnitudeType tolerance, const bool keepDiagonal=true, const size_t expectedNNZperRow=0)
Remove explicit zeros.
iterator begin() const
void Request(const FactoryBase &factory)
Increment the storage counter for all the inputs of a factory.
bool is_null() const