46 #ifndef MUELU_IPCFACTORY_DEF_HPP 47 #define MUELU_IPCFACTORY_DEF_HPP 49 #include <Xpetra_Matrix.hpp> 50 #include <Xpetra_IO.hpp> 60 #include "MueLu_PerfUtils.hpp" 62 #include "MueLu_Utilities.hpp" 64 #include "Teuchos_ScalarTraits.hpp" 72 #include "Intrepid2_HGRAD_LINE_C1_FEM.hpp" 73 #include "Intrepid2_HGRAD_LINE_Cn_FEM.hpp" 78 #include "Intrepid2_HGRAD_QUAD_C1_FEM.hpp" 80 #include "Intrepid2_HGRAD_QUAD_Cn_FEM.hpp" 95 #define MUELU_LEVEL_SET_IF_REQUESTED_OR_KEPT(level,ename,entry) \ 96 {if (level.IsRequested(ename,this) || level.GetKeepFlag(ename,this) != 0) this->Set(level,ename,entry);} 104 namespace MueLuIntrepid {
105 inline std::string
tolower(
const std::string & str) {
106 std::string data(str);
107 std::transform(data.begin(), data.end(), data.begin(), [](
unsigned char c) {
return std::tolower(c); });
113 template<
class Basis,
class LOFieldContainer,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
115 std::vector<std::vector<LocalOrdinal> > &seeds,
116 const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> &rowMap,
117 const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> &columnMap)
129 shards::CellTopology cellTopo = basis->getBaseCellTopology();
130 int spaceDim = cellTopo.getDimension();
132 seeds.resize(spaceDim + 1);
133 typedef GlobalOrdinal GO;
134 typedef LocalOrdinal LO;
136 LocalOrdinal lo_invalid = Teuchos::OrdinalTraits<LO>::invalid();
137 GlobalOrdinal go_invalid = Teuchos::OrdinalTraits<GO>::invalid();
140 std::vector<std::set<LocalOrdinal>> seedSets(spaceDim+1);
142 int numCells = elementToNodeMap.dimension(0);
143 for (
int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++)
145 for (
int d=0; d<=spaceDim; d++)
147 int subcellCount = cellTopo.getSubcellCount(d);
148 for (
int subcord=0; subcord<subcellCount; subcord++)
150 int dofCount = basis->getDofCount(d,subcord);
151 if (dofCount == 0)
continue;
153 GO leastGlobalDofOrdinal = go_invalid;
154 LO LID_leastGlobalDofOrdinal = lo_invalid;
155 for (
int basisOrdinalOrdinal=0; basisOrdinalOrdinal<dofCount; basisOrdinalOrdinal++)
157 int basisOrdinal = basis->getDofOrdinal(d,subcord,basisOrdinalOrdinal);
158 int colLID = elementToNodeMap(cellOrdinal,basisOrdinal);
159 if (colLID != Teuchos::OrdinalTraits<LO>::invalid())
161 GlobalOrdinal colGID = columnMap.getGlobalElement(colLID);
162 LocalOrdinal rowLID = rowMap.getLocalElement(colGID);
163 if (rowLID != lo_invalid)
165 if ((leastGlobalDofOrdinal == go_invalid) || (colGID < leastGlobalDofOrdinal))
168 leastGlobalDofOrdinal = colGID;
169 LID_leastGlobalDofOrdinal = rowLID;
174 if (leastGlobalDofOrdinal != go_invalid)
176 seedSets[d].insert(LID_leastGlobalDofOrdinal);
181 for (
int d=0; d<=spaceDim;d++)
183 seeds[d] = std::vector<LocalOrdinal>(seedSets[d].begin(),seedSets[d].end());
194 #ifdef HAVE_MUELU_INTREPID2_REFACTOR 195 template<
class Scalar,
class KokkosExecutionSpace>
196 Teuchos::RCP< Intrepid2::Basis<KokkosExecutionSpace,Scalar,Scalar> >
BasisFactory(
const std::string & name,
int & degree)
198 template<
class Scalar>
199 Teuchos::RCP<Intrepid2::Basis<Scalar,Intrepid2::FieldContainer<Scalar> > >
BasisFactory(
const std::string & name,
int & degree)
204 string myerror(
"IntrepidBasisFactory: cannot parse string name '"+name+
"'");
209 size_t pos1 = name.find_first_of(
" _");
210 if(pos1==0)
throw std::runtime_error(myerror);
211 string deriv =
tolower(name.substr(0,pos1));
212 if(deriv!=
"hgrad" && deriv!=
"hcurl" && deriv!=
"hdiv")
throw std::runtime_error(myerror);
216 size_t pos2 = name.find_first_of(
" _",pos1);
217 if(pos2==0)
throw std::runtime_error(myerror);
218 string el =
tolower(name.substr(pos1,pos2-pos1));
219 if(el!=
"hex" && el!=
"line" && el!=
"poly" && el!=
"pyr" && el!=
"quad" && el!=
"tet" && el!=
"tri" && el!=
"wedge")
throw std::runtime_error(myerror);
223 string poly =
tolower(name.substr(pos2,1));
224 if(poly!=
"c" && poly!=
"i")
throw std::runtime_error(myerror);
228 degree=std::stoi(name.substr(pos2,1));
229 if(degree<=0)
throw std::runtime_error(myerror);
232 #ifdef HAVE_MUELU_INTREPID2_REFACTOR 233 if(deriv==
"hgrad" && el==
"quad" && poly==
"c"){
234 if(degree==1)
return rcp(
new Intrepid2::Basis_HGRAD_QUAD_C1_FEM<KokkosExecutionSpace,Scalar,Scalar>());
235 else return rcp(
new Intrepid2::Basis_HGRAD_QUAD_Cn_FEM<KokkosExecutionSpace,Scalar,Scalar>(degree,Intrepid2::POINTTYPE_EQUISPACED));
237 else if(deriv==
"hgrad" && el==
"line" && poly==
"c"){
238 if(degree==1)
return rcp(
new Intrepid2::Basis_HGRAD_LINE_C1_FEM<KokkosExecutionSpace,Scalar,Scalar>());
239 else return rcp(
new Intrepid2::Basis_HGRAD_LINE_Cn_FEM<KokkosExecutionSpace,Scalar,Scalar>(degree,Intrepid2::POINTTYPE_EQUISPACED));
242 typedef Intrepid2::FieldContainer<Scalar> ArrayScalar;
243 if(deriv==
"hgrad" && el==
"quad" && poly==
"c"){
244 if(degree==1)
return rcp(
new Intrepid2::Basis_HGRAD_QUAD_C1_FEM<Scalar,ArrayScalar>());
245 else return rcp(
new Intrepid2::Basis_HGRAD_QUAD_Cn_FEM<Scalar,ArrayScalar>(degree,Intrepid2::POINTTYPE_EQUISPACED));
247 else if(deriv==
"hgrad" && el==
"line" && poly==
"c"){
248 if(degree==1)
return rcp(
new Intrepid2::Basis_HGRAD_LINE_C1_FEM<Scalar,ArrayScalar>());
249 else return rcp(
new Intrepid2::Basis_HGRAD_LINE_Cn_FEM<Scalar,ArrayScalar>(degree,Intrepid2::POINTTYPE_EQUISPACED));
255 throw std::runtime_error(myerror);
256 return Teuchos::null;
266 #ifdef HAVE_MUELU_INTREPID2_REFACTOR 267 template<
class Scalar,
class KokkosDeviceType>
268 void IntrepidGetP1NodeInHi(
const Teuchos::RCP<Intrepid2::Basis<typename KokkosDeviceType::execution_space,Scalar,Scalar> >&hi_basis,
269 std::vector<size_t> & lo_node_in_hi,
270 Kokkos::DynRankView<Scalar,KokkosDeviceType> & hi_DofCoords) {
272 typedef typename KokkosDeviceType::execution_space KokkosExecutionSpace;
274 size_t degree = hi_basis->getDegree();
275 lo_node_in_hi.resize(0);
277 if(!rcp_dynamic_cast<Intrepid2::Basis_HGRAD_QUAD_Cn_FEM<KokkosExecutionSpace,Scalar,Scalar> >(hi_basis).is_null()) {
279 lo_node_in_hi.insert(lo_node_in_hi.end(),{0,degree, (degree+1)*(degree+1)-1, degree*(degree+1)});
281 else if(!rcp_dynamic_cast<Intrepid2::Basis_HGRAD_LINE_Cn_FEM<KokkosExecutionSpace,Scalar,Scalar> >(hi_basis).is_null()) {
283 lo_node_in_hi.insert(lo_node_in_hi.end(),{0,degree});
286 throw std::runtime_error(
"IntrepidPCoarsenFactory: Unknown element type");
289 Kokkos::Experimental::resize(hi_DofCoords,hi_basis->getCardinality(),hi_basis->getBaseCellTopology().getDimension());
290 hi_basis->getDofCoords(hi_DofCoords);
293 typedef<class Scalar, class ArrayScalar>
295 std::vector<size_t> & lo_node_in_hi,
296 ArrayScalar & hi_DofCoords) {
299 size_t degree = hi_basis->getDegree();
300 lo_node_in_hi.resize(0);
301 RCP<Intrepid2::DofCoordsInterface<ArrayScalar> > hi_dci;
302 if(!rcp_dynamic_cast<Intrepid2::Basis_HGRAD_QUAD_Cn_FEM<Scalar,ArrayScalar> >(hi_basis).is_null()) {
304 lo_node_in_hi.insert(lo_node_in_hi.end(),{0,degree, (degree+1)*(degree+1)-1, degree*(degree+1)});
305 hi_dci = rcp_dynamic_cast<Intrepid2::Basis_HGRAD_QUAD_Cn_FEM<Scalar,ArrayScalar> >(hi_basis);
307 else if(!rcp_dynamic_cast<Intrepid2::Basis_HGRAD_LINE_Cn_FEM<Scalar,ArrayScalar> >(hi_basis).is_null()) {
309 lo_node_in_hi.insert(lo_node_in_hi.end(),{0,degree});
310 hi_dci = rcp_dynamic_cast<Intrepid2::Basis_HGRAD_LINE_Cn_FEM<Scalar,ArrayScalar> >(hi_basis);
313 throw std::runtime_error(
"IntrepidPCoarsenFactory: Unknown element type");
316 hi_DofCoords.resize(hi_basis->getCardinality(),hi_basis->getBaseCellTopology().getDimension());
317 hi_dci->getDofCoords(hi_DofCoords);
330 template<
class LocalOrdinal,
class GlobalOrdinal,
class Node,
class LOFieldContainer>
332 RCP<
const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > & hi_columnMap,
333 LOFieldContainer & lo_elemToHiRepresentativeNode) {
334 typedef GlobalOrdinal GO;
339 size_t numElem = hi_elemToNode.dimension(0);
340 size_t lo_nperel = candidates.size();
341 Kokkos::Experimental::resize(lo_elemToHiRepresentativeNode,numElem, lo_nperel);
344 for(
size_t i=0; i<numElem; i++)
345 for(
size_t j=0; j<lo_nperel; j++) {
346 if(candidates[j].size() == 1)
347 lo_elemToHiRepresentativeNode(i,j) = hi_elemToNode(i,candidates[j][0]);
350 std::vector<GO> GID(candidates[j].size());
351 for(
size_t k=0; k<(size_t)candidates[j].size(); k++)
352 GID[k] = hi_columnMap->getGlobalElement(hi_elemToNode(i,candidates[j][k]));
355 size_t which = std::distance(GID.begin(),std::min_element(GID.begin(),GID.end()));
358 lo_elemToHiRepresentativeNode(i,j) = hi_elemToNode(i,candidates[j][which]);
373 template <
class LocalOrdinal,
class LOFieldContainer>
375 const std::vector<bool> & hi_nodeIsOwned,
376 const LOFieldContainer & lo_elemToHiRepresentativeNode,
377 LOFieldContainer & lo_elemToNode,
378 std::vector<bool> & lo_nodeIsOwned,
379 std::vector<LocalOrdinal> & hi_to_lo_map,
380 int & lo_numOwnedNodes) {
381 typedef LocalOrdinal LO;
384 size_t numElem = hi_elemToNode.dimension(0);
385 size_t hi_numNodes = hi_nodeIsOwned.size();
386 size_t lo_nperel = lo_elemToHiRepresentativeNode.dimension(1);
387 Kokkos::Experimental::resize(lo_elemToNode,numElem, lo_nperel);
390 std::vector<bool> is_low_order(hi_numNodes,
false);
391 for(
size_t i=0; i<numElem; i++)
392 for(
size_t j=0; j<lo_nperel; j++) {
393 LO
id = lo_elemToHiRepresentativeNode(i,j);
394 is_low_order[id] =
true;
399 size_t lo_numNodes=0;
400 hi_to_lo_map.resize(hi_numNodes,Teuchos::OrdinalTraits<LO>::invalid());
402 for(
size_t i=0; i<hi_numNodes; i++)
403 if(is_low_order[i]) {
404 hi_to_lo_map[i] = lo_numNodes;
406 if(hi_nodeIsOwned[i]) lo_numOwnedNodes++;
410 lo_nodeIsOwned.resize(lo_numNodes,
false);
411 for(
size_t i=0; i<hi_numNodes; i++) {
412 if(is_low_order[i] && hi_nodeIsOwned[i])
413 lo_nodeIsOwned[hi_to_lo_map[i]]=
true;
417 for(
size_t i=0; i<numElem; i++)
418 for(
size_t j=0; j<lo_nperel; j++)
419 lo_elemToNode(i,j) = hi_to_lo_map[lo_elemToHiRepresentativeNode(i,j)];
424 bool map_ordering_test_passed=
true;
425 for(
size_t i=0; i<lo_numNodes-1; i++)
426 if(!lo_nodeIsOwned[i] && lo_nodeIsOwned[i+1])
427 map_ordering_test_passed=
false;
429 if(!map_ordering_test_passed)
430 throw std::runtime_error(
"MueLu::MueLuIntrepid::BuildLoElemToNodeViaRepresentatives failed map ordering test");
446 template <
class LocalOrdinal,
class LOFieldContainer>
448 const std::vector<bool> & hi_nodeIsOwned,
449 const std::vector<size_t> & lo_node_in_hi,
450 const Teuchos::ArrayRCP<const int> & hi_isDirichlet,
451 LOFieldContainer & lo_elemToNode,
452 std::vector<bool> & lo_nodeIsOwned,
453 std::vector<LocalOrdinal> & hi_to_lo_map,
454 int & lo_numOwnedNodes) {
455 typedef LocalOrdinal LO;
457 LocalOrdinal LOINVALID = Teuchos::OrdinalTraits<LocalOrdinal>::invalid();
460 size_t numElem = hi_elemToNode.dimension(0);
461 size_t hi_numNodes = hi_nodeIsOwned.size();
463 size_t lo_nperel = lo_node_in_hi.size();
464 Kokkos::Experimental::resize(lo_elemToNode,numElem, lo_nperel);
467 std::vector<bool> is_low_order(hi_numNodes,
false);
468 for(
size_t i=0; i<numElem; i++)
469 for(
size_t j=0; j<lo_nperel; j++) {
470 LO lid = hi_elemToNode(i,lo_node_in_hi[j]);
473 if(hi_isDirichlet[lid])
474 lo_elemToNode(i,j) = LOINVALID;
476 lo_elemToNode(i,j) = lid;
477 is_low_order[hi_elemToNode(i,lo_node_in_hi[j])] =
true;
483 size_t lo_numNodes=0;
484 hi_to_lo_map.resize(hi_numNodes,Teuchos::OrdinalTraits<LO>::invalid());
486 for(
size_t i=0; i<hi_numNodes; i++)
487 if(is_low_order[i]) {
488 hi_to_lo_map[i] = lo_numNodes;
490 if(hi_nodeIsOwned[i]) lo_numOwnedNodes++;
494 lo_nodeIsOwned.resize(lo_numNodes,
false);
495 for(
size_t i=0; i<hi_numNodes; i++) {
496 if(is_low_order[i] && hi_nodeIsOwned[i])
497 lo_nodeIsOwned[hi_to_lo_map[i]]=
true;
501 for(
size_t i=0; i<numElem; i++)
502 for(
size_t j=0; j<lo_nperel; j++) {
503 if(lo_elemToNode(i,j) != LOINVALID)
504 lo_elemToNode(i,j) = hi_to_lo_map[lo_elemToNode(i,j)];
509 bool map_ordering_test_passed=
true;
510 for(
size_t i=0; i<lo_numNodes-1; i++)
511 if(!lo_nodeIsOwned[i] && lo_nodeIsOwned[i+1])
512 map_ordering_test_passed=
false;
514 if(!map_ordering_test_passed)
515 throw std::runtime_error(
"MueLu::MueLuIntrepid::BuildLoElemToNode failed map ordering test");
528 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
529 void GenerateColMapFromImport(
const Xpetra::Import<LocalOrdinal,GlobalOrdinal, Node> & hi_importer,
const std::vector<LocalOrdinal> &hi_to_lo_map,
const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> & lo_domainMap,
const size_t & lo_columnMapLength, RCP<
const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > & lo_columnMap) {
530 typedef LocalOrdinal LO;
531 typedef GlobalOrdinal GO;
533 typedef Xpetra::Map<LO,GO,NO> Map;
534 typedef Xpetra::Vector<GO,LO,GO,NO> GOVector;
536 GO go_invalid = Teuchos::OrdinalTraits<GO>::invalid();
537 LO lo_invalid = Teuchos::OrdinalTraits<LO>::invalid();
539 RCP<const Map> hi_domainMap = hi_importer.getSourceMap();
540 RCP<const Map> hi_columnMap = hi_importer.getTargetMap();
546 RCP<GOVector> dvec = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(hi_domainMap);
547 ArrayRCP<GO> dvec_data = dvec->getDataNonConst(0);
548 for(
size_t i=0; i<hi_domainMap->getNodeNumElements(); i++) {
549 if(hi_to_lo_map[i]!=lo_invalid) dvec_data[i] = lo_domainMap.getGlobalElement(hi_to_lo_map[i]);
550 else dvec_data[i] = go_invalid;
554 RCP<GOVector> cvec = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(hi_columnMap,
true);
555 cvec->doImport(*dvec,hi_importer,Xpetra::ADD);
559 Array<GO> lo_col_data(lo_columnMapLength);
560 ArrayRCP<GO> cvec_data = cvec->getDataNonConst(0);
561 for(
size_t i=0,idx=0; i<hi_columnMap->getNodeNumElements(); i++) {
562 if(hi_to_lo_map[i]!=lo_invalid) {
563 lo_col_data[idx] = cvec_data[i];
568 lo_columnMap = Xpetra::MapFactory<LO,GO,NO>::Build(lo_domainMap.lib(),Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(),lo_col_data(),lo_domainMap.getIndexBase(),lo_domainMap.getComm());
579 template<
class Basis,
class SCFieldContainer>
580 void GenerateRepresentativeBasisNodes(
const Basis & basis,
const SCFieldContainer & ReferenceNodeLocations,
const double threshold,std::vector<std::vector<size_t> > & representative_node_candidates) {
581 typedef SCFieldContainer FC;
582 #ifdef HAVE_MUELU_INTREPID2_REFACTOR 583 typedef typename FC::data_type SC;
585 typedef typename FC::scalar_type SC;
588 size_t numFieldsHi = ReferenceNodeLocations.dimension(0);
590 size_t numFieldsLo = basis.getCardinality();
592 #ifdef HAVE_MUELU_INTREPID2_REFACTOR 593 FC LoValues(
"LoValues",numFieldsLo,numFieldsHi);
595 FC LoValues(numFieldsLo,numFieldsHi);
598 basis.getValues(LoValues, ReferenceNodeLocations , Intrepid2::OPERATOR_VALUE);
602 printf(
"** LoValues[%d,%d] **\n",(
int)numFieldsLo,(
int)numFieldsHi);
603 for(
size_t i=0; i<numFieldsLo; i++) {
604 for(
size_t j=0; j<numFieldsHi; j++)
605 printf(
"%6.4e ",LoValues(i,j));
608 printf(
"**************\n");fflush(stdout);
611 representative_node_candidates.resize(numFieldsLo);
612 for(
size_t i=0; i<numFieldsLo; i++) {
614 double vmax = Teuchos::ScalarTraits<SC>::zero();
615 for(
size_t j=0; j<numFieldsHi; j++)
616 vmax = std::max(vmax,Teuchos::ScalarTraits<SC>::magnitude(LoValues(i,j)));
619 for(
size_t j=0; j<numFieldsHi; j++) {
620 if(Teuchos::ScalarTraits<SC>::magnitude(vmax - LoValues(i,j)) < threshold*vmax)
621 representative_node_candidates[i].push_back(j);
626 for(
size_t i=0; i<numFieldsLo; i++)
627 if(!representative_node_candidates[i].size())
628 throw std::runtime_error(
"ERROR: GenerateRepresentativeBasisNodes: No candidates found!");
641 template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
643 const std::vector<bool> & hi_nodeIsOwned,
645 const std::vector<size_t> &lo_node_in_hi,
646 const Basis &lo_basis,
647 const std::vector<LocalOrdinal> & hi_to_lo_map,
648 const Teuchos::RCP<const Map> & lo_colMap,
649 const Teuchos::RCP<const Map> & lo_domainMap,
650 const Teuchos::RCP<const Map> & hi_map,
651 Teuchos::RCP<Matrix>& P)
const{
654 size_t numFieldsHi = hi_elemToNode.dimension(1);
655 size_t numFieldsLo = lo_basis.getCardinality();
656 LocalOrdinal LOINVALID = Teuchos::OrdinalTraits<LocalOrdinal>::invalid();
657 #ifdef HAVE_MUELU_INTREPID2_REFACTOR 658 FC LoValues_at_HiDofs(
"LoValues_at_HiDofs",numFieldsLo,numFieldsHi);
660 FC LoValues_at_HiDofs(numFieldsLo,numFieldsHi);
662 lo_basis.getValues(LoValues_at_HiDofs, hi_DofCoords, Intrepid2::OPERATOR_VALUE);
664 typedef typename Teuchos::ScalarTraits<SC>::halfPrecision SClo;
665 typedef typename Teuchos::ScalarTraits<SClo>::magnitudeType MT;
666 MT effective_zero = Teuchos::ScalarTraits<MT>::eps();
669 P = rcp(
new CrsMatrixWrap(hi_map,lo_colMap,0));
670 RCP<CrsMatrix> Pcrs = rcp_dynamic_cast<CrsMatrixWrap>(P)->getCrsMatrix();
673 size_t Nelem=hi_elemToNode.dimension(0);
674 std::vector<bool> touched(hi_map->getNodeNumElements(),
false);
675 Teuchos::Array<GO> col_gid(1);
676 Teuchos::Array<SC> val(1);
677 for(
size_t i=0; i<Nelem; i++) {
678 for(
size_t j=0; j<numFieldsHi; j++) {
679 LO row_lid = hi_elemToNode(i,j);
680 GO row_gid = hi_map->getGlobalElement(row_lid);
681 if(hi_nodeIsOwned[row_lid] && !touched[row_lid]) {
682 for(
size_t k=0; k<numFieldsLo; k++) {
684 LO col_lid = hi_to_lo_map[hi_elemToNode(i,lo_node_in_hi[k])];
685 if(col_lid==LOINVALID)
continue;
687 col_gid[0] = {lo_colMap->getGlobalElement(col_lid)};
688 val[0] = LoValues_at_HiDofs(k,j);
691 if(Teuchos::ScalarTraits<SC>::magnitude(val[0]) >= effective_zero)
692 P->insertGlobalValues(row_gid,col_gid(),val());
694 touched[row_lid]=
true;
698 P->fillComplete(lo_domainMap,hi_map);
702 template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
704 const std::vector<bool> & hi_nodeIsOwned,
707 const Basis &lo_basis,
708 const std::vector<LocalOrdinal> & hi_to_lo_map,
709 const Teuchos::RCP<const Map> & lo_colMap,
710 const Teuchos::RCP<const Map> & lo_domainMap,
711 const Teuchos::RCP<const Map> & hi_map,
712 Teuchos::RCP<Matrix>& P)
const{
715 size_t numFieldsHi = hi_elemToNode.dimension(1);
716 size_t numFieldsLo = lo_basis.getCardinality();
717 #ifdef HAVE_MUELU_INTREPID2_REFACTOR 718 FC LoValues_at_HiDofs(
"LoValues_at_HiDofs",numFieldsLo,numFieldsHi);
720 FC LoValues_at_HiDofs(numFieldsLo,numFieldsHi);
722 lo_basis.getValues(LoValues_at_HiDofs, hi_DofCoords, Intrepid2::OPERATOR_VALUE);
724 typedef typename Teuchos::ScalarTraits<SC>::halfPrecision SClo;
725 typedef typename Teuchos::ScalarTraits<SClo>::magnitudeType MT;
726 MT effective_zero = Teuchos::ScalarTraits<MT>::eps();
729 P = rcp(
new CrsMatrixWrap(hi_map,lo_colMap,0));
730 RCP<CrsMatrix> Pcrs = rcp_dynamic_cast<CrsMatrixWrap>(P)->getCrsMatrix();
733 size_t Nelem=hi_elemToNode.dimension(0);
734 std::vector<bool> touched(hi_map->getNodeNumElements(),
false);
735 Teuchos::Array<GO> col_gid(1);
736 Teuchos::Array<SC> val(1);
737 for(
size_t i=0; i<Nelem; i++) {
738 for(
size_t j=0; j<numFieldsHi; j++) {
739 LO row_lid = hi_elemToNode(i,j);
740 GO row_gid = hi_map->getGlobalElement(row_lid);
741 if(hi_nodeIsOwned[row_lid] && !touched[row_lid]) {
742 for(
size_t k=0; k<numFieldsLo; k++) {
744 LO col_lid = hi_to_lo_map[lo_elemToHiRepresentativeNode(i,k)];
745 col_gid[0] = {lo_colMap->getGlobalElement(col_lid)};
746 val[0] = LoValues_at_HiDofs(k,j);
749 if(Teuchos::ScalarTraits<SC>::magnitude(val[0]) >= effective_zero)
750 P->insertGlobalValues(row_gid,col_gid(),val());
752 touched[row_lid]=
true;
756 P->fillComplete(lo_domainMap,hi_map);
760 template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
762 RCP<ParameterList> validParamList = rcp(
new ParameterList());
764 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name)) 767 #undef SET_VALID_ENTRY 769 validParamList->set< RCP<const FactoryBase> >(
"A", Teuchos::null,
"Generating factory of the matrix A used during the prolongator smoothing process");
771 validParamList->set< RCP<const FactoryBase> >(
"Nullspace", Teuchos::null,
"Generating factory of the nullspace");
772 validParamList->set< RCP<const FactoryBase> >(
"pcoarsen: element to node map", Teuchos::null,
"Generating factory of the element to node map");
773 return validParamList;
777 template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
779 Input(fineLevel,
"A");
780 Input(fineLevel,
"pcoarsen: element to node map");
781 Input(fineLevel,
"Nullspace");
785 template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
787 return BuildP(fineLevel, coarseLevel);
791 template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
795 const std::string prefix =
"MueLu::IntrepidPCoarsenFactory(" + levelIDs +
"): ";
798 #ifdef HAVE_MUELU_INTREPID2_REFACTOR 799 typedef Kokkos::DynRankView<LocalOrdinal,typename Node::device_type> FCi;
800 typedef Kokkos::DynRankView<double,typename Node::device_type> FC;
802 typedef Intrepid2::FieldContainer<LocalOrdinal> FCi;
803 typedef Intrepid2::FieldContainer<double> FC;
807 RCP<Matrix> A = Get< RCP<Matrix> >(fineLevel,
"A");
808 RCP<MultiVector> fineNullspace = Get< RCP<MultiVector> >(fineLevel,
"Nullspace");
809 Xpetra::CrsMatrixWrap<Scalar,LocalOrdinal,GlobalOrdinal,Node>& Acrs =
dynamic_cast<Xpetra::CrsMatrixWrap<Scalar,LocalOrdinal,GlobalOrdinal,Node>&
>(*A);
812 if (restrictionMode_) {
818 std::vector<LocalOrdinal> A_dirichletRows;
825 RCP<ParameterList> APparams = rcp(
new ParameterList);
826 if (coarseLevel.
IsAvailable(
"AP reuse data",
this)) {
827 GetOStream(static_cast<MsgType>(
Runtime0 |
Test)) <<
"Reusing previous AP data" << std::endl;
829 APparams = coarseLevel.
Get< RCP<ParameterList> >(
"AP reuse data",
this);
831 if (APparams->isParameter(
"graph"))
832 finalP = APparams->get< RCP<Matrix> >(
"graph");
834 const ParameterList& pL = GetParameterList();
841 int lo_degree, hi_degree;
842 #ifdef HAVE_MUELU_INTREPID2_REFACTOR 843 RCP<Basis> hi_basis = MueLuIntrepid::BasisFactory<double,typename Node::device_type::execution_space>(pL.get<std::string>(
"pcoarsen: hi basis"),hi_degree);
844 RCP<Basis> lo_basis = MueLuIntrepid::BasisFactory<double,typename Node::device_type::execution_space>(pL.get<std::string>(
"pcoarsen: lo basis"),lo_degree);
846 RCP<Basis> hi_basis = MueLuIntrepid::BasisFactory<double>(pL.get<std::string>(
"pcoarsen: hi basis"),hi_degree);
847 RCP<Basis> lo_basis = MueLuIntrepid::BasisFactory<double>(pL.get<std::string>(
"pcoarsen: lo basis"),lo_degree);
851 GetOStream(
Statistics1) <<
"P-Coarsening from basis "<<pL.get<std::string>(
"pcoarsen: hi basis")<<
" to "<<pL.get<std::string>(
"pcoarsen: lo basis") <<std::endl;
855 const Teuchos::RCP<FCi> Pn_elemToNode = Get<Teuchos::RCP<FCi> >(fineLevel,
"pcoarsen: element to node map");
862 RCP<const Map> rowMap = A->getRowMap();
863 RCP<const Map> colMap = Acrs.getColMap();
864 RCP<const Map> domainMap = A->getDomainMap();
865 int NumProc = rowMap->getComm()->getSize();
866 assert(rowMap->isSameAs(*domainMap));
867 std::vector<bool> Pn_nodeIsOwned(colMap->getNodeNumElements(),
false);
868 LO num_owned_rows = 0;
869 for(
size_t i=0; i<rowMap->getNodeNumElements(); i++) {
870 if(rowMap->getGlobalElement(i) == colMap->getGlobalElement(i)) {
871 Pn_nodeIsOwned[i] =
true;
878 Teuchos::RCP<FCi> P1_elemToNode = rcp(
new FCi());
880 std::vector<bool> P1_nodeIsOwned;
881 int P1_numOwnedNodes;
882 std::vector<LO> hi_to_lo_map;
885 std::vector<size_t> lo_node_in_hi;
888 FCi lo_elemToHiRepresentativeNode;
891 RCP<Xpetra::Vector<int,LocalOrdinal,GlobalOrdinal,Node> > hi_isDirichletRow, hi_isDirichletCol;
895 printf(
"[%d] isDirichletRow = ",A->getRowMap()->getComm()->getRank());
896 for(
size_t i=0;i<hi_isDirichletRow->getMap()->getNodeNumElements(); i++)
897 printf(
"%d ",hi_isDirichletRow->getData(0)[i]);
899 printf(
"[%d] isDirichletCol = ",A->getRowMap()->getComm()->getRank());
900 for(
size_t i=0;i<hi_isDirichletCol->getMap()->getNodeNumElements(); i++)
901 printf(
"%d ",hi_isDirichletCol->getData(0)[i]);
909 MueLuIntrepid::IntrepidGetP1NodeInHi(hi_basis,lo_node_in_hi,hi_DofCoords);
912 MueLuIntrepid::BuildLoElemToNode(*Pn_elemToNode,Pn_nodeIsOwned,lo_node_in_hi,hi_isDirichletCol->getData(0),*P1_elemToNode,P1_nodeIsOwned,hi_to_lo_map,P1_numOwnedNodes);
913 assert(hi_to_lo_map.size() == colMap->getNodeNumElements());
917 double threshold = 1e-10;
918 std::vector<std::vector<size_t> > candidates;
919 #ifdef HAVE_MUELU_INTREPID2_REFACTOR 920 Kokkos::Experimental::resize(hi_DofCoords,hi_basis->getCardinality(),hi_basis->getBaseCellTopology().getDimension());
921 hi_basis->getDofCoords(hi_DofCoords);
924 RCP<Intrepid2::DofCoordsInterface<ArrayScalar> > hi_dci = rcp_dynamic_cast<Intrepid2::DofCoordsInterface<ArrayScalar> >(hi_basis);
925 hi_DofCoords.resize(hi_basis->getCardinality(),hi_basis->getBaseCellTopology().getDimension());
926 hi_dci->getDofCoords(hi_DofCoords);
929 MueLu::MueLuIntrepid::GenerateRepresentativeBasisNodes<Basis,FC>(*lo_basis,hi_DofCoords,threshold,candidates);
940 RCP<const Map> P1_domainMap = MapFactory::Build(rowMap->lib(),Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(),P1_numOwnedNodes,rowMap->getIndexBase(),rowMap->getComm());
944 RCP<const Map> P1_colMap;
945 if(NumProc==1) P1_colMap = P1_domainMap;
946 else MueLuIntrepid::GenerateColMapFromImport<LO,GO,NO>(*Acrs.getCrsGraph()->getImporter(),hi_to_lo_map,*P1_domainMap,P1_nodeIsOwned.size(),P1_colMap);
951 GenerateLinearCoarsening_pn_kirby_to_p1(*Pn_elemToNode,Pn_nodeIsOwned,hi_DofCoords,lo_node_in_hi,*lo_basis,hi_to_lo_map,P1_colMap,P1_domainMap,A->getRowMap(),finalP);
953 GenerateLinearCoarsening_pn_kirby_to_pm(*Pn_elemToNode,Pn_nodeIsOwned,hi_DofCoords,lo_elemToHiRepresentativeNode,*lo_basis,hi_to_lo_map,P1_colMap,P1_domainMap,A->getRowMap(),finalP);
961 RCP<MultiVector> coarseNullspace = MultiVectorFactory::Build(P1_domainMap, fineNullspace->getNumVectors());
962 finalP->apply(*fineNullspace,*coarseNullspace,Teuchos::TRANS);
963 Set(coarseLevel,
"Nullspace", coarseNullspace);
966 if (!restrictionMode_) {
968 Set(coarseLevel,
"P", finalP);
970 APparams->set(
"graph", finalP);
974 RCP<ParameterList> params = rcp(
new ParameterList());
975 params->set(
"printLoadBalancingInfo",
true);
976 params->set(
"printCommInfo",
true);
987 Set(coarseLevel,
"R", R);
990 RCP<ParameterList> params = rcp(
new ParameterList());
991 params->set(
"printLoadBalancingInfo",
true);
992 params->set(
"printCommInfo",
true);
1001 #endif // MUELU_IPCFACTORY_DEF_HPP void GenerateLoNodeInHiViaGIDs(const std::vector< std::vector< size_t > > &candidates, const LOFieldContainer &hi_elemToNode, RCP< const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > &hi_columnMap, LOFieldContainer &lo_elemToHiRepresentativeNode)
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->Get< RCP<Matrix> >("A", factory) if factory == NULL => use default factory.
void FindGeometricSeedOrdinals(Teuchos::RCP< Basis > basis, const LOFieldContainer &elementToNodeMap, std::vector< std::vector< LocalOrdinal > > &seeds, const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &rowMap, const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &columnMap)
std::string toString(const T &what)
Little helper function to convert non-string types to strings.
void GenerateLinearCoarsening_pn_kirby_to_pm(const LOFieldContainer &hi_elemToNode, const std::vector< bool > &hi_nodeIsOwned, const SCFieldContainer &hi_DofCoords, const LOFieldContainer &lo_elemToHiRepresentativeNode, const Basis &lo_basis, const std::vector< LocalOrdinal > &hi_to_lo_map, const Teuchos::RCP< const Map > &lo_colMap, const Teuchos::RCP< const Map > &lo_domainMap, const Teuchos::RCP< const Map > &hi_map, Teuchos::RCP< Matrix > &P) const
Timer to be used in factories. Similar to Monitor but with additional timers.
typedef< class Scalar, class ArrayScalar > void IntrepidGetP1NodeIn(const Teuchos::RCP< Intrepid2::Basis< Scalar, ArrayScalar > > &hi_basis, std::vector< size_t > &lo_node_in_hi, ArrayScalar &hi_DofCoords)
One-liner description of what is happening.
std::string tolower(const std::string &str)
Namespace for MueLu classes and methods.
Print skeleton for the run, i.e. factory calls and used parameters.
Intrepid2::FieldContainer< double > SCFieldContainer
int GetLevelID() const
Return level number.
Teuchos::RCP< Intrepid2::Basis< Scalar, Intrepid2::FieldContainer< Scalar > > > BasisFactory(const std::string &name, int °ree)
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
Class that holds all level-specific information.
static void FindDirichletRowsAndPropagateToCols(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, Teuchos::RCP< Xpetra::Vector< int, LocalOrdinal, GlobalOrdinal, Node > > &isDirichletRow, Teuchos::RCP< Xpetra::Vector< int, LocalOrdinal, GlobalOrdinal, Node > > &isDirichletCol)
Timer to be used in factories. Similar to SubMonitor but adds a timer level by level.
void BuildLoElemToNode(const LOFieldContainer &hi_elemToNode, const std::vector< bool > &hi_nodeIsOwned, const std::vector< size_t > &lo_node_in_hi, const Teuchos::ArrayRCP< const int > &hi_isDirichlet, LOFieldContainer &lo_elemToNode, std::vector< bool > &lo_nodeIsOwned, std::vector< LocalOrdinal > &hi_to_lo_map, int &lo_numOwnedNodes)
void BuildLoElemToNodeViaRepresentatives(const LOFieldContainer &hi_elemToNode, const std::vector< bool > &hi_nodeIsOwned, const LOFieldContainer &lo_elemToHiRepresentativeNode, LOFieldContainer &lo_elemToNode, std::vector< bool > &lo_nodeIsOwned, std::vector< LocalOrdinal > &hi_to_lo_map, int &lo_numOwnedNodes)
#define MUELU_LEVEL_SET_IF_REQUESTED_OR_KEPT(level, ename, entry)
static void ZeroDirichletRows(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, const std::vector< LocalOrdinal > &dirichletRows)
static void FindDirichletRows(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, std::vector< LocalOrdinal > &dirichletRows, bool count_twos_as_dirichlet=false)
static RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Transpose(Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, bool optimizeTranspose=false, const std::string &label=std::string(), const Teuchos::RCP< Teuchos::ParameterList > ¶ms=Teuchos::null)
void GenerateLinearCoarsening_pn_kirby_to_p1(const LOFieldContainer &hi_elemToNode, const std::vector< bool > &hi_nodeIsOwned, const SCFieldContainer &hi_DofCoords, const std::vector< size_t > &lo_node_in_hi, const Basis &lo_Basis, const std::vector< LocalOrdinal > &hi_to_lo_map, const Teuchos::RCP< const Map > &lo_colMap, const Teuchos::RCP< const Map > &lo_domainMap, const Teuchos::RCP< const Map > &hi_map, Teuchos::RCP< Matrix > &P) const
void BuildP(Level &fineLevel, Level &coarseLevel) const
Abstract Build method.
static std::string PrintMatrixInfo(const Matrix &A, const std::string &msgTag, RCP< const Teuchos::ParameterList > params=Teuchos::null)
Intrepid2::FieldContainer< LocalOrdinal > LOFieldContainer
void GenerateColMapFromImport(const Xpetra::Import< LocalOrdinal, GlobalOrdinal, Node > &hi_importer, const std::vector< LocalOrdinal > &hi_to_lo_map, const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &lo_domainMap, const size_t &lo_columnMapLength, RCP< const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > &lo_columnMap)
void GenerateRepresentativeBasisNodes(const Basis &basis, const SCFieldContainer &ReferenceNodeLocations, const double threshold, std::vector< std::vector< size_t > > &representative_node_candidates)
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need's value has been saved.
void DeclareInput(Level &fineLevel, Level &coarseLevel) const
Input.
void Build(Level &fineLevel, Level &coarseLevel) const
Build method.
#define SET_VALID_ENTRY(name)