MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_NullspaceFactory_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_NULLSPACEFACTORY_DEF_HPP
11#define MUELU_NULLSPACEFACTORY_DEF_HPP
12
14
15#include <Xpetra_Matrix.hpp>
16#include <Xpetra_MultiVectorFactory.hpp>
17
18#include "MueLu_Level.hpp"
19#include "MueLu_Monitor.hpp"
20#include "MueLu_MasterList.hpp"
21#include "Tpetra_Access.hpp"
22
23namespace MueLu {
24
25template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
27 RCP<ParameterList> validParamList = rcp(new ParameterList());
28
29#define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
30 SET_VALID_ENTRY("nullspace: calculate rotations");
31#undef SET_VALID_ENTRY
32 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).");
33
34 validParamList->set<RCP<const FactoryBase>>("A", Teuchos::null, "Generating factory of the fine level matrix (only needed if default null space is generated)");
35 validParamList->set<RCP<const FactoryBase>>("Nullspace", Teuchos::null, "Generating factory of the fine level null space");
36 validParamList->set<RCP<const FactoryBase>>("Coordinates", Teuchos::null, "Generating factory of the coordinates");
37
38 // TODO not very elegant.
39
40 // 1/20/2016: we could add a sublist (e.g. "Nullspaces" which is excluded from parameter validation)
41 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.");
42 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.");
43 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.");
44 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.");
45 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.");
46 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.");
47 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.");
48 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.");
49 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.");
50
51 return validParamList;
52}
53
54template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
56 const ParameterList& pL = GetParameterList();
57 std::string nspName = pL.get<std::string>("Fine level nullspace");
58
59 // only request "A" in DeclareInput if
60 // 1) there is not nspName (e.g. "Nullspace") is available in Level, AND
61 // 2) it is the finest level (i.e. LevelID == 0)
62 if (currentLevel.IsAvailable(nspName, NoFactory::get()) == false && currentLevel.GetLevelID() == 0)
63 Input(currentLevel, "A");
64
65 if (currentLevel.GetLevelID() == 0 &&
66 currentLevel.IsAvailable("Coordinates", NoFactory::get()) && // we have coordinates (provided by user app)
67 pL.get<bool>("nullspace: calculate rotations")) { // and we want to calculate rotation modes
68 calculateRotations_ = true;
69 Input(currentLevel, "Coordinates");
70 }
71
72 if (currentLevel.GetLevelID() != 0) {
73 // validate nullspaceFact_
74 // 1) The factory for "Nullspace" (or nspName) must not be Teuchos::null, since the default factory
75 // for "Nullspace" is a NullspaceFactory
76 // 2) The factory for "Nullspace" (or nspName) must be a TentativePFactory or any other TwoLevelFactoryBase derived object
77 // which generates the variable "Nullspace" as output
78 TEUCHOS_TEST_FOR_EXCEPTION(GetFactory(nspName).is_null(), Exceptions::RuntimeError,
79 "MueLu::NullspaceFactory::DeclareInput(): You must declare an existing factory which "
80 "produces the variable \"Nullspace\" in the NullspaceFactory (e.g. a TentativePFactory).");
81 currentLevel.DeclareInput("Nullspace", GetFactory(nspName).get(), this); /* ! "Nullspace" and nspName mismatch possible here */
82 }
83}
84
85template <class NullspaceType, class CoordsType, class MeanCoordsType, class LO>
87 private:
88 NullspaceType nullspace;
89 CoordsType coords;
90 MeanCoordsType mean;
93 typedef typename NullspaceType::value_type SC;
94 typedef KokkosKernels::ArithTraits<SC> ATS;
95
96 public:
97 NullspaceFunctor(NullspaceType nullspace_, CoordsType coords_, MeanCoordsType mean_, LO numPDEs_, LO nullspaceDim_)
98 : nullspace(nullspace_)
99 , coords(coords_)
100 , mean(mean_)
101 , numPDEs(numPDEs_)
102 , nullspaceDim(nullspaceDim_) {
103 static_assert(static_cast<int>(NullspaceType::rank) == 2, "Nullspace needs to be a rank 2 view.");
104 static_assert(static_cast<int>(CoordsType::rank) == 2, "Coords needs to be a rank 2 view.");
105 static_assert(static_cast<int>(MeanCoordsType::rank) == 1, "Mean needs to be a rank 1 view.");
106 }
107
108 KOKKOS_INLINE_FUNCTION
109 void operator()(const LO j) const {
110 SC one = ATS::one();
111 for (LO i = 0; i < numPDEs; i++)
112 nullspace(j * numPDEs + i, i) = one;
113 if ((nullspaceDim > numPDEs) && (numPDEs > 1)) {
114 // xy rotation
115 nullspace(j * numPDEs + 0, numPDEs) = -(coords(j, 1) - mean(1));
116 nullspace(j * numPDEs + 1, numPDEs) = (coords(j, 0) - mean(0));
117 }
118 if ((nullspaceDim == numPDEs + 3) && (numPDEs > 2)) {
119 // xz rotation
120 nullspace(j * numPDEs + 1, numPDEs + 1) = -(coords(j, 2) - mean(2));
121 nullspace(j * numPDEs + 2, numPDEs + 1) = (coords(j, 1) - mean(1));
122
123 // yz rotation
124 nullspace(j * numPDEs + 0, numPDEs + 2) = -(coords(j, 2) - mean(2));
125 nullspace(j * numPDEs + 2, numPDEs + 2) = (coords(j, 0) - mean(0));
126 }
127 }
128};
129
130template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
132 FactoryMonitor m(*this, "Nullspace factory", currentLevel);
133
134 RCP<MultiVector> nullspace;
135
136 // TEUCHOS_TEST_FOR_EXCEPTION(currentLevel.GetLevelID() != 0, Exceptions::RuntimeError, "MueLu::NullspaceFactory::Build(): NullspaceFactory can be used for finest level (LevelID == 0) only.");
137 const ParameterList& pL = GetParameterList();
138 std::string nspName = pL.get<std::string>("Fine level nullspace");
139
140 // get coordinates and compute mean of coordinates. (or centroid).
141
142 RCP<RealValuedMultiVector> Coords;
143
144 if (currentLevel.GetLevelID() == 0) {
145 if (currentLevel.IsAvailable(nspName, NoFactory::get())) {
146 // When a fine nullspace have already been defined by user using Set("Nullspace", ...) or
147 // Set("Nullspace1", ...), we use it.
148 nullspace = currentLevel.Get<RCP<MultiVector>>(nspName, NoFactory::get());
149 GetOStream(Runtime1) << "Use user-given nullspace " << nspName << ":"
150 << " nullspace dimension=" << nullspace->getNumVectors()
151 << " nullspace length=" << nullspace->getGlobalLength() << std::endl;
152
153 } else {
154 // "Nullspace" (nspName) is not available
155 auto A = Get<RCP<Matrix>>(currentLevel, "A");
156
157 // Determine numPDEs
158 LO numPDEs = 1;
159 if (A->IsView("stridedMaps") == true) {
160 Xpetra::viewLabel_t oldView = A->SwitchToView("stridedMaps"); // note: "stridedMaps are always non-overlapping (correspond to range and domain maps!)
161 TEUCHOS_TEST_FOR_EXCEPTION(rcp_dynamic_cast<const StridedMap>(A->getRowMap()).is_null(), Exceptions::BadCast,
162 "MueLu::CoalesceFactory::Build: cast to strided row map failed.");
163 numPDEs = rcp_dynamic_cast<const StridedMap>(A->getRowMap())->getFixedBlockSize();
164 oldView = A->SwitchToView(oldView);
165 }
166
167 LO nullspaceDim = numPDEs;
168
169 CoordsType coordsView;
170 MeanCoordsType meanView;
171 if (calculateRotations_) {
172 Coords = Get<RCP<RealValuedMultiVector>>(currentLevel, "Coordinates");
173 if (Coords->getNumVectors() > 1) nullspaceDim++;
174 if (Coords->getNumVectors() > 2) nullspaceDim += 2;
175
176 meanView = MeanCoordsType("mean coords", Coords->getNumVectors());
177 Teuchos::Array<coordinate_type> hostMeans(Coords->getNumVectors());
178 Coords->meanValue(hostMeans);
179 Kokkos::View<typename RealValuedMultiVector::impl_scalar_type*, Kokkos::HostSpace> hostMeanView(hostMeans.getRawPtr(), hostMeans.size());
180 Kokkos::deep_copy(meanView, hostMeanView);
181 coordsView = Coords->getLocalViewDevice(Tpetra::Access::ReadOnly);
182 GetOStream(Runtime1) << "Generating nullspace with rotations: dimension = " << nullspaceDim << std::endl;
183 } else
184 GetOStream(Runtime1) << "Generating canonical nullspace: dimension = " << numPDEs << std::endl;
185
186 nullspace = MultiVectorFactory::Build(A->getDomainMap(), nullspaceDim, true);
187
188 fillNullspaceVector(nullspace, numPDEs, nullspaceDim, coordsView, meanView);
189 }
190
191 } else {
192 // On coarser levels always use "Nullspace" as variable name, since it is expected by
193 // tentative P factory to be "Nullspace"
194 nullspace = currentLevel.Get<RCP<MultiVector>>("Nullspace", GetFactory(nspName).get()); // NOTE: "Nullspace" and nspName mismatch possible here
195 }
196
197 // provide "Nullspace" variable on current level (used by TentativePFactory)
198 Set(currentLevel, "Nullspace", nullspace);
199
200} // Build
201
202template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
203void NullspaceFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::fillNullspaceVector(const RCP<MultiVector>& nullspace, LocalOrdinal numPDEs, LocalOrdinal nullspaceDim, CoordsType coordsView, MeanCoordsType meanView) const {
204 RCP<BlockedMultiVector> bnsp = Teuchos::rcp_dynamic_cast<BlockedMultiVector>(nullspace);
205 if (bnsp.is_null() == true) {
206 auto nullspaceView = nullspace->getLocalViewDevice(Tpetra::Access::OverwriteAll);
207
208 int numBlocks = nullspace->getLocalLength() / numPDEs;
209 if (nullspaceDim > numPDEs)
210 TEUCHOS_TEST_FOR_EXCEPTION(numBlocks != coordsView.extent_int(0), Exceptions::RuntimeError, "MueLu::NullspaceFactory::fillNullspaceVector(): number of coordinates does not match ndofs/numPDEs.");
211
212 NullspaceFunctor<decltype(nullspaceView), decltype(coordsView), decltype(meanView), LO> nullspaceFunctor(nullspaceView, coordsView, meanView, numPDEs, nullspaceDim);
213 Kokkos::parallel_for("MueLu:NullspaceF:Build:for", range_type(0, numBlocks), nullspaceFunctor);
214
215 /*
216 // Scale columns to match what Galeri does. Not sure that this is necessary as the qr factorizatoin
217 // of the tentative prolongator also takes care of scaling issues. I'm leaving the code here
218 // just in case.
219 if ( (int) nullspaceDim > numPDEs ) {
220 Teuchos::Array<typename Teuchos::ScalarTraits<Scalar>::magnitudeType> norms2(nullspaceDim);
221 nullspace->norm2(norms2);
222 Teuchos::Array<Scalar> norms2scalar(nullspaceDim);
223 for (int i = 0; i < nullspaceDim; i++)
224 norms2scalar[i] = norms2[0] / norms2[i];
225 nullspace->scale(norms2scalar);
226 }
227 */
228
229 } else {
230 RCP<const BlockedMap> bmap = bnsp->getBlockedMap();
231 for (size_t r = 0; r < bmap->getNumMaps(); r++) {
232 Teuchos::RCP<MultiVector> part = bnsp->getMultiVector(r);
233 fillNullspaceVector(part, numPDEs, nullspaceDim, coordsView, meanView);
234 }
235 }
236}
237
238} // namespace MueLu
239
240#endif // MUELU_NULLSPACEFACTORY_DEF_HPP
#define SET_VALID_ENTRY(name)
MueLu::DefaultLocalOrdinal LocalOrdinal
Exception indicating invalid cast attempted.
Exception throws to report errors in the internal logical of the program.
Timer to be used in factories. Similar to Monitor but with additional timers.
Class that holds all level-specific information.
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need's value has been saved.
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput()
int GetLevelID() const
Return level number.
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access)....
static const NoFactory * get()
void fillNullspaceVector(const RCP< MultiVector > &nullspace, LocalOrdinal numPDEs, LocalOrdinal nullspaceDim, CoordsType coordsView, MeanCoordsType meanView) const
void Build(Level &currentLevel) const
Build an object with this factory.
Kokkos::View< typename RealValuedMultiVector::impl_scalar_type *, typename Node::memory_space > MeanCoordsType
typename RealValuedMultiVector::dual_view_type::t_dev_const_um CoordsType
Kokkos::RangePolicy< local_ordinal_type, execution_space > range_type
RCP< const ParameterList > GetValidParameterList() const
Define valid parameters for internal factory parameters.
void DeclareInput(Level &currentLevel) const
Specifies the data that this class needs, and the factories that generate that data.
KOKKOS_INLINE_FUNCTION void operator()(const LO j) const
KokkosKernels::ArithTraits< SC > ATS
NullspaceFunctor(NullspaceType nullspace_, CoordsType coords_, MeanCoordsType mean_, LO numPDEs_, LO nullspaceDim_)
Namespace for MueLu classes and methods.
@ Runtime1
Description of what is happening (more verbose)