MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_NullspaceFactory_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_NULLSPACEFACTORY_DEF_HPP
47 #define MUELU_NULLSPACEFACTORY_DEF_HPP
48 
50 
51 #include <Xpetra_Matrix.hpp>
52 #include <Xpetra_MultiVectorFactory.hpp>
53 
54 #include "MueLu_Level.hpp"
55 #include "MueLu_Monitor.hpp"
56 #include "MueLu_MasterList.hpp"
57 #include "Xpetra_Access.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("nullspace: calculate rotations");
67 #undef SET_VALID_ENTRY
68  validParamList->set<std::string>("Fine level nullspace", "Nullspace", "Variable name which is used to store null space multi vector on the finest level (default=\"Nullspace\"). For block matrices also \"Nullspace1\" to \"Nullspace9\" are accepted to describe the null space vectors for the (i,i) block (i=1..9).");
69 
70  validParamList->set<RCP<const FactoryBase>>("A", Teuchos::null, "Generating factory of the fine level matrix (only needed if default null space is generated)");
71  validParamList->set<RCP<const FactoryBase>>("Nullspace", Teuchos::null, "Generating factory of the fine level null space");
72  validParamList->set<RCP<const FactoryBase>>("Coordinates", Teuchos::null, "Generating factory of the coordinates");
73 
74  // TODO not very elegant.
75 
76  // 1/20/2016: we could add a sublist (e.g. "Nullspaces" which is excluded from parameter validation)
77  validParamList->set<RCP<const FactoryBase>>("Nullspace1", Teuchos::null, "Generating factory of the fine level null space associated with the (1,1) block in your n x n block matrix.");
78  validParamList->set<RCP<const FactoryBase>>("Nullspace2", Teuchos::null, "Generating factory of the fine level null space associated with the (2,2) block in your n x n block matrix.");
79  validParamList->set<RCP<const FactoryBase>>("Nullspace3", Teuchos::null, "Generating factory of the fine level null space associated with the (3,3) block in your n x n block matrix.");
80  validParamList->set<RCP<const FactoryBase>>("Nullspace4", Teuchos::null, "Generating factory of the fine level null space associated with the (4,4) block in your n x n block matrix.");
81  validParamList->set<RCP<const FactoryBase>>("Nullspace5", Teuchos::null, "Generating factory of the fine level null space associated with the (5,5) block in your n x n block matrix.");
82  validParamList->set<RCP<const FactoryBase>>("Nullspace6", Teuchos::null, "Generating factory of the fine level null space associated with the (6,6) block in your n x n block matrix.");
83  validParamList->set<RCP<const FactoryBase>>("Nullspace7", Teuchos::null, "Generating factory of the fine level null space associated with the (7,7) block in your n x n block matrix.");
84  validParamList->set<RCP<const FactoryBase>>("Nullspace8", Teuchos::null, "Generating factory of the fine level null space associated with the (8,8) block in your n x n block matrix.");
85  validParamList->set<RCP<const FactoryBase>>("Nullspace9", Teuchos::null, "Generating factory of the fine level null space associated with the (9,9) block in your n x n block matrix.");
86 
87  return validParamList;
88 }
89 
90 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
92  const ParameterList& pL = GetParameterList();
93  std::string nspName = pL.get<std::string>("Fine level nullspace");
94 
95  // only request "A" in DeclareInput if
96  // 1) there is not nspName (e.g. "Nullspace") is available in Level, AND
97  // 2) it is the finest level (i.e. LevelID == 0)
98  if (currentLevel.IsAvailable(nspName, NoFactory::get()) == false && currentLevel.GetLevelID() == 0)
99  Input(currentLevel, "A");
100 
101  if (currentLevel.GetLevelID() == 0 &&
102  currentLevel.IsAvailable("Coordinates", NoFactory::get()) && // we have coordinates (provided by user app)
103  pL.get<bool>("nullspace: calculate rotations")) { // and we want to calculate rotation modes
104  calculateRotations_ = true;
105  Input(currentLevel, "Coordinates");
106  }
107 
108  if (currentLevel.GetLevelID() != 0) {
109  // validate nullspaceFact_
110  // 1) The factory for "Nullspace" (or nspName) must not be Teuchos::null, since the default factory
111  // for "Nullspace" is a NullspaceFactory
112  // 2) The factory for "Nullspace" (or nspName) must be a TentativePFactory or any other TwoLevelFactoryBase derived object
113  // which generates the variable "Nullspace" as output
115  "MueLu::NullspaceFactory::DeclareInput(): You must declare an existing factory which "
116  "produces the variable \"Nullspace\" in the NullspaceFactory (e.g. a TentativePFactory).");
117  currentLevel.DeclareInput("Nullspace", GetFactory(nspName).get(), this); /* ! "Nullspace" and nspName mismatch possible here */
118  }
119 }
120 
121 template <class NullspaceType, class CoordsType, class MeanCoordsType, class LO>
123  private:
124  NullspaceType nullspace;
125  CoordsType coords;
126  MeanCoordsType mean;
129  typedef typename NullspaceType::value_type SC;
130  typedef Kokkos::ArithTraits<SC> ATS;
131 
132  public:
133  NullspaceFunctor(NullspaceType nullspace_, CoordsType coords_, MeanCoordsType mean_, LO numPDEs_, LO nullspaceDim_)
134  : nullspace(nullspace_)
135  , coords(coords_)
136  , mean(mean_)
137  , numPDEs(numPDEs_)
138  , nullspaceDim(nullspaceDim_) {
139  static_assert(static_cast<int>(NullspaceType::rank) == 2, "Nullspace needs to be a rank 2 view.");
140  static_assert(static_cast<int>(CoordsType::rank) == 2, "Coords needs to be a rank 2 view.");
141  static_assert(static_cast<int>(MeanCoordsType::rank) == 1, "Mean needs to be a rank 1 view.");
142  }
143 
144  KOKKOS_INLINE_FUNCTION
145  void operator()(const LO j) const {
146  SC one = ATS::one();
147  for (LO i = 0; i < numPDEs; i++)
148  nullspace(j * numPDEs + i, i) = one;
149  if ((nullspaceDim > numPDEs) && (numPDEs > 1)) {
150  // xy rotation
151  nullspace(j * numPDEs + 0, numPDEs) = -(coords(j, 1) - mean(1));
152  nullspace(j * numPDEs + 1, numPDEs) = (coords(j, 0) - mean(0));
153  }
154  if ((nullspaceDim == numPDEs + 3) && (numPDEs > 2)) {
155  // xz rotation
156  nullspace(j * numPDEs + 1, numPDEs + 1) = -(coords(j, 2) - mean(2));
157  nullspace(j * numPDEs + 2, numPDEs + 1) = (coords(j, 1) - mean(1));
158 
159  // yz rotation
160  nullspace(j * numPDEs + 0, numPDEs + 2) = -(coords(j, 2) - mean(2));
161  nullspace(j * numPDEs + 2, numPDEs + 2) = (coords(j, 0) - mean(0));
162  }
163  }
164 };
165 
166 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
168  FactoryMonitor m(*this, "Nullspace factory", currentLevel);
169 
170  RCP<MultiVector> nullspace;
171 
172  // TEUCHOS_TEST_FOR_EXCEPTION(currentLevel.GetLevelID() != 0, Exceptions::RuntimeError, "MueLu::NullspaceFactory::Build(): NullspaceFactory can be used for finest level (LevelID == 0) only.");
173  const ParameterList& pL = GetParameterList();
174  std::string nspName = pL.get<std::string>("Fine level nullspace");
175 
176  // get coordinates and compute mean of coordinates. (or centroid).
177 
179 
180  if (currentLevel.GetLevelID() == 0) {
181  if (currentLevel.IsAvailable(nspName, NoFactory::get())) {
182  // When a fine nullspace have already been defined by user using Set("Nullspace", ...) or
183  // Set("Nullspace1", ...), we use it.
184  nullspace = currentLevel.Get<RCP<MultiVector>>(nspName, NoFactory::get());
185  GetOStream(Runtime1) << "Use user-given nullspace " << nspName << ":"
186  << " nullspace dimension=" << nullspace->getNumVectors()
187  << " nullspace length=" << nullspace->getGlobalLength() << std::endl;
188 
189  } else {
190  // "Nullspace" (nspName) is not available
191  auto A = Get<RCP<Matrix>>(currentLevel, "A");
192 
193  // Determine numPDEs
194  LO numPDEs = 1;
195  if (A->IsView("stridedMaps") == true) {
196  Xpetra::viewLabel_t oldView = A->SwitchToView("stridedMaps"); // note: "stridedMaps are always non-overlapping (correspond to range and domain maps!)
197  TEUCHOS_TEST_FOR_EXCEPTION(rcp_dynamic_cast<const StridedMap>(A->getRowMap()).is_null(), Exceptions::BadCast,
198  "MueLu::CoalesceFactory::Build: cast to strided row map failed.");
199  numPDEs = rcp_dynamic_cast<const StridedMap>(A->getRowMap())->getFixedBlockSize();
200  oldView = A->SwitchToView(oldView);
201  }
202 
203  LO nullspaceDim = numPDEs;
204 
205  CoordsType coordsView;
206  MeanCoordsType meanView;
207  if (calculateRotations_) {
208  Coords = Get<RCP<RealValuedMultiVector>>(currentLevel, "Coordinates");
209  if (Coords->getNumVectors() > 1) nullspaceDim++;
210  if (Coords->getNumVectors() > 2) nullspaceDim += 2;
211 
212  meanView = MeanCoordsType("mean coords", Coords->getNumVectors());
213  Teuchos::Array<coordinate_type> hostMeans(Coords->getNumVectors());
214  Coords->meanValue(hostMeans);
215  Kokkos::View<typename RealValuedMultiVector::impl_scalar_type*, Kokkos::HostSpace> hostMeanView(hostMeans.getRawPtr(), hostMeans.size());
216  Kokkos::deep_copy(meanView, hostMeanView);
217  coordsView = Coords->getDeviceLocalView(Xpetra::Access::ReadOnly);
218  GetOStream(Runtime1) << "Generating nullspace with rotations: dimension = " << nullspaceDim << std::endl;
219  } else
220  GetOStream(Runtime1) << "Generating canonical nullspace: dimension = " << numPDEs << std::endl;
221 
222  nullspace = MultiVectorFactory::Build(A->getDomainMap(), nullspaceDim);
223 
224  fillNullspaceVector(nullspace, numPDEs, nullspaceDim, coordsView, meanView);
225  }
226 
227  } else {
228  // On coarser levels always use "Nullspace" as variable name, since it is expected by
229  // tentative P factory to be "Nullspace"
230  nullspace = currentLevel.Get<RCP<MultiVector>>("Nullspace", GetFactory(nspName).get()); // NOTE: "Nullspace" and nspName mismatch possible here
231  }
232 
233  // provide "Nullspace" variable on current level (used by TentativePFactory)
234  Set(currentLevel, "Nullspace", nullspace);
235 
236 } // Build
237 
238 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
240  RCP<BlockedMultiVector> bnsp = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(nullspace);
241  if (bnsp.is_null() == true) {
242  auto nullspaceView = nullspace->getDeviceLocalView(Xpetra::Access::OverwriteAll);
243 
244  int numBlocks = nullspace->getLocalLength() / numPDEs;
245  if (nullspaceDim > numPDEs)
246  TEUCHOS_TEST_FOR_EXCEPTION(numBlocks != coordsView.extent_int(0), Exceptions::RuntimeError, "MueLu::NullspaceFactory::fillNullspaceVector(): number of coordinates does not match ndofs/numPDEs.");
247 
248  NullspaceFunctor<decltype(nullspaceView), decltype(coordsView), decltype(meanView), LO> nullspaceFunctor(nullspaceView, coordsView, meanView, numPDEs, nullspaceDim);
249  Kokkos::parallel_for("MueLu:NullspaceF:Build:for", range_type(0, numBlocks), nullspaceFunctor);
250 
251  /*
252  // Scale columns to match what Galeri does. Not sure that this is necessary as the qr factorizatoin
253  // of the tentative prolongator also takes care of scaling issues. I'm leaving the code here
254  // just in case.
255  if ( (int) nullspaceDim > numPDEs ) {
256  Teuchos::Array<typename Teuchos::ScalarTraits<Scalar>::magnitudeType> norms2(nullspaceDim);
257  nullspace->norm2(norms2);
258  Teuchos::Array<Scalar> norms2scalar(nullspaceDim);
259  for (int i = 0; i < nullspaceDim; i++)
260  norms2scalar[i] = norms2[0] / norms2[i];
261  nullspace->scale(norms2scalar);
262  }
263  */
264 
265  } else {
266  RCP<const BlockedMap> bmap = bnsp->getBlockedMap();
267  for (size_t r = 0; r < bmap->getNumMaps(); r++) {
268  Teuchos::RCP<MultiVector> part = bnsp->getMultiVector(r);
269  fillNullspaceVector(part, numPDEs, nullspaceDim, coordsView, meanView);
270  }
271  }
272 }
273 
274 } // namespace MueLu
275 
276 #endif // MUELU_NULLSPACEFACTORY_DEF_HPP
Exception indicating invalid cast attempted.
MueLu::DefaultLocalOrdinal LocalOrdinal
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.
bool is_null(const boost::shared_ptr< T > &p)
RCP< const ParameterList > GetValidParameterList() const
Define valid parameters for internal factory parameters.
Kokkos::RangePolicy< local_ordinal_type, execution_space > range_type
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)
Timer to be used in factories. Similar to Monitor but with additional timers.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
typename RealValuedMultiVector::dual_view_type::t_dev_const_um CoordsType
LocalOrdinal LO
static const NoFactory * get()
void fillNullspaceVector(const RCP< MultiVector > &nullspace, LocalOrdinal numPDEs, LocalOrdinal nullspaceDim, CoordsType coordsView, MeanCoordsType meanView) const
void DeclareInput(Level &currentLevel) const
Specifies the data that this class needs, and the factories that generate that data.
Kokkos::View< typename RealValuedMultiVector::impl_scalar_type *, typename Node::memory_space > MeanCoordsType
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
KOKKOS_INLINE_FUNCTION void operator()(const LO j) const
std::string viewLabel_t
NullspaceFunctor(NullspaceType nullspace_, CoordsType coords_, MeanCoordsType mean_, LO numPDEs_, LO nullspaceDim_)
int GetLevelID() const
Return level number.
Definition: MueLu_Level.cpp:76
Exception throws to report errors in the internal logical of the program.
Description of what is happening (more verbose)
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput()
#define SET_VALID_ENTRY(name)
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need&#39;s value has been saved.
void Build(Level &currentLevel) const
Build an object with this factory.
bool is_null() const