Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panzer_L2Projection.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Panzer: A partial differential equation assembly
4 // engine for strongly coupled complex multiphysics systems
5 //
6 // Copyright 2011 NTESS and the Panzer contributors.
7 // SPDX-License-Identifier: BSD-3-Clause
8 // *****************************************************************************
9 // @HEADER
10 
11 #ifndef PANZER_L2_PROJECTION_IMPL_HPP
12 #define PANZER_L2_PROJECTION_IMPL_HPP
13 
15 #include "Tpetra_CrsGraph.hpp"
16 #include "Tpetra_MultiVector.hpp"
17 #include "Tpetra_CrsMatrix.hpp"
18 #include "Panzer_L2Projection.hpp"
21 #include "Panzer_TpetraLinearObjFactory.hpp"
29 #include "Panzer_Workset.hpp"
30 
31 namespace panzer {
32 
34  const panzer::IntegrationDescriptor& integrationDescriptor,
35  const Teuchos::RCP<const Teuchos::MpiComm<int>>& comm,
36  const Teuchos::RCP<const panzer::ConnManager>& connManager,
37  const std::vector<std::string>& elementBlockNames,
38  const Teuchos::RCP<panzer::WorksetContainer> worksetContainer)
39  {
40  targetBasisDescriptor_ = targetBasis;
41  integrationDescriptor_ = integrationDescriptor;
42  comm_ = comm;
43  connManager_ = connManager;
44  elementBlockNames_ = elementBlockNames;
45  worksetContainer_ = worksetContainer;
46  setupCalled_ = true;
47  useUserSuppliedBasisValues_ = false;
48 
49  // Build target DOF Manager
50  targetGlobalIndexer_ =
51  Teuchos::rcp(new panzer::DOFManager(Teuchos::rcp_const_cast<panzer::ConnManager>(connManager),*(comm->getRawMpiComm())));
52 
53  // For hybrid mesh, blocks could have different topology
54  for (const auto& eBlock : elementBlockNames_) {
55  std::vector<shards::CellTopology> topologies;
56  connManager_->getElementBlockTopologies(topologies);
57  std::vector<std::string> ebNames;
58  connManager_->getElementBlockIds(ebNames);
59  const auto search = std::find(ebNames.cbegin(),ebNames.cend(),eBlock);
60  TEUCHOS_ASSERT(search != ebNames.cend());
61  const int index = std::distance(ebNames.cbegin(),search);
62  const auto& cellTopology = topologies[index];
63 
64  auto intrepidBasis = panzer::createIntrepid2Basis<PHX::Device,double,double>(targetBasisDescriptor_.getType(),
65  targetBasisDescriptor_.getOrder(),
66  cellTopology);
68  // Field name is the basis type
69  targetGlobalIndexer_->addField(eBlock,targetBasisDescriptor_.getType(),fieldPattern);
70  }
71 
72  targetGlobalIndexer_->buildGlobalUnknowns();
73 
74  // Check workset needs are correct
75  }
76 
78  {
79  useUserSuppliedBasisValues_ = true;
80  basisValues_ = bv;
81 
82  // Check that the basis and integration descriptor match what was
83  // supplied in setup.
84  for (const auto& eblock : elementBlockNames_) {
85  TEUCHOS_ASSERT(basisValues_[eblock]->getBasisDescriptor()==targetBasisDescriptor_);
86  }
87  }
88 
91  {return targetGlobalIndexer_;}
92 
95  const std::unordered_map<std::string,double>* elementBlockMultipliers)
96  {
97  PANZER_FUNC_TIME_MONITOR_DIFF("L2Projection::Build Mass Matrix",TopBuildMassMatrix);
98  TEUCHOS_ASSERT(setupCalled_);
99 
100  if (elementBlockMultipliers != nullptr) {
101  TEUCHOS_ASSERT(elementBlockMultipliers->size() == elementBlockNames_.size());
102  }
103 
104  // Allocate the owned matrix
105  std::vector<Teuchos::RCP<const panzer::GlobalIndexer>> indexers;
106  indexers.push_back(targetGlobalIndexer_);
107 
109 
110  auto ownedMatrix = factory.getTpetraMatrix(0,0);
111  auto ghostedMatrix = factory.getGhostedTpetraMatrix(0,0);
112  ownedMatrix->resumeFill();
113  ownedMatrix->setAllToScalar(0.0);
114  ghostedMatrix->resumeFill();
115  ghostedMatrix->setAllToScalar(0.0);
116 
117  const int fieldIndex = targetGlobalIndexer_->getFieldNum(targetBasisDescriptor_.getType());
118 
119  const bool is_scalar = targetBasisDescriptor_.getType()=="HGrad" || targetBasisDescriptor_.getType()=="Const" || targetBasisDescriptor_.getType()=="HVol";
120 
121  // Loop over element blocks and fill mass matrix
122  if(is_scalar){
123  auto M = ghostedMatrix->getLocalMatrixDevice();
124  for (const auto& block : elementBlockNames_) {
125 
126  double ebMultiplier = 1.0;
127  if (elementBlockMultipliers != nullptr)
128  ebMultiplier = elementBlockMultipliers->find(block)->second;
129 
130  // Get the cell local ids and set the BasisValues object (BV
131  // can come from a user defined set or from WorksetContainer).
132  const panzer::BasisValues2<double>* bv_ptr;
133  int num_cells_owned_ghosted_virtual = 0;
134  int num_cells_owned = 0;
136  if (useUserSuppliedBasisValues_) {
137  // Skip this block if there are no elements in this block on this mpi process
138  auto tmp = connManager_->getElementBlock(block); // no ghosting or virtual in this case
139  if (tmp.size() == 0)
140  continue;
141 
142  Kokkos::View<panzer::LocalOrdinal*>::HostMirror cell_local_ids_host(tmp.data(),tmp.size());
143  Kokkos::View<panzer::LocalOrdinal*> cell_local_ids_nonconst("cell_local_ids",tmp.size());
144  Kokkos::deep_copy(cell_local_ids_nonconst,cell_local_ids_host);
145  cell_local_ids = cell_local_ids_nonconst;
146 
147  bv_ptr = basisValues_[block].get();
148  num_cells_owned_ghosted_virtual = cell_local_ids.extent(0);
149  num_cells_owned = cell_local_ids.extent(0);
150  }
151  else {
152  // Based on descriptor, currently assumes there should only
153  // be one workset (partitioned path assumes a single
154  // workset).
156  const auto worksets = worksetContainer_->getWorksets(wd);
157  // Skip this block if there are no elements in this block on this mpi process
158  if (worksets->size() == 0)
159  continue;
160 
161  TEUCHOS_ASSERT(worksets->size() == 1);
162 
163  const auto& workset = (*worksets)[0];
164  bv_ptr = &(workset.getBasisValues(targetBasisDescriptor_,integrationDescriptor_));
165  num_cells_owned_ghosted_virtual = workset.numOwnedCells()+workset.numGhostCells()+workset.numVirtualCells();
166  num_cells_owned = workset.numOwnedCells();
167  cell_local_ids = workset.getLocalCellIDs();
168  }
169  const auto& basisValues = *bv_ptr;
170 
171  const auto unweightedBasis = basisValues.getBasisValues(false).get_static_view();
172  const auto weightedBasis = basisValues.getBasisValues(true).get_static_view();
173 
174  const std::vector<panzer::LocalOrdinal>& offsets = targetGlobalIndexer_->getGIDFieldOffsets(block,fieldIndex);
175  PHX::View<panzer::LocalOrdinal*> kOffsets("MassMatrix: Offsets",offsets.size());
176  auto kOffsets_h = Kokkos::create_mirror_view(kOffsets);
177 
178  for(const auto& i : offsets)
179  kOffsets_h(i) = offsets[i];
180 
181  Kokkos::deep_copy(kOffsets, kOffsets_h);
182 
183  // Local Ids
184  PHX::View<panzer::LocalOrdinal**> localIds("MassMatrix: LocalIds", num_cells_owned_ghosted_virtual,
185  targetGlobalIndexer_->getElementBlockGIDCount(block));
186 
187  // Remove the ghosted cell ids or the call to getElementLocalIds will spill array bounds
188  const auto cellLocalIdsNoGhost = Kokkos::subview(cell_local_ids,std::make_pair(0,num_cells_owned));
189 
190  targetGlobalIndexer_->getElementLIDs(cellLocalIdsNoGhost,localIds);
191 
192  const int numBasisPoints = static_cast<int>(weightedBasis.extent(1));
193  if ( use_lumping ) {
194  Kokkos::parallel_for(num_cells_owned,KOKKOS_LAMBDA (const int& cell) {
195  double total_mass = 0.0, trace = 0.0;
196 
197  panzer::LocalOrdinal cLIDs[256];
198  const int numIds = static_cast<int>(localIds.extent(1));
199  for(int i=0;i<numIds;++i)
200  cLIDs[i] = localIds(cell,i);
201 
202  double vals[256]={0.0};
203  const int numQP = static_cast<int>(unweightedBasis.extent(2));
204 
205  for (int row=0; row < numBasisPoints; ++row) {
206  for (int col=0; col < numIds; ++col) {
207  for (int qp=0; qp < numQP; ++qp) {
208  auto tmp = unweightedBasis(cell,row,qp) * weightedBasis(cell,col,qp) * ebMultiplier;
209  total_mass += tmp;
210  if (col == row )
211  trace += tmp;
212  }
213  }
214  }
215 
216  for (int row=0; row < numBasisPoints; ++row) {
217  for (int col=0; col < numBasisPoints; ++col)
218  vals[col] = 0;
219 
220  int offset = kOffsets(row);
221  panzer::LocalOrdinal lid = localIds(cell,offset);
222  int col = row;
223  vals[col] = 0.0;
224  for (int qp=0; qp < numQP; ++qp)
225  vals[col] += unweightedBasis(cell,row,qp) * weightedBasis(cell,col,qp) * ebMultiplier * total_mass / trace;
226 
227  M.sumIntoValues(lid,cLIDs,numIds,vals,true,true);
228  }
229  });
230 
231  } else {
232  Kokkos::parallel_for(num_cells_owned,KOKKOS_LAMBDA (const int& cell) {
233  panzer::LocalOrdinal cLIDs[256];
234  const int numIds = static_cast<int>(localIds.extent(1));
235  for(int i=0;i<numIds;++i)
236  cLIDs[i] = localIds(cell,i);
237 
238  double vals[256];
239  const int numQP = static_cast<int>(unweightedBasis.extent(2));
240 
241  for (int row=0; row < numBasisPoints; ++row) {
242  int offset = kOffsets(row);
243  panzer::LocalOrdinal lid = localIds(cell,offset);
244 
245  for (int col=0; col < numIds; ++col) {
246  vals[col] = 0.0;
247  for (int qp=0; qp < numQP; ++qp)
248  vals[col] += unweightedBasis(cell,row,qp) * weightedBasis(cell,col,qp) * ebMultiplier;
249  }
250  M.sumIntoValues(lid,cLIDs,numIds,vals,true,true);
251 
252  }
253  });
254  }
255  }
256  } else {
257  auto M = ghostedMatrix->getLocalMatrixDevice();
258  for (const auto& block : elementBlockNames_) {
259 
260  double ebMultiplier = 1.0;
261  if (elementBlockMultipliers != nullptr)
262  ebMultiplier = elementBlockMultipliers->find(block)->second;
263 
264  // Get the cell local ids and set the BasisValues object (BV
265  // can come from a user defined set or from WorksetContainer).
266  const panzer::BasisValues2<double>* bv_ptr;
267  int num_cells_owned_ghosted_virtual = 0;
268  int num_cells_owned = 0;
270  if (useUserSuppliedBasisValues_) {
271  // Skip this block if there are no elements in this block on this mpi process
272  auto tmp = connManager_->getElementBlock(block); // no ghosting or virtual in this case
273  if (tmp.size() == 0)
274  continue;
275 
276  Kokkos::View<panzer::LocalOrdinal*>::HostMirror cell_local_ids_host(tmp.data(),tmp.size());
277  Kokkos::View<panzer::LocalOrdinal*> cell_local_ids_nonconst("cell_local_ids",tmp.size());
278  Kokkos::deep_copy(cell_local_ids_nonconst,cell_local_ids_host);
279  cell_local_ids = cell_local_ids_nonconst;
280 
281  bv_ptr = basisValues_[block].get();
282  num_cells_owned_ghosted_virtual = cell_local_ids.extent(0);
283  num_cells_owned = cell_local_ids.extent(0);
284  }
285  else {
286  // Based on descriptor, currently assumes there should only
287  // be one workset (partitioned path assumes a single
288  // workset).
290  const auto worksets = worksetContainer_->getWorksets(wd);
291  // Skip this block if there are no elements in this block on this mpi process
292  if (worksets->size() == 0)
293  continue;
294 
295  TEUCHOS_ASSERT(worksets->size() == 1);
296 
297  const auto& workset = (*worksets)[0];
298  bv_ptr = &(workset.getBasisValues(targetBasisDescriptor_,integrationDescriptor_));
299  num_cells_owned_ghosted_virtual = workset.numOwnedCells()+workset.numGhostCells()+workset.numVirtualCells();
300  num_cells_owned = workset.numOwnedCells();
301  cell_local_ids = workset.getLocalCellIDs();
302  }
303  const auto& basisValues = *bv_ptr;
304 
305  const auto unweightedBasis = basisValues.getVectorBasisValues(false).get_static_view();
306  const auto weightedBasis = basisValues.getVectorBasisValues(true).get_static_view();
307 
308  const std::vector<panzer::LocalOrdinal>& offsets = targetGlobalIndexer_->getGIDFieldOffsets(block,fieldIndex);
309  PHX::View<panzer::LocalOrdinal*> kOffsets("MassMatrix: Offsets",offsets.size());
310  auto kOffsets_h = Kokkos::create_mirror_view(kOffsets);
311 
312  for(const auto& i : offsets)
313  kOffsets_h(i) = offsets[i];
314 
315  Kokkos::deep_copy(kOffsets, kOffsets_h);
316 
317  // Local Ids
318  PHX::View<panzer::LocalOrdinal**> localIds("MassMatrix: LocalIds", num_cells_owned_ghosted_virtual,
319  targetGlobalIndexer_->getElementBlockGIDCount(block));
320 
321  // Remove the ghosted cell ids or the call to getElementLocalIds will spill array bounds
322  const PHX::View<const int*> cellLocalIdsNoGhost = Kokkos::subview(cell_local_ids,std::make_pair(0,num_cells_owned));
323 
324  targetGlobalIndexer_->getElementLIDs(cellLocalIdsNoGhost,localIds);
325 
326  const int numBasisPoints = static_cast<int>(weightedBasis.extent(1));
327  Kokkos::parallel_for(num_cells_owned,KOKKOS_LAMBDA (const int& cell) {
328 
329  panzer::LocalOrdinal cLIDs[256];
330  const int numIds = static_cast<int>(localIds.extent(1));
331  for(int i=0;i<numIds;++i)
332  cLIDs[i] = localIds(cell,i);
333 
334  double vals[256];
335  const int numQP = static_cast<int>(unweightedBasis.extent(2));
336 
337  for (int qp=0; qp < numQP; ++qp) {
338  for (int row=0; row < numBasisPoints; ++row) {
339  int offset = kOffsets(row);
340  panzer::LocalOrdinal lid = localIds(cell,offset);
341 
342  for (int col=0; col < numIds; ++col){
343  vals[col] = 0.0;
344  for(int dim=0; dim < static_cast<int>(weightedBasis.extent(3)); ++dim)
345  vals[col] += unweightedBasis(cell,row,qp,dim) * weightedBasis(cell,col,qp,dim) * ebMultiplier;
346  }
347 
348  M.sumIntoValues(lid,cLIDs,numIds,vals,true,true);
349  }
350  }
351  });
352  }
353  }
354 
355  {
356  PANZER_FUNC_TIME_MONITOR_DIFF("Exporting of mass matrix",ExportMM);
357  auto map = factory.getMap(0);
358  ghostedMatrix->fillComplete(map,map);
359  const auto exporter = factory.getGhostedExport(0);
360  ownedMatrix->doExport(*ghostedMatrix, *exporter, Tpetra::ADD);
361  ownedMatrix->fillComplete();
362  }
363  return ownedMatrix;
364  }
365 
368  {
369  PANZER_FUNC_TIME_MONITOR_DIFF("L2Projection<panzer::LocalOrdinal,panzer::GlobalOrdinal>::buildInverseLumpedMassMatrix",buildInvLMM);
370  using Teuchos::rcp;
371  const auto massMatrix = this->buildMassMatrix(true);
372  const auto lumpedMassMatrix = rcp(new Tpetra::MultiVector<double,panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>(massMatrix->getDomainMap(),1,true));
373  const auto tmp = rcp(new Tpetra::MultiVector<double,panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>(massMatrix->getRangeMap(),1,false));
374  tmp->putScalar(1.0);
375  {
376  PANZER_FUNC_TIME_MONITOR_DIFF("Apply",Apply);
377  massMatrix->apply(*tmp,*lumpedMassMatrix);
378  }
379  {
380  PANZER_FUNC_TIME_MONITOR_DIFF("Reciprocal",Reciprocal);
381  lumpedMassMatrix->reciprocal(*lumpedMassMatrix);
382  }
383  return lumpedMassMatrix;
384  }
385 
388  const Teuchos::RCP<const Tpetra::Map<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>>& inputOwnedSourceMap,
389  const std::string& sourceFieldName,
390  const panzer::BasisDescriptor& sourceBasisDescriptor,
391  const int directionIndex)
392  {
393  // *******************
394  // Create Retangular matrix (both ghosted and owned).
395  // *******************
396  using Teuchos::RCP;
397  using Teuchos::rcp;
398  using MapType = Tpetra::Map<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>;
399  using GraphType = Tpetra::CrsGraph<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>;
400  using ExportType = Tpetra::Export<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>;
401  using MatrixType = Tpetra::CrsMatrix<double,panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>;
402 
403  // *******************
404  // Build ghosted graph
405  // *******************
406 
407  RCP<MapType> ghostedTargetMap;
408  {
409  std::vector<panzer::GlobalOrdinal> indices;
410  targetGlobalIndexer_->getOwnedAndGhostedIndices(indices);
411  ghostedTargetMap = rcp(new MapType(Teuchos::OrdinalTraits<panzer::GlobalOrdinal>::invalid(),indices,0,comm_));
412  }
413 
414  RCP<MapType> ghostedSourceMap;
415  {
416  std::vector<panzer::GlobalOrdinal> indices;
417  sourceGlobalIndexer.getOwnedAndGhostedIndices(indices);
418  ghostedSourceMap = rcp(new MapType(Teuchos::OrdinalTraits<panzer::GlobalOrdinal>::invalid(),indices,0,comm_));
419  }
420 
421 
422  // Now insert the non-zero pattern per row
423  // count number of entries per row; required by CrsGraph constructor
424  std::vector<size_t> nEntriesPerRow(ghostedTargetMap->getLocalNumElements(),0);
425  std::vector<std::string> elementBlockIds;
426  targetGlobalIndexer_->getElementBlockIds(elementBlockIds);
427  std::vector<std::string>::const_iterator blockItr;
428  for (blockItr=elementBlockIds.begin();blockItr!=elementBlockIds.end();++blockItr) {
429  std::string blockId = *blockItr;
430  const std::vector<panzer::LocalOrdinal> & elements = targetGlobalIndexer_->getElementBlock(blockId);
431 
432  std::vector<panzer::GlobalOrdinal> row_gids;
433  std::vector<panzer::GlobalOrdinal> col_gids;
434 
435  for(std::size_t elmt=0;elmt<elements.size();elmt++) {
436  targetGlobalIndexer_->getElementGIDs(elements[elmt],row_gids);
437  sourceGlobalIndexer.getElementGIDs(elements[elmt],col_gids);
438  for(std::size_t row=0;row<row_gids.size();row++) {
439  panzer::LocalOrdinal lid =
440  ghostedTargetMap->getLocalElement(row_gids[row]);
441  nEntriesPerRow[lid] += col_gids.size();
442  }
443  }
444  }
445 
446  Teuchos::ArrayView<const size_t> nEntriesPerRowView(nEntriesPerRow);
447  RCP<GraphType> ghostedGraph = rcp(new GraphType(ghostedTargetMap,ghostedSourceMap,nEntriesPerRowView));
448 
449  for (blockItr=elementBlockIds.begin();blockItr!=elementBlockIds.end();++blockItr) {
450  std::string blockId = *blockItr;
451  const std::vector<panzer::LocalOrdinal> & elements = targetGlobalIndexer_->getElementBlock(blockId);
452 
453  std::vector<panzer::GlobalOrdinal> row_gids;
454  std::vector<panzer::GlobalOrdinal> col_gids;
455 
456  for(std::size_t elmt=0;elmt<elements.size();elmt++) {
457  targetGlobalIndexer_->getElementGIDs(elements[elmt],row_gids);
458  sourceGlobalIndexer.getElementGIDs(elements[elmt],col_gids);
459  for(std::size_t row=0;row<row_gids.size();row++)
460  ghostedGraph->insertGlobalIndices(row_gids[row],col_gids);
461  }
462  }
463 
464  RCP<MapType> ownedTargetMap;
465  {
466  std::vector<panzer::GlobalOrdinal> indices;
467  targetGlobalIndexer_->getOwnedIndices(indices);
468  ownedTargetMap = rcp(new MapType(Teuchos::OrdinalTraits<panzer::GlobalOrdinal>::invalid(),indices,0,comm_));
469  }
470 
471  RCP<const MapType> ownedSourceMap = inputOwnedSourceMap;
472  if (is_null(ownedSourceMap)) {
473  std::vector<panzer::GlobalOrdinal> indices;
474  sourceGlobalIndexer.getOwnedIndices(indices);
475  ownedSourceMap = rcp(new MapType(Teuchos::OrdinalTraits<panzer::GlobalOrdinal>::invalid(),indices,0,comm_));
476  }
477 
478  // Fill complete with owned range and domain map
479  ghostedGraph->fillComplete(ownedSourceMap,ownedTargetMap);
480 
481  // *****************
482  // Build owned graph
483  // *****************
484 
485  RCP<GraphType> ownedGraph = rcp(new GraphType(ownedTargetMap,0));
486  RCP<const ExportType> exporter = rcp(new ExportType(ghostedTargetMap,ownedTargetMap));
487  ownedGraph->doExport(*ghostedGraph, *exporter, Tpetra::INSERT);
488  ownedGraph->fillComplete(ownedSourceMap,ownedTargetMap);
489 
490  RCP<MatrixType> ghostedMatrix = rcp(new MatrixType(ghostedGraph));
491  RCP<MatrixType> ownedMatrix = rcp(new MatrixType(ownedGraph));
492  // ghostedMatrix.fillComplete();
493  // ghostedMatrix.resumeFill();
494 
495  ghostedMatrix->setAllToScalar(0.0);
496  ownedMatrix->setAllToScalar(0.0);
497 
498  // *******************
499  // Fill ghosted matrix
500  // *******************
501  for (const auto& block : elementBlockNames_) {
502 
504  const auto& worksets = worksetContainer_->getWorksets(wd);
505  for (const auto& workset : *worksets) {
506 
507  // Get target basis values: current implementation assumes target basis is HGrad
508  const auto& targetBasisValues = workset.getBasisValues(targetBasisDescriptor_,integrationDescriptor_);
509  const auto& targetWeightedBasis = targetBasisValues.getBasisValues(true).get_static_view();
510 
511  // Sources can be any basis
512  const auto& sourceBasisValues = workset.getBasisValues(sourceBasisDescriptor,integrationDescriptor_);
513  PHX::View<const double***> sourceUnweightedScalarBasis;
514  PHX::View<const double****> sourceUnweightedVectorBasis;
515  bool useRankThreeBasis = false; // default to gradient or vector basis
516  if ( (sourceBasisDescriptor.getType() == "HGrad") || (sourceBasisDescriptor.getType() == "Const") || (sourceBasisDescriptor.getType() == "HVol") ) {
517  if (directionIndex == -1) { // Project dof value
518  sourceUnweightedScalarBasis = sourceBasisValues.getBasisValues(false).get_static_view();
519  useRankThreeBasis = true;
520  }
521  else { // Project dof gradient of scalar basis
522  sourceUnweightedVectorBasis = sourceBasisValues.getGradBasisValues(false).get_static_view();
523  }
524  }
525  else { // Project vector value
526  sourceUnweightedVectorBasis = sourceBasisValues.getVectorBasisValues(false).get_static_view();
527  }
528 
529  // Get the element local ids
530  PHX::View<panzer::LocalOrdinal**> targetLocalIds("buildRHSMatrix: targetLocalIds", workset.numOwnedCells(),
531  targetGlobalIndexer_->getElementBlockGIDCount(block));
532  PHX::View<panzer::LocalOrdinal**> sourceLocalIds("buildRHSMatrix: sourceLocalIds", workset.numOwnedCells(),
533  sourceGlobalIndexer.getElementBlockGIDCount(block));
534  {
535  // Remove the ghosted cell ids or the call to getElementLocalIds will spill array bounds
536  const auto cellLocalIdsNoGhost = Kokkos::subview(workset.cell_local_ids_k,std::make_pair(0,workset.numOwnedCells()));
537  targetGlobalIndexer_->getElementLIDs(cellLocalIdsNoGhost,targetLocalIds);
538  sourceGlobalIndexer.getElementLIDs(cellLocalIdsNoGhost,sourceLocalIds);
539  }
540 
541  // Get the offsets
542  PHX::View<panzer::LocalOrdinal*> targetFieldOffsets;
543  {
544  const auto fieldIndex = targetGlobalIndexer_->getFieldNum(targetBasisDescriptor_.getType());
545  const std::vector<panzer::LocalOrdinal>& offsets = targetGlobalIndexer_->getGIDFieldOffsets(block,fieldIndex);
546  targetFieldOffsets = PHX::View<panzer::LocalOrdinal*>("L2Projection:buildRHS:targetFieldOffsets",offsets.size());
547  const auto hostOffsets = Kokkos::create_mirror_view(targetFieldOffsets);
548  for(size_t i=0; i < offsets.size(); ++i)
549  hostOffsets(i) = offsets[i];
550  Kokkos::deep_copy(targetFieldOffsets,hostOffsets);
551  }
552 
553  PHX::View<panzer::LocalOrdinal*> sourceFieldOffsets;
554  {
555  const auto fieldIndex = sourceGlobalIndexer.getFieldNum(sourceFieldName);
556  const std::vector<panzer::LocalOrdinal>& offsets = sourceGlobalIndexer.getGIDFieldOffsets(block,fieldIndex);
557  TEUCHOS_TEST_FOR_EXCEPTION(offsets.size() == 0, std::runtime_error,
558  "ERROR: panzer::L2Projection::buildRHSMatrix() - The source field, \""
559  << sourceFieldName << "\", does not exist in element block \""
560  << block << "\"!");
561  sourceFieldOffsets = PHX::View<panzer::LocalOrdinal*>("L2Projection:buildRHS:sourceFieldOffsets",offsets.size());
562  const auto hostOffsets = Kokkos::create_mirror_view(sourceFieldOffsets);
563  for(size_t i=0; i <offsets.size(); ++i)
564  hostOffsets(i) = offsets[i];
565  Kokkos::deep_copy(sourceFieldOffsets,hostOffsets);
566  }
567 
568  const auto localMatrix = ghostedMatrix->getLocalMatrixDevice();
569  const int numRows = static_cast<int>(targetWeightedBasis.extent(1));
570  int tmpNumCols = -1;
571  int tmpNumQP = -1;
572  if (useRankThreeBasis) {
573  tmpNumCols = static_cast<int>(sourceUnweightedScalarBasis.extent(1));
574  tmpNumQP = static_cast<int>(sourceUnweightedScalarBasis.extent(2));
575  }
576  else {
577  tmpNumCols = static_cast<int>(sourceUnweightedVectorBasis.extent(1));
578  tmpNumQP = static_cast<int>(sourceUnweightedVectorBasis.extent(2));
579  }
580  const int numCols = tmpNumCols;
581  const int numQP = tmpNumQP;
582 
583  Kokkos::parallel_for(Kokkos::RangePolicy<PHX::Device>(0,workset.numOwnedCells()),KOKKOS_LAMBDA (const int& cell) {
584  panzer::LocalOrdinal cLIDs[256];
585  double vals[256];
586  for (int row = 0; row < numRows; ++row) {
587  const int rowOffset = targetFieldOffsets(row);
588  const int rowLID = targetLocalIds(cell,rowOffset);
589  for (int col = 0; col < numCols; ++col)
590  vals[col] = 0.0;
591 
592  for (int col = 0; col < numCols; ++col) {
593  for (int qp = 0; qp < numQP; ++qp) {
594  const int colOffset = sourceFieldOffsets(col);
595  const int colLID = sourceLocalIds(cell,colOffset);
596  cLIDs[col] = colLID;
597  if (useRankThreeBasis)
598  vals[col] += sourceUnweightedScalarBasis(cell,col,qp) * targetWeightedBasis(cell,row,qp);
599  else
600  vals[col] += sourceUnweightedVectorBasis(cell,col,qp,directionIndex) * targetWeightedBasis(cell,row,qp);
601  }
602  }
603  localMatrix.sumIntoValues(rowLID,cLIDs,numCols,vals,true,true);
604  }
605  });
606  }
607 
608  }
609  ghostedMatrix->fillComplete(ownedSourceMap,ownedTargetMap);
610  ownedMatrix->resumeFill();
611  ownedMatrix->doExport(*ghostedMatrix,*exporter,Tpetra::ADD);
612  ownedMatrix->fillComplete(ownedSourceMap,ownedTargetMap);
613 
614  return ownedMatrix;
615  }
616 
617 }
618 
619 #endif
Teuchos::RCP< CrsMatrixType > getTpetraMatrix(int i, int j) const
bool is_null(const boost::shared_ptr< T > &p)
Teuchos::RCP< Tpetra::CrsMatrix< double, panzer::LocalOrdinal, panzer::GlobalOrdinal, Tpetra::KokkosCompat::KokkosDeviceWrapperNode< PHX::Device > > > buildRHSMatrix(const panzer::GlobalIndexer &sourceDOFManager, const Teuchos::RCP< const Tpetra::Map< panzer::LocalOrdinal, panzer::GlobalOrdinal, Tpetra::KokkosCompat::KokkosDeviceWrapperNode< PHX::Device >>> &ownedSourceMap, const std::string &sourceFieldName, const panzer::BasisDescriptor &sourceBasisDescriptor, const int vectorOrGradientDirectionIndex=-1)
Allocates, fills and returns a rectangular matrix for L2 projection of a scalar field, one dimension of gradient (for hgrad basis), or one dimension of a vector field onto the target scalar basis. If you wish to project all values of a vector field or all the gradients of a scalar field, then you will need three separate RHS matrices to form the RHS for each independently. The vectors must be independent Tpetra vectors to solve multiple right hand sides with the linear solver.
virtual Teuchos::RCP< const ExportType > getGhostedExport(int j) const
get exporter for converting an overalapped object to a &quot;normal&quot; object
void setup(const panzer::BasisDescriptor &targetBasis, const panzer::IntegrationDescriptor &integrationDescriptor, const Teuchos::RCP< const Teuchos::MpiComm< int >> &comm, const Teuchos::RCP< const panzer::ConnManager > &connManager, const std::vector< std::string > &elementBlockNames, const Teuchos::RCP< panzer::WorksetContainer > worksetContainer=Teuchos::null)
Setup base objects for L2 Projections - requires target scalar basis and creates worksets if not supp...
const Kokkos::View< const panzer::LocalOrdinal *, Kokkos::LayoutRight, PHX::Device > getElementLIDs(panzer::LocalOrdinal localElmtId) const
virtual int getElementBlockGIDCount(const std::size_t &blockIndex) const =0
How any GIDs are associate with each element in a particular element block.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Teuchos::RCP< panzer::GlobalIndexer > getTargetGlobalIndexer() const
Returns the target global indexer. Will be null if setup() has not been called.
PHX::View< const int * > offsets
virtual void getOwnedIndices(std::vector< panzer::GlobalOrdinal > &indices) const =0
Get the set of indices owned by this processor.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
const std::string & getType() const
Get type of basis.
ConstArray_CellBasisIP getBasisValues(const bool weighted, const bool cache=true, const bool force=false) const
Get the basis values evaluated at mesh points.
Kokkos::View< typename Sacado::ScalarType< ScalarT >::type **, Kokkos::LayoutRight, PHX::Device > vals
KOKKOS_FORCEINLINE_FUNCTION array_type get_static_view()
virtual int getFieldNum(const std::string &str) const =0
Get the number used for access to this field.
virtual void getOwnedAndGhostedIndices(std::vector< panzer::GlobalOrdinal > &indices) const =0
Get the set of owned and ghosted indices for this processor.
virtual Teuchos::RCP< const MapType > getMap(int i) const
get the map from the matrix
void useBasisValues(const std::map< std::string, Teuchos::RCP< panzer::BasisValues2< double >>> &map_eblock_to_bv)
Override using the panzer::WorksetContainer and instead use the registered BasisValues object...
ConstArray_CellBasisIPDim getVectorBasisValues(const bool weighted, const bool cache=true, const bool force=false) const
Get the vector basis values evaluated at mesh points.
Teuchos::RCP< CrsMatrixType > getGhostedTpetraMatrix(int i, int j) const
virtual const std::vector< int > & getGIDFieldOffsets(const std::string &blockId, int fieldNum) const =0
Use the field pattern so that you can find a particular field in the GIDs array.
virtual void getElementGIDs(panzer::LocalOrdinal localElmtId, std::vector< panzer::GlobalOrdinal > &gids, const std::string &blockIdHint="") const =0
Get the global IDs for a particular element. This function overwrites the gids variable.
Teuchos::RCP< Tpetra::MultiVector< double, panzer::LocalOrdinal, panzer::GlobalOrdinal, Tpetra::KokkosCompat::KokkosDeviceWrapperNode< PHX::Device > > > buildInverseLumpedMassMatrix()
Allocates, fills and returns a Tpetra::MultiVector containing the inverse lumped mass matrix values a...
#define TEUCHOS_ASSERT(assertion_test)
Workset size is set to the total number of local elements in the MPI process.
Teuchos::RCP< Tpetra::CrsMatrix< double, panzer::LocalOrdinal, panzer::GlobalOrdinal, Tpetra::KokkosCompat::KokkosDeviceWrapperNode< PHX::Device > > > buildMassMatrix(bool use_lumping=false, const std::unordered_map< std::string, double > *elementBlockMultipliers=nullptr)
Allocates, fills and returns a mass matrix for L2 projection onto a target basis. ...