36 const Teuchos::RCP<const panzer::ConnManager>& connManager,
37 const std::vector<std::string>& elementBlockNames,
38 const Teuchos::RCP<panzer::WorksetContainer> worksetContainer)
40 targetBasisDescriptor_ = targetBasis;
41 integrationDescriptor_ = integrationDescriptor;
43 connManager_ = connManager;
44 elementBlockNames_ = elementBlockNames;
45 worksetContainer_ = worksetContainer;
47 useUserSuppliedBasisValues_ =
false;
50 targetGlobalIndexer_ =
51 Teuchos::rcp(
new panzer::DOFManager(Teuchos::rcp_const_cast<panzer::ConnManager>(connManager),*(comm->getRawMpiComm())));
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];
64 auto intrepidBasis = panzer::createIntrepid2Basis<PHX::Device,double,double>(targetBasisDescriptor_.getType(),
65 targetBasisDescriptor_.getOrder(),
69 targetGlobalIndexer_->addField(eBlock,targetBasisDescriptor_.getType(),fieldPattern);
72 targetGlobalIndexer_->buildGlobalUnknowns();
95 const std::unordered_map<std::string,double>* elementBlockMultipliers)
97 PANZER_FUNC_TIME_MONITOR_DIFF(
"L2Projection::Build Mass Matrix",TopBuildMassMatrix);
98 TEUCHOS_ASSERT(setupCalled_);
100 if (elementBlockMultipliers !=
nullptr) {
101 TEUCHOS_ASSERT(elementBlockMultipliers->size() == elementBlockNames_.size());
105 std::vector<Teuchos::RCP<const panzer::GlobalIndexer>> indexers;
106 indexers.push_back(targetGlobalIndexer_);
112 ownedMatrix->resumeFill();
113 ownedMatrix->setAllToScalar(0.0);
114 ghostedMatrix->resumeFill();
115 ghostedMatrix->setAllToScalar(0.0);
117 const int fieldIndex = targetGlobalIndexer_->getFieldNum(targetBasisDescriptor_.getType());
119 const bool is_scalar = targetBasisDescriptor_.getType()==
"HGrad" || targetBasisDescriptor_.getType()==
"Const" || targetBasisDescriptor_.getType()==
"HVol";
123 auto M = ghostedMatrix->getLocalMatrixDevice();
124 for (
const auto& block : elementBlockNames_) {
126 double ebMultiplier = 1.0;
127 if (elementBlockMultipliers !=
nullptr)
128 ebMultiplier = elementBlockMultipliers->find(block)->second;
133 int num_cells_owned_ghosted_virtual = 0;
134 int num_cells_owned = 0;
135 Kokkos::View<const panzer::LocalOrdinal*> cell_local_ids;
136 if (useUserSuppliedBasisValues_) {
138 auto tmp = connManager_->getElementBlock(block);
142 Kokkos::View<panzer::LocalOrdinal*>::host_mirror_type 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;
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);
156 const auto worksets = worksetContainer_->getWorksets(wd);
158 if (worksets->size() == 0)
161 TEUCHOS_ASSERT(worksets->size() == 1);
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();
169 const auto& basisValues = *bv_ptr;
171 const auto unweightedBasis = basisValues.
getBasisValues(
false).get_static_view();
172 const auto weightedBasis = basisValues.getBasisValues(
true).get_static_view();
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);
181 Kokkos::deep_copy(kOffsets, kOffsets_h);
184 PHX::View<panzer::LocalOrdinal**> localIds(
"MassMatrix: LocalIds", num_cells_owned_ghosted_virtual,
185 targetGlobalIndexer_->getElementBlockGIDCount(block));
188 const auto cellLocalIdsNoGhost = Kokkos::subview(cell_local_ids,std::make_pair(0,num_cells_owned));
190 targetGlobalIndexer_->getElementLIDs(cellLocalIdsNoGhost,localIds);
192 const int numBasisPoints =
static_cast<int>(weightedBasis.extent(1));
194 Kokkos::parallel_for(num_cells_owned,KOKKOS_LAMBDA (
const int& cell) {
195 double total_mass = 0.0, trace = 0.0;
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);
202 double vals[256]={0.0};
203 const int numQP =
static_cast<int>(unweightedBasis.extent(2));
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;
216 for (
int row=0; row < numBasisPoints; ++row) {
217 for (
int col=0; col < numBasisPoints; ++col)
220 int offset = kOffsets(row);
221 panzer::LocalOrdinal lid = localIds(cell,offset);
224 for (
int qp=0; qp < numQP; ++qp)
225 vals[col] += unweightedBasis(cell,row,qp) * weightedBasis(cell,col,qp) * ebMultiplier * total_mass / trace;
227 M.sumIntoValues(lid,cLIDs,numIds,
vals,
true,
true);
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);
239 const int numQP =
static_cast<int>(unweightedBasis.extent(2));
241 for (
int row=0; row < numBasisPoints; ++row) {
242 int offset = kOffsets(row);
243 panzer::LocalOrdinal lid = localIds(cell,offset);
245 for (
int col=0; col < numIds; ++col) {
247 for (
int qp=0; qp < numQP; ++qp)
248 vals[col] += unweightedBasis(cell,row,qp) * weightedBasis(cell,col,qp) * ebMultiplier;
250 M.sumIntoValues(lid,cLIDs,numIds,
vals,
true,
true);
257 auto M = ghostedMatrix->getLocalMatrixDevice();
258 for (
const auto& block : elementBlockNames_) {
260 double ebMultiplier = 1.0;
261 if (elementBlockMultipliers !=
nullptr)
262 ebMultiplier = elementBlockMultipliers->find(block)->second;
267 int num_cells_owned_ghosted_virtual = 0;
268 int num_cells_owned = 0;
269 Kokkos::View<const panzer::LocalOrdinal*> cell_local_ids;
270 if (useUserSuppliedBasisValues_) {
272 auto tmp = connManager_->getElementBlock(block);
276 Kokkos::View<panzer::LocalOrdinal*>::host_mirror_type 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;
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);
290 const auto worksets = worksetContainer_->getWorksets(wd);
292 if (worksets->size() == 0)
295 TEUCHOS_ASSERT(worksets->size() == 1);
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();
303 const auto& basisValues = *bv_ptr;
306 const auto weightedBasis = basisValues.getVectorBasisValues(
true).get_static_view();
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);
315 Kokkos::deep_copy(kOffsets, kOffsets_h);
318 PHX::View<panzer::LocalOrdinal**> localIds(
"MassMatrix: LocalIds", num_cells_owned_ghosted_virtual,
319 targetGlobalIndexer_->getElementBlockGIDCount(block));
322 const PHX::View<const int*> cellLocalIdsNoGhost = Kokkos::subview(cell_local_ids,std::make_pair(0,num_cells_owned));
324 targetGlobalIndexer_->getElementLIDs(cellLocalIdsNoGhost,localIds);
326 const int numBasisPoints =
static_cast<int>(weightedBasis.extent(1));
327 Kokkos::parallel_for(num_cells_owned,KOKKOS_LAMBDA (
const int& cell) {
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);
335 const int numQP =
static_cast<int>(unweightedBasis.extent(2));
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);
342 for (
int col=0; col < numIds; ++col){
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;
348 M.sumIntoValues(lid,cLIDs,numIds,
vals,
true,
true);
356 PANZER_FUNC_TIME_MONITOR_DIFF(
"Exporting of mass matrix",ExportMM);
357 auto map = factory.
getMap(0);
358 ghostedMatrix->fillComplete(map,map);
360 ownedMatrix->doExport(*ghostedMatrix, *exporter, Tpetra::ADD);
361 ownedMatrix->fillComplete();
388 const Teuchos::RCP<
const Tpetra::Map<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>>& inputOwnedSourceMap,
389 const std::string& sourceFieldName,
391 const int directionIndex)
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>;
407 RCP<MapType> ghostedTargetMap;
409 std::vector<panzer::GlobalOrdinal> indices;
410 targetGlobalIndexer_->getOwnedAndGhostedIndices(indices);
411 ghostedTargetMap = rcp(
new MapType(Teuchos::OrdinalTraits<panzer::GlobalOrdinal>::invalid(),indices,0,comm_));
414 RCP<MapType> ghostedSourceMap;
416 std::vector<panzer::GlobalOrdinal> indices;
418 ghostedSourceMap = rcp(
new MapType(Teuchos::OrdinalTraits<panzer::GlobalOrdinal>::invalid(),indices,0,comm_));
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);
432 std::vector<panzer::GlobalOrdinal> row_gids;
433 std::vector<panzer::GlobalOrdinal> col_gids;
435 for(std::size_t elmt=0;elmt<elements.size();elmt++) {
436 targetGlobalIndexer_->getElementGIDs(elements[elmt],row_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();
446 Teuchos::ArrayView<const size_t> nEntriesPerRowView(nEntriesPerRow);
447 RCP<GraphType> ghostedGraph = rcp(
new GraphType(ghostedTargetMap,ghostedSourceMap,nEntriesPerRowView));
449 for (blockItr=elementBlockIds.begin();blockItr!=elementBlockIds.end();++blockItr) {
450 std::string blockId = *blockItr;
451 const std::vector<panzer::LocalOrdinal> & elements = targetGlobalIndexer_->getElementBlock(blockId);
453 std::vector<panzer::GlobalOrdinal> row_gids;
454 std::vector<panzer::GlobalOrdinal> col_gids;
456 for(std::size_t elmt=0;elmt<elements.size();elmt++) {
457 targetGlobalIndexer_->getElementGIDs(elements[elmt],row_gids);
459 for(std::size_t row=0;row<row_gids.size();row++)
460 ghostedGraph->insertGlobalIndices(row_gids[row],col_gids);
464 RCP<MapType> ownedTargetMap;
466 std::vector<panzer::GlobalOrdinal> indices;
467 targetGlobalIndexer_->getOwnedIndices(indices);
468 ownedTargetMap = rcp(
new MapType(Teuchos::OrdinalTraits<panzer::GlobalOrdinal>::invalid(),indices,0,comm_));
471 RCP<const MapType> ownedSourceMap = inputOwnedSourceMap;
472 if (is_null(ownedSourceMap)) {
473 std::vector<panzer::GlobalOrdinal> indices;
475 ownedSourceMap = rcp(
new MapType(Teuchos::OrdinalTraits<panzer::GlobalOrdinal>::invalid(),indices,0,comm_));
479 ghostedGraph->fillComplete(ownedSourceMap,ownedTargetMap);
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);
490 RCP<MatrixType> ghostedMatrix = rcp(
new MatrixType(ghostedGraph));
491 RCP<MatrixType> ownedMatrix = rcp(
new MatrixType(ownedGraph));
495 ghostedMatrix->setAllToScalar(0.0);
496 ownedMatrix->setAllToScalar(0.0);
501 for (
const auto& block : elementBlockNames_) {
504 const auto& worksets = worksetContainer_->getWorksets(wd);
505 for (
const auto& workset : *worksets) {
508 const auto& targetBasisValues = workset.getBasisValues(targetBasisDescriptor_,integrationDescriptor_);
509 const auto& targetWeightedBasis = targetBasisValues.getBasisValues(
true).get_static_view();
512 const auto& sourceBasisValues = workset.getBasisValues(sourceBasisDescriptor,integrationDescriptor_);
513 PHX::View<const double***> sourceUnweightedScalarBasis;
514 PHX::View<const double****> sourceUnweightedVectorBasis;
515 bool useRankThreeBasis =
false;
516 if ( (sourceBasisDescriptor.
getType() ==
"HGrad") || (sourceBasisDescriptor.
getType() ==
"Const") || (sourceBasisDescriptor.
getType() ==
"HVol") ) {
517 if (directionIndex == -1) {
518 sourceUnweightedScalarBasis = sourceBasisValues.getBasisValues(
false).get_static_view();
519 useRankThreeBasis =
true;
522 sourceUnweightedVectorBasis = sourceBasisValues.getGradBasisValues(
false).get_static_view();
526 sourceUnweightedVectorBasis = sourceBasisValues.getVectorBasisValues(
false).get_static_view();
530 PHX::View<panzer::LocalOrdinal**> targetLocalIds(
"buildRHSMatrix: targetLocalIds", workset.numOwnedCells(),
531 targetGlobalIndexer_->getElementBlockGIDCount(block));
532 PHX::View<panzer::LocalOrdinal**> sourceLocalIds(
"buildRHSMatrix: sourceLocalIds", workset.numOwnedCells(),
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);
542 PHX::View<panzer::LocalOrdinal*> targetFieldOffsets;
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)
550 Kokkos::deep_copy(targetFieldOffsets,hostOffsets);
553 PHX::View<panzer::LocalOrdinal*> sourceFieldOffsets;
555 const auto fieldIndex = sourceGlobalIndexer.
getFieldNum(sourceFieldName);
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 \""
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)
565 Kokkos::deep_copy(sourceFieldOffsets,hostOffsets);
568 const auto localMatrix = ghostedMatrix->getLocalMatrixDevice();
569 const int numRows =
static_cast<int>(targetWeightedBasis.extent(1));
572 if (useRankThreeBasis) {
573 tmpNumCols =
static_cast<int>(sourceUnweightedScalarBasis.extent(1));
574 tmpNumQP =
static_cast<int>(sourceUnweightedScalarBasis.extent(2));
577 tmpNumCols =
static_cast<int>(sourceUnweightedVectorBasis.extent(1));
578 tmpNumQP =
static_cast<int>(sourceUnweightedVectorBasis.extent(2));
580 const int numCols = tmpNumCols;
581 const int numQP = tmpNumQP;
583 Kokkos::parallel_for(Kokkos::RangePolicy<PHX::Device>(0,workset.numOwnedCells()),KOKKOS_LAMBDA (
const int& cell) {
584 panzer::LocalOrdinal cLIDs[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)
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);
597 if (useRankThreeBasis)
598 vals[col] += sourceUnweightedScalarBasis(cell,col,qp) * targetWeightedBasis(cell,row,qp);
600 vals[col] += sourceUnweightedVectorBasis(cell,col,qp,directionIndex) * targetWeightedBasis(cell,row,qp);
603 localMatrix.sumIntoValues(rowLID,cLIDs,numCols,
vals,
true,
true);
609 ghostedMatrix->fillComplete(ownedSourceMap,ownedTargetMap);
610 ownedMatrix->resumeFill();
611 ownedMatrix->doExport(*ghostedMatrix,*exporter,Tpetra::ADD);
612 ownedMatrix->fillComplete(ownedSourceMap,ownedTargetMap);