4 #ifndef PANZER_L2_PROJECTION_IMPL_HPP
5 #define PANZER_L2_PROJECTION_IMPL_HPP
8 #include "Tpetra_CrsGraph.hpp"
9 #include "Tpetra_MultiVector.hpp"
10 #include "Tpetra_CrsMatrix.hpp"
13 #include "Panzer_TpetraLinearObjFactory.hpp"
16 #include "Panzer_DOFManagerFactory.hpp"
17 #include "Panzer_BlockedDOFManagerFactory.hpp"
25 template<
typename LO,
typename GO>
30 const std::vector<std::string>& elementBlockNames,
33 targetBasisDescriptor_ = targetBasis;
34 integrationDescriptor_ = integrationDescriptor;
36 connManager_ = connManager;
37 elementBlockNames_ = elementBlockNames;
38 worksetContainer_ = worksetContainer;
42 targetGlobalIndexer_ =
46 for (
const auto& eBlock : elementBlockNames_) {
47 std::vector<shards::CellTopology> topologies;
48 connManager_->getElementBlockTopologies(topologies);
49 std::vector<std::string> ebNames;
50 connManager_->getElementBlockIds(ebNames);
51 const auto search = std::find(ebNames.cbegin(),ebNames.cend(),eBlock);
53 const int index = std::distance(ebNames.cbegin(),search);
54 const auto& cellTopology = topologies[index];
56 auto intrepidBasis = panzer::createIntrepid2Basis<PHX::Device,double,double>(targetBasisDescriptor_.getType(),
57 targetBasisDescriptor_.getOrder(),
61 targetGlobalIndexer_->addField(eBlock,targetBasisDescriptor_.getType(),fieldPattern);
64 targetGlobalIndexer_->buildGlobalUnknowns();
69 template<
typename LO,
typename GO>
72 {
return targetGlobalIndexer_;}
74 template<
typename LO,
typename GO>
77 const std::unordered_map<std::string,double>* elementBlockMultipliers)
79 PANZER_FUNC_TIME_MONITOR_DIFF(
"L2Projection::Build Mass Matrix",TopBuildMassMatrix);
82 if (elementBlockMultipliers !=
nullptr) {
83 TEUCHOS_ASSERT(elementBlockMultipliers->size() == elementBlockNames_.size());
87 std::vector<Teuchos::RCP<const panzer::UniqueGlobalIndexer<LO,GO>>> indexers;
88 indexers.push_back(targetGlobalIndexer_);
94 ownedMatrix->resumeFill();
95 ownedMatrix->setAllToScalar(0.0);
96 ghostedMatrix->resumeFill();
97 ghostedMatrix->setAllToScalar(0.0);
100 auto M = ghostedMatrix->getLocalMatrix();
101 const int fieldIndex = targetGlobalIndexer_->getFieldNum(targetBasisDescriptor_.getType());
103 const bool is_scalar = targetBasisDescriptor_.getType()==
"HGrad" || targetBasisDescriptor_.getType()==
"Const" || targetBasisDescriptor_.getType()==
"HVol";
107 for (
const auto& block : elementBlockNames_) {
109 double ebMultiplier = 1.0;
110 if (elementBlockMultipliers !=
nullptr)
111 ebMultiplier = elementBlockMultipliers->find(block)->second;
115 const auto& worksets = worksetContainer_->getWorksets(wd);
117 for (
const auto& workset : *worksets) {
119 const auto& basisValues = workset.getBasisValues(targetBasisDescriptor_,integrationDescriptor_);
121 const auto& unweightedBasis = basisValues.basis_scalar;
122 const auto& weightedBasis = basisValues.weighted_basis_scalar;
125 const std::vector<LO>&
offsets = targetGlobalIndexer_->getGIDFieldOffsets(block,fieldIndex);
126 PHX::View<LO*> kOffsets(
"MassMatrix: Offsets",offsets.size());
127 for(
const auto& i : offsets)
128 kOffsets(i) = offsets[i];
130 PHX::Device::fence();
133 Kokkos::View<LO**,PHX::Device> localIds(
"MassMatrix: LocalIds", workset.numOwnedCells()+workset.numGhostCells()+workset.numVirtualCells(),
134 targetGlobalIndexer_->getElementBlockGIDCount(block));
137 const auto cellLocalIdsNoGhost = Kokkos::subview(workset.cell_local_ids_k,std::make_pair(0,workset.numOwnedCells()));
139 targetGlobalIndexer_->getElementLIDs(cellLocalIdsNoGhost,localIds);
141 const int numBasisPoints =
static_cast<int>(weightedBasis.extent(1));
143 Kokkos::parallel_for(workset.numOwnedCells(),KOKKOS_LAMBDA (
const int& cell) {
144 double total_mass = 0.0, trace = 0.0;
147 const int numIds =
static_cast<int>(localIds.extent(1));
148 for(
int i=0;i<numIds;++i)
149 cLIDs[i] = localIds(cell,i);
151 double vals[256]={0.0};
152 const int numQP =
static_cast<int>(unweightedBasis.extent(2));
154 for (
int row=0; row < numBasisPoints; ++row) {
155 for (
int col=0; col < numIds; ++col) {
156 for (
int qp=0; qp < numQP; ++qp) {
157 auto tmp = unweightedBasis(cell,row,qp) * weightedBasis(cell,col,qp) * ebMultiplier;
165 for (
int row=0; row < numBasisPoints; ++row) {
166 for (
int col=0; col < numBasisPoints; ++col)
169 int offset = kOffsets(row);
170 LO lid = localIds(cell,offset);
173 for (
int qp=0; qp < numQP; ++qp)
174 vals[col] += unweightedBasis(cell,row,qp) * weightedBasis(cell,col,qp) * ebMultiplier * total_mass / trace;
176 M.sumIntoValues(lid,cLIDs,numIds,vals,
true,
true);
181 Kokkos::parallel_for(workset.numOwnedCells(),KOKKOS_LAMBDA (
const int& cell) {
184 const int numIds =
static_cast<int>(localIds.extent(1));
185 for(
int i=0;i<numIds;++i)
186 cLIDs[i] = localIds(cell,i);
189 const int numQP =
static_cast<int>(unweightedBasis.extent(2));
191 for (
int row=0; row < numBasisPoints; ++row) {
192 int offset = kOffsets(row);
193 LO lid = localIds(cell,offset);
195 for (
int col=0; col < numIds; ++col) {
197 for (
int qp=0; qp < numQP; ++qp)
198 vals[col] += unweightedBasis(cell,row,qp) * weightedBasis(cell,col,qp) * ebMultiplier;
200 M.sumIntoValues(lid,cLIDs,numIds,vals,
true,
true);
209 for (
const auto& block : elementBlockNames_) {
211 double ebMultiplier = 1.0;
212 if (elementBlockMultipliers !=
nullptr)
213 ebMultiplier = elementBlockMultipliers->find(block)->second;
217 const auto& worksets = worksetContainer_->getWorksets(wd);
219 for (
const auto& workset : *worksets) {
221 const auto& basisValues = workset.getBasisValues(targetBasisDescriptor_,integrationDescriptor_);
223 const auto& unweightedBasis = basisValues.basis_vector;
224 const auto& weightedBasis = basisValues.weighted_basis_vector;
227 const std::vector<LO>&
offsets = targetGlobalIndexer_->getGIDFieldOffsets(block,fieldIndex);
228 PHX::View<LO*> kOffsets(
"MassMatrix: Offsets",offsets.size());
229 for(
const auto& i : offsets)
230 kOffsets(i) = offsets[i];
232 PHX::Device::fence();
235 Kokkos::View<LO**,PHX::Device> localIds(
"MassMatrix: LocalIds", workset.numOwnedCells()+workset.numGhostCells()+workset.numVirtualCells(),
236 targetGlobalIndexer_->getElementBlockGIDCount(block));
239 const auto cellLocalIdsNoGhost = Kokkos::subview(workset.cell_local_ids_k,std::make_pair(0,workset.numOwnedCells()));
241 targetGlobalIndexer_->getElementLIDs(cellLocalIdsNoGhost,localIds);
243 const int numBasisPoints =
static_cast<int>(weightedBasis.extent(1));
244 Kokkos::parallel_for(workset.numOwnedCells(),KOKKOS_LAMBDA (
const int& cell) {
247 const int numIds =
static_cast<int>(localIds.extent(1));
248 for(
int i=0;i<numIds;++i)
249 cLIDs[i] = localIds(cell,i);
252 const int numQP =
static_cast<int>(unweightedBasis.extent(2));
254 for (
int qp=0; qp < numQP; ++qp) {
255 for (
int row=0; row < numBasisPoints; ++row) {
256 int offset = kOffsets(row);
257 LO lid = localIds(cell,offset);
259 for (
int col=0; col < numIds; ++col){
261 for(
int dim=0; dim < static_cast<int>(weightedBasis.extent(3)); ++dim)
262 vals[col] += unweightedBasis(cell,row,qp,dim) * weightedBasis(cell,col,qp,dim) * ebMultiplier;
265 M.sumIntoValues(lid,cLIDs,numIds,vals,
true,
true);
273 PHX::exec_space::fence();
276 PANZER_FUNC_TIME_MONITOR_DIFF(
"Exporting of mass matrix",ExportMM);
277 auto map = factory.
getMap(0);
278 ghostedMatrix->fillComplete(map,map);
280 ownedMatrix->doExport(*ghostedMatrix, *exporter, Tpetra::ADD);
281 ownedMatrix->fillComplete();
286 template<
typename LO,
typename GO>
290 PANZER_FUNC_TIME_MONITOR_DIFF(
"L2Projection<LO,GO>::buildInverseLumpedMassMatrix",buildInvLMM);
292 const auto massMatrix = this->buildMassMatrix(
true);
293 const auto lumpedMassMatrix =
rcp(
new Tpetra::MultiVector<double,LO,GO,panzer::TpetraNodeType>(massMatrix->getDomainMap(),1,
true));
294 const auto tmp =
rcp(
new Tpetra::MultiVector<double,LO,GO,panzer::TpetraNodeType>(massMatrix->getRangeMap(),1,
false));
297 PANZER_FUNC_TIME_MONITOR_DIFF(
"Apply",Apply);
298 massMatrix->apply(*tmp,*lumpedMassMatrix);
301 PANZER_FUNC_TIME_MONITOR_DIFF(
"Reciprocal",Reciprocal);
302 lumpedMassMatrix->reciprocal(*lumpedMassMatrix);
304 return lumpedMassMatrix;
307 template<
typename LO,
typename GO>
310 const Teuchos::RCP<
const Tpetra::Map<LO,GO,panzer::TpetraNodeType>>& inputOwnedSourceMap,
311 const std::string& sourceFieldName,
313 const int directionIndex)
320 using MapType = Tpetra::Map<LO,GO,panzer::TpetraNodeType>;
321 using GraphType = Tpetra::CrsGraph<LO,GO,panzer::TpetraNodeType>;
322 using ExportType = Tpetra::Export<LO,GO,panzer::TpetraNodeType>;
323 using MatrixType = Tpetra::CrsMatrix<double,LO,GO,panzer::TpetraNodeType>;
331 std::vector<GO> indices;
332 targetGlobalIndexer_->getOwnedAndGhostedIndices(indices);
338 std::vector<GO> indices;
343 RCP<GraphType> ghostedGraph =
rcp(
new GraphType(ghostedTargetMap,ghostedSourceMap,0));
346 std::vector<std::string> elementBlockIds;
347 targetGlobalIndexer_->getElementBlockIds(elementBlockIds);
348 std::vector<std::string>::const_iterator blockItr;
349 for (blockItr=elementBlockIds.begin();blockItr!=elementBlockIds.end();++blockItr) {
350 std::string blockId = *blockItr;
351 const std::vector<LO> & elements = targetGlobalIndexer_->getElementBlock(blockId);
353 std::vector<GO> row_gids;
354 std::vector<GO> col_gids;
356 for(std::size_t elmt=0;elmt<elements.size();elmt++) {
357 targetGlobalIndexer_->getElementGIDs(elements[elmt],row_gids);
359 for(std::size_t row=0;row<row_gids.size();row++)
360 ghostedGraph->insertGlobalIndices(row_gids[row],col_gids);
366 std::vector<GO> indices;
367 targetGlobalIndexer_->getOwnedIndices(indices);
373 std::vector<GO> indices;
379 ghostedGraph->fillComplete(ownedSourceMap,ownedTargetMap);
387 ownedGraph->doExport(*ghostedGraph, *exporter, Tpetra::INSERT);
388 ownedGraph->fillComplete(ownedSourceMap,ownedTargetMap);
395 ghostedMatrix->setAllToScalar(0.0);
396 ownedMatrix->setAllToScalar(0.0);
397 PHX::Device::fence();
402 for (
const auto& block : elementBlockNames_) {
405 const auto& worksets = worksetContainer_->getWorksets(wd);
406 for (
const auto& workset : *worksets) {
409 const auto& targetBasisValues = workset.getBasisValues(targetBasisDescriptor_,integrationDescriptor_);
410 const auto& targetWeightedBasis = targetBasisValues.weighted_basis_scalar.get_static_view();
413 const auto& sourceBasisValues = workset.getBasisValues(sourceBasisDescriptor,integrationDescriptor_);
414 Kokkos::View<const double***,PHX::Device> sourceUnweightedScalarBasis;
415 Kokkos::View<const double****,PHX::Device> sourceUnweightedVectorBasis;
416 bool useRankThreeBasis =
false;
417 if ( (sourceBasisDescriptor.
getType() ==
"HGrad") || (sourceBasisDescriptor.
getType() ==
"Const") || (sourceBasisDescriptor.
getType() ==
"HVol") ) {
418 if (directionIndex == -1) {
419 sourceUnweightedScalarBasis = sourceBasisValues.basis_scalar.get_static_view();
420 useRankThreeBasis =
true;
423 sourceUnweightedVectorBasis = sourceBasisValues.grad_basis.get_static_view();
427 sourceUnweightedVectorBasis = sourceBasisValues.basis_vector.get_static_view();
431 Kokkos::View<LO**,PHX::Device> targetLocalIds(
"buildRHSMatrix: targetLocalIds", workset.numOwnedCells(),
432 targetGlobalIndexer_->getElementBlockGIDCount(block));
433 Kokkos::View<LO**,PHX::Device> sourceLocalIds(
"buildRHSMatrix: sourceLocalIds", workset.numOwnedCells(),
437 const auto cellLocalIdsNoGhost = Kokkos::subview(workset.cell_local_ids_k,std::make_pair(0,workset.numOwnedCells()));
438 targetGlobalIndexer_->getElementLIDs(cellLocalIdsNoGhost,targetLocalIds);
439 sourceGlobalIndexer.
getElementLIDs(cellLocalIdsNoGhost,sourceLocalIds);
443 Kokkos::View<LO*,PHX::Device> targetFieldOffsets;
445 const auto fieldIndex = targetGlobalIndexer_->getFieldNum(targetBasisDescriptor_.getType());
446 const std::vector<LO>&
offsets = targetGlobalIndexer_->getGIDFieldOffsets(block,fieldIndex);
447 targetFieldOffsets = Kokkos::View<LO*,PHX::Device>(
"L2Projection:buildRHS:targetFieldOffsets",offsets.size());
448 const auto hostOffsets = Kokkos::create_mirror_view(targetFieldOffsets);
449 for(
size_t i=0; i < offsets.size(); ++i)
450 hostOffsets(i) = offsets[i];
451 Kokkos::deep_copy(targetFieldOffsets,hostOffsets);
452 PHX::Device::fence();
455 Kokkos::View<LO*,PHX::Device> sourceFieldOffsets;
457 const auto fieldIndex = sourceGlobalIndexer.
getFieldNum(sourceFieldName);
460 "ERROR: panzer::L2Projection::buildRHSMatrix() - The source field, \""
461 << sourceFieldName <<
"\", does not exist in element block \""
463 sourceFieldOffsets = Kokkos::View<LO*,PHX::Device>(
"L2Projection:buildRHS:sourceFieldOffsets",offsets.size());
464 const auto hostOffsets = Kokkos::create_mirror_view(sourceFieldOffsets);
465 for(
size_t i=0; i <offsets.size(); ++i)
466 hostOffsets(i) = offsets[i];
467 Kokkos::deep_copy(sourceFieldOffsets,hostOffsets);
468 PHX::Device::fence();
471 const auto localMatrix = ghostedMatrix->getLocalMatrix();
472 const int numRows =
static_cast<int>(targetWeightedBasis.extent(1));
475 if (useRankThreeBasis) {
476 tmpNumCols =
static_cast<int>(sourceUnweightedScalarBasis.extent(1));
477 tmpNumQP =
static_cast<int>(sourceUnweightedScalarBasis.extent(2));
480 tmpNumCols =
static_cast<int>(sourceUnweightedVectorBasis.extent(1));
481 tmpNumQP =
static_cast<int>(sourceUnweightedVectorBasis.extent(2));
483 const int numCols = tmpNumCols;
484 const int numQP = tmpNumQP;
486 Kokkos::parallel_for(Kokkos::RangePolicy<PHX::Device>(0,workset.numOwnedCells()),KOKKOS_LAMBDA (
const int& cell) {
489 for (
int row = 0; row < numRows; ++row) {
490 const int rowOffset = targetFieldOffsets(row);
491 const int rowLID = targetLocalIds(cell,rowOffset);
492 for (
int col = 0; col < numCols; ++col)
495 for (
int col = 0; col < numCols; ++col) {
496 for (
int qp = 0; qp < numQP; ++qp) {
497 const int colOffset = sourceFieldOffsets(col);
498 const int colLID = sourceLocalIds(cell,colOffset);
500 if (useRankThreeBasis)
501 vals[col] += sourceUnweightedScalarBasis(cell,col,qp) * targetWeightedBasis(cell,row,qp);
503 vals[col] += sourceUnweightedVectorBasis(cell,col,qp,directionIndex) * targetWeightedBasis(cell,row,qp);
506 localMatrix.sumIntoValues(rowLID,cLIDs,numCols,vals,
true,
true);
512 ghostedMatrix->fillComplete(ownedSourceMap,ownedTargetMap);
513 ownedMatrix->resumeFill();
514 ownedMatrix->doExport(*ghostedMatrix,*exporter,Tpetra::ADD);
515 ownedMatrix->fillComplete(ownedSourceMap,ownedTargetMap);
const Kokkos::View< const LocalOrdinalT *, Kokkos::LayoutRight, PHX::Device > getElementLIDs(LocalOrdinalT localElmtId) const
virtual void getElementGIDs(LocalOrdinalT localElmtId, std::vector< GlobalOrdinalT > &gids, const std::string &blockIdHint="") const =0
Get the global IDs for a particular element. This function overwrites the gids variable.
Teuchos::RCP< CrsMatrixType > getTpetraMatrix(int i, int j) const
bool is_null(const boost::shared_ptr< T > &p)
virtual Teuchos::RCP< const ExportType > getGhostedExport(int j) const
get exporter for converting an overalapped object to a "normal" object
virtual void getOwnedAndGhostedIndices(std::vector< GlobalOrdinalT > &indices) const =0
Get the set of owned and ghosted indices for this processor.
Teuchos::RCP< Tpetra::MultiVector< double, LO, GO, Kokkos::Compat::KokkosDeviceWrapperNode< PHX::Device > > > buildInverseLumpedMassMatrix()
Allocates, fills and returns a Tpetra::MultiVector containing the inverse lumped mass matrix values a...
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
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.
Teuchos::RCP< panzer::UniqueGlobalIndexer< LO, GO > > getTargetGlobalIndexer() const
Returns the target global indexer. Will be null if setup() has not been called.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
const std::string & getType() const
Get type of basis.
virtual Teuchos::RCP< const MapType > getMap(int i) const
get the map from the matrix
virtual int getElementBlockGIDCount(const std::string &blockId) const =0
How many GIDs are associate with a particular element block.
Teuchos::RCP< Tpetra::CrsMatrix< double, LO, GO, Kokkos::Compat::KokkosDeviceWrapperNode< PHX::Device > > > buildRHSMatrix(const panzer::UniqueGlobalIndexer< LO, GO > &sourceDOFManager, const Teuchos::RCP< const Tpetra::Map< LO, GO, Kokkos::Compat::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 int getFieldNum(const std::string &str) const =0
Get the number used for access to this field.
Teuchos::RCP< CrsMatrixType > getGhostedTpetraMatrix(int i, int j) const
#define TEUCHOS_ASSERT(assertion_test)
virtual void getOwnedIndices(std::vector< GlobalOrdinalT > &indices) const =0
Get the set of indices owned by this processor.
void setup(const panzer::BasisDescriptor &targetBasis, const panzer::IntegrationDescriptor &integrationDescriptor, const Teuchos::RCP< const Teuchos::MpiComm< int >> &comm, const Teuchos::RCP< const panzer::ConnManager< LO, GO >> &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...
Teuchos::RCP< Tpetra::CrsMatrix< double, LO, GO, Kokkos::Compat::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. ...
Kokkos::View< const int *, PHX::Device > offsets
Workset size is set to the total number of local elements in the MPI process.