10#ifndef THYRA_MUELU_MAXWELL1_PRECONDITIONER_FACTORY_DEF_HPP
11#define THYRA_MUELU_MAXWELL1_PRECONDITIONER_FACTORY_DEF_HPP
15#include <Xpetra_CrsMatrixWrap.hpp>
16#include <Xpetra_CrsMatrix.hpp>
17#include <Xpetra_Matrix.hpp>
18#include <Xpetra_ThyraUtils.hpp>
19#include <MueLu_Maxwell1.hpp>
20#include <Xpetra_TpetraHalfPrecisionOperator.hpp>
22#if defined(HAVE_MUELU_STRATIMIKOS) && defined(HAVE_MUELU_THYRA)
25#if ((defined(HAVE_TPETRA_INST_DOUBLE) && defined(HAVE_TPETRA_INST_FLOAT) && !defined(HAVE_TPETRA_INST_COMPLEX_DOUBLE) && !defined(HAVE_TPETRA_INST_COMPLEX_FLOAT)) || \
26 (!defined(HAVE_TPETRA_INST_DOUBLE) && !defined(HAVE_TPETRA_INST_FLOAT) && defined(HAVE_TPETRA_INST_COMPLEX_DOUBLE) && defined(HAVE_TPETRA_INST_COMPLEX_FLOAT)) || \
27 (defined(HAVE_TPETRA_INST_DOUBLE) && defined(HAVE_TPETRA_INST_FLOAT) && defined(HAVE_TPETRA_INST_COMPLEX_DOUBLE) && defined(HAVE_TPETRA_INST_COMPLEX_FLOAT)))
28#define MUELU_CAN_USE_MIXED_PRECISION
33using Teuchos::ParameterList;
36using Teuchos::rcp_const_cast;
37using Teuchos::rcp_dynamic_cast;
41template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
42MueLuMaxwell1PreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::MueLuMaxwell1PreconditionerFactory()
43 : paramList_(rcp(new ParameterList())) {}
47template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
48bool MueLuMaxwell1PreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::isCompatible(
const LinearOpSourceBase<Scalar>& fwdOpSrc)
const {
49 const RCP<const LinearOpBase<Scalar>> fwdOp = fwdOpSrc.getOp();
51 if (Xpetra::ThyraUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::isTpetra(fwdOp))
return true;
56template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
57RCP<PreconditionerBase<Scalar>> MueLuMaxwell1PreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::createPrec()
const {
58 return Teuchos::rcp(
new DefaultPreconditioner<Scalar>);
61template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
62void MueLuMaxwell1PreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
63 initializePrec(
const RCP<
const LinearOpSourceBase<Scalar>>& fwdOpSrc, PreconditionerBase<Scalar>* prec,
const ESupportSolveUse supportSolveUse)
const {
65 typedef Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node> XpOp;
66 typedef Xpetra::ThyraUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node> XpThyUtils;
67 typedef Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> XpMat;
68 typedef Thyra::LinearOpBase<Scalar> ThyLinOpBase;
70#if defined(MUELU_CAN_USE_MIXED_PRECISION)
71 typedef Xpetra::TpetraHalfPrecisionOperator<Scalar, LocalOrdinal, GlobalOrdinal, Node> XpHalfPrecOp;
72 typedef Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node> XpMV;
73 typedef typename XpHalfPrecOp::HalfScalar HalfScalar;
74 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType Magnitude;
75 typedef typename Teuchos::ScalarTraits<Magnitude>::halfPrecision HalfMagnitude;
76 typedef Xpetra::MultiVector<HalfScalar, LocalOrdinal, GlobalOrdinal, Node> XphMV;
77 typedef Xpetra::MultiVector<Magnitude, LocalOrdinal, GlobalOrdinal, Node> XpmMV;
78 typedef Xpetra::MultiVector<HalfMagnitude, LocalOrdinal, GlobalOrdinal, Node> XphmMV;
79 typedef Xpetra::Matrix<HalfScalar, LocalOrdinal, GlobalOrdinal, Node> XphMat;
81 Teuchos::TimeMonitor tM(*Teuchos::TimeMonitor::getNewTimer(std::string(
"ThyraMueLuMaxwell1::initializePrec")));
84 TEUCHOS_ASSERT(Teuchos::nonnull(fwdOpSrc));
85 TEUCHOS_ASSERT(this->isCompatible(*fwdOpSrc));
89 ParameterList paramList = *paramList_;
92 const RCP<const ThyLinOpBase> fwdOp = fwdOpSrc->getOp();
93 TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(fwdOp));
96 bool bIsTpetra = XpThyUtils::isTpetra(fwdOp);
97 TEUCHOS_TEST_FOR_EXCEPT((bIsTpetra ==
false));
101 RCP<XpMat> A = XpThyUtils::toXpetra(Teuchos::rcp_const_cast<ThyLinOpBase>(fwdOp));
102 TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(A));
105 const Teuchos::Ptr<DefaultPreconditioner<Scalar>> defaultPrec = Teuchos::ptr(
dynamic_cast<DefaultPreconditioner<Scalar>*
>(prec));
106 TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(defaultPrec));
109 RCP<ThyLinOpBase> thyra_precOp = Teuchos::null;
110 thyra_precOp = rcp_dynamic_cast<Thyra::LinearOpBase<Scalar>>(defaultPrec->getNonconstUnspecifiedPrecOp(),
true);
115 const bool startingOver = (thyra_precOp.is_null() || !paramList.isParameter(
"Maxwell1: enable reuse") || !paramList.get<
bool>(
"Maxwell1: enable reuse"));
116 const bool useHalfPrecision = paramList.get<
bool>(
"half precision",
false) && bIsTpetra;
119 if (startingOver ==
true) {
121 std::list<std::string> convertXpetra = {
"Coordinates",
"Nullspace",
"Kn",
"D0",
"CurlCurl"};
122 for (
auto it = convertXpetra.begin(); it != convertXpetra.end(); ++it)
123 Converters<Scalar, LocalOrdinal, GlobalOrdinal, Node>::replaceWithXpetra(paramList, *it);
125 std::list<std::string> sublists = {
"maxwell1: 11list",
"maxwell1: 22list"};
126 for (
auto itSublist = sublists.begin(); itSublist != sublists.end(); ++itSublist)
127 if (paramList.isSublist(*itSublist)) {
128 ParameterList& sublist = paramList.sublist(*itSublist);
129 if (sublist.isSublist(
"user data")) {
130 auto& userData = sublist.sublist(
"user data");
131 std::list<std::string> convertKeys;
132 for (
auto it = userData.begin(); it != userData.end(); ++it)
133 convertKeys.push_back(userData.name(it));
134 for (
auto it = convertKeys.begin(); it != convertKeys.end(); ++it)
135 Converters<Scalar, LocalOrdinal, GlobalOrdinal, Node>::replaceWithXpetra(userData, *it);
137 for (
int lvlNo = 0; lvlNo < 10; ++lvlNo) {
138 if (sublist.isSublist(
"level " + std::to_string(lvlNo) +
" user data")) {
139 ParameterList& lvlList = sublist.sublist(
"level " + std::to_string(lvlNo) +
" user data");
140 std::list<std::string> convertKeys;
141 for (
auto it = lvlList.begin(); it != lvlList.end(); ++it)
142 convertKeys.push_back(lvlList.name(it));
143 for (
auto it = convertKeys.begin(); it != convertKeys.end(); ++it)
144 Converters<Scalar, LocalOrdinal, GlobalOrdinal, Node>::replaceWithXpetra(lvlList, *it);
149 ParameterList& sublist = paramList.sublist(
"maxwell1: 11list");
150 if (sublist.isParameter(
"D0")) {
151 Converters<Scalar, LocalOrdinal, GlobalOrdinal, Node>::replaceWithXpetra(sublist,
"D0");
154 paramList.set<
bool>(
"Maxwell1: use as preconditioner",
true);
155 if (useHalfPrecision) {
156#if defined(MUELU_CAN_USE_MIXED_PRECISION)
159 RCP<XphMat> halfA = Xpetra::convertToHalfPrecision(A);
160 if (paramList.isType<RCP<XpmMV>>(
"Coordinates")) {
161 RCP<XpmMV> coords = paramList.get<RCP<XpmMV>>(
"Coordinates");
162 paramList.remove(
"Coordinates");
163 RCP<XphmMV> halfCoords = Xpetra::convertToHalfPrecision(coords);
164 paramList.set(
"Coordinates", halfCoords);
166 if (paramList.isType<RCP<XpMV>>(
"Nullspace")) {
167 RCP<XpMV> nullspace = paramList.get<RCP<XpMV>>(
"Nullspace");
168 paramList.remove(
"Nullspace");
169 RCP<XphMV> halfNullspace = Xpetra::convertToHalfPrecision(nullspace);
170 paramList.set(
"Nullspace", halfNullspace);
172 std::list<std::string> convertMat = {
"Kn",
"D0"};
173 for (
auto it = convertMat.begin(); it != convertMat.end(); ++it) {
174 if (paramList.isType<RCP<XpMat>>(*it)) {
175 RCP<XpMat> M = paramList.get<RCP<XpMat>>(*it);
176 paramList.remove(*it);
177 RCP<XphMat> halfM = Xpetra::convertToHalfPrecision(M);
178 paramList.set(*it, halfM);
184 xpPrecOp = rcp(
new XpHalfPrecOp(halfPrec));
186 TEUCHOS_TEST_FOR_EXCEPT(
true);
191 xpPrecOp = rcp_dynamic_cast<XpOp>(preconditioner);
196 RCP<ThyXpOp> thyXpOp = rcp_dynamic_cast<ThyXpOp>(thyra_precOp,
true);
197 RCP<XpOp> xpOp = thyXpOp->getXpetraOperator();
198#if defined(MUELU_CAN_USE_MIXED_PRECISION)
199 RCP<XpHalfPrecOp> xpHalfPrecOp = rcp_dynamic_cast<XpHalfPrecOp>(xpOp);
200 if (!xpHalfPrecOp.is_null()) {
201 RCP<MueLu::Maxwell1<HalfScalar, LocalOrdinal, GlobalOrdinal, Node>> preconditioner = rcp_dynamic_cast<MueLu::Maxwell1<HalfScalar, LocalOrdinal, GlobalOrdinal, Node>>(xpHalfPrecOp->GetHalfPrecisionOperator(),
true);
202 RCP<XphMat> halfA = Xpetra::convertToHalfPrecision(A);
203 preconditioner->resetMatrix(halfA);
204 xpPrecOp = rcp_dynamic_cast<XpOp>(preconditioner);
208 RCP<MueLu::Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>> preconditioner = rcp_dynamic_cast<MueLu::Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>>(xpOp,
true);
209 preconditioner->resetMatrix(A);
210 xpPrecOp = rcp_dynamic_cast<XpOp>(preconditioner);
215 RCP<const VectorSpaceBase<Scalar>> thyraRangeSpace = Xpetra::ThyraUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::toThyra(xpPrecOp->getRangeMap());
216 RCP<const VectorSpaceBase<Scalar>> thyraDomainSpace = Xpetra::ThyraUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::toThyra(xpPrecOp->getDomainMap());
218 RCP<ThyLinOpBase> thyraPrecOp = Thyra::xpetraLinearOp<Scalar, LocalOrdinal, GlobalOrdinal, Node>(thyraRangeSpace, thyraDomainSpace, xpPrecOp);
219 TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(thyraPrecOp));
221 defaultPrec->initializeUnspecified(thyraPrecOp);
224template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
225void MueLuMaxwell1PreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
226 uninitializePrec(PreconditionerBase<Scalar>* prec, RCP<
const LinearOpSourceBase<Scalar>>* fwdOp, ESupportSolveUse* supportSolveUse)
const {
227 TEUCHOS_ASSERT(prec);
230 const Teuchos::Ptr<DefaultPreconditioner<Scalar>> defaultPrec = Teuchos::ptr(
dynamic_cast<DefaultPreconditioner<Scalar>*
>(prec));
231 TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(defaultPrec));
235 *fwdOp = Teuchos::null;
238 if (supportSolveUse) {
240 *supportSolveUse = Thyra::SUPPORT_SOLVE_UNSPECIFIED;
243 defaultPrec->uninitialize();
247template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
248void MueLuMaxwell1PreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::setParameterList(RCP<ParameterList>
const& paramList) {
249 TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(paramList));
250 paramList_ = paramList;
253template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
254RCP<ParameterList> MueLuMaxwell1PreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getNonconstParameterList() {
258template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
259RCP<ParameterList> MueLuMaxwell1PreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::unsetParameterList() {
260 RCP<ParameterList> savedParamList = paramList_;
261 paramList_ = Teuchos::null;
262 return savedParamList;
265template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
266RCP<const ParameterList> MueLuMaxwell1PreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getParameterList()
const {
270template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
271RCP<const ParameterList> MueLuMaxwell1PreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getValidParameters()
const {
272 static RCP<const ParameterList> validPL;
274 if (Teuchos::is_null(validPL))
275 validPL = rcp(
new ParameterList());
281template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
282std::string MueLuMaxwell1PreconditionerFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::description()
const {
283 return "Thyra::MueLuMaxwell1PreconditionerFactory";
Preconditioner (wrapped as a Xpetra::Operator) for Maxwell's equations in curl-curl form.
Concrete Thyra::LinearOpBase subclass for Xpetra::Operator.