1 #ifndef DUNE_FEM_PETSCLINEAROPERATOR_HH 2 #define DUNE_FEM_PETSCLINEAROPERATOR_HH 3 4 #include <cassert> 5 #include <cstddef> 6 7 #include <iostream> 8 #include <memory> 9 #include <string> 10 #include <type_traits> 11 #include <vector> 12 13 #include <dune/common/dynmatrix.hh> 14 15 #include <dune/fem/function/petscdiscretefunction/petscdiscretefunction.hh> 16 #include <dune/fem/misc/functor.hh> 17 #include <dune/fem/misc/fmatrixconverter.hh> 18 #include <dune/fem/misc/petsc/petsccommon.hh> 19 #include <dune/fem/operator/common/localcontribution.hh> 20 #include <dune/fem/operator/common/localmatrix.hh> 21 #include <dune/fem/operator/common/localmatrixwrapper.hh> 22 #include <dune/fem/operator/common/temporarylocalmatrix.hh> 23 #include <dune/fem/operator/common/operator.hh> 24 #include <dune/fem/operator/common/stencil.hh> 25 #include <dune/fem/operator/matrix/columnobject.hh> 26 #include <dune/fem/operator/matrix/functor.hh> 27 #include <dune/fem/space/mapper/nonblockmapper.hh> 28 #include <dune/fem/space/mapper/petsc.hh> 29 #include <dune/fem/storage/objectstack.hh> 30 31 #include <dune/fem/solver/parameter.hh> 32 33 #if HAVE_PETSC 34 35 #include "petscmat.h" 36 37 38 namespace Dune 39 { 40 namespace Fem 41 { 42 43 struct PetscSolverParameter : public LocalParameter< SolverParameter, PetscSolverParameter > 44 { 45 typedef LocalParameter< SolverParameter, PetscSolverParameter > BaseType; 46 47 public: 48 using BaseType :: parameter ; 49 using BaseType :: keyPrefix ; 50 PetscSolverParameterDune::Fem::PetscSolverParameter51 PetscSolverParameter( const ParameterReader ¶meter = Parameter::container() ) 52 : BaseType( parameter ) 53 {} 54 PetscSolverParameterDune::Fem::PetscSolverParameter55 PetscSolverParameter( const SolverParameter& sp ) 56 : PetscSolverParameter( sp.keyPrefix(), sp.parameter() ) 57 {} 58 PetscSolverParameterDune::Fem::PetscSolverParameter59 PetscSolverParameter( const std::string &keyPrefix, const ParameterReader ¶meter = Parameter::container() ) 60 : BaseType( keyPrefix, parameter ) 61 {} 62 isPetscSolverParameterDune::Fem::PetscSolverParameter63 bool isPetscSolverParameter() const { return true; } 64 65 static const int boomeramg = 0; 66 static const int parasails = 1; 67 static const int pilut = 2; 68 hypreMethodDune::Fem::PetscSolverParameter69 int hypreMethod() const 70 { 71 const std::string hyprePCNames[] = { "boomer-amg", "parasails", "pilu-t" }; 72 int hypreType = 0; 73 if (parameter().exists("petsc.preconditioning.method")) 74 { 75 hypreType = parameter().getEnum( "petsc.preconditioning.hypre.method", hyprePCNames, 0 ); 76 std::cout << "WARNING: using deprecated parameter 'petsc.preconditioning.hypre.method' use " 77 << keyPrefix() << "preconditioning.hypre.method instead\n"; 78 } 79 else 80 hypreType = parameter().getEnum( keyPrefix()+"hypre.method", hyprePCNames, 0 ); 81 return hypreType; 82 } 83 superluMethodDune::Fem::PetscSolverParameter84 int superluMethod() const 85 { 86 const std::string factorizationNames[] = { "petsc", "superlu", "mumps" }; 87 int factorType = 0; 88 if (parameter().exists("petsc.preconditioning.lu.method")) 89 { 90 factorType = parameter().getEnum( "petsc.preconditioning.lu.method", factorizationNames, 0 ); 91 std::cout << "WARNING: using deprecated parameter 'petsc.preconditioning.lu.method' use " 92 << keyPrefix() << "preconditioning.lu.method instead\n"; 93 } 94 else 95 factorType = parameter().getEnum( keyPrefix()+"preconditioning.lu.method", factorizationNames, 0 ); 96 return factorType; 97 } 98 viennaCLDune::Fem::PetscSolverParameter99 bool viennaCL () const { 100 return parameter().getValue< bool > ( keyPrefix() + "petsc.viennacl", false ); 101 } blockedModeDune::Fem::PetscSolverParameter102 bool blockedMode () const { 103 return parameter().getValue< bool > ( keyPrefix() + "petsc.blockedmode", true ); 104 } 105 }; 106 107 108 109 /* ======================================== 110 * class PetscLinearOperator 111 */ 112 template< typename DomainFunction, typename RangeFunction > 113 class PetscLinearOperator 114 : public Fem::AssembledOperator< DomainFunction, RangeFunction > 115 { 116 typedef PetscLinearOperator< DomainFunction, RangeFunction > ThisType; 117 public: 118 typedef Mat MatrixType; 119 typedef DomainFunction DomainFunctionType; 120 typedef RangeFunction RangeFunctionType; 121 typedef typename DomainFunctionType::RangeFieldType DomainFieldType; 122 typedef typename RangeFunctionType::RangeFieldType RangeFieldType; 123 typedef typename DomainFunctionType::DiscreteFunctionSpaceType DomainSpaceType; 124 typedef typename RangeFunctionType::DiscreteFunctionSpaceType RangeSpaceType; 125 126 typedef PetscDiscreteFunction< DomainSpaceType > PetscDomainFunctionType; 127 typedef PetscDiscreteFunction< RangeSpaceType > PetscRangeFunctionType; 128 129 typedef typename DomainSpaceType::GridPartType::template Codim< 0 >::EntityType DomainEntityType; 130 typedef typename RangeSpaceType::GridPartType::template Codim< 0 >::EntityType RangeEntityType; 131 132 static const unsigned int domainLocalBlockSize = DomainSpaceType::localBlockSize; 133 static const unsigned int rangeLocalBlockSize = RangeSpaceType::localBlockSize; 134 135 static constexpr bool squareBlocked = domainLocalBlockSize == rangeLocalBlockSize ; 136 static constexpr bool blockedMatrix = domainLocalBlockSize > 1 && squareBlocked; 137 138 // is this right? It should be rangeBS x domainBS - the system is 139 // Ad=r so domain gives columns and r gives range 140 typedef FlatFieldMatrix< RangeFieldType, domainLocalBlockSize, rangeLocalBlockSize > MatrixBlockType; 141 typedef MatrixBlockType block_type; 142 143 private: 144 enum Status {statAssembled=0,statAdd=1,statInsert=2,statGet=3,statNothing=4}; 145 146 typedef PetscMappers< DomainSpaceType > DomainMappersType; 147 typedef PetscMappers< RangeSpaceType > RangeMappersType; 148 149 typedef AuxiliaryDofs< typename DomainSpaceType::GridPartType, typename DomainMappersType::GhostMapperType > DomainAuxiliaryDofsType; 150 typedef AuxiliaryDofs< typename RangeSpaceType::GridPartType, typename RangeMappersType::GhostMapperType > RangeAuxiliaryDofsType; 151 152 public: 153 // the local matrix 154 class LocalMatrix; 155 156 struct LocalMatrixTraits 157 { 158 typedef typename DomainFunctionType::DiscreteFunctionSpaceType DomainSpaceType; 159 typedef typename RangeFunctionType::DiscreteFunctionSpaceType RangeSpaceType; 160 typedef LocalMatrix LocalMatrixType; 161 typedef typename RangeSpaceType::RangeFieldType RangeFieldType; 162 163 // copied this typedef from spmatrix.hh 164 typedef RangeFieldType LittleBlockType; 165 }; 166 167 //! type of local matrix object 168 typedef LocalMatrix ObjectType; 169 typedef ThisType LocalMatrixFactoryType; 170 typedef ObjectStack< LocalMatrixFactoryType > LocalMatrixStackType; 171 172 //! type of local matrix using stacking mechanism 173 typedef LocalMatrixWrapper< LocalMatrixStackType > LocalMatrixType; 174 typedef ColumnObject< ThisType > LocalColumnObjectType; 175 PetscLinearOperator(const DomainSpaceType & domainSpace,const RangeSpaceType & rangeSpace,const PetscSolverParameter & param=PetscSolverParameter ())176 PetscLinearOperator ( const DomainSpaceType &domainSpace, const RangeSpaceType &rangeSpace, 177 const PetscSolverParameter& param = PetscSolverParameter() ) 178 : domainMappers_( domainSpace ), 179 rangeMappers_( rangeSpace ), 180 localMatrixStack_( *this ), 181 status_(statNothing), 182 viennaCL_( param.viennaCL() ), 183 blockedMode_( blockedMatrix && (!viennaCL_) && param.blockedMode() ) 184 {} 185 PetscLinearOperator(const std::string &,const DomainSpaceType & domainSpace,const RangeSpaceType & rangeSpace,const PetscSolverParameter & param=PetscSolverParameter ())186 PetscLinearOperator ( const std::string &, const DomainSpaceType &domainSpace, const RangeSpaceType &rangeSpace, 187 const PetscSolverParameter& param = PetscSolverParameter() ) 188 : PetscLinearOperator( domainSpace, rangeSpace, param ) 189 {} 190 191 //! destructor deleting PETSc Mat object ~PetscLinearOperator()192 ~PetscLinearOperator () 193 { 194 destroy(); 195 } 196 flushAssembly()197 void flushAssembly() 198 { 199 ::Dune::Petsc::MatAssemblyBegin( petscMatrix_, MAT_FLUSH_ASSEMBLY ); 200 ::Dune::Petsc::MatAssemblyEnd ( petscMatrix_, MAT_FLUSH_ASSEMBLY ); 201 setStatus( statAssembled ); 202 } 203 finalize()204 void finalize () 205 { 206 if( ! finalizedAlready() ) 207 { 208 ::Dune::Petsc::MatAssemblyBegin( petscMatrix_, MAT_FINAL_ASSEMBLY ); 209 ::Dune::Petsc::MatAssemblyEnd ( petscMatrix_, MAT_FINAL_ASSEMBLY ); 210 211 if( ! unitRows_.empty() ) 212 { 213 ::Dune::Petsc::MatZeroRows( petscMatrix_, unitRows_.size(), unitRows_.data(), 1. ); 214 // remove all cached unit rows 215 unitRows_.clear(); 216 } 217 } 218 } 219 220 protected: finalizedAlready() const221 bool finalizedAlready() const 222 { 223 PetscBool assembled = PETSC_FALSE ; 224 ::Dune::Petsc::MatAssembled( petscMatrix_, &assembled ); 225 return assembled == PETSC_TRUE; 226 } 227 finalizeAssembly() const228 void finalizeAssembly () const 229 { 230 const_cast< ThisType& > (*this).finalize(); 231 } 232 233 public: domainSpace() const234 const DomainSpaceType &domainSpace () const { return domainMappers_.space(); } rangeSpace() const235 const RangeSpaceType &rangeSpace () const { return rangeMappers_.space(); } 236 237 /** \brief application operator for arbitrary DiscreteFunction 238 * \note This functions needs to make copies of the dof vectors into 239 * PetscDiscreteFunction */ 240 template <class DF, class RF> apply(const DF & arg,RF & dest) const241 void apply ( const DF &arg, RF &dest ) const 242 { 243 if( ! petscArg_ ) 244 petscArg_.reset( new PetscDomainFunctionType( "PetscOp-arg", domainSpace() ) ); 245 if( ! petscDest_ ) 246 petscDest_.reset( new PetscRangeFunctionType( "PetscOp-arg", rangeSpace() ) ); 247 248 petscArg_->assign( arg ); 249 apply( *petscArg_, *petscDest_ ); 250 dest.assign( *petscDest_ ); 251 } 252 253 /** \brief application operator for PetscDiscreteFunction */ apply(const PetscDomainFunctionType & arg,PetscRangeFunctionType & dest) const254 void apply ( const PetscDomainFunctionType &arg, PetscRangeFunctionType &dest ) const 255 { 256 // make sure matrix is in correct state 257 finalizeAssembly(); 258 ::Dune::Petsc::MatMult( petscMatrix_, *arg.petscVec() , *dest.petscVec() ); 259 } 260 operator ()(const DomainFunctionType & arg,RangeFunctionType & dest) const261 void operator() ( const DomainFunctionType &arg, RangeFunctionType &dest ) const 262 { 263 apply( arg, dest ); 264 } 265 reserve()266 void reserve () 267 { 268 reserve( SimpleStencil<DomainSpaceType,RangeSpaceType>(0), true ); 269 } 270 271 template <class Set> reserve(const std::vector<Set> & sparsityPattern)272 void reserve (const std::vector< Set >& sparsityPattern ) 273 { 274 reserve( StencilWrapper< DomainSpaceType,RangeSpaceType, Set >( sparsityPattern ), true ); 275 } 276 277 //! reserve memory for assemble based on the provided stencil 278 template <class StencilType> reserve(const StencilType & stencil,const bool isSimpleStencil=false)279 void reserve (const StencilType &stencil, const bool isSimpleStencil = false ) 280 { 281 domainMappers_.update(); 282 rangeMappers_.update(); 283 284 if(sequence_ != domainSpace().sequence()) 285 { 286 // clear Petsc Mat 287 destroy(); 288 289 // reset temporary Petsc discrete functions 290 petscArg_.reset(); 291 petscDest_.reset(); 292 293 unitRows_.clear(); 294 295 // create matrix 296 ::Dune::Petsc::MatCreate( domainSpace().gridPart().comm(), &petscMatrix_ ); 297 298 // set sizes of the matrix (columns == domain and rows == range) 299 const PetscInt localCols = domainMappers_.ghostMapper().interiorSize() * domainLocalBlockSize; 300 const PetscInt localRows = rangeMappers_.ghostMapper().interiorSize() * rangeLocalBlockSize; 301 302 const PetscInt globalCols = domainMappers_.parallelMapper().size() * domainLocalBlockSize; 303 const PetscInt globalRows = rangeMappers_.parallelMapper().size() * rangeLocalBlockSize; 304 305 ::Dune::Petsc::MatSetSizes( petscMatrix_, localRows, localCols, globalRows, globalCols ); 306 307 PetscInt bs = 1; 308 if( viennaCL_ ) 309 { 310 ::Dune::Petsc::MatSetType( petscMatrix_, MATAIJVIENNACL ); 311 } 312 else if( blockedMode_ ) 313 { 314 bs = domainLocalBlockSize ; 315 ::Dune::Petsc::MatSetType( petscMatrix_, MATBAIJ ); 316 // set block size 317 ::Dune::Petsc::MatSetBlockSize( petscMatrix_, bs ); 318 } 319 else 320 { 321 ::Dune::Petsc::MatSetType( petscMatrix_, MATAIJ ); 322 } 323 /* 324 std::cout << "Matrix dimension with bs=" << bs << " " 325 << localRows << "x" << localCols << " " 326 << globalRows << "x" << globalCols << " " 327 << rangeLocalBlockSize/bs << "x" << domainLocalBlockSize/bs << " " 328 << std::endl; 329 */ 330 331 // there is an issue with the stencil and non zero pattern in the 332 // case of domainSpace != rangeSpace. In this case additional 333 // mallocs are required during matrix assembly which heavily 334 // impacts the preformance. As a quick fix we use a global value 335 // for the number of non zeros per row. That leads to a 336 // significant increase in memory usage but not to much 337 // computational overhead in assembly. The issue with the stencil 338 // is a bug and needs fixing.... 339 if( isSimpleStencil || std::is_same< StencilType,SimpleStencil<DomainSpaceType,RangeSpaceType> >::value ) 340 { 341 ::Dune::Petsc::MatSetUp( petscMatrix_, bs, domainLocalBlockSize * stencil.maxNonZerosEstimate() ); 342 } 343 else 344 { 345 DomainAuxiliaryDofsType domainAuxiliaryDofs( domainMappers_.ghostMapper() ); 346 RangeAuxiliaryDofsType rangeAuxiliaryDofs( rangeMappers_.ghostMapper() ); 347 348 std::vector< PetscInt > d_nnz( localRows / bs, 0 ); 349 std::vector< PetscInt > o_nnz( localRows / bs, 0 ); 350 for( const auto entry : stencil.globalStencil() ) 351 { 352 const int petscIndex = rangeMappers_.ghostIndex( entry.first ); 353 if( rangeAuxiliaryDofs.contains( petscIndex ) ) 354 continue; 355 356 for (unsigned int rb = 0; rb<rangeLocalBlockSize/bs; ++rb) 357 { 358 const size_t row = petscIndex*rangeLocalBlockSize/bs + rb; 359 // Remark: ghost entities should not be inserted into the stencil for dg to 360 // get optimal results but they are needed for istl.... 361 assert( row < size_t(localRows/bs) ); 362 d_nnz[ row ] = o_nnz[ row ] = 0; 363 for( const auto local : entry.second ) 364 { 365 if( !domainAuxiliaryDofs.contains( domainMappers_.ghostIndex( local ) ) ) 366 d_nnz[ row ] += domainLocalBlockSize/bs; 367 else 368 o_nnz[ row ] += domainLocalBlockSize/bs; 369 } 370 } 371 } 372 ::Dune::Petsc::MatSetUp( petscMatrix_, bs, &d_nnz[0], &o_nnz[0] ); 373 } 374 sequence_ = domainSpace().sequence(); 375 } 376 377 flushAssembly(); 378 status_ = statAssembled ; 379 } 380 clear()381 void clear () 382 { 383 ::Dune::Petsc::MatZeroEntries( petscMatrix_ ); 384 flushAssembly(); 385 } 386 387 template <class Vector> setUnitRows(const Vector & rows)388 void setUnitRows( const Vector &rows ) 389 { 390 std::vector< PetscInt > r( rows.size() ); 391 for( std::size_t i =0 ; i< rows.size(); ++i ) 392 { 393 const PetscInt block = rangeMappers_.parallelIndex( rows[ i ] / rangeLocalBlockSize ); 394 r[ i ] = block * rangeLocalBlockSize + (rows[ i ] % rangeLocalBlockSize); 395 } 396 397 if( finalizedAlready() ) 398 { 399 ::Dune::Petsc::MatZeroRows( petscMatrix_, r.size(), r.data(), 1. ); 400 } 401 else 402 { 403 unitRows_.reserve( unitRows_.size() + r.size() ); 404 for( const auto& row : r ) 405 unitRows_.push_back( row ); 406 } 407 } 408 409 //! interface method from LocalMatrixFactory newObject() const410 ObjectType* newObject() const 411 { 412 return new ObjectType( *this, domainSpace(), rangeSpace() ); 413 } 414 415 /** \deprecated Use TemporaryLocalMatrix in combination with 416 * {add,set,get}LocalMatrix on matrix object 417 * return local matrix object 418 */ 419 [[deprecated("Use TemporaryLocalMatrix,LocalContribution and {get,add,set}LocalMatrix")]] localMatrix(const DomainEntityType & domainEntity,const RangeEntityType & rangeEntity) const420 LocalMatrixType localMatrix ( const DomainEntityType &domainEntity, const RangeEntityType &rangeEntity ) const 421 { 422 return LocalMatrixType(localMatrixStack_, domainEntity, rangeEntity); 423 } 424 localColumn(const DomainEntityType & colEntity) const425 LocalColumnObjectType localColumn( const DomainEntityType &colEntity ) const 426 { 427 return LocalColumnObjectType ( *this, colEntity ); 428 } 429 430 public: unitRow(const PetscInt localRow,const PetscScalar diag=1.0)431 void unitRow( const PetscInt localRow, const PetscScalar diag = 1.0 ) 432 { 433 std::array< PetscInt, domainLocalBlockSize > rows; 434 const PetscInt row = rangeMappers_.parallelIndex( localRow ); 435 for( unsigned int i=0, r = row * domainLocalBlockSize; i<domainLocalBlockSize; ++i, ++r ) 436 { 437 rows[ i ] = r; 438 } 439 440 if( finalizedAlready() ) 441 { 442 // set given row to a zero row with diagonal entry equal to diag 443 ::Dune::Petsc::MatZeroRows( petscMatrix_, domainLocalBlockSize, rows.data(), diag ); 444 } 445 else 446 { 447 // this only works for diag = 1 448 assert( std::abs( diag - 1. ) < 1e-12 ); 449 unitRows_.reserve( unitRows_.size() + domainLocalBlockSize ); 450 for( const auto& r : rows ) 451 { 452 unitRows_.push_back( r ); 453 } 454 } 455 } 456 blockedMode() const457 bool blockedMode() const { return blockedMode_; } 458 459 protected: 460 template< class PetscOp > applyToBlock(const PetscInt localRow,const PetscInt localCol,const MatrixBlockType & block,PetscOp op)461 void applyToBlock ( const PetscInt localRow, const PetscInt localCol, const MatrixBlockType& block, PetscOp op ) 462 { 463 #ifndef NDEBUG 464 const PetscInt localCols = domainMappers_.ghostMapper().interiorSize() * domainLocalBlockSize; 465 const PetscInt localRows = rangeMappers_.ghostMapper().interiorSize() * rangeLocalBlockSize; 466 assert( localRow < localRows ); 467 assert( localCol < localCols ); 468 #endif 469 470 if( blockedMode_ ) 471 { 472 // convert process local indices to global indices 473 const PetscInt row = rangeMappers_.parallelIndex( localRow ); 474 const PetscInt col = rangeMappers_.parallelIndex( localCol ); 475 ::Dune::Petsc::MatSetValuesBlocked( petscMatrix_, 1, &row, 1, &col, block.data(), op ); 476 } 477 else 478 { 479 // convert process local indices to global indices 480 const PetscInt row = rangeMappers_.parallelIndex( localRow ); 481 const PetscInt col = rangeMappers_.parallelIndex( localCol ); 482 std::array< PetscInt, domainLocalBlockSize > rows; 483 std::array< PetscInt, domainLocalBlockSize > cols; 484 for( unsigned int i=0, r = row * domainLocalBlockSize, c = col * domainLocalBlockSize; i<domainLocalBlockSize; ++i, ++r, ++c ) 485 { 486 rows[ i ] = r; 487 cols[ i ] = c; 488 } 489 490 // set given row to a zero row with diagonal entry equal to diag 491 ::Dune::Petsc::MatSetValues( petscMatrix_, domainLocalBlockSize, rows.data(), domainLocalBlockSize, cols.data(), block.data(), op ); 492 } 493 setStatus( statAssembled ); 494 } 495 496 template< class LocalBlock, class PetscOp > applyToBlock(const size_t row,const size_t col,const LocalBlock & block,PetscOp op)497 void applyToBlock ( const size_t row, const size_t col, const LocalBlock& block, PetscOp op ) 498 { 499 assert( block.rows() == rangeLocalBlockSize ); 500 assert( block.cols() == domainLocalBlockSize ); 501 502 // copy to MatrixBlockType data structure suited to be inserted into Mat 503 MatrixBlockType matBlock( block ); 504 applyToBlock( row, col, matBlock, op ); 505 } 506 507 template< class LocalBlock > setBlock(const size_t row,const size_t col,const LocalBlock & block)508 void setBlock ( const size_t row, const size_t col, const LocalBlock& block ) 509 { 510 #ifndef _OPENMP 511 assert( status_==statAssembled || status_==statInsert ); 512 #endif 513 assert( row < std::numeric_limits< int > :: max() ); 514 assert( col < std::numeric_limits< int > :: max() ); 515 516 setStatus( statInsert ); 517 applyToBlock( static_cast< PetscInt > (row), static_cast< PetscInt > (col), block, INSERT_VALUES ); 518 } 519 520 template< class LocalBlock > addBlock(const size_t row,const size_t col,const LocalBlock & block)521 void addBlock ( const size_t row, const size_t col, const LocalBlock& block ) 522 { 523 #ifndef _OPENMP 524 assert( status_==statAssembled || status_==statInsert ); 525 #endif 526 assert( row < std::numeric_limits< int > :: max() ); 527 assert( col < std::numeric_limits< int > :: max() ); 528 529 setStatus( statAdd ); 530 applyToBlock( static_cast< PetscInt > (row), static_cast< PetscInt > (col), block, ADD_VALUES ); 531 } 532 533 protected: 534 typedef TemporaryLocalMatrix< DomainSpaceType, RangeSpaceType > TemporaryLocalMatrixType; 535 536 // specialization for temporary local matrix, then copy of values is not needed 537 template <class Operation> getValues(const unsigned int rSize,const unsigned int cSize,const TemporaryLocalMatrixType & localMat,const Operation &,const std::integral_constant<bool,false> nonscaled)538 const PetscScalar* getValues( const unsigned int rSize, const unsigned int cSize, 539 const TemporaryLocalMatrixType &localMat, const Operation&, 540 const std::integral_constant< bool, false> nonscaled ) 541 { 542 return localMat.data(); 543 } 544 545 // specialization for temporary local matrix, then copy of values is not needed 546 template <class LM, class Operation> getValues(const unsigned int rSize,const unsigned int cSize,const Assembly::Impl::LocalMatrixGetter<LM> & localMat,const Operation &,const std::integral_constant<bool,false> nonscaled)547 const PetscScalar* getValues( const unsigned int rSize, const unsigned int cSize, 548 const Assembly::Impl::LocalMatrixGetter< LM >& localMat, const Operation&, 549 const std::integral_constant< bool, false> nonscaled ) 550 { 551 return localMat.localMatrix().data(); 552 } 553 554 // retrieve values for arbitrary local matrix 555 template <class LocalMatrix, class Operation, bool T> getValues(const unsigned int rSize,const unsigned int cSize,const LocalMatrix & localMat,const Operation & operation,const std::integral_constant<bool,T> scaled)556 const PetscScalar* getValues( const unsigned int rSize, const unsigned int cSize, 557 const LocalMatrix &localMat, const Operation& operation, 558 const std::integral_constant< bool, T> scaled ) 559 { 560 std::vector< PetscScalar >& v = v_; 561 v.resize( rSize * cSize ); 562 for( unsigned int i = 0, ic = 0 ; i< rSize; ++i ) 563 { 564 for( unsigned int j =0; j< cSize; ++j, ++ic ) 565 { 566 v[ ic ] = operation( localMat.get( i, j ) ); 567 } 568 } 569 return v.data(); 570 } 571 572 template< class LocalMatrix, class Operation, class PetscOp, bool T > applyLocalMatrix(const DomainEntityType & domainEntity,const RangeEntityType & rangeEntity,const LocalMatrix & localMat,const Operation & operation,PetscOp petscOp,const std::integral_constant<bool,T> scaled)573 void applyLocalMatrix ( const DomainEntityType &domainEntity, const RangeEntityType &rangeEntity, 574 const LocalMatrix &localMat, const Operation& operation, 575 PetscOp petscOp, 576 const std::integral_constant<bool, T> scaled ) 577 { 578 std::vector< PetscInt >& r = r_; 579 std::vector< PetscInt >& c = c_; 580 581 if( blockedMode_ ) 582 { 583 setupIndicesBlocked( rangeMappers_, rangeEntity, r ); 584 setupIndicesBlocked( domainMappers_, domainEntity, c ); 585 586 // domainLocalBlockSize == rangeLocalBlockSize 587 const unsigned int rSize = r.size() * domainLocalBlockSize ; 588 const unsigned int cSize = c.size() * domainLocalBlockSize ; 589 590 const PetscScalar* values = getValues( rSize, cSize, localMat, operation, scaled ); 591 ::Dune::Petsc::MatSetValuesBlocked( petscMatrix_, r.size(), r.data(), c.size(), c.data(), values, petscOp ); 592 } 593 else 594 { 595 setupIndices( rangeMappers_, rangeEntity, r ); 596 setupIndices( domainMappers_, domainEntity, c ); 597 598 const unsigned int rSize = r.size(); 599 const unsigned int cSize = c.size(); 600 601 const PetscScalar* values = getValues( rSize, cSize, localMat, operation, scaled ); 602 ::Dune::Petsc::MatSetValues( petscMatrix_, rSize, r.data(), cSize, c.data(), values, petscOp ); 603 } 604 setStatus( statAssembled ); 605 } 606 607 public: 608 template< class LocalMatrix > addLocalMatrix(const DomainEntityType & domainEntity,const RangeEntityType & rangeEntity,const LocalMatrix & localMat)609 void addLocalMatrix ( const DomainEntityType &domainEntity, const RangeEntityType &rangeEntity, const LocalMatrix &localMat ) 610 { 611 assert( status_==statAssembled || status_==statAdd ); 612 setStatus( statAdd ); 613 614 auto operation = [] ( const PetscScalar& value ) -> PetscScalar { return value; }; 615 616 applyLocalMatrix( domainEntity, rangeEntity, localMat, operation, ADD_VALUES, std::integral_constant< bool, false>() ); 617 } 618 619 template< class LocalMatrix, class Scalar > addScaledLocalMatrix(const DomainEntityType & domainEntity,const RangeEntityType & rangeEntity,const LocalMatrix & localMat,const Scalar & s)620 void addScaledLocalMatrix ( const DomainEntityType &domainEntity, const RangeEntityType &rangeEntity, const LocalMatrix &localMat, const Scalar &s ) 621 { 622 assert( status_==statAssembled || status_==statAdd ); 623 setStatus( statAdd ); 624 625 auto operation = [ &s ] ( const PetscScalar& value ) -> PetscScalar { return s * value; }; 626 627 applyLocalMatrix( domainEntity, rangeEntity, localMat, operation, ADD_VALUES, std::integral_constant< bool, true>() ); 628 } 629 630 template< class LocalMatrix > setLocalMatrix(const DomainEntityType & domainEntity,const RangeEntityType & rangeEntity,const LocalMatrix & localMat)631 void setLocalMatrix ( const DomainEntityType &domainEntity, const RangeEntityType &rangeEntity, const LocalMatrix &localMat ) 632 { 633 assert( status_==statAssembled || status_==statInsert ); 634 setStatus( statInsert ); 635 636 auto operation = [] ( const PetscScalar& value ) -> PetscScalar { return value; }; 637 638 applyLocalMatrix( domainEntity, rangeEntity, localMat, operation, INSERT_VALUES, std::integral_constant< bool, false>() ); 639 } 640 641 template< class LocalMatrix > getLocalMatrix(const DomainEntityType & domainEntity,const RangeEntityType & rangeEntity,LocalMatrix & localMat) const642 void getLocalMatrix ( const DomainEntityType &domainEntity, const RangeEntityType &rangeEntity, LocalMatrix &localMat ) const 643 { 644 // make sure matrix is in correct state before using 645 finalizeAssembly(); 646 647 assert( status_==statAssembled || status_==statGet ); 648 setStatus( statGet ); 649 650 std::vector< PetscInt >& r = r_; 651 std::vector< PetscInt >& c = c_; 652 std::vector< PetscScalar >& v = v_; 653 654 setupIndices( rangeMappers_, rangeEntity, r ); 655 setupIndices( domainMappers_, domainEntity, c ); 656 657 v.resize( r.size() * c.size() ); 658 ::Dune::Petsc::MatGetValues( petscMatrix_, r.size(), r.data(), c.size(), c.data(), v.data() ); 659 660 for( std::size_t i =0 ; i< r.size(); ++i ) 661 for( std::size_t j =0; j< c.size(); ++j ) 662 localMat.set( i, j, v[ i * c.size() +j ] ); 663 664 setStatus( statAssembled ); 665 } 666 scaleLocalMatrix(const DomainEntityType & domainEntity,const RangeEntityType & rangeEntity,const RangeFieldType & s)667 void scaleLocalMatrix ( const DomainEntityType &domainEntity, const RangeEntityType &rangeEntity, const RangeFieldType &s ) 668 { 669 // make sure matrix is in correct state before using 670 finalizeAssembly(); 671 672 assert( status_==statAssembled || status_==statGet ); 673 setStatus( statGet ); 674 675 std::vector< PetscInt >& r = r_; 676 std::vector< PetscInt >& c = c_; 677 std::vector< PetscScalar >& v = v_; 678 679 setupIndices( rangeMappers_, rangeEntity, r ); 680 setupIndices( domainMappers_, domainEntity, c ); 681 682 const unsigned int rSize = r.size(); 683 const unsigned int cSize = c.size(); 684 const std::size_t size = rSize * cSize; 685 686 v.resize( size ); 687 // get values 688 ::Dune::Petsc::MatGetValues( petscMatrix_, r.size(), r.data(), c.size(), c.data(), v.data() ); 689 690 // scale values 691 for( std::size_t i=0; i<size; ++i ) 692 v[ i ] *= s; 693 694 // set values again 695 ::Dune::Petsc::MatSetValues( petscMatrix_, rSize, r.data(), cSize, c.data(), v.data(), INSERT_VALUES ); 696 setStatus( statAssembled ); 697 } 698 699 // just here for debugging view() const700 void view () const 701 { 702 ::Dune::Petsc::MatView( petscMatrix_, PETSC_VIEWER_STDOUT_WORLD ); 703 } 704 705 // print matrix just here for debugging print(std::ostream & s) const706 void print( std::ostream& s ) const 707 { 708 if( &s == &std::cout || &s == &std::cerr ) 709 { 710 view(); 711 } 712 } 713 714 // return reference to PETSc matrix object exportMatrix() const715 Mat& exportMatrix () const 716 { 717 // make sure matrix is in correct state 718 finalizeAssembly(); 719 return petscMatrix_; 720 } 721 722 private: 723 PetscLinearOperator (); 724 725 //! destructor deleting PETSc Mat object destroy()726 void destroy () 727 { 728 if( status_ != statNothing ) 729 { 730 ::Dune::Petsc::MatDestroy( &petscMatrix_ ); 731 status_ = statNothing ; 732 } 733 sequence_ = -1; 734 } 735 setStatus(const Status & newstatus) const736 void setStatus (const Status &newstatus) const 737 { 738 // in case OpenMP is used simply avoid status check 739 #ifndef _OPENMP 740 status_ = newstatus; 741 #endif 742 } 743 744 template< class DFS, class Entity > setupIndices(const PetscMappers<DFS> & mappers,const Entity & entity,std::vector<PetscInt> & indices)745 static void setupIndices ( const PetscMappers< DFS > &mappers, const Entity &entity, std::vector< PetscInt > &indices ) 746 { 747 NonBlockMapper< const typename PetscMappers< DFS >::ParallelMapperType, DFS::localBlockSize > nonBlockMapper( mappers.parallelMapper() ); 748 nonBlockMapper.map( entity, indices ); 749 } 750 751 template< class DFS, class Entity > setupIndicesBlocked(const PetscMappers<DFS> & mappers,const Entity & entity,std::vector<PetscInt> & indices)752 static void setupIndicesBlocked ( const PetscMappers< DFS > &mappers, const Entity &entity, std::vector< PetscInt > &indices ) 753 { 754 mappers.parallelMapper().map( entity, indices ); 755 } 756 757 /* 758 * data fields 759 */ 760 DomainMappersType domainMappers_; 761 RangeMappersType rangeMappers_; 762 763 int sequence_ = -1; 764 mutable Mat petscMatrix_; 765 766 mutable LocalMatrixStackType localMatrixStack_; 767 mutable Status status_; 768 769 const bool viennaCL_; 770 const bool blockedMode_; 771 772 mutable std::unique_ptr< PetscDomainFunctionType > petscArg_; 773 mutable std::unique_ptr< PetscRangeFunctionType > petscDest_; 774 775 mutable std::vector< PetscScalar > v_; 776 mutable std::vector< PetscInt > r_; 777 mutable std::vector< PetscInt > c_; 778 779 mutable std::vector< PetscInt > unitRows_; 780 }; 781 782 783 784 /* ======================================== 785 * class PetscLinearOperator::LocalMatrix 786 */ 787 template< typename DomainFunction, typename RangeFunction > 788 class PetscLinearOperator< DomainFunction, RangeFunction >::LocalMatrix 789 : public LocalMatrixDefault< typename PetscLinearOperator< DomainFunction, RangeFunction >::LocalMatrixTraits > 790 { 791 typedef LocalMatrix ThisType; 792 typedef LocalMatrixDefault< typename PetscLinearOperator< DomainFunction, RangeFunction >::LocalMatrixTraits > BaseType; 793 794 typedef PetscLinearOperator< DomainFunction, RangeFunction > PetscLinearOperatorType; 795 796 797 public: 798 typedef PetscInt DofIndexType; 799 typedef std::vector< DofIndexType > IndexVectorType; 800 typedef typename DomainFunction::DiscreteFunctionSpaceType DomainSpaceType; 801 typedef typename RangeFunction::DiscreteFunctionSpaceType RangeSpaceType; 802 typedef typename DomainSpaceType::BasisFunctionSetType DomainBasisFunctionSetType; 803 typedef typename RangeSpaceType::BasisFunctionSetType RangeBasisFunctionSetType; 804 805 enum { rangeBlockSize = RangeSpaceType::localBlockSize }; 806 enum { domainBlockSize = DomainSpaceType ::localBlockSize }; 807 808 private: 809 810 // needed for .mapEach below 811 template< typename PetscMapping > 812 struct PetscAssignFunctor 813 { PetscAssignFunctorDune::Fem::PetscLinearOperator::LocalMatrix::PetscAssignFunctor814 explicit PetscAssignFunctor ( const PetscMapping &petscMapping, IndexVectorType &indices ) 815 : petscMapping_( petscMapping ), 816 indices_( indices ) 817 {} 818 819 template< typename T > operator ()Dune::Fem::PetscLinearOperator::LocalMatrix::PetscAssignFunctor820 void operator() ( const std::size_t localIndex, T globalIndex ) { indices_[ localIndex ] = petscMapping_.globalMapping( globalIndex ); } 821 822 private: 823 const PetscMapping &petscMapping_; 824 IndexVectorType &indices_; 825 }; 826 827 public: LocalMatrix(const PetscLinearOperatorType & petscLinOp,const DomainSpaceType & domainSpace,const RangeSpaceType & rangeSpace)828 LocalMatrix ( const PetscLinearOperatorType &petscLinOp, 829 const DomainSpaceType &domainSpace, 830 const RangeSpaceType &rangeSpace ) 831 : BaseType( domainSpace, rangeSpace ), 832 petscLinearOperator_( petscLinOp ) 833 {} 834 finalize()835 void finalize() 836 { 837 } 838 init(const DomainEntityType & domainEntity,const RangeEntityType & rangeEntity)839 void init ( const DomainEntityType &domainEntity, const RangeEntityType &rangeEntity ) 840 { 841 // call initialize on base class 842 BaseType :: init( domainEntity, rangeEntity ); 843 844 //************************************************* 845 // The rows belong to the domain space 846 // it's indices are determained by the rangeSpace 847 // 848 // The columns belong to the range space 849 // it's indices are determained by the domainSpace 850 //************************************************* 851 852 setupIndices( petscLinearOperator_.rangeMappers_, rangeEntity, rowIndices_ ); 853 setupIndices( petscLinearOperator_.domainMappers_, domainEntity, colIndices_ ); 854 855 status_ = statAssembled; 856 petscLinearOperator_.setStatus(status_); 857 } 858 add(const int localRow,const int localCol,const RangeFieldType & value)859 inline void add ( const int localRow, const int localCol, const RangeFieldType &value ) 860 { 861 assert( status_==statAssembled || status_==statAdd ); 862 status_ = statAdd; 863 petscLinearOperator_.setStatus(status_); 864 ::Dune::Petsc::MatSetValue( petscMatrix(), globalRowIndex( localRow ), globalColIndex( localCol ) , value, ADD_VALUES ); 865 } 866 set(const int localRow,const int localCol,const RangeFieldType & value)867 inline void set(const int localRow, const int localCol, const RangeFieldType &value ) 868 { 869 assert( status_==statAssembled || status_==statInsert ); 870 status_ = statInsert; 871 petscLinearOperator_.setStatus(status_); 872 ::Dune::Petsc::MatSetValue( petscMatrix(), globalRowIndex( localRow ), globalColIndex( localCol ) , value, INSERT_VALUES ); 873 } 874 875 //! set matrix row to zero clearRow(const int localRow)876 void clearRow ( const int localRow ) 877 { 878 assert( status_==statAssembled || status_==statInsert ); 879 status_ = statInsert; 880 petscLinearOperator_.setStatus(status_); 881 const int col = this->columns(); 882 const int globalRowIdx = globalRowIndex( localRow ); 883 for(int localCol=0; localCol<col; ++localCol) 884 { 885 ::Dune::Petsc::MatSetValue( petscMatrix(), globalRowIdx, globalColIndex( localCol ), 0.0, INSERT_VALUES ); 886 } 887 } 888 get(const int localRow,const int localCol) const889 inline const RangeFieldType get ( const int localRow, const int localCol ) const 890 { 891 assert( status_==statAssembled || status_==statGet ); 892 status_ = statGet; 893 petscLinearOperator_.setStatus(status_); 894 RangeFieldType v[1]; 895 const int r[] = {globalRowIndex( localRow )}; 896 const int c[] = {globalColIndex( localCol )}; 897 ::Dune::Petsc::MatGetValues( petscMatrix(), 1, r, 1, c, v ); 898 return v[0]; 899 } 900 scale(const RangeFieldType & factor)901 inline void scale ( const RangeFieldType &factor ) 902 { 903 const_cast< PetscLinearOperatorType& > (petscLinearOperator_).scaleLocalMatrix( this->domainEntity(), this->rangeEntity(), factor ); 904 } 905 906 private: 907 LocalMatrix (); 908 petscMatrix()909 Mat& petscMatrix () { return petscLinearOperator_.petscMatrix_; } petscMatrix() const910 const Mat& petscMatrix () const { return petscLinearOperator_.petscMatrix_; } 911 912 public: rows() const913 int rows() const { return rowIndices_.size(); } columns() const914 int columns() const { return colIndices_.size(); } 915 916 private: globalRowIndex(const int localRow) const917 DofIndexType globalRowIndex( const int localRow ) const 918 { 919 assert( localRow < static_cast< int >( rowIndices_.size() ) ); 920 return rowIndices_[ localRow ]; 921 } 922 globalColIndex(const int localCol) const923 DofIndexType globalColIndex( const int localCol ) const 924 { 925 assert( localCol < static_cast< int >( colIndices_.size() ) ); 926 return colIndices_[ localCol ]; 927 } 928 929 /* 930 * data fields 931 */ 932 const PetscLinearOperatorType &petscLinearOperator_; 933 IndexVectorType rowIndices_; 934 IndexVectorType colIndices_; 935 mutable Status status_; 936 }; 937 938 939 } // namespace Fem 940 941 } // namespace Dune 942 943 #endif // #if HAVE_PETSC 944 945 #endif // #ifndef DUNE_FEM_PETSCLINEAROPERATOR_HH 946