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 // MueLu: A package for multigrid based preconditioning
4 //
5 // Copyright 2012 NTESS and the MueLu contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef MUELU_MAXWELL_UTILS_DEF_HPP
11 #define MUELU_MAXWELL_UTILS_DEF_HPP
12 
13 #include <sstream>
14 
15 #include "MueLu_ConfigDefs.hpp"
16 
17 #include "Xpetra_Map.hpp"
19 #include "Xpetra_MatrixUtils.hpp"
20 
22 
23 #include "MueLu_Level.hpp"
24 #include "MueLu_ThresholdAFilterFactory.hpp"
25 #include "MueLu_Utilities.hpp"
26 #include "MueLu_RAPFactory.hpp"
27 
28 namespace MueLu {
29 
30 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
32  RCP<Matrix>& D0_Matrix_,
33  magnitudeType rowSumTol,
34  bool useKokkos_,
35  Kokkos::View<bool*, typename Node::device_type::memory_space>& BCrowsKokkos_,
36  Kokkos::View<bool*, typename Node::device_type::memory_space>& BCcolsKokkos_,
37  Kokkos::View<bool*, typename Node::device_type::memory_space>& BCdomainKokkos_,
38  int& BCedges_,
39  int& BCnodes_,
40  Teuchos::ArrayRCP<bool>& BCrows_,
41  Teuchos::ArrayRCP<bool>& BCcols_,
42  Teuchos::ArrayRCP<bool>& BCdomain_,
43  bool& allEdgesBoundary_,
44  bool& allNodesBoundary_) {
45  // clean rows associated with boundary conditions
46  // Find rows with only 1 or 2 nonzero entries, record them in BCrows_.
47  // BCrows_[i] is true, iff i is a boundary row
48  // BCcols_[i] is true, iff i is a boundary column
49  int BCedgesLocal = 0;
50  int BCnodesLocal = 0;
51  if (useKokkos_) {
52  BCrowsKokkos_ = Utilities::DetectDirichletRows_kokkos(*SM_Matrix_, Teuchos::ScalarTraits<magnitudeType>::eps(), /*count_twos_as_dirichlet=*/true);
53 
54  if (rowSumTol > 0.)
55  Utilities::ApplyRowSumCriterion(*SM_Matrix_, rowSumTol, BCrowsKokkos_);
56 
57  BCcolsKokkos_ = Kokkos::View<bool*, typename Node::device_type>(Kokkos::ViewAllocateWithoutInitializing("dirichletCols"), D0_Matrix_->getColMap()->getLocalNumElements());
58  BCdomainKokkos_ = Kokkos::View<bool*, typename Node::device_type>(Kokkos::ViewAllocateWithoutInitializing("dirichletDomains"), D0_Matrix_->getDomainMap()->getLocalNumElements());
59  Utilities::DetectDirichletColsAndDomains(*D0_Matrix_, BCrowsKokkos_, BCcolsKokkos_, BCdomainKokkos_);
60 
61  auto BCrowsKokkos = BCrowsKokkos_;
62  Kokkos::parallel_reduce(
63  BCrowsKokkos_.size(), KOKKOS_LAMBDA(int i, int& sum) {
64  if (BCrowsKokkos(i))
65  ++sum;
66  },
67  BCedgesLocal);
68 
69  auto BCdomainKokkos = BCdomainKokkos_;
70  Kokkos::parallel_reduce(
71  BCdomainKokkos_.size(), KOKKOS_LAMBDA(int i, int& sum) {
72  if (BCdomainKokkos(i))
73  ++sum;
74  },
75  BCnodesLocal);
76  } else {
77  BCrows_ = Teuchos::arcp_const_cast<bool>(Utilities::DetectDirichletRows(*SM_Matrix_, Teuchos::ScalarTraits<magnitudeType>::eps(), /*count_twos_as_dirichlet=*/true));
78 
79  if (rowSumTol > 0.)
80  Utilities::ApplyRowSumCriterion(*SM_Matrix_, rowSumTol, BCrows_);
81 
82  BCcols_.resize(D0_Matrix_->getColMap()->getLocalNumElements());
83  BCdomain_.resize(D0_Matrix_->getDomainMap()->getLocalNumElements());
84  Utilities::DetectDirichletColsAndDomains(*D0_Matrix_, BCrows_, BCcols_, BCdomain_);
85 
86  for (auto it = BCrows_.begin(); it != BCrows_.end(); ++it)
87  if (*it)
88  BCedgesLocal += 1;
89  for (auto it = BCdomain_.begin(); it != BCdomain_.end(); ++it)
90  if (*it)
91  BCnodesLocal += 1;
92  }
93 
94  MueLu_sumAll(SM_Matrix_->getRowMap()->getComm(), BCedgesLocal, BCedges_);
95  MueLu_sumAll(SM_Matrix_->getRowMap()->getComm(), BCnodesLocal, BCnodes_);
96 
97  allEdgesBoundary_ = Teuchos::as<Xpetra::global_size_t>(BCedges_) >= D0_Matrix_->getRangeMap()->getGlobalNumElements();
98  allNodesBoundary_ = Teuchos::as<Xpetra::global_size_t>(BCnodes_) >= D0_Matrix_->getDomainMap()->getGlobalNumElements();
99 }
100 
101 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
103  RCP<Matrix>& D0_Matrix_,
104  magnitudeType rowSumTol,
105  Kokkos::View<bool*, typename Node::device_type::memory_space>& BCrowsKokkos_,
106  Kokkos::View<bool*, typename Node::device_type::memory_space>& BCcolsKokkos_,
107  Kokkos::View<bool*, typename Node::device_type::memory_space>& BCdomainKokkos_,
108  int& BCedges_,
109  int& BCnodes_,
110  bool& allEdgesBoundary_,
111  bool& allNodesBoundary_) {
112  // clean rows associated with boundary conditions
113  // Find rows with only 1 or 2 nonzero entries, record them in BCrows_.
114  // BCrows_[i] is true, iff i is a boundary row
115  // BCcols_[i] is true, iff i is a boundary column
116  int BCedgesLocal = 0;
117  int BCnodesLocal = 0;
118  {
119  BCrowsKokkos_ = Utilities::DetectDirichletRows_kokkos(*SM_Matrix_, Teuchos::ScalarTraits<magnitudeType>::eps(), /*count_twos_as_dirichlet=*/true);
120 
121  if (rowSumTol > 0.)
122  Utilities::ApplyRowSumCriterion(*SM_Matrix_, rowSumTol, BCrowsKokkos_);
123 
124  BCcolsKokkos_ = Kokkos::View<bool*, typename Node::device_type>(Kokkos::ViewAllocateWithoutInitializing("dirichletCols"), D0_Matrix_->getColMap()->getLocalNumElements());
125  BCdomainKokkos_ = Kokkos::View<bool*, typename Node::device_type>(Kokkos::ViewAllocateWithoutInitializing("dirichletDomains"), D0_Matrix_->getDomainMap()->getLocalNumElements());
126  Utilities::DetectDirichletColsAndDomains(*D0_Matrix_, BCrowsKokkos_, BCcolsKokkos_, BCdomainKokkos_);
127 
128  auto BCrowsKokkos = BCrowsKokkos_;
129  Kokkos::parallel_reduce(
130  BCrowsKokkos_.size(), KOKKOS_LAMBDA(int i, int& sum) {
131  if (BCrowsKokkos(i))
132  ++sum;
133  },
134  BCedgesLocal);
135 
136  auto BCdomainKokkos = BCdomainKokkos_;
137  Kokkos::parallel_reduce(
138  BCdomainKokkos_.size(), KOKKOS_LAMBDA(int i, int& sum) {
139  if (BCdomainKokkos(i))
140  ++sum;
141  },
142  BCnodesLocal);
143  }
144 
145  MueLu_sumAll(SM_Matrix_->getRowMap()->getComm(), BCedgesLocal, BCedges_);
146  MueLu_sumAll(SM_Matrix_->getRowMap()->getComm(), BCnodesLocal, BCnodes_);
147 
148  allEdgesBoundary_ = Teuchos::as<Xpetra::global_size_t>(BCedges_) >= D0_Matrix_->getRangeMap()->getGlobalNumElements();
149  allNodesBoundary_ = Teuchos::as<Xpetra::global_size_t>(BCnodes_) >= D0_Matrix_->getDomainMap()->getGlobalNumElements();
150 }
151 
152 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
155  const magnitudeType tolerance,
156  const bool keepDiagonal,
157  const size_t expectedNNZperRow) {
158  Level fineLevel;
159  fineLevel.SetFactoryManager(null);
160  fineLevel.SetLevelID(0);
161  fineLevel.Set("A", A);
162  fineLevel.setlib(A->getDomainMap()->lib());
163  RCP<ThresholdAFilterFactory> ThreshFact = rcp(new ThresholdAFilterFactory("A", tolerance, keepDiagonal, expectedNNZperRow));
164  fineLevel.Request("A", ThreshFact.get());
165  ThreshFact->Build(fineLevel);
166  return fineLevel.Get<RCP<Matrix> >("A", ThreshFact.get());
167 }
168 
169 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
171  RCP<Matrix>& D0_Matrix_,
172  RCP<Matrix>& SM_Matrix_,
173  RCP<Matrix>& M1_Matrix_,
174  RCP<Matrix>& Ms_Matrix_) {
175  bool defaultFilter = false;
176 
177  // Remove zero entries from D0 if necessary.
178  // In the construction of the prolongator we use the graph of the
179  // matrix, so zero entries mess it up.
180  if (parameterList_.get<bool>("refmaxwell: filter D0", true) && D0_Matrix_->getLocalMaxNumRowEntries() > 2) {
181  D0_Matrix_ = removeExplicitZeros(D0_Matrix_, 1e-8, false, 2);
182 
183  // If D0 has too many zeros, maybe SM and M1 do as well.
184  defaultFilter = true;
185  }
186 
187  if (!M1_Matrix_.is_null() && parameterList_.get<bool>("refmaxwell: filter M1", defaultFilter)) {
188  RCP<Vector> diag = VectorFactory::Build(M1_Matrix_->getRowMap());
189  // find a reasonable absolute value threshold
190  M1_Matrix_->getLocalDiagCopy(*diag);
191  magnitudeType threshold = 1.0e-8 * diag->normInf();
192 
193  M1_Matrix_ = removeExplicitZeros(M1_Matrix_, threshold, true);
194  }
195 
196  if (!Ms_Matrix_.is_null() && parameterList_.get<bool>("refmaxwell: filter Ms", defaultFilter)) {
197  RCP<Vector> diag = VectorFactory::Build(Ms_Matrix_->getRowMap());
198  // find a reasonable absolute value threshold
199  Ms_Matrix_->getLocalDiagCopy(*diag);
200  magnitudeType threshold = 1.0e-8 * diag->normInf();
201 
202  Ms_Matrix_ = removeExplicitZeros(Ms_Matrix_, threshold, true);
203  }
204 
205  if (!SM_Matrix_.is_null() && parameterList_.get<bool>("refmaxwell: filter SM", defaultFilter)) {
206  RCP<Vector> diag = VectorFactory::Build(SM_Matrix_->getRowMap());
207  // find a reasonable absolute value threshold
208  SM_Matrix_->getLocalDiagCopy(*diag);
209  magnitudeType threshold = 1.0e-8 * diag->normInf();
210 
211  SM_Matrix_ = removeExplicitZeros(SM_Matrix_, threshold, true);
212  }
213 }
214 
215 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
218  const magnitudeType threshold) {
219  using ATS = Kokkos::ArithTraits<Scalar>;
220  using impl_Scalar = typename ATS::val_type;
221  using impl_ATS = Kokkos::ArithTraits<impl_Scalar>;
222  using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
223 
224  const impl_Scalar impl_SC_ONE = impl_ATS::one();
225  const impl_Scalar impl_SC_ZERO = impl_ATS::zero();
226 
227  {
228  auto lclMat = A->getLocalMatrixDevice();
229  Kokkos::parallel_for(
230  "thresholdedAbs",
231  range_type(0, lclMat.nnz()),
232  KOKKOS_LAMBDA(const size_t i) {
233  if (impl_ATS::magnitude(lclMat.values(i)) > threshold)
234  lclMat.values(i) = impl_SC_ONE;
235  else
236  lclMat.values(i) = impl_SC_ZERO;
237  });
238  }
239 }
240 
241 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
243  setMatvecParams(Matrix& A, RCP<ParameterList> matvecParams) {
244  RCP<const Import> xpImporter = A.getCrsGraph()->getImporter();
245  if (!xpImporter.is_null())
246  xpImporter->setDistributorParameters(matvecParams);
247  RCP<const Export> xpExporter = A.getCrsGraph()->getExporter();
248  if (!xpExporter.is_null())
249  xpExporter->setDistributorParameters(matvecParams);
250 }
251 
252 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
255  PtAPWrapper(const RCP<Matrix>& A, const RCP<Matrix>& P, ParameterList& params, const std::string& label) {
256  Level fineLevel, coarseLevel;
257  fineLevel.SetFactoryManager(null);
258  coarseLevel.SetFactoryManager(null);
259  coarseLevel.SetPreviousLevel(rcpFromRef(fineLevel));
260  fineLevel.SetLevelID(0);
261  coarseLevel.SetLevelID(1);
262  fineLevel.Set("A", A);
263  coarseLevel.Set("P", P);
264  coarseLevel.setlib(A->getDomainMap()->lib());
265  fineLevel.setlib(A->getDomainMap()->lib());
266  coarseLevel.setObjectLabel(label);
267  fineLevel.setObjectLabel(label);
268 
269  RCP<RAPFactory> rapFact = rcp(new RAPFactory());
270  ParameterList rapList = *(rapFact->GetValidParameterList());
271  rapList.set("transpose: use implicit", true);
272  rapList.set("rap: fix zero diagonals", params.get<bool>("rap: fix zero diagonals", true));
273  rapList.set("rap: fix zero diagonals threshold", params.get<double>("rap: fix zero diagonals threshold", Teuchos::ScalarTraits<double>::eps()));
274  rapList.set("rap: triple product", params.get<bool>("rap: triple product", false));
275  rapFact->SetParameterList(rapList);
276 
277  coarseLevel.Request("A", rapFact.get());
278 
279  return coarseLevel.Get<RCP<Matrix> >("A", rapFact.get());
280 }
281 
282 } // namespace MueLu
283 
284 #define MUELU_MAXWELL_UTILS_SHORT
285 #endif // ifdef MUELU_MAXWELL_UTILS_DEF_HPP
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)
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:62
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
void SetFactoryManager(const RCP< const FactoryManagerBase > &factoryManager)
Set default factories (used internally by Hierarchy::SetLevel()).
Definition: MueLu_Level.cpp:69
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:63
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.
static RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > PtAPWrapper(const RCP< Matrix > &A, const RCP< Matrix > &P, Teuchos::ParameterList &params, const std::string &label)
Performs an P^T AP.
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:53
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