DUNE-FEM (unstable)

petscvector.hh
1#ifndef DUNE_FEM_PETSCVECTOR_HH
2#define DUNE_FEM_PETSCVECTOR_HH
3
4#include <cassert>
5#include <cstddef>
6
7#include <algorithm>
8#include <string>
9
11
12#include <dune/fem/storage/dynamicarray.hh>
13#include <dune/fem/storage/envelope.hh>
14
15#include <dune/fem/common/hybrid.hh>
16
17#include <dune/fem/function/blockvectors/defaultblockvectors.hh>
18
19#if HAVE_PETSC
20
21#include <dune/fem/misc/petsc/petsccommon.hh>
22#include <dune/fem/misc/petsc/petscdofblock.hh>
23#include <dune/fem/space/common/commoperations.hh>
24#include <dune/fem/space/common/dofmanager.hh>
25#include <dune/fem/space/mapper/petsc.hh>
26
27namespace Dune
28{
29
30 namespace Fem
31 {
32
33 // Internal Forward Declarations
34 // -----------------------------
35
36 template< class DFSpace >
37 class PetscVector;
38
39
40 // External Forward Declarations
41 // -----------------------------
42
43 template< class >
44 class PetscDofBlock;
45
46 template< class >
47 class PetscDofProxy;
48
49
50
51 // PetscManagedDofStorage
52 // ----------------------
53
55 template < class DiscreteFunctionSpace, class Mapper >
56 class PetscManagedDofStorage
57 : public ManagedDofStorageImplementation< typename DiscreteFunctionSpace::GridPartType::GridType, Mapper, PetscVector< DiscreteFunctionSpace > >
58 {
59 typedef typename DiscreteFunctionSpace::GridPartType::GridType GridType;
60 typedef Mapper MapperType ;
61 typedef PetscVector< DiscreteFunctionSpace > DofArrayType ;
62 typedef ManagedDofStorageImplementation< GridType, MapperType, DofArrayType > BaseType;
63
64 public:
65 typedef typename BaseType :: SizeType SizeType;
66
68 PetscManagedDofStorage( const DiscreteFunctionSpace& space,
69 const MapperType& mapper )
70 : BaseType( space.grid(), mapper, myArray_ ),
71 myArray_( space )
72 {
73 }
74
75 void resize( const bool ) override
76 { // do nothing here, only in compress
77 }
78
79 void reserve( const SizeType ) override
80 {
81 // do nothing here, only in compress
82 }
83
84 void dofCompress( const bool clearResizedArrays ) override
85 {
86 myArray_.resize();
87 if( clearResizedArrays )
88 {
89 myArray_.clear();
90 }
91 }
92
94 void enableDofCompression() override
95 {
96 std::cerr << "WARNING: PetscVector cannot handle dof compression!" << std::endl;
97 }
98 protected:
99 DofArrayType myArray_;
100 };
101
102
103 // PetscVector
104 // -----------
105
106 /*
107 * This encapsules a PETSc Vec with ghosts.
108 * Some conceptual explanations:
109 * The PETSc vector, as modelled by this class, consists of three parts:
110 * 1) the whole PETSc vector, which might be distributed across several MPI processes.
111 * We call this the _global vector_
112 * 2) Each process holds a portion of this global vector, we call this part the
113 * _process vector_.
114 * 3) And there is a representation of the process vector, which also has 'ghost dof blocks'.
115 * We call this represenation the _ghosted vector_.
116 */
117 template< class DFSpace >
118 class PetscVector
119 {
120 typedef PetscVector< DFSpace > ThisType;
121 friend class PetscDofBlock< ThisType >;
122 friend class PetscDofBlock< const ThisType >;
123 friend class PetscDofProxy< ThisType >;
124 friend class PetscDofProxy< const ThisType >;
125 public:
126 typedef PetscScalar value_type ;
127 typedef Vec DofContainerType;
128
129 static constexpr int blockSize = DFSpace::localBlockSize;
130 typedef Hybrid::IndexRange< int, blockSize > BlockIndices;
131
132 typedef PetscDofBlock< ThisType > DofBlockType;
133 typedef PetscDofBlock< const ThisType > ConstDofBlockType;
134 typedef typename DofBlockType::DofIterator DofIteratorType;
135 typedef typename ConstDofBlockType::DofIterator ConstDofIteratorType;
136 typedef Envelope< DofBlockType > DofBlockPtrType;
137 typedef Envelope< ConstDofBlockType > ConstDofBlockPtrType;
138 typedef typename DofBlockType::IndexType IndexType;
139
140 typedef DofIteratorType IteratorType;
141 typedef ConstDofIteratorType ConstIteratorType;
142 typedef typename DFSpace::RangeFieldType FieldType;
143 typedef int SizeType;
144
145 typedef PetscMappers< DFSpace > MappersType;
146
147 struct FakeDF
148 {
149 typedef DFSpace DiscreteFunctionSpaceType;
150 };
151
152 // need to pass something that contains a typedef DiscreteFunctionSpaceType
153 typedef typename DFSpace::template CommDataHandle< FakeDF >::OperationType DefaultCommunicationOperationType;
154
155 // note that Vec is a pointer type so no deep copy is made
156 PetscVector ( const DFSpace& space, Vec vec )
157 : mappers_( space ), vec_(vec), owner_(false)
158 {
159 static_assert( DefaultCommunicationOperationType::value == DFCommunicationOperation::copy ||
160 DefaultCommunicationOperationType::value == DFCommunicationOperation::add,
161 "only copy/add are available communication operations for petsc");
162 ::Dune::Petsc::VecGhostGetLocalForm( vec_, &ghostedVec_ );
163 }
164 PetscVector ( const DFSpace& space )
165 : mappers_( space ), owner_(true)
166 {
167 static_assert( DefaultCommunicationOperationType::value == DFCommunicationOperation::copy ||
168 DefaultCommunicationOperationType::value == DFCommunicationOperation::add,
169 "only copy/add are available communication operations for petsc");
170 // init vector
171 init();
172 }
173
174 // TODO: think about sequence overflows...
175 PetscVector ( const ThisType &other )
176 : mappers_( other.mappers_ ), owner_(true)
177 {
178 // init vector
179 init();
180
181 // copy dofs
182 assign( other );
183 }
184
185 ~PetscVector ()
186 {
187 if (owner_)
188 // destroy vectors
189 removeObj();
190 }
191
192 std::size_t size () const { return mappers().ghostMapper().size(); }
193
194 void resize( const std::size_t newsize = 0 )
195 {
196 // TODO: keep old data stored in current vector
197 // remove old vectors
198 removeObj();
199
200 // initialize new
201 init();
202
203 hasBeenModified ();
204 }
205
206 void reserve( const std::size_t capacity )
207 {
208 resize( capacity );
209 }
210
211 void hasBeenModified () { ++sequence_; }
212
213 void communicate ()
214 {
215 communicateFlag_ = true;
216 }
217
218 // accessors for the underlying PETSc vectors
219 Vec* getVector ()
220 {
221 communicateIfNecessary();
222 return &vec_;
223 }
224
225 const Vec* getVector () const
226 {
227 communicateIfNecessary();
228 return &vec_;
229 }
230
231 // accessors for the underlying PETSc vectors
232 Vec& array ()
233 {
234 communicateIfNecessary();
235 return vec_;
236 }
237
238 const Vec& array () const
239 {
240 communicateIfNecessary();
241 return vec_;
242 }
243
244 Vec* getGhostedVector ()
245 {
246 communicateIfNecessary();
247 return &ghostedVec_;
248 }
249
250 const Vec* getGhostedVector () const
251 {
252 communicateIfNecessary();
253 return &ghostedVec_;
254 }
255
256 void beginAssemble()
257 {
258 ::Dune::Petsc::VecAssemblyBegin( vec_ );
259 }
260
261 void endAssemble( const bool communicate )
262 {
263 ::Dune::Petsc::VecAssemblyEnd( vec_ );
264 if( communicate )
265 communicateIfNecessary();
266 }
267
268 // force communication _now_
269 template <class Operation>
270 void communicateNow (const Operation& operation) const
271 {
272 communicateFlag_ = true;
273 ++sequence_;
274 communicateIfNecessary( operation );
275 }
276
277 DofBlockType operator[] ( const IndexType index ) { return DofBlockType( *this,index ); }
278 ConstDofBlockType operator[] ( const IndexType index ) const { return ConstDofBlockType( *this,index ); }
279
280 ConstDofBlockPtrType block ( IndexType index ) const { return blockPtr( index ); }
281 DofBlockPtrType block ( IndexType index ) { return blockPtr( index ); }
282
283 DofBlockPtrType blockPtr ( IndexType index )
284 {
285 assert( static_cast< std::size_t >( index ) < mappers().size() );
286 return DofBlockPtrType( typename DofBlockType::UnaryConstructorParamType( *this, index ) );
287 }
288
289 ConstDofBlockPtrType blockPtr ( IndexType index ) const
290 {
291 assert( static_cast< std::size_t >( index ) < mappers().size() );
292 return ConstDofBlockPtrType( typename ConstDofBlockType::UnaryConstructorParamType( *this, index ) );
293 }
294
295 DofIteratorType begin () { return DofIteratorType( *this, 0, 0 ); }
296 ConstDofIteratorType begin () const { return ConstDofIteratorType( *this, 0, 0 ); }
297 DofIteratorType end () { return DofIteratorType( *this, mappers().size() ); }
298 ConstDofIteratorType end () const { return ConstDofIteratorType( *this, mappers().size() ); }
299
300 DofIteratorType beforeEnd ()
301 {
302 DUNE_THROW(NotImplemented,"PetscVector::beforeEnd is not implemented yet");
303 return end();
304 }
305
306 ConstDofIteratorType beforeEnd () const
307 {
308 DUNE_THROW(NotImplemented,"PetscVector::beforeEnd is not implemented yet");
309 return end();
310 }
311
312 DofIteratorType beforeBegin ()
313 {
314 DUNE_THROW(NotImplemented,"PetscVector::beforeBegin is not implemented yet");
315 return end();
316 }
317 ConstDofIteratorType beforeBegin () const
318 {
319 DUNE_THROW(NotImplemented,"PetscVector::beforeBegin is not implemented yet");
320 return end();
321 }
322
323 DofIteratorType dbegin () { return begin(); }
324 ConstDofIteratorType dbegin () const { return begin(); }
325 DofIteratorType dend () { return end(); }
326 ConstDofIteratorType dend () const { return end(); }
327
328 void clear ()
329 {
330 ::Dune::Petsc::VecSet( *getVector(), 0. );
331 updateGhostRegions();
332 vectorIsUpToDateNow();
333 }
334
335 PetscScalar operator* ( const ThisType &other ) const
336 {
337 PetscScalar ret;
338 ::Dune::Petsc::VecDot( *getVector(), *other.getVector(), &ret );
339 return ret;
340 }
341
342 const ThisType& operator+= ( const ThisType &other )
343 {
344 ::Dune::Petsc::VecAXPY( *getVector(), 1., *other.getVector() );
345 updateGhostRegions();
346 vectorIsUpToDateNow();
347 return *this;
348 }
349
350 const ThisType& operator-= ( const ThisType &other )
351 {
352 ::Dune::Petsc::VecAXPY( *getVector(), -1., *other.getVector() );
353 updateGhostRegions();
354 vectorIsUpToDateNow();
355 return *this;
356 }
357
358 const ThisType& operator*= ( PetscScalar scalar )
359 {
360 ::Dune::Petsc::VecScale( *getVector(), scalar );
361 updateGhostRegions();
362 vectorIsUpToDateNow();
363 return *this;
364 }
365
366 const ThisType& operator/= ( PetscScalar scalar )
367 {
368 assert( scalar != 0 );
369 return this->operator*=( 1./scalar );
370 }
371
372 void axpy ( const PetscScalar &scalar, const ThisType &other )
373 {
374 ::Dune::Petsc::VecAXPY( *getVector(), scalar, *other.getVector() );
375 hasBeenModified();
376 }
377
378 void clearGhost( )
379 {
380 PetscScalar *array;
381 // create local memory
382 VecGetArray( ghostedVec_,&array );
383 std::fill_n( array + mappers().ghostMapper().interiorSize() * blockSize, mappers().ghostMapper().ghostSize() * blockSize, PetscScalar( 0 ) );
384 // destroy memory
385 VecRestoreArray( ghostedVec_, &array );
386 }
387
388 // debugging; comes in handy to call these 2 methods in gdb
389 // doit is only here to prevent the compiler from optimizing these calls away...
390 void printGlobal ( bool doit )
391 {
392 if( !doit )
393 return;
394 VecView( vec_, PETSC_VIEWER_STDOUT_WORLD );
395 }
396
397 void printGhost ( bool doit)
398 {
399 if( !doit )
400 return;
401
402 PetscScalar *array;
403 VecGetArray( ghostedVec_,&array );
404 for( std::size_t i = 0; i < size(); i++ )
405 {
406 PetscSynchronizedPrintf(PETSC_COMM_WORLD,"%D %G\n",i,PetscRealPart(array[i]));
407 }
408 VecRestoreArray( ghostedVec_, &array );
409#if PETSC_VERSION_MAJOR <= 3 && PETSC_VERSION_MINOR < 5
410 PetscSynchronizedFlush( PETSC_COMM_WORLD );
411#else
412 PetscSynchronizedFlush( PETSC_COMM_WORLD, PETSC_STDOUT );
413#endif
414 }
415
416 // assign from other given PetscVector
417 void assign( const ThisType& other )
418 {
419 // we want the 'other' to do all its communication right now before
420 // we start copying values from it
421 other.communicateIfNecessary();
422
423 // copy vector entries
424 ::Dune::Petsc::VecCopy( other.vec_, vec_ );
425
426 // update ghost values
427 updateGhostRegions();
428 }
429
430 // assign from other given SimpleBlockVector with same block size
431 template <class Container>
432 void assignVector( const SimpleBlockVector< Container, blockSize >& other )
433 {
434 Vec& vec = *getGhostedVector();
435
436 // use mapping from the ghost mapper which removes duplicate dofs
437 const auto& mapping = mappers_.ghostMapper().mapping();
438 const size_t blocks = mapping.size();
439 assert( blocks == other.size() );
440 for( size_t b=0, bs = 0; b<blocks; ++b, bs += blockSize)
441 {
442 PetscInt block = mapping[ b ];
443 const PetscScalar* values = static_cast< const PetscScalar* > (other.data()+bs);
444 ::Dune::Petsc::VecSetValuesBlocked( vec, 1, &block, values, INSERT_VALUES );
445 }
446 ::Dune::Petsc::VecGhostGetLocalForm( vec_, &ghostedVec_ );
447
448 updateGhostRegions();
449 }
450
451 // assign from other given ISTLBlockVector with same block size
452 template <class DofBlock>
453 void assignVector( const ISTLBlockVector< DofBlock >& other )
454 {
455 assert( DofBlock :: dimension == blockSize );
456 Vec& vec = *getGhostedVector();
457
458 // use mapping from the ghost mapper which removes duplicate dofs
459 const auto& mapping = mappers_.ghostMapper().mapping();
460 const size_t blocks = mapping.size();
461 assert( blocks == other.size() );
462 for( size_t b=0; b<blocks; ++b )
463 {
464 PetscInt block = mapping[ b ];
465 const PetscScalar* values = static_cast< const PetscScalar* > (&(other[ b ][ 0 ])) ;
466 ::Dune::Petsc::VecSetValuesBlocked( vec, 1, &block, values, INSERT_VALUES );
467 }
468 ::Dune::Petsc::VecGhostGetLocalForm( vec_, &ghostedVec_ );
469
470 updateGhostRegions();
471 }
472
473 // assign from other given SimpleBlockVector with same block size
474 template <class Container>
475 void copyTo( SimpleBlockVector< Container, blockSize >& other ) const
476 {
477 typedef typename Container::FieldType FieldType;
478 const PetscScalar *array = nullptr;
479 VecGetArrayRead( ghostedVec_, &array );
480
481 // use mapping from the ghost mapper which removes duplicate dofs
482 const auto& mapping = mappers_.ghostMapper().mapping();
483 const size_t blocks = mapping.size();
484 assert( blocks == other.size() );
485 for( size_t b=0; b<blocks; ++b )
486 {
487 const PetscScalar* petscBlock = array + (blockSize * mapping[ b ]);
488 FieldType* otherBlock = other.data() + (b * blockSize);
489 for( int i=0; i<blockSize; ++i )
490 {
491 otherBlock[ i ] = petscBlock[ i ];
492 }
493 }
494 VecRestoreArrayRead( ghostedVec_, &array );
495 }
496
497 // assign from other given ISTLBlockVector with same block size
498 template <class DofBlock>
499 void copyTo ( ISTLBlockVector< DofBlock >& other ) const
500 {
501 assert( DofBlock :: dimension == blockSize );
502 const PetscScalar *array = nullptr;
503 VecGetArrayRead( ghostedVec_, &array );
504
505 // use mapping from the ghost mapper which removes duplicate dofs
506 const auto& mapping = mappers_.ghostMapper().mapping();
507 const size_t blocks = mapping.size();
508 assert( blocks == other.size() );
509 for( size_t b=0; b<blocks; ++b )
510 {
511 const PetscScalar* petscBlock = array + (blockSize * mapping[ b ]);
512 DofBlock& otherBlock = other[ b ];
513 for( int i=0; i<blockSize; ++i )
514 {
515 otherBlock[ i ] = petscBlock[ i ];
516 }
517 }
518 VecRestoreArrayRead( ghostedVec_, &array );
519 }
520
521 PetscVector& operator= ( const ThisType& other )
522 {
523 assign( other );
524 return *this;
525 }
526
527 const MappersType &mappers() const { return mappers_; }
528
529 std::size_t usedMemorySize() const
530 {
531 return size() * sizeof(value_type);
532 }
533
534 static void setMemoryFactor(const double memFactor)
535 {
536 // do nothing here
537 }
538
540 void memMoveBackward( const int length, const int oldStartIdx, const int newStartIdx)
541 {
542 DUNE_THROW(NotImplemented,"memMoveBackward is to be implemented");
543 }
544
546 void memMoveForward(const int length, const int oldStartIdx, const int newStartIdx)
547 {
548 DUNE_THROW(NotImplemented,"memMoveForward is to be implemented");
549 }
550
551 void copyContent( const int newIndex, const int oldIndex )
552 {
553 DUNE_THROW(NotImplemented,"copyContent is to be implemented");
554 }
555
556 protected:
557 // setup vector according to mapping sizes
558 void init()
559 {
560 mappers_.update();
561
562 const PetscInt localBlocks = mappers_.ghostMapper().interiorSize();
563 const PetscInt numGhostBlocks = mappers_.ghostMapper().ghostSize();
564
565 const PetscInt localSize = localBlocks * blockSize;
566 const PetscInt globalSize = mappers_.parallelMapper().size() * blockSize;
567
568 // finally, create the PETSc Vecs
569 const PetscInt *ghostBlocks = mappers_.parallelMapper().mapping().data() + localBlocks;
570 const auto& comm = mappers_.space().gridPart().comm();
571 if( blockSize == 1 )
572 ::Dune::Petsc::VecCreateGhost( comm, localSize, globalSize, numGhostBlocks, ghostBlocks, &vec_ );
573 else
574 ::Dune::Petsc::VecCreateGhostBlock( comm, blockSize, localSize, globalSize, numGhostBlocks, ghostBlocks, &vec_ );
575 ::Dune::Petsc::VecGhostGetLocalForm( vec_, &ghostedVec_ );
576 }
577
578 // delete vectors
579 void removeObj()
580 {
581 ::Dune::Petsc::VecGhostRestoreLocalForm( vec_, &ghostedVec_ );
582 ::Dune::Petsc::VecDestroy( &vec_ );
583 }
584
585 // communicate using the space default communication option
586 void communicateIfNecessary () const
587 {
588 DefaultCommunicationOperationType op;
589 communicateIfNecessary( op );
590 }
591
592 template <class Operation>
593 void communicateIfNecessary (const Operation& op) const
594 {
595 // communicate this process' values
596 if( communicateFlag_ && memorySequence_ < sequence_ )
597 {
598 if ( memorySequence_ < sequence_ )
599 {
600 if ( Operation::value == DFCommunicationOperation::add )
601 {
602 ::Dune::Petsc::VecGhostUpdateBegin( vec_, ADD_VALUES, SCATTER_REVERSE );
603 ::Dune::Petsc::VecGhostUpdateEnd( vec_, ADD_VALUES, SCATTER_REVERSE );
604 }
605 ::Dune::Petsc::VecGhostUpdateBegin( vec_, INSERT_VALUES, SCATTER_FORWARD );
606 ::Dune::Petsc::VecGhostUpdateEnd( vec_, INSERT_VALUES, SCATTER_FORWARD );
607
608 memorySequence_ = sequence_;
609 }
610
611 communicateFlag_ = false;
612 }
613 }
614
615 // Updates the ghost dofs, obtains them from the owning process
616 void updateGhostRegions ()
617 {
618 ::Dune::Petsc::VecGhostUpdateBegin( vec_, INSERT_VALUES, SCATTER_FORWARD );
619 ::Dune::Petsc::VecGhostUpdateEnd( vec_, INSERT_VALUES, SCATTER_FORWARD );
620 }
621
622 void vectorIsUpToDateNow () const
623 {
624 memorySequence_ = sequence_;
625 communicateFlag_ = false;
626 }
627
628 /*
629 * data fields
630 */
631 MappersType mappers_;
632 Vec vec_;
633 Vec ghostedVec_;
634
635 mutable unsigned long memorySequence_ = 0; // represents the state of the PETSc vec in memory
636 mutable unsigned long sequence_ = 0; // represents the modifications to the PETSc vec
637
638 mutable bool communicateFlag_ = false;
639 bool owner_;
640 };
641
642 } // namespace Fem
643
644} // namespace Dune
645
646#endif // #if HAVE_PETSC
647
648#endif // DUNE_FEM_PETSCVECTOR_HH
discrete function space
A few common exception classes.
#define DUNE_THROW(E, m)
Definition: exceptions.hh:218
Dune namespace.
Definition: alignedallocator.hh:13
constexpr std::integral_constant< std::size_t, sizeof...(II)> size(std::integer_sequence< T, II... >)
Return the size of the sequence.
Definition: integersequence.hh:75
void assign(T &dst, const T &src, bool mask)
masked Simd assignment (scalar version)
Definition: simd.hh:447
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 27, 22:29, 2024)