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"
14 #include "Panzer_TpetraLinearObjFactory.hpp"
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();
71 {
return targetGlobalIndexer_;}
75 const std::unordered_map<std::string,double>* elementBlockMultipliers)
77 PANZER_FUNC_TIME_MONITOR_DIFF(
"L2Projection::Build Mass Matrix",TopBuildMassMatrix);
80 if (elementBlockMultipliers !=
nullptr) {
81 TEUCHOS_ASSERT(elementBlockMultipliers->size() == elementBlockNames_.size());
85 std::vector<Teuchos::RCP<const panzer::GlobalIndexer>> indexers;
86 indexers.push_back(targetGlobalIndexer_);
92 ownedMatrix->resumeFill();
93 ownedMatrix->setAllToScalar(0.0);
94 ghostedMatrix->resumeFill();
95 ghostedMatrix->setAllToScalar(0.0);
96 PHX::Device().fence();
98 auto M = ghostedMatrix->getLocalMatrix();
99 const int fieldIndex = targetGlobalIndexer_->getFieldNum(targetBasisDescriptor_.getType());
101 const bool is_scalar = targetBasisDescriptor_.getType()==
"HGrad" || targetBasisDescriptor_.getType()==
"Const" || targetBasisDescriptor_.getType()==
"HVol";
105 for (
const auto& block : elementBlockNames_) {
107 double ebMultiplier = 1.0;
108 if (elementBlockMultipliers !=
nullptr)
109 ebMultiplier = elementBlockMultipliers->find(block)->second;
113 const auto worksets = worksetContainer_->getWorksets(wd);
115 for (
const auto& workset : *worksets) {
117 const auto basisValues = workset.getBasisValues(targetBasisDescriptor_,integrationDescriptor_);
119 const auto unweightedBasis = basisValues.basis_scalar;
120 const auto weightedBasis = basisValues.weighted_basis_scalar;
123 const std::vector<panzer::LocalOrdinal>&
offsets = targetGlobalIndexer_->getGIDFieldOffsets(block,fieldIndex);
124 PHX::View<panzer::LocalOrdinal*> kOffsets(
"MassMatrix: Offsets",offsets.size());
125 for(
const auto& i : offsets)
126 kOffsets(i) = offsets[i];
128 PHX::Device().fence();
131 Kokkos::View<panzer::LocalOrdinal**,PHX::Device> localIds(
"MassMatrix: LocalIds", workset.numOwnedCells()+workset.numGhostCells()+workset.numVirtualCells(),
132 targetGlobalIndexer_->getElementBlockGIDCount(block));
135 const auto cellLocalIdsNoGhost = Kokkos::subview(workset.cell_local_ids_k,std::make_pair(0,workset.numOwnedCells()));
137 targetGlobalIndexer_->getElementLIDs(cellLocalIdsNoGhost,localIds);
139 const int numBasisPoints =
static_cast<int>(weightedBasis.extent(1));
141 Kokkos::parallel_for(workset.numOwnedCells(),KOKKOS_LAMBDA (
const int& cell) {
142 double total_mass = 0.0, trace = 0.0;
144 panzer::LocalOrdinal cLIDs[256];
145 const int numIds =
static_cast<int>(localIds.extent(1));
146 for(
int i=0;i<numIds;++i)
147 cLIDs[i] = localIds(cell,i);
149 double vals[256]={0.0};
150 const int numQP =
static_cast<int>(unweightedBasis.extent(2));
152 for (
int row=0; row < numBasisPoints; ++row) {
153 for (
int col=0; col < numIds; ++col) {
154 for (
int qp=0; qp < numQP; ++qp) {
155 auto tmp = unweightedBasis(cell,row,qp) * weightedBasis(cell,col,qp) * ebMultiplier;
163 for (
int row=0; row < numBasisPoints; ++row) {
164 for (
int col=0; col < numBasisPoints; ++col)
167 int offset = kOffsets(row);
168 panzer::LocalOrdinal lid = localIds(cell,offset);
171 for (
int qp=0; qp < numQP; ++qp)
172 vals[col] += unweightedBasis(cell,row,qp) * weightedBasis(cell,col,qp) * ebMultiplier * total_mass / trace;
174 M.sumIntoValues(lid,cLIDs,numIds,vals,
true,
true);
179 Kokkos::parallel_for(workset.numOwnedCells(),KOKKOS_LAMBDA (
const int& cell) {
181 panzer::LocalOrdinal cLIDs[256];
182 const int numIds =
static_cast<int>(localIds.extent(1));
183 for(
int i=0;i<numIds;++i)
184 cLIDs[i] = localIds(cell,i);
187 const int numQP =
static_cast<int>(unweightedBasis.extent(2));
189 for (
int row=0; row < numBasisPoints; ++row) {
190 int offset = kOffsets(row);
191 panzer::LocalOrdinal lid = localIds(cell,offset);
193 for (
int col=0; col < numIds; ++col) {
195 for (
int qp=0; qp < numQP; ++qp)
196 vals[col] += unweightedBasis(cell,row,qp) * weightedBasis(cell,col,qp) * ebMultiplier;
198 M.sumIntoValues(lid,cLIDs,numIds,vals,
true,
true);
207 for (
const auto& block : elementBlockNames_) {
209 double ebMultiplier = 1.0;
210 if (elementBlockMultipliers !=
nullptr)
211 ebMultiplier = elementBlockMultipliers->find(block)->second;
215 const auto& worksets = worksetContainer_->getWorksets(wd);
217 for (
const auto& workset : *worksets) {
219 const auto basisValues = workset.getBasisValues(targetBasisDescriptor_,integrationDescriptor_);
221 const auto unweightedBasis = basisValues.basis_vector;
222 const auto weightedBasis = basisValues.weighted_basis_vector;
225 const std::vector<panzer::LocalOrdinal>&
offsets = targetGlobalIndexer_->getGIDFieldOffsets(block,fieldIndex);
226 PHX::View<panzer::LocalOrdinal*> kOffsets(
"MassMatrix: Offsets",offsets.size());
227 for(
const auto& i : offsets)
228 kOffsets(i) = offsets[i];
230 PHX::Device().fence();
233 Kokkos::View<panzer::LocalOrdinal**,PHX::Device> localIds(
"MassMatrix: LocalIds", workset.numOwnedCells()+workset.numGhostCells()+workset.numVirtualCells(),
234 targetGlobalIndexer_->getElementBlockGIDCount(block));
237 const auto cellLocalIdsNoGhost = Kokkos::subview(workset.cell_local_ids_k,std::make_pair(0,workset.numOwnedCells()));
239 targetGlobalIndexer_->getElementLIDs(cellLocalIdsNoGhost,localIds);
241 const int numBasisPoints =
static_cast<int>(weightedBasis.extent(1));
242 Kokkos::parallel_for(workset.numOwnedCells(),KOKKOS_LAMBDA (
const int& cell) {
244 panzer::LocalOrdinal cLIDs[256];
245 const int numIds =
static_cast<int>(localIds.extent(1));
246 for(
int i=0;i<numIds;++i)
247 cLIDs[i] = localIds(cell,i);
250 const int numQP =
static_cast<int>(unweightedBasis.extent(2));
252 for (
int qp=0; qp < numQP; ++qp) {
253 for (
int row=0; row < numBasisPoints; ++row) {
254 int offset = kOffsets(row);
255 panzer::LocalOrdinal lid = localIds(cell,offset);
257 for (
int col=0; col < numIds; ++col){
259 for(
int dim=0; dim < static_cast<int>(weightedBasis.extent(3)); ++dim)
260 vals[col] += unweightedBasis(cell,row,qp,dim) * weightedBasis(cell,col,qp,dim) * ebMultiplier;
263 M.sumIntoValues(lid,cLIDs,numIds,vals,
true,
true);
271 PHX::exec_space().fence();
274 PANZER_FUNC_TIME_MONITOR_DIFF(
"Exporting of mass matrix",ExportMM);
275 auto map = factory.
getMap(0);
276 ghostedMatrix->fillComplete(map,map);
278 ownedMatrix->doExport(*ghostedMatrix, *exporter, Tpetra::ADD);
279 ownedMatrix->fillComplete();
287 PANZER_FUNC_TIME_MONITOR_DIFF(
"L2Projection<panzer::LocalOrdinal,panzer::GlobalOrdinal>::buildInverseLumpedMassMatrix",buildInvLMM);
289 const auto massMatrix = this->buildMassMatrix(
true);
290 const auto lumpedMassMatrix =
rcp(
new Tpetra::MultiVector<double,panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>(massMatrix->getDomainMap(),1,
true));
291 const auto tmp =
rcp(
new Tpetra::MultiVector<double,panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>(massMatrix->getRangeMap(),1,
false));
294 PANZER_FUNC_TIME_MONITOR_DIFF(
"Apply",Apply);
295 massMatrix->apply(*tmp,*lumpedMassMatrix);
298 PANZER_FUNC_TIME_MONITOR_DIFF(
"Reciprocal",Reciprocal);
299 lumpedMassMatrix->reciprocal(*lumpedMassMatrix);
301 return lumpedMassMatrix;
306 const Teuchos::RCP<
const Tpetra::Map<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>>& inputOwnedSourceMap,
307 const std::string& sourceFieldName,
309 const int directionIndex)
316 using MapType = Tpetra::Map<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>;
317 using GraphType = Tpetra::CrsGraph<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>;
318 using ExportType = Tpetra::Export<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>;
319 using MatrixType = Tpetra::CrsMatrix<double,panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>;
327 std::vector<panzer::GlobalOrdinal> indices;
328 targetGlobalIndexer_->getOwnedAndGhostedIndices(indices);
334 std::vector<panzer::GlobalOrdinal> indices;
339 RCP<GraphType> ghostedGraph =
rcp(
new GraphType(ghostedTargetMap,ghostedSourceMap,0));
342 std::vector<std::string> elementBlockIds;
343 targetGlobalIndexer_->getElementBlockIds(elementBlockIds);
344 std::vector<std::string>::const_iterator blockItr;
345 for (blockItr=elementBlockIds.begin();blockItr!=elementBlockIds.end();++blockItr) {
346 std::string blockId = *blockItr;
347 const std::vector<panzer::LocalOrdinal> & elements = targetGlobalIndexer_->getElementBlock(blockId);
349 std::vector<panzer::GlobalOrdinal> row_gids;
350 std::vector<panzer::GlobalOrdinal> col_gids;
352 for(std::size_t elmt=0;elmt<elements.size();elmt++) {
353 targetGlobalIndexer_->getElementGIDs(elements[elmt],row_gids);
355 for(std::size_t row=0;row<row_gids.size();row++)
356 ghostedGraph->insertGlobalIndices(row_gids[row],col_gids);
362 std::vector<panzer::GlobalOrdinal> indices;
363 targetGlobalIndexer_->getOwnedIndices(indices);
369 std::vector<panzer::GlobalOrdinal> indices;
375 ghostedGraph->fillComplete(ownedSourceMap,ownedTargetMap);
383 ownedGraph->doExport(*ghostedGraph, *exporter, Tpetra::INSERT);
384 ownedGraph->fillComplete(ownedSourceMap,ownedTargetMap);
391 ghostedMatrix->setAllToScalar(0.0);
392 ownedMatrix->setAllToScalar(0.0);
393 PHX::Device().fence();
398 for (
const auto& block : elementBlockNames_) {
401 const auto& worksets = worksetContainer_->getWorksets(wd);
402 for (
const auto& workset : *worksets) {
405 const auto& targetBasisValues = workset.getBasisValues(targetBasisDescriptor_,integrationDescriptor_);
406 const auto& targetWeightedBasis = targetBasisValues.weighted_basis_scalar.get_static_view();
409 const auto& sourceBasisValues = workset.getBasisValues(sourceBasisDescriptor,integrationDescriptor_);
410 Kokkos::View<const double***,PHX::Device> sourceUnweightedScalarBasis;
411 Kokkos::View<const double****,PHX::Device> sourceUnweightedVectorBasis;
412 bool useRankThreeBasis =
false;
413 if ( (sourceBasisDescriptor.
getType() ==
"HGrad") || (sourceBasisDescriptor.
getType() ==
"Const") || (sourceBasisDescriptor.
getType() ==
"HVol") ) {
414 if (directionIndex == -1) {
415 sourceUnweightedScalarBasis = sourceBasisValues.basis_scalar.get_static_view();
416 useRankThreeBasis =
true;
419 sourceUnweightedVectorBasis = sourceBasisValues.grad_basis.get_static_view();
423 sourceUnweightedVectorBasis = sourceBasisValues.basis_vector.get_static_view();
427 Kokkos::View<panzer::LocalOrdinal**,PHX::Device> targetLocalIds(
"buildRHSMatrix: targetLocalIds", workset.numOwnedCells(),
428 targetGlobalIndexer_->getElementBlockGIDCount(block));
429 Kokkos::View<panzer::LocalOrdinal**,PHX::Device> sourceLocalIds(
"buildRHSMatrix: sourceLocalIds", workset.numOwnedCells(),
433 const auto cellLocalIdsNoGhost = Kokkos::subview(workset.cell_local_ids_k,std::make_pair(0,workset.numOwnedCells()));
434 targetGlobalIndexer_->getElementLIDs(cellLocalIdsNoGhost,targetLocalIds);
435 sourceGlobalIndexer.
getElementLIDs(cellLocalIdsNoGhost,sourceLocalIds);
439 Kokkos::View<panzer::LocalOrdinal*,PHX::Device> targetFieldOffsets;
441 const auto fieldIndex = targetGlobalIndexer_->getFieldNum(targetBasisDescriptor_.getType());
442 const std::vector<panzer::LocalOrdinal>&
offsets = targetGlobalIndexer_->getGIDFieldOffsets(block,fieldIndex);
443 targetFieldOffsets = Kokkos::View<panzer::LocalOrdinal*,PHX::Device>(
"L2Projection:buildRHS:targetFieldOffsets",offsets.size());
444 const auto hostOffsets = Kokkos::create_mirror_view(targetFieldOffsets);
445 for(
size_t i=0; i < offsets.size(); ++i)
446 hostOffsets(i) = offsets[i];
447 Kokkos::deep_copy(targetFieldOffsets,hostOffsets);
448 PHX::Device().fence();
451 Kokkos::View<panzer::LocalOrdinal*,PHX::Device> sourceFieldOffsets;
453 const auto fieldIndex = sourceGlobalIndexer.
getFieldNum(sourceFieldName);
456 "ERROR: panzer::L2Projection::buildRHSMatrix() - The source field, \""
457 << sourceFieldName <<
"\", does not exist in element block \""
459 sourceFieldOffsets = Kokkos::View<panzer::LocalOrdinal*,PHX::Device>(
"L2Projection:buildRHS:sourceFieldOffsets",offsets.size());
460 const auto hostOffsets = Kokkos::create_mirror_view(sourceFieldOffsets);
461 for(
size_t i=0; i <offsets.size(); ++i)
462 hostOffsets(i) = offsets[i];
463 Kokkos::deep_copy(sourceFieldOffsets,hostOffsets);
464 PHX::Device().fence();
467 const auto localMatrix = ghostedMatrix->getLocalMatrix();
468 const int numRows =
static_cast<int>(targetWeightedBasis.extent(1));
471 if (useRankThreeBasis) {
472 tmpNumCols =
static_cast<int>(sourceUnweightedScalarBasis.extent(1));
473 tmpNumQP =
static_cast<int>(sourceUnweightedScalarBasis.extent(2));
476 tmpNumCols =
static_cast<int>(sourceUnweightedVectorBasis.extent(1));
477 tmpNumQP =
static_cast<int>(sourceUnweightedVectorBasis.extent(2));
479 const int numCols = tmpNumCols;
480 const int numQP = tmpNumQP;
482 Kokkos::parallel_for(Kokkos::RangePolicy<PHX::Device>(0,workset.numOwnedCells()),KOKKOS_LAMBDA (
const int& cell) {
483 panzer::LocalOrdinal cLIDs[256];
485 for (
int row = 0; row < numRows; ++row) {
486 const int rowOffset = targetFieldOffsets(row);
487 const int rowLID = targetLocalIds(cell,rowOffset);
488 for (
int col = 0; col < numCols; ++col)
491 for (
int col = 0; col < numCols; ++col) {
492 for (
int qp = 0; qp < numQP; ++qp) {
493 const int colOffset = sourceFieldOffsets(col);
494 const int colLID = sourceLocalIds(cell,colOffset);
496 if (useRankThreeBasis)
497 vals[col] += sourceUnweightedScalarBasis(cell,col,qp) * targetWeightedBasis(cell,row,qp);
499 vals[col] += sourceUnweightedVectorBasis(cell,col,qp,directionIndex) * targetWeightedBasis(cell,row,qp);
502 localMatrix.sumIntoValues(rowLID,cLIDs,numCols,vals,
true,
true);
508 ghostedMatrix->fillComplete(ownedSourceMap,ownedTargetMap);
509 ownedMatrix->resumeFill();
510 ownedMatrix->doExport(*ghostedMatrix,*exporter,Tpetra::ADD);
511 ownedMatrix->fillComplete(ownedSourceMap,ownedTargetMap);
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
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 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.
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.
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
Teuchos::RCP< Tpetra::CrsMatrix< double, panzer::LocalOrdinal, panzer::GlobalOrdinal, Kokkos::Compat::KokkosDeviceWrapperNode< PHX::Device > > > buildRHSMatrix(const panzer::GlobalIndexer &sourceDOFManager, const Teuchos::RCP< const Tpetra::Map< panzer::LocalOrdinal, panzer::GlobalOrdinal, 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.
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, Kokkos::Compat::KokkosDeviceWrapperNode< PHX::Device > > > buildInverseLumpedMassMatrix()
Allocates, fills and returns a Tpetra::MultiVector containing the inverse lumped mass matrix values a...
#define TEUCHOS_ASSERT(assertion_test)
Kokkos::View< const int *, PHX::Device > offsets
Workset size is set to the total number of local elements in the MPI process.
Teuchos::RCP< Tpetra::CrsMatrix< double, panzer::LocalOrdinal, panzer::GlobalOrdinal, 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. ...