MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_IntrepidPCoarsenFactory_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_IPCFACTORY_DEF_HPP
47 #define MUELU_IPCFACTORY_DEF_HPP
48 
49 #include <Xpetra_Matrix.hpp>
50 #include <Xpetra_IO.hpp>
51 #include <sstream>
52 #include <algorithm>
53 
55 
56 #include "MueLu_Level.hpp"
57 #include "MueLu_MasterList.hpp"
58 #include "MueLu_Monitor.hpp"
59 #include "MueLu_PerfUtils.hpp"
60 #include "MueLu_Utilities.hpp"
61 
62 #include "Teuchos_ScalarTraits.hpp"
63 
64 // Intrepid Headers
65 
66 // Intrepid_HGRAD_HEX_C1_FEM.hpp
67 // Intrepid_HGRAD_HEX_C2_FEM.hpp
68 // Intrepid_HGRAD_HEX_Cn_FEM.hpp
69 // Intrepid_HGRAD_HEX_I2_FEM.hpp
70 #include "Intrepid2_HGRAD_LINE_C1_FEM.hpp"
71 #include "Intrepid2_HGRAD_LINE_Cn_FEM.hpp"
72 // Intrepid_HGRAD_LINE_Cn_FEM_JACOBI.hpp
73 // Intrepid_HGRAD_POLY_C1_FEM.hpp
74 // Intrepid_HGRAD_PYR_C1_FEM.hpp
75 // Intrepid_HGRAD_PYR_I2_FEM.hpp
76 #include "Intrepid2_HGRAD_QUAD_C1_FEM.hpp"
77 //#include Intrepid_HGRAD_QUAD_C2_FEM.hpp
78 #include "Intrepid2_HGRAD_QUAD_Cn_FEM.hpp"
79 // Intrepid_HGRAD_TET_C1_FEM.hpp
80 // Intrepid_HGRAD_TET_C2_FEM.hpp
81 // Intrepid_HGRAD_TET_Cn_FEM.hpp
82 // Intrepid_HGRAD_TET_Cn_FEM_ORTH.hpp
83 // Intrepid_HGRAD_TET_COMP12_FEM.hpp
84 // Intrepid_HGRAD_TRI_C1_FEM.hpp
85 // Intrepid_HGRAD_TRI_C2_FEM.hpp
86 // Intrepid_HGRAD_TRI_Cn_FEM.hpp
87 // Intrepid_HGRAD_TRI_Cn_FEM_ORTH.hpp
88 // Intrepid_HGRAD_WEDGE_C1_FEM.hpp
89 // Intrepid_HGRAD_WEDGE_C2_FEM.hpp
90 // Intrepid_HGRAD_WEDGE_I2_FEM.hpp
91 
92 // Helper Macro to avoid "unrequested" warnings
93 #define MUELU_LEVEL_SET_IF_REQUESTED_OR_KEPT(level, ename, entry) \
94  { \
95  if (level.IsRequested(ename, this) || level.GetKeepFlag(ename, this) != 0) this->Set(level, ename, entry); \
96  }
97 
98 namespace MueLu {
99 
100 /*********************************************************************************************************/
101 namespace MueLuIntrepid {
102 inline std::string tolower(const std::string &str) {
103  std::string data(str);
104  std::transform(data.begin(), data.end(), data.begin(), ::tolower);
105  return data;
106 }
107 
108 /*********************************************************************************************************/
109 template <class Basis, class LOFieldContainer, class LocalOrdinal, class GlobalOrdinal, class Node>
110 void FindGeometricSeedOrdinals(Teuchos::RCP<Basis> basis, const LOFieldContainer &elementToNodeMap,
111  std::vector<std::vector<LocalOrdinal>> &seeds,
114  // For each subcell represented by the elements in elementToNodeMap, we want to identify a globally
115  // unique degree of freedom. Because the other "seed" interfaces in MueLu expect a local ordinal, we
116  // store local ordinals in the resulting seeds container.
117 
118  // The approach is as follows. For each element, we iterate through the subcells of the domain topology.
119  // We determine which, if any, of these has the lowest global ID owned that is locally owned. We then insert
120  // the local ID corresponding to this in a vector<set<int>> container whose outer index is the spatial dimension
121  // of the subcell. The set lets us conveniently enforce uniqueness of the stored LIDs.
122 
123  shards::CellTopology cellTopo = basis->getBaseCellTopology();
124  int spaceDim = cellTopo.getDimension();
125  seeds.clear();
126  seeds.resize(spaceDim + 1);
127  typedef GlobalOrdinal GO;
128  typedef LocalOrdinal LO;
129 
132 
133  std::vector<std::set<LocalOrdinal>> seedSets(spaceDim + 1);
134 
135  int numCells = elementToNodeMap.extent(0);
136  auto elementToNodeMap_host = Kokkos::create_mirror_view(elementToNodeMap);
137  Kokkos::deep_copy(elementToNodeMap_host, elementToNodeMap);
138  for (int cellOrdinal = 0; cellOrdinal < numCells; cellOrdinal++) {
139  for (int d = 0; d <= spaceDim; d++) {
140  int subcellCount = cellTopo.getSubcellCount(d);
141  for (int subcord = 0; subcord < subcellCount; subcord++) {
142  int dofCount = basis->getDofCount(d, subcord);
143  if (dofCount == 0) continue;
144  // otherwise, we want to insert the LID corresponding to the least globalID that is locally owned
145  GO leastGlobalDofOrdinal = go_invalid;
146  LO LID_leastGlobalDofOrdinal = lo_invalid;
147  for (int basisOrdinalOrdinal = 0; basisOrdinalOrdinal < dofCount; basisOrdinalOrdinal++) {
148  int basisOrdinal = basis->getDofOrdinal(d, subcord, basisOrdinalOrdinal);
149  int colLID = elementToNodeMap_host(cellOrdinal, basisOrdinal);
150  if (colLID != Teuchos::OrdinalTraits<LO>::invalid()) {
151  GlobalOrdinal colGID = columnMap.getGlobalElement(colLID);
152  LocalOrdinal rowLID = rowMap.getLocalElement(colGID);
153  if (rowLID != lo_invalid) {
154  if ((leastGlobalDofOrdinal == go_invalid) || (colGID < leastGlobalDofOrdinal)) {
155  // replace with rowLID
156  leastGlobalDofOrdinal = colGID;
157  LID_leastGlobalDofOrdinal = rowLID;
158  }
159  }
160  }
161  }
162  if (leastGlobalDofOrdinal != go_invalid) {
163  seedSets[d].insert(LID_leastGlobalDofOrdinal);
164  }
165  }
166  }
167  }
168  for (int d = 0; d <= spaceDim; d++) {
169  seeds[d] = std::vector<LocalOrdinal>(seedSets[d].begin(), seedSets[d].end());
170  }
171 }
172 
173 /*********************************************************************************************************/
174 // Syntax [HGRAD|HCURL|HDIV][_| ][HEX|LINE|POLY|PYR|QUAD|TET|TRI|WEDGE][_| ][C|I][1|2|n]
175 // Inputs:
176 // name - name of the intrepid basis to generate
177 // Outputs:
178 // degree - order of resulting discretization
179 // return value - Intrepid2 basis correspionding to the name
180 template <class Scalar, class KokkosExecutionSpace>
182  using std::string;
183  using Teuchos::rcp;
184  string myerror("IntrepidBasisFactory: cannot parse string name '" + name + "'");
185 
186  // Syntax [HGRAD|HCURL|HDIV][_| ][HEX|LINE|POLY|PYR|QUAD|TET|TRI|WEDGE][_| ][C|I][1|2|n]
187 
188  // Get the derivative type
189  size_t pos1 = name.find_first_of(" _");
190  if (pos1 == 0) throw std::runtime_error(myerror);
191  string deriv = tolower(name.substr(0, pos1));
192  if (deriv != "hgrad" && deriv != "hcurl" && deriv != "hdiv") throw std::runtime_error(myerror);
193 
194  // Get the element type
195  pos1++;
196  size_t pos2 = name.find_first_of(" _", pos1);
197  if (pos2 == 0) throw std::runtime_error(myerror);
198  string el = tolower(name.substr(pos1, pos2 - pos1));
199  if (el != "hex" && el != "line" && el != "poly" && el != "pyr" && el != "quad" && el != "tet" && el != "tri" && el != "wedge") throw std::runtime_error(myerror);
200 
201  // Get the polynomial type
202  pos2++;
203  string poly = tolower(name.substr(pos2, 1));
204  if (poly != "c" && poly != "i") throw std::runtime_error(myerror);
205 
206  // Get the degree
207  pos2++;
208  degree = std::stoi(name.substr(pos2, 1));
209  if (degree <= 0) throw std::runtime_error(myerror);
210 
211  // FIXME LATER: Allow for alternative point types for Kirby elements
212  if (deriv == "hgrad" && el == "quad" && poly == "c") {
213  if (degree == 1)
214  return rcp(new Intrepid2::Basis_HGRAD_QUAD_C1_FEM<KokkosExecutionSpace, Scalar, Scalar>());
215  else
216  return rcp(new Intrepid2::Basis_HGRAD_QUAD_Cn_FEM<KokkosExecutionSpace, Scalar, Scalar>(degree, Intrepid2::POINTTYPE_EQUISPACED));
217  } else if (deriv == "hgrad" && el == "line" && poly == "c") {
218  if (degree == 1)
219  return rcp(new Intrepid2::Basis_HGRAD_LINE_C1_FEM<KokkosExecutionSpace, Scalar, Scalar>());
220  else
221  return rcp(new Intrepid2::Basis_HGRAD_LINE_Cn_FEM<KokkosExecutionSpace, Scalar, Scalar>(degree, Intrepid2::POINTTYPE_EQUISPACED));
222  }
223 
224  // Error out
225  throw std::runtime_error(myerror);
226  TEUCHOS_UNREACHABLE_RETURN(Teuchos::null);
227 }
228 
229 /*********************************************************************************************************/
230 // Gets the "lo" nodes nested into a "hi" basis. Only works on quads and lines for a lo basis of p=1
231 // Inputs:
232 // hi_basis - Higher order Basis
233 // Outputs:
234 // lo_node_in_hi - std::vector<size_t> of size lo dofs in the reference element, which describes the coindcident hi dots
235 // hi_DofCoords - FC<Scalar> of size (#hi dofs, dim) with the coordinate locations of the hi dofs on the reference element
236 template <class Scalar, class KokkosDeviceType>
237 void IntrepidGetP1NodeInHi(const Teuchos::RCP<Intrepid2::Basis<typename KokkosDeviceType::execution_space, Scalar, Scalar>> &hi_basis,
238  std::vector<size_t> &lo_node_in_hi,
239  Kokkos::DynRankView<Scalar, KokkosDeviceType> &hi_DofCoords) {
240  typedef typename KokkosDeviceType::execution_space KokkosExecutionSpace;
241  // Figure out which unknowns in hi_basis correspond to nodes on lo_basis. This varies by element type.
242  size_t degree = hi_basis->getDegree();
243  lo_node_in_hi.resize(0);
244 
245  if (!rcp_dynamic_cast<Intrepid2::Basis_HGRAD_QUAD_Cn_FEM<KokkosExecutionSpace, Scalar, Scalar>>(hi_basis).is_null()) {
246  // HGRAD QUAD Cn: Numbering as per the Kirby convention (straight across, bottom to top)
247  lo_node_in_hi.insert(lo_node_in_hi.end(), {0, degree, (degree + 1) * (degree + 1) - 1, degree * (degree + 1)});
248  } else if (!rcp_dynamic_cast<Intrepid2::Basis_HGRAD_LINE_Cn_FEM<KokkosExecutionSpace, Scalar, Scalar>>(hi_basis).is_null()) {
249  // HGRAD LINE Cn: Numbering as per the Kirby convention (straight across)
250  lo_node_in_hi.insert(lo_node_in_hi.end(), {0, degree});
251  } else
252  throw std::runtime_error("IntrepidPCoarsenFactory: Unknown element type");
253 
254  // Get coordinates of the hi_basis dof's
255  Kokkos::resize(hi_DofCoords, hi_basis->getCardinality(), hi_basis->getBaseCellTopology().getDimension());
256  hi_basis->getDofCoords(hi_DofCoords);
257 }
258 
259 /*********************************************************************************************************/
260 // Given a list of candidates picks a definitive list of "representative" higher order nodes for each lo order node via the "smallest GID" rule
261 // Input:
262 // representative_node_candidates - std::vector<std::vector<size_t> > of lists of "representative candidate" hi dofs for each lo dof
263 // hi_elemToNode - FC<LO> containing the high order element-to-node map
264 // hi_columnMap - Column map of the higher order matrix
265 // Output:
266 // lo_elemToHiRepresentativeNode - FC<LO> of size (# elements, # lo dofs per element) listing the hi unknown chosen as the single representative for each lo unknown for counting purposes
267 template <class LocalOrdinal, class GlobalOrdinal, class Node, class LOFieldContainer>
268 void GenerateLoNodeInHiViaGIDs(const std::vector<std::vector<size_t>> &candidates, const LOFieldContainer &hi_elemToNode,
270  LOFieldContainer &lo_elemToHiRepresentativeNode) {
271  typedef GlobalOrdinal GO;
272 
273  // Given: A set of "candidate" hi-DOFs to serve as the "representative" DOF for each lo-DOF on the reference element.
274  // Algorithm: For each element, we choose the lowest GID of the candidates for each DOF to generate the lo_elemToHiRepresentativeNode map
275 
276  size_t numElem = hi_elemToNode.extent(0);
277  size_t lo_nperel = candidates.size();
278  Kokkos::resize(lo_elemToHiRepresentativeNode, numElem, lo_nperel);
279 
280  auto lo_elemToHiRepresentativeNode_host = Kokkos::create_mirror_view(lo_elemToHiRepresentativeNode);
281  auto hi_elemToNode_host = Kokkos::create_mirror_view(hi_elemToNode);
282  Kokkos::deep_copy(hi_elemToNode_host, hi_elemToNode);
283  for (size_t i = 0; i < numElem; i++)
284  for (size_t j = 0; j < lo_nperel; j++) {
285  if (candidates[j].size() == 1)
286  lo_elemToHiRepresentativeNode_host(i, j) = hi_elemToNode_host(i, candidates[j][0]);
287  else {
288  // First we get the GIDs for each candidate
289  std::vector<GO> GID(candidates[j].size());
290  for (size_t k = 0; k < (size_t)candidates[j].size(); k++)
291  GID[k] = hi_columnMap->getGlobalElement(hi_elemToNode_host(i, candidates[j][k]));
292 
293  // Find the one with smallest GID
294  size_t which = std::distance(GID.begin(), std::min_element(GID.begin(), GID.end()));
295 
296  // Record this
297  lo_elemToHiRepresentativeNode_host(i, j) = hi_elemToNode_host(i, candidates[j][which]);
298  }
299  }
300  Kokkos::deep_copy(lo_elemToHiRepresentativeNode, lo_elemToHiRepresentativeNode_host);
301 }
302 
303 /*********************************************************************************************************/
304 // Inputs:
305 // hi_elemToNode - FC<LO> containing the high order element-to-node map
306 // hi_nodeIsOwned - std::vector<bool> of size hi's column map, which described hi node ownership
307 // lo_elemToHiRepresentativeNode - FC<LO> of size (# elements, # lo dofs per element) listing the hi unknown chosen as the single representative for each lo unknown for counting purposes
308 // Outputs:
309 // lo_elemToNode - FC<LO> containing the low order element-to-node map.
310 // lo_nodeIsOwned - std::vector<bool> of size lo's (future) column map, which described lo node ownership
311 // hi_to_lo_map - std::vector<LO> of size equal to hi's column map, which contains the lo id each hi idea maps to (or invalid if it doesn't)
312 // lo_numOwnedNodes- Number of lo owned nodes
313 template <class LocalOrdinal, class LOFieldContainer>
314 void BuildLoElemToNodeViaRepresentatives(const LOFieldContainer &hi_elemToNode,
315  const std::vector<bool> &hi_nodeIsOwned,
316  const LOFieldContainer &lo_elemToHiRepresentativeNode,
317  LOFieldContainer &lo_elemToNode,
318  std::vector<bool> &lo_nodeIsOwned,
319  std::vector<LocalOrdinal> &hi_to_lo_map,
320  int &lo_numOwnedNodes) {
321  typedef LocalOrdinal LO;
322  using Teuchos::RCP;
323  // printf("CMS:BuildLoElemToNodeViaRepresentatives: hi_elemToNode.rank() = %d hi_elemToNode.size() = %d\n",hi_elemToNode.rank(), hi_elemToNode.size());
324  size_t numElem = hi_elemToNode.extent(0);
325  size_t hi_numNodes = hi_nodeIsOwned.size();
326  size_t lo_nperel = lo_elemToHiRepresentativeNode.extent(1);
327  Kokkos::resize(lo_elemToNode, numElem, lo_nperel);
328 
329  // Start by flagginc the representative nodes
330  auto lo_elemToHiRepresentativeNode_host = Kokkos::create_mirror_view(lo_elemToHiRepresentativeNode);
331  Kokkos::deep_copy(lo_elemToHiRepresentativeNode_host, lo_elemToHiRepresentativeNode);
332  std::vector<bool> is_low_order(hi_numNodes, false);
333  for (size_t i = 0; i < numElem; i++)
334  for (size_t j = 0; j < lo_nperel; j++) {
335  LO id = lo_elemToHiRepresentativeNode_host(i, j);
336  is_low_order[id] = true; // This can overwrite and that is OK.
337  }
338 
339  // Count the number of lo owned nodes, generating a local index for lo nodes
340  lo_numOwnedNodes = 0;
341  size_t lo_numNodes = 0;
342  hi_to_lo_map.resize(hi_numNodes, Teuchos::OrdinalTraits<LO>::invalid());
343 
344  for (size_t i = 0; i < hi_numNodes; i++)
345  if (is_low_order[i]) {
346  hi_to_lo_map[i] = lo_numNodes;
347  lo_numNodes++;
348  if (hi_nodeIsOwned[i]) lo_numOwnedNodes++;
349  }
350 
351  // Flag the owned lo nodes
352  lo_nodeIsOwned.resize(lo_numNodes, false);
353  for (size_t i = 0; i < hi_numNodes; i++) {
354  if (is_low_order[i] && hi_nodeIsOwned[i])
355  lo_nodeIsOwned[hi_to_lo_map[i]] = true;
356  }
357 
358  // Translate lo_elemToNode to a lo local index
359  auto lo_elemToNode_host = Kokkos::create_mirror_view(lo_elemToNode);
360  for (size_t i = 0; i < numElem; i++)
361  for (size_t j = 0; j < lo_nperel; j++)
362  lo_elemToNode_host(i, j) = hi_to_lo_map[lo_elemToHiRepresentativeNode_host(i, j)];
363 
364  // Check for the [E|T]petra column map ordering property, namely LIDs for owned nodes should all appear first.
365  // Since we're injecting from the higher-order mesh, it should be true, but we should add an error check & throw in case.
366  bool map_ordering_test_passed = true;
367  for (size_t i = 0; i < lo_numNodes - 1; i++)
368  if (!lo_nodeIsOwned[i] && lo_nodeIsOwned[i + 1])
369  map_ordering_test_passed = false;
370 
371  if (!map_ordering_test_passed)
372  throw std::runtime_error("MueLu::MueLuIntrepid::BuildLoElemToNodeViaRepresentatives failed map ordering test");
373  Kokkos::deep_copy(lo_elemToNode, lo_elemToNode_host);
374 }
375 
376 /*********************************************************************************************************/
377 // Inputs:
378 // hi_elemToNode - FC<LO> containing the high order element-to-node map
379 // hi_nodeIsOwned - std::vector<bool> of size hi's column map, which described hi node ownership
380 // lo_node_in_hi - std::vector<size_t> of size lo dofs in the reference element, which describes the coindcident hi dots
381 // hi_isDirichlet - ArrayView<int> of size of hi's column map, which has a 1 if the unknown is Dirichlet and a 0 if it isn't.
382 // Outputs:
383 // lo_elemToNode - FC<LO> containing the low order element-to-node map.
384 // lo_nodeIsOwned - std::vector<bool> of size lo's (future) column map, which described lo node ownership
385 // hi_to_lo_map - std::vector<LO> of size equal to hi's column map, which contains the lo id each hi idea maps to (or invalid if it doesn't)
386 // lo_numOwnedNodes- Number of lo owned nodes
387 template <class LocalOrdinal, class LOFieldContainer>
388 void BuildLoElemToNode(const LOFieldContainer &hi_elemToNode,
389  const std::vector<bool> &hi_nodeIsOwned,
390  const std::vector<size_t> &lo_node_in_hi,
391  const Teuchos::ArrayRCP<const int> &hi_isDirichlet,
392  LOFieldContainer &lo_elemToNode,
393  std::vector<bool> &lo_nodeIsOwned,
394  std::vector<LocalOrdinal> &hi_to_lo_map,
395  int &lo_numOwnedNodes) {
396  typedef LocalOrdinal LO;
397  using Teuchos::RCP;
399  // printf("CMS:BuildLoElemToNode: hi_elemToNode.rank() = %d hi_elemToNode.size() = %d\n",hi_elemToNode.rank(), hi_elemToNode.size());
400 
401  size_t numElem = hi_elemToNode.extent(0);
402  size_t hi_numNodes = hi_nodeIsOwned.size();
403 
404  size_t lo_nperel = lo_node_in_hi.size();
405  Kokkos::resize(lo_elemToNode, numElem, lo_nperel);
406 
407  // Build lo_elemToNode (in the hi local index ordering) and flag owned ones
408  std::vector<bool> is_low_order(hi_numNodes, false);
409  auto hi_elemToNode_host = Kokkos::create_mirror_view(hi_elemToNode);
410  Kokkos::deep_copy(hi_elemToNode_host, hi_elemToNode);
411  auto lo_elemToNode_host = Kokkos::create_mirror_view(lo_elemToNode);
412  for (size_t i = 0; i < numElem; i++)
413  for (size_t j = 0; j < lo_nperel; j++) {
414  LO lid = hi_elemToNode_host(i, lo_node_in_hi[j]);
415 
416  // Remove Dirichlet
417  if (hi_isDirichlet[lid])
418  lo_elemToNode_host(i, j) = LOINVALID;
419  else {
420  lo_elemToNode_host(i, j) = lid;
421  is_low_order[hi_elemToNode_host(i, lo_node_in_hi[j])] = true; // This can overwrite and that is OK.
422  }
423  }
424 
425  // Count the number of lo owned nodes, generating a local index for lo nodes
426  lo_numOwnedNodes = 0;
427  size_t lo_numNodes = 0;
428  hi_to_lo_map.resize(hi_numNodes, Teuchos::OrdinalTraits<LO>::invalid());
429 
430  for (size_t i = 0; i < hi_numNodes; i++)
431  if (is_low_order[i]) {
432  hi_to_lo_map[i] = lo_numNodes;
433  lo_numNodes++;
434  if (hi_nodeIsOwned[i]) lo_numOwnedNodes++;
435  }
436 
437  // Flag the owned lo nodes
438  lo_nodeIsOwned.resize(lo_numNodes, false);
439  for (size_t i = 0; i < hi_numNodes; i++) {
440  if (is_low_order[i] && hi_nodeIsOwned[i])
441  lo_nodeIsOwned[hi_to_lo_map[i]] = true;
442  }
443 
444  // Translate lo_elemToNode to a lo local index
445  for (size_t i = 0; i < numElem; i++)
446  for (size_t j = 0; j < lo_nperel; j++) {
447  if (lo_elemToNode_host(i, j) != LOINVALID)
448  lo_elemToNode_host(i, j) = hi_to_lo_map[lo_elemToNode_host(i, j)];
449  }
450  Kokkos::deep_copy(lo_elemToNode, lo_elemToNode_host);
451 
452  // Check for the [E|T]petra column map ordering property, namely LIDs for owned nodes should all appear first.
453  // Since we're injecting from the higher-order mesh, it should be true, but we should add an error check & throw in case.
454  bool map_ordering_test_passed = true;
455  for (size_t i = 0; i < lo_numNodes - 1; i++)
456  if (!lo_nodeIsOwned[i] && lo_nodeIsOwned[i + 1])
457  map_ordering_test_passed = false;
458 
459  if (!map_ordering_test_passed)
460  throw std::runtime_error("MueLu::MueLuIntrepid::BuildLoElemToNode failed map ordering test");
461 }
462 
463 /*********************************************************************************************************/
464 // Generates the lo_columnMap
465 // Input:
466 // hi_importer - Importer from the hi matrix
467 // hi_to_lo_map - std::vector<LO> of size equal to hi's column map, which contains the lo id each hi idea maps to (or invalid if it doesn't)
468 // lo_DomainMap - Domain map for the lo matrix
469 // lo_columnMapLength - Number of local columns in the lo column map
470 // Output:
471 // lo_columnMap - Column map of the lower order matrix
472 template <class LocalOrdinal, class GlobalOrdinal, class Node>
473 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) {
474  typedef LocalOrdinal LO;
475  typedef GlobalOrdinal GO;
476  typedef Node NO;
477  typedef Xpetra::Map<LO, GO, NO> Map;
478  typedef Xpetra::Vector<GO, LO, GO, NO> GOVector;
479 
480  GO go_invalid = Teuchos::OrdinalTraits<GO>::invalid();
481  LO lo_invalid = Teuchos::OrdinalTraits<LO>::invalid();
482 
483  RCP<const Map> hi_domainMap = hi_importer.getSourceMap();
484  RCP<const Map> hi_columnMap = hi_importer.getTargetMap();
485  // Figure out the GIDs of my non-owned P1 nodes
486  // HOW: We can build a GOVector(domainMap) and fill the values with either invalid() or the P1 domainMap.GID() for that guy.
487  // Then we can use A's importer to get a GOVector(colMap) with that information.
488 
489  // NOTE: This assumes rowMap==colMap and [E|T]petra ordering of all the locals first in the colMap
491  {
492  ArrayRCP<GO> dvec_data = dvec->getDataNonConst(0);
493  for (size_t i = 0; i < hi_domainMap->getLocalNumElements(); i++) {
494  if (hi_to_lo_map[i] != lo_invalid)
495  dvec_data[i] = lo_domainMap.getGlobalElement(hi_to_lo_map[i]);
496  else
497  dvec_data[i] = go_invalid;
498  }
499  }
500 
502  cvec->doImport(*dvec, hi_importer, Xpetra::ADD);
503 
504  // Generate the lo_columnMap
505  // HOW: We can use the local hi_to_lo_map from the GID's in cvec to generate the non-contiguous colmap ids.
506  Array<GO> lo_col_data(lo_columnMapLength);
507  {
508  ArrayRCP<GO> cvec_data = cvec->getDataNonConst(0);
509  for (size_t i = 0, idx = 0; i < hi_columnMap->getLocalNumElements(); i++) {
510  if (hi_to_lo_map[i] != lo_invalid) {
511  lo_col_data[idx] = cvec_data[i];
512  idx++;
513  }
514  }
515  }
516 
517  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());
518 }
519 
520 /*********************************************************************************************************/
521 // Generates a list of "representative candidate" hi dofs for each lo dof on the reference element. This is to be used in global numbering.
522 // Input:
523 // basis - The low order basis
524 // ReferenceNodeLocations - FC<Scalar> of size (#hidofs, dim) Locations of higher order nodes on the reference element
525 // threshold - tolerance for equivalance testing
526 // Output:
527 // representative_node_candidates - std::vector<std::vector<size_t> > of lists of "representative candidate" hi dofs for each lo dof
528 template <class Basis, class SCFieldContainer>
529 void GenerateRepresentativeBasisNodes(const Basis &basis, const SCFieldContainer &ReferenceNodeLocations, const double threshold, std::vector<std::vector<size_t>> &representative_node_candidates) {
530  typedef SCFieldContainer FC;
531  typedef typename FC::data_type SC;
532 
533  // Evaluate the linear basis functions at the Pn nodes
534  size_t numFieldsHi = ReferenceNodeLocations.extent(0);
535  // size_t dim = ReferenceNodeLocations.extent(1);
536  size_t numFieldsLo = basis.getCardinality();
537 
538  FC LoValues("LoValues", numFieldsLo, numFieldsHi);
539 
540  basis.getValues(LoValues, ReferenceNodeLocations, Intrepid2::OPERATOR_VALUE);
541 
542  Kokkos::fence(); // for kernel in getValues
543 
544 #if 0
545  printf("** LoValues[%d,%d] **\n",(int)numFieldsLo,(int)numFieldsHi);
546  for(size_t i=0; i<numFieldsLo; i++) {
547  for(size_t j=0; j<numFieldsHi; j++)
548  printf("%6.4e ",LoValues(i,j));
549  printf("\n");
550  }
551  printf("**************\n");fflush(stdout);
552 #endif
553 
554  representative_node_candidates.resize(numFieldsLo);
555  auto LoValues_host = Kokkos::create_mirror_view(LoValues);
556  Kokkos::deep_copy(LoValues_host, LoValues);
557  for (size_t i = 0; i < numFieldsLo; i++) {
558  // 1st pass: find the max value
560  for (size_t j = 0; j < numFieldsHi; j++)
561  vmax = std::max(vmax, Teuchos::ScalarTraits<SC>::magnitude(LoValues_host(i, j)));
562 
563  // 2nd pass: Find all values w/i threshhold of target
564  for (size_t j = 0; j < numFieldsHi; j++) {
565  if (Teuchos::ScalarTraits<SC>::magnitude(vmax - LoValues_host(i, j)) < threshold * vmax)
566  representative_node_candidates[i].push_back(j);
567  }
568  }
569 
570  // Sanity check
571  for (size_t i = 0; i < numFieldsLo; i++)
572  if (!representative_node_candidates[i].size())
573  throw std::runtime_error("ERROR: GenerateRepresentativeBasisNodes: No candidates found!");
574 }
575 
576 } // namespace MueLuIntrepid
577 
578 /*********************************************************************************************************/
579 /*********************************************************************************************************/
580 /*********************************************************************************************************/
581 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
583  const std::vector<bool> &hi_nodeIsOwned,
584  const SCFieldContainer &hi_DofCoords,
585  const std::vector<size_t> &lo_node_in_hi,
586  const Basis &lo_basis,
587  const std::vector<LocalOrdinal> &hi_to_lo_map,
588  const Teuchos::RCP<const Map> &lo_colMap,
589  const Teuchos::RCP<const Map> &lo_domainMap,
590  const Teuchos::RCP<const Map> &hi_map,
591  Teuchos::RCP<Matrix> &P) const {
592  typedef SCFieldContainer FC;
593  // Evaluate the linear basis functions at the Pn nodes
594  size_t numFieldsHi = hi_elemToNode.extent(1);
595  size_t numFieldsLo = lo_basis.getCardinality();
597  FC LoValues_at_HiDofs("LoValues_at_HiDofs", numFieldsLo, numFieldsHi);
598  lo_basis.getValues(LoValues_at_HiDofs, hi_DofCoords, Intrepid2::OPERATOR_VALUE);
599  auto LoValues_at_HiDofs_host = Kokkos::create_mirror_view(LoValues_at_HiDofs);
600  Kokkos::deep_copy(LoValues_at_HiDofs_host, LoValues_at_HiDofs);
601  Kokkos::fence(); // for kernel in getValues
602 
603  typedef typename Teuchos::ScalarTraits<SC>::halfPrecision SClo;
604  typedef typename Teuchos::ScalarTraits<SClo>::magnitudeType MT;
605  MT effective_zero = Teuchos::ScalarTraits<MT>::eps();
606 
607  // Allocate P
608  P = rcp(new CrsMatrixWrap(hi_map, lo_colMap, numFieldsHi)); // FIXLATER: Need faster fill
609  RCP<CrsMatrix> Pcrs = rcp_dynamic_cast<CrsMatrixWrap>(P)->getCrsMatrix();
610 
611  // Slow-ish fill
612  size_t Nelem = hi_elemToNode.extent(0);
613  std::vector<bool> touched(hi_map->getLocalNumElements(), false);
614  Teuchos::Array<GO> col_gid(1);
615  Teuchos::Array<SC> val(1);
616  auto hi_elemToNode_host = Kokkos::create_mirror_view(hi_elemToNode);
617  Kokkos::deep_copy(hi_elemToNode_host, hi_elemToNode);
618  for (size_t i = 0; i < Nelem; i++) {
619  for (size_t j = 0; j < numFieldsHi; j++) {
620  LO row_lid = hi_elemToNode_host(i, j);
621  GO row_gid = hi_map->getGlobalElement(row_lid);
622  if (hi_nodeIsOwned[row_lid] && !touched[row_lid]) {
623  for (size_t k = 0; k < numFieldsLo; k++) {
624  // Get the local id in P1's column map
625  LO col_lid = hi_to_lo_map[hi_elemToNode_host(i, lo_node_in_hi[k])];
626  if (col_lid == LOINVALID) continue;
627 
628  col_gid[0] = {lo_colMap->getGlobalElement(col_lid)};
629  val[0] = LoValues_at_HiDofs_host(k, j);
630 
631  // Skip near-zeros
632  if (Teuchos::ScalarTraits<SC>::magnitude(val[0]) >= effective_zero)
633  P->insertGlobalValues(row_gid, col_gid(), val());
634  }
635  touched[row_lid] = true;
636  }
637  }
638  }
639  P->fillComplete(lo_domainMap, hi_map);
640 }
641 
642 /*********************************************************************************************************/
643 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
645  const std::vector<bool> &hi_nodeIsOwned,
646  const SCFieldContainer &hi_DofCoords,
647  const LOFieldContainer &lo_elemToHiRepresentativeNode,
648  const Basis &lo_basis,
649  const std::vector<LocalOrdinal> &hi_to_lo_map,
650  const Teuchos::RCP<const Map> &lo_colMap,
651  const Teuchos::RCP<const Map> &lo_domainMap,
652  const Teuchos::RCP<const Map> &hi_map,
653  Teuchos::RCP<Matrix> &P) const {
654  typedef SCFieldContainer FC;
655  // Evaluate the linear basis functions at the Pn nodes
656  size_t numFieldsHi = hi_elemToNode.extent(1);
657  size_t numFieldsLo = lo_basis.getCardinality();
658  FC LoValues_at_HiDofs("LoValues_at_HiDofs", numFieldsLo, numFieldsHi);
659  lo_basis.getValues(LoValues_at_HiDofs, hi_DofCoords, Intrepid2::OPERATOR_VALUE);
660  auto LoValues_at_HiDofs_host = Kokkos::create_mirror_view(LoValues_at_HiDofs);
661  auto hi_elemToNode_host = Kokkos::create_mirror_view(hi_elemToNode);
662  auto lo_elemToHiRepresentativeNode_host = Kokkos::create_mirror_view(lo_elemToHiRepresentativeNode);
663  Kokkos::deep_copy(LoValues_at_HiDofs_host, LoValues_at_HiDofs);
664  Kokkos::deep_copy(hi_elemToNode_host, hi_elemToNode);
665  Kokkos::deep_copy(lo_elemToHiRepresentativeNode_host, lo_elemToHiRepresentativeNode);
666  Kokkos::fence(); // for kernel in getValues
667 
668  typedef typename Teuchos::ScalarTraits<SC>::halfPrecision SClo;
669  typedef typename Teuchos::ScalarTraits<SClo>::magnitudeType MT;
670  MT effective_zero = Teuchos::ScalarTraits<MT>::eps();
671 
672  // Allocate P
673  P = rcp(new CrsMatrixWrap(hi_map, lo_colMap, numFieldsHi)); // FIXLATER: Need faster fill
674  RCP<CrsMatrix> Pcrs = rcp_dynamic_cast<CrsMatrixWrap>(P)->getCrsMatrix();
675 
676  // Slow-ish fill
677  size_t Nelem = hi_elemToNode.extent(0);
678  std::vector<bool> touched(hi_map->getLocalNumElements(), false);
679  Teuchos::Array<GO> col_gid(1);
680  Teuchos::Array<SC> val(1);
681  for (size_t i = 0; i < Nelem; i++) {
682  for (size_t j = 0; j < numFieldsHi; j++) {
683  LO row_lid = hi_elemToNode_host(i, j);
684  GO row_gid = hi_map->getGlobalElement(row_lid);
685  if (hi_nodeIsOwned[row_lid] && !touched[row_lid]) {
686  for (size_t k = 0; k < numFieldsLo; k++) {
687  // Get the local id in P1's column map
688  LO col_lid = hi_to_lo_map[lo_elemToHiRepresentativeNode_host(i, k)];
689  col_gid[0] = {lo_colMap->getGlobalElement(col_lid)};
690  val[0] = LoValues_at_HiDofs_host(k, j);
691 
692  // Skip near-zeros
693  if (Teuchos::ScalarTraits<SC>::magnitude(val[0]) >= effective_zero)
694  P->insertGlobalValues(row_gid, col_gid(), val());
695  }
696  touched[row_lid] = true;
697  }
698  }
699  }
700  P->fillComplete(lo_domainMap, hi_map);
701 }
702 
703 /*********************************************************************************************************/
704 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
706  RCP<ParameterList> validParamList = rcp(new ParameterList());
707 
708 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
709  SET_VALID_ENTRY("pcoarsen: hi basis");
710  SET_VALID_ENTRY("pcoarsen: lo basis");
711 #undef SET_VALID_ENTRY
712 
713  validParamList->set<RCP<const FactoryBase>>("A", Teuchos::null, "Generating factory of the matrix A used during the prolongator smoothing process");
714 
715  validParamList->set<RCP<const FactoryBase>>("Nullspace", Teuchos::null, "Generating factory of the nullspace");
716  validParamList->set<RCP<const FactoryBase>>("pcoarsen: element to node map", Teuchos::null, "Generating factory of the element to node map");
717  return validParamList;
718 }
719 
720 /*********************************************************************************************************/
721 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
723  Input(fineLevel, "A");
724  Input(fineLevel, "pcoarsen: element to node map");
725  Input(fineLevel, "Nullspace");
726 }
727 
728 /*********************************************************************************************************/
729 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
731  return BuildP(fineLevel, coarseLevel);
732 }
733 
734 /*********************************************************************************************************/
735 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
737  FactoryMonitor m(*this, "P Coarsening", coarseLevel);
738  std::string levelIDs = toString(coarseLevel.GetLevelID());
739  const std::string prefix = "MueLu::IntrepidPCoarsenFactory(" + levelIDs + "): ";
740 
741  // NOTE: This is hardwired to double on purpose. See the note below.
742  typedef Kokkos::DynRankView<LocalOrdinal, typename Node::device_type> FCi;
743  typedef Kokkos::DynRankView<double, typename Node::device_type> FC;
744 
745  // Level Get
746  RCP<Matrix> A = Get<RCP<Matrix>>(fineLevel, "A");
747  RCP<MultiVector> fineNullspace = Get<RCP<MultiVector>>(fineLevel, "Nullspace");
749 
750  if (restrictionMode_) {
751  SubFactoryMonitor m2(*this, "Transpose A", coarseLevel);
752  A = Utilities::Transpose(*A, true); // build transpose of A explicitly
753  }
754 
755  // Find the Dirichlet rows in A
756  std::vector<LocalOrdinal> A_dirichletRows;
757  Utilities::FindDirichletRows(A, A_dirichletRows);
758 
759  // Build final prolongator
760  RCP<Matrix> finalP;
761 
762  // Reuse pattern if available
763  RCP<ParameterList> APparams = rcp(new ParameterList);
764  if (coarseLevel.IsAvailable("AP reuse data", this)) {
765  GetOStream(static_cast<MsgType>(Runtime0 | Test)) << "Reusing previous AP data" << std::endl;
766 
767  APparams = coarseLevel.Get<RCP<ParameterList>>("AP reuse data", this);
768 
769  if (APparams->isParameter("graph"))
770  finalP = APparams->get<RCP<Matrix>>("graph");
771  }
772  const ParameterList &pL = GetParameterList();
773 
774  /*******************/
775  // FIXME LATER: Allow these to be manually specified instead of Intrepid
776  // Get the Intrepid bases
777  // NOTE: To make sure Stokhos works we only instantiate these guys with double. There's a lot
778  // of stuff in the guts of Intrepid2 that doesn't play well with Stokhos as of yet.
779  int lo_degree, hi_degree;
780  RCP<Basis> hi_basis = MueLuIntrepid::BasisFactory<double, typename Node::device_type::execution_space>(pL.get<std::string>("pcoarsen: hi basis"), hi_degree);
781  RCP<Basis> lo_basis = MueLuIntrepid::BasisFactory<double, typename Node::device_type::execution_space>(pL.get<std::string>("pcoarsen: lo basis"), lo_degree);
782 
783  // Useful Output
784  GetOStream(Statistics1) << "P-Coarsening from basis " << pL.get<std::string>("pcoarsen: hi basis") << " to " << pL.get<std::string>("pcoarsen: lo basis") << std::endl;
785 
786  /*******************/
787  // Get the higher-order element-to-node map
788  const Teuchos::RCP<FCi> Pn_elemToNode = Get<Teuchos::RCP<FCi>>(fineLevel, "pcoarsen: element to node map");
789 
790  // Calculate node ownership (the quick and dirty way)
791  // NOTE: This exploits two things:
792  // 1) domainMap == rowMap
793  // 2) Standard [e|t]petra ordering (namely the local unknowns are always numbered first).
794  // This routine does not work in general.
795  RCP<const Map> rowMap = A->getRowMap();
796  RCP<const Map> colMap = Acrs.getColMap();
797  RCP<const Map> domainMap = A->getDomainMap();
798  int NumProc = rowMap->getComm()->getSize();
799  assert(rowMap->isSameAs(*domainMap));
800  std::vector<bool> Pn_nodeIsOwned(colMap->getLocalNumElements(), false);
801  LO num_owned_rows = 0;
802  for (size_t i = 0; i < rowMap->getLocalNumElements(); i++) {
803  if (rowMap->getGlobalElement(i) == colMap->getGlobalElement(i)) {
804  Pn_nodeIsOwned[i] = true;
805  num_owned_rows++;
806  }
807  }
808 
809  // Used in all cases
810  FC hi_DofCoords;
811  Teuchos::RCP<FCi> P1_elemToNode = rcp(new FCi());
812 
813  std::vector<bool> P1_nodeIsOwned;
814  int P1_numOwnedNodes;
815  std::vector<LO> hi_to_lo_map;
816 
817  // Degree-1 variables
818  std::vector<size_t> lo_node_in_hi;
819 
820  // Degree-n variables
821  FCi lo_elemToHiRepresentativeNode;
822 
823  // Get Dirichlet unknown information
824  RCP<Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node>> hi_isDirichletRow, hi_isDirichletCol;
825  Utilities::FindDirichletRowsAndPropagateToCols(A, hi_isDirichletRow, hi_isDirichletCol);
826 
827 #if 0
828  printf("[%d] isDirichletRow = ",A->getRowMap()->getComm()->getRank());
829  for(size_t i=0;i<hi_isDirichletRow->getMap()->getLocalNumElements(); i++)
830  printf("%d ",hi_isDirichletRow->getData(0)[i]);
831  printf("\n");
832  printf("[%d] isDirichletCol = ",A->getRowMap()->getComm()->getRank());
833  for(size_t i=0;i<hi_isDirichletCol->getMap()->getLocalNumElements(); i++)
834  printf("%d ",hi_isDirichletCol->getData(0)[i]);
835  printf("\n");
836  fflush(stdout);
837 #endif
838 
839  /*******************/
840  if (lo_degree == 1) {
841  // Get reference coordinates and the lo-to-hi injection list for the reference element
842  MueLuIntrepid::IntrepidGetP1NodeInHi(hi_basis, lo_node_in_hi, hi_DofCoords);
843 
844  // Generate lower-order element-to-node map
845  MueLuIntrepid::BuildLoElemToNode(*Pn_elemToNode, Pn_nodeIsOwned, lo_node_in_hi, hi_isDirichletCol->getData(0), *P1_elemToNode, P1_nodeIsOwned, hi_to_lo_map, P1_numOwnedNodes);
846  assert(hi_to_lo_map.size() == colMap->getLocalNumElements());
847  } else {
848  // Get lo-order candidates
849  double threshold = 1e-10;
850  std::vector<std::vector<size_t>> candidates;
851  Kokkos::resize(hi_DofCoords, hi_basis->getCardinality(), hi_basis->getBaseCellTopology().getDimension());
852  hi_basis->getDofCoords(hi_DofCoords);
853 
854  MueLu::MueLuIntrepid::GenerateRepresentativeBasisNodes<Basis, FC>(*lo_basis, hi_DofCoords, threshold, candidates);
855 
856  // Generate the representative nodes
857  MueLu::MueLuIntrepid::GenerateLoNodeInHiViaGIDs(candidates, *Pn_elemToNode, colMap, lo_elemToHiRepresentativeNode);
858  MueLu::MueLuIntrepid::BuildLoElemToNodeViaRepresentatives(*Pn_elemToNode, Pn_nodeIsOwned, lo_elemToHiRepresentativeNode, *P1_elemToNode, P1_nodeIsOwned, hi_to_lo_map, P1_numOwnedNodes);
859  }
860  MUELU_LEVEL_SET_IF_REQUESTED_OR_KEPT(coarseLevel, "pcoarsen: element to node map", P1_elemToNode);
861 
862  /*******************/
863  // Generate the P1_domainMap
864  // HOW: Since we know how many each proc has, we can use the non-uniform contiguous map constructor to do the work for us
865  RCP<const Map> P1_domainMap = MapFactory::Build(rowMap->lib(), Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(), P1_numOwnedNodes, rowMap->getIndexBase(), rowMap->getComm());
866  MUELU_LEVEL_SET_IF_REQUESTED_OR_KEPT(coarseLevel, "CoarseMap", P1_domainMap);
867 
868  // Generate the P1_columnMap
869  RCP<const Map> P1_colMap;
870  if (NumProc == 1)
871  P1_colMap = P1_domainMap;
872  else
873  MueLuIntrepid::GenerateColMapFromImport<LO, GO, NO>(*Acrs.getCrsGraph()->getImporter(), hi_to_lo_map, *P1_domainMap, P1_nodeIsOwned.size(), P1_colMap);
874 
875  /*******************/
876  // Generate the coarsening
877  if (lo_degree == 1)
878  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);
879  else
880  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);
881 
882  /*******************/
883  // Zero out the Dirichlet rows in P
884  Utilities::ZeroDirichletRows(finalP, A_dirichletRows);
885 
886  /*******************/
887  // Build the nullspace
888  RCP<MultiVector> coarseNullspace = MultiVectorFactory::Build(P1_domainMap, fineNullspace->getNumVectors());
889  finalP->apply(*fineNullspace, *coarseNullspace, Teuchos::TRANS);
890  Set(coarseLevel, "Nullspace", coarseNullspace);
891 
892  // Level Set
893  if (!restrictionMode_) {
894  // The factory is in prolongation mode
895  Set(coarseLevel, "P", finalP);
896 
897  APparams->set("graph", finalP);
898  MUELU_LEVEL_SET_IF_REQUESTED_OR_KEPT(coarseLevel, "AP reuse data", APparams);
899 
900  if (IsPrint(Statistics1)) {
901  RCP<ParameterList> params = rcp(new ParameterList());
902  params->set("printLoadBalancingInfo", true);
903  params->set("printCommInfo", true);
904  GetOStream(Statistics1) << PerfUtils::PrintMatrixInfo(*finalP, "P", params);
905  }
906  } else {
907  // The factory is in restriction mode
908  RCP<Matrix> R;
909  {
910  SubFactoryMonitor m2(*this, "Transpose P", coarseLevel);
911  R = Utilities::Transpose(*finalP, true);
912  }
913 
914  Set(coarseLevel, "R", R);
915 
916  if (IsPrint(Statistics2)) {
917  RCP<ParameterList> params = rcp(new ParameterList());
918  params->set("printLoadBalancingInfo", true);
919  params->set("printCommInfo", true);
920  GetOStream(Statistics2) << PerfUtils::PrintMatrixInfo(*R, "R", params);
921  }
922  }
923 
924 } // Build()
925 
926 } // namespace MueLu
927 
928 #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)
virtual Teuchos::RCP< const Teuchos::Comm< int > > getComm() const =0
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.
Teuchos::RCP< Intrepid2::Basis< KokkosExecutionSpace, Scalar, Scalar > > BasisFactory(const std::string &name, int &degree)
bool is_null(const boost::shared_ptr< T > &p)
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)
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)
std::string toString(const T &what)
Little helper function to convert non-string types to strings.
static magnitudeType eps()
GlobalOrdinal GO
T & get(const std::string &name, T def_value)
void BuildP(Level &fineLevel, Level &coarseLevel) const
Abstract Build method.
Timer to be used in factories. Similar to Monitor but with additional timers.
Print more statistics.
void IntrepidGetP1NodeInHi(const Teuchos::RCP< Intrepid2::Basis< typename KokkosDeviceType::execution_space, Scalar, Scalar >> &hi_basis, std::vector< size_t > &lo_node_in_hi, Kokkos::DynRankView< Scalar, KokkosDeviceType > &hi_DofCoords)
LocalOrdinal LO
One-liner description of what is happening.
static void ZeroDirichletRows(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node >> &A, const std::vector< LocalOrdinal > &dirichletRows, Scalar replaceWith=Teuchos::ScalarTraits< Scalar >::zero())
T * get() const
virtual LocalOrdinal getLocalElement(GlobalOrdinal globalIndex) const =0
std::string tolower(const std::string &str)
virtual GlobalOrdinal getIndexBase() const =0
MueLu::DefaultNode Node
Kokkos::DynRankView< LocalOrdinal, typename Node::device_type > LOFieldContainer
Print even more statistics.
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getTargetMap() const =0
static void FindDirichletRows(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node >> &A, std::vector< LocalOrdinal > &dirichletRows, bool count_twos_as_dirichlet=false)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
MueLu::DefaultGlobalOrdinal GlobalOrdinal
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:99
static Teuchos::RCP< Map< LocalOrdinal, GlobalOrdinal, Node > > Build(UnderlyingLib lib, global_size_t numGlobalElements, GlobalOrdinal indexBase, const Teuchos::RCP< const Teuchos::Comm< int >> &comm, LocalGlobal lg=Xpetra::GloballyDistributed)
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)
Kokkos::DynRankView< double, typename Node::device_type > SCFieldContainer
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 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 > &params=Teuchos::null)
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
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
virtual GlobalOrdinal getGlobalElement(LocalOrdinal localIndex) const =0
void DeclareInput(Level &fineLevel, Level &coarseLevel) const
Input.
static std::string PrintMatrixInfo(const Matrix &A, const std::string &msgTag, RCP< const Teuchos::ParameterList > params=Teuchos::null)
static RCP< Vector > Build(const Teuchos::RCP< const Map > &map, bool zeroOut=true)
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)
Intrepid2::Basis< typename Node::device_type::execution_space, double, double > Basis
#define TEUCHOS_UNREACHABLE_RETURN(dummyReturnVal)
RCP< const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > getDomainMap() const
void Build(Level &fineLevel, Level &coarseLevel) const
Build method.
Scalar SC
void GenerateRepresentativeBasisNodes(const Basis &basis, const SCFieldContainer &ReferenceNodeLocations, const double threshold, std::vector< std::vector< size_t > > &representative_node_candidates)
Node NO
int GetLevelID() const
Return level number.
Definition: MueLu_Level.cpp:76
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
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getSourceMap() const =0
virtual UnderlyingLib lib() const =0
#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.