00001 #ifndef DUNE_ALBERTA_MACRODATA_HH
00002 #define DUNE_ALBERTA_MACRODATA_HH
00003
00004 #include <dune/common/fvector.hh>
00005 #include <dune/common/fmatrix.hh>
00006
00007 #include <dune/grid/albertagrid/misc.hh>
00008 #include <dune/grid/albertagrid/albertaheader.hh>
00009 #include <dune/grid/albertagrid/referencetopo.hh>
00010
00011 #if HAVE_ALBERTA
00012
00013 namespace Dune
00014 {
00015
00016 namespace Alberta
00017 {
00018
00019 template< int dim >
00020 class MacroData
00021 {
00022 typedef MacroData< dim > This;
00023
00024 typedef ALBERTA MACRO_DATA Data;
00025
00026 static const int dimension = dim;
00027 static const int numVertices = NumSubEntities< dimension, dimension >::value;
00028 static const int numEdges = NumSubEntities< dimension, dimension-1 >::value;
00029
00030 static const int initialSize = 4096;
00031
00032 public:
00033 typedef int ElementId[ numVertices ];
00034
00035 static const int supportPeriodicity = (DUNE_ALBERTA_VERSION >= 0x201);
00036
00037 private:
00038 Data *data_;
00039 int vertexCount_;
00040 int elementCount_;
00041
00042 public:
00043 MacroData ()
00044 : data_( NULL ),
00045 vertexCount_( -1 ),
00046 elementCount_( -1 )
00047 {}
00048
00049 operator Data * () const
00050 {
00051 return data_;
00052 }
00053
00054 int vertexCount () const
00055 {
00056 return (vertexCount_ < 0 ? data_->n_total_vertices : vertexCount_);
00057 }
00058
00059 int elementCount () const
00060 {
00061 return (elementCount_ < 0 ? data_->n_macro_elements : elementCount_);
00062 }
00063
00064 ElementId &element ( int i ) const;
00065 GlobalVector &vertex ( int i ) const;
00066 int &neighbor ( int element, int i ) const;
00067 BoundaryId &boundaryId ( int element, int i ) const;
00068
00073 void create ();
00074
00083 void finalize ();
00084
00093 void markLongestEdge ();
00094
00096 void release ()
00097 {
00098 if( data_ != NULL )
00099 {
00100 ALBERTA free_macro_data( data_ );
00101 data_ = NULL;
00102 }
00103 vertexCount_ = elementCount_ = -1;
00104 }
00105
00111 int insertElement ( const ElementId &id )
00112 {
00113 assert( elementCount_ >= 0 );
00114 if( elementCount_ >= data_->n_macro_elements )
00115 resizeElements( 2*elementCount_ );
00116
00117 ElementId &e = element( elementCount_ );
00118 for( int i = 0; i < numVertices; ++i )
00119 {
00120 e[ i ] = id[ i ];
00121 boundaryId( elementCount_, i ) = InteriorBoundary;
00122 }
00123
00124 return elementCount_++;
00125 }
00126
00132 int insertVertex ( const GlobalVector &coords )
00133 {
00134 assert( vertexCount_ >= 0 );
00135 if( vertexCount_ >= data_->n_total_vertices )
00136 resizeVertices( 2*vertexCount_ );
00137 copy( coords, vertex( vertexCount_ ) );
00138 return vertexCount_++;
00139 }
00140
00146 int insertVertex ( const FieldVector< Real, dimWorld > &coords )
00147 {
00148 assert( vertexCount_ >= 0 );
00149 if( vertexCount_ >= data_->n_total_vertices )
00150 resizeVertices( 2*vertexCount_ );
00151 copy( coords, vertex( vertexCount_ ) );
00152 return vertexCount_++;
00153 }
00154
00155 void insertWallTrafo ( const GlobalMatrix &m, const GlobalVector &t );
00156 void insertWallTrafo ( const FieldMatrix< Real, dimWorld, dimWorld > &matrix,
00157 const FieldVector< Real, dimWorld > &shift );
00158
00159 void read ( const std::string &filename, bool binary = false );
00160
00161 bool write ( const std::string &filename, bool binary = false ) const
00162 {
00163 if( binary )
00164 return ALBERTA write_macro_data_xdr( data_, filename.c_str() );
00165 else
00166 return ALBERTA write_macro_data( data_, filename.c_str() );
00167 }
00168
00169 private:
00170 Real edgeLength ( const ElementId &e, int edge ) const;
00171 int longestEdge ( const ElementId &e ) const;
00172
00173 template< class Vector >
00174 void copy ( const Vector &x, GlobalVector &y )
00175 {
00176 for( int i = 0; i < dimWorld; ++i )
00177 y[ i ] = x[ i ];
00178 }
00179
00180 #if DUNE_ALBERTA_VERSION >= 0x200
00181 template< class Type >
00182 void rotate ( Type *array, int i, int shift );
00183 #else
00184 template< class Type >
00185 void rotate ( Type (*array)[ numVertices ], int i, int shift );
00186 #endif
00187
00188 void resizeElements ( const int newSize );
00189
00190 void resizeVertices ( const int newSize )
00191 {
00192 const int oldSize = data_->n_total_vertices;
00193 data_->n_total_vertices = newSize;
00194 data_->coords = memReAlloc< GlobalVector >( data_->coords, oldSize, newSize );
00195 assert( (data_->coords != NULL) || (newSize == 0) );
00196 }
00197 };
00198
00199
00200 #if DUNE_ALBERTA_VERSION >= 0x200
00201 template< int dim >
00202 inline typename MacroData< dim >::ElementId &
00203 MacroData< dim >::element ( int i ) const
00204 {
00205 assert( (i >= 0) && (i < data_->n_macro_elements) );
00206 const int offset = i * numVertices;
00207 return *reinterpret_cast< ElementId * >( data_->mel_vertices + offset );
00208 }
00209 #endif // #if DUNE_ALBERTA_VERSION >= 0x200
00210
00211 #if DUNE_ALBERTA_VERSION < 0x200
00212 template< int dim >
00213 inline typename MacroData< dim >::ElementId &
00214 MacroData< dim >::element ( int i ) const
00215 {
00216 assert( (i >= 0) && (i < data_->n_macro_elements) );
00217 return data_->mel_vertices[ i ];
00218 }
00219 #endif // #if DUNE_ALBERTA_VERSION < 0x200
00220
00221
00222 template< int dim >
00223 inline GlobalVector &MacroData< dim >::vertex ( int i ) const
00224 {
00225 assert( (i >= 0) && (i < data_->n_total_vertices) );
00226 return data_->coords[ i ];
00227 }
00228
00229
00230 #if DUNE_ALBERTA_VERSION >= 0x200
00231 template< int dim >
00232 inline int &MacroData< dim >::neighbor ( int element, int i ) const
00233 {
00234 assert( (element >= 0) && (element < data_->n_macro_elements) );
00235 assert( (i >= 0) && (i < numVertices) );
00236 return data_->neigh[ element*numVertices + i ];
00237 }
00238 #endif // #if DUNE_ALBERTA_VERSION >= 0x200
00239
00240 #if DUNE_ALBERTA_VERSION < 0x200
00241 template< int dim >
00242 inline int &MacroData< dim >::neighbor ( int element, int i ) const
00243 {
00244 assert( (element >= 0) && (element < data_->n_macro_elements) );
00245 assert( (i >= 0) && (i < numVertices) );
00246 return data_->neigh[ element ][ i ];
00247 }
00248 #endif // #if DUNE_ALBERTA_VERSION < 0x200
00249
00250
00251 #if DUNE_ALBERTA_VERSION >= 0x200
00252 template< int dim >
00253 inline BoundaryId &MacroData< dim >::boundaryId ( int element, int i ) const
00254 {
00255 assert( (element >= 0) && (element < data_->n_macro_elements) );
00256 assert( (i >= 0) && (i < numVertices) );
00257 return data_->boundary[ element*numVertices + i ];
00258 }
00259 #endif // #if DUNE_ALBERTA_VERSION >= 0x200
00260
00261 #if DUNE_ALBERTA_VERSION < 0x200
00262 template< int dim >
00263 inline BoundaryId &MacroData< dim >::boundaryId ( int element, int i ) const
00264 {
00265 assert( (element >= 0) && (element < data_->n_macro_elements) );
00266 assert( (i >= 0) && (i < numVertices) );
00267 return data_->boundary[ element ][ i ];
00268 }
00269 #endif // #if DUNE_ALBERTA_VERSION < 0x200
00270
00271
00272 #if DUNE_ALBERTA_VERSION >= 0x201
00273 template< int dim >
00274 inline void MacroData< dim >::create ()
00275 {
00276 release();
00277 data_ = ALBERTA alloc_macro_data( dim, initialSize, initialSize );
00278 data_->boundary = memAlloc< BoundaryId >( initialSize*numVertices );
00279 vertexCount_ = elementCount_ = 0;
00280 elementCount_ = 0;
00281 }
00282 #endif // #if DUNE_ALBERTA_VERSION >= 0x201
00283
00284 #if DUNE_ALBERTA_VERSION == 0x200
00285 template< int dim >
00286 inline void MacroData< dim >::create ()
00287 {
00288 release();
00289 data_ = ALBERTA alloc_macro_data( dim, initialSize, initialSize, 0 );
00290 data_->boundary = memAlloc< BoundaryId >( initialSize*numVertices );
00291 vertexCount_ = elementCount_ = 0;
00292 elementCount_ = 0;
00293 }
00294 #endif // #if DUNE_ALBERTA_VERSION == 0x200
00295
00296 #if DUNE_ALBERTA_VERSION < 0x200
00297 template< int dim >
00298 inline void MacroData< dim >::create ()
00299 {
00300 dune_static_assert( dimension == dimGrid,
00301 "Wrong grid dimension used for ALBERTA 1.2." );
00302 release();
00303 data_ = ALBERTA alloc_macro_data( initialSize, initialSize, 0 );
00304 data_->boundary = memAlloc< BoundaryId[ numVertices ] >( initialSize );
00305 vertexCount_ = elementCount_ = 0;
00306 elementCount_ = 0;
00307 }
00308 #endif // #if DUNE_ALBERTA_VERSION < 0x200
00309
00310
00311 #if DUNE_ALBERTA_VERSION >= 0x200
00312 template< int dim >
00313 inline void MacroData< dim >::finalize ()
00314 {
00315 if( (vertexCount_ >= 0) && (elementCount_ >= 0) )
00316 {
00317 resizeVertices( vertexCount_ );
00318 resizeElements( elementCount_ );
00319 ALBERTA compute_neigh_fast( data_ );
00320
00321
00322 for( int element = 0; element < elementCount_; ++element )
00323 {
00324 for( int i = 0; i < numVertices; ++i )
00325 {
00326 BoundaryId &id = boundaryId( element, i );
00327 if( neighbor( element, i ) >= 0 )
00328 {
00329 assert( id == InteriorBoundary );
00330 id = InteriorBoundary;
00331 }
00332 else
00333 id = (id == InteriorBoundary ? DirichletBoundary : id);
00334 }
00335 }
00336
00337 vertexCount_ = elementCount_ = -1;
00338 }
00339 assert( (vertexCount_ < 0) && (elementCount_ < 0) );
00340 }
00341 #endif // #if DUNE_ALBERTA_VERSION >= 0x200
00342
00343 #if DUNE_ALBERTA_VERSION < 0x200
00344 template< int dim >
00345 inline void MacroData< dim >::finalize ()
00346 {
00347 if( (vertexCount_ >= 0) && (elementCount_ >= 0) )
00348 {
00349 resizeVertices( vertexCount_ );
00350 resizeElements( elementCount_ );
00351
00352 std::cerr << "Warning: GridFactory for ALBERTA 1.2 does not support "
00353 << "boundary ids, yet." << std::endl << std::endl;
00354 memFree( data_->boundary, elementCount_ );
00355 data_->boundary = NULL;
00356
00357 vertexCount_ = elementCount_ = -1;
00358 }
00359 assert( (vertexCount_ < 0) && (elementCount_ < 0) );
00360 }
00361 #endif // #if DUNE_ALBERTA_VERSION < 0x200
00362
00363
00364 template< int dim >
00365 inline void MacroData< dim >::markLongestEdge ()
00366 {
00367 assert( data_ != NULL );
00368 if( dimension == 1 )
00369 return;
00370
00371 const int count = elementCount();
00372 for( int i = 0; i < count; ++i )
00373 {
00374 const int refEdge = RefinementEdge< dimension >::value;
00375 const int edge = longestEdge( element( i ) );
00376 if( edge == refEdge )
00377 continue;
00378
00379
00380 const int shift = edge + (numVertices - refEdge);
00381
00382
00383 rotate( data_->mel_vertices, i, shift );
00384
00385
00386 #if DUNE_ALBERTA_VERSION >= 0x201
00387 if( data_->opp_vertex != NULL )
00388 {
00389 assert( data_->neigh != NULL );
00390 const int shiftBack = numVertices - (shift % numVertices);
00391 for( int j = 0; j < numVertices; ++j )
00392 {
00393 const int nb = data_->neigh[ i*numVertices + j ];
00394 if( nb < 0 )
00395 continue;
00396 const int ov = data_->opp_vertex[ i*numVertices + j ];
00397 assert( data_->neigh[ nb*numVertices + ov ] == i );
00398 assert( data_->opp_vertex[ nb*numVertices + ov ] == j );
00399 data_->opp_vertex[ nb*numVertices + ov ] = (j+shiftBack) % numVertices;
00400 }
00401 rotate( data_->opp_vertex, i, shift );
00402 }
00403 #endif
00404
00405
00406 rotate( data_->neigh, i, shift );
00407 rotate( data_->boundary, i, shift );
00408 }
00409 }
00410
00411
00412 #if DUNE_ALBERTA_VERSION >= 0x201
00413 template< int dim >
00414 inline void MacroData< dim >
00415 ::insertWallTrafo ( const GlobalMatrix &matrix, const GlobalVector &shift )
00416 {
00417 int &count = data_->n_wall_trafos;
00418 AffineTransformation *&array = data_->wall_trafos;
00419
00420
00421 array = memReAlloc< AffineTransformation >( array, count, count+1 );
00422 assert( data_->wall_trafos != NULL );
00423
00424
00425 for( int i = 0; i < dimWorld; ++i )
00426 copy( matrix[ i ], array[ count ].M[ i ] );
00427 copy( shift, array[ count ].t );
00428 ++count;
00429 }
00430
00431 template< int dim >
00432 inline void MacroData< dim >
00433 ::insertWallTrafo ( const FieldMatrix< Real, dimWorld, dimWorld > &matrix,
00434 const FieldVector< Real, dimWorld > &shift )
00435 {
00436 int &count = data_->n_wall_trafos;
00437 AffineTransformation *&array = data_->wall_trafos;
00438
00439
00440 array = memReAlloc< AffineTransformation >( array, count, count+1 );
00441 assert( data_->wall_trafos != NULL );
00442
00443
00444 for( int i = 0; i < dimWorld; ++i )
00445 copy( matrix[ i ], array[ count ].M[ i ] );
00446 copy( shift, array[ count ].t );
00447 ++count;
00448 }
00449 #endif // #if DUNE_ALBERTA_VERSION >= 0x201
00450
00451 #if DUNE_ALBERTA_VERSION <= 0x200
00452 template< int dim >
00453 inline void MacroData< dim >
00454 ::insertWallTrafo ( const GlobalMatrix &m, const GlobalVector &t )
00455 {
00456 DUNE_THROW( AlbertaError,
00457 "Periodic grids are only supported in ALBERTA 2.1 or higher." );
00458 }
00459
00460 template< int dim >
00461 inline void MacroData< dim >
00462 ::insertWallTrafo ( const FieldMatrix< Real, dimWorld, dimWorld > &matrix,
00463 const FieldVector< Real, dimWorld > &shift )
00464 {
00465 DUNE_THROW( AlbertaError,
00466 "Periodic grids are only supported in ALBERTA 2.1 or higher." );
00467 }
00468 #endif // #if DUNE_ALBERTA_VERSION <= 0x200
00469
00470
00471 #if DUNE_ALBERTA_VERSION >= 0x200
00472 template< int dim >
00473 inline void MacroData< dim >::read ( const std::string &filename, bool binary )
00474 {
00475 release();
00476 if( binary )
00477 data_ = ALBERTA read_macro_xdr( filename.c_str() );
00478 else
00479 data_ = ALBERTA read_macro( filename.c_str() );
00480 }
00481 #endif // #if DUNE_ALBERTA_VERSION >= 0x200
00482
00483 #if DUNE_ALBERTA_VERSION < 0x200
00484 template< int dim >
00485 inline void MacroData< dim >::read ( const std::string &filename, bool binary )
00486 {
00487 release();
00488 DUNE_THROW( NotImplemented, "In ALBERTA 1.2, macro data cannot be read." );
00489 }
00490 #endif // #if DUNE_ALBERTA_VERSION < 0x200
00491
00492
00493 template< int dim >
00494 inline Real MacroData< dim >::edgeLength ( const ElementId &e, int edge ) const
00495 {
00496 const int i = ALBERTA AlbertHelp::MapVertices< 1, dim >::mapVertices( edge, 0 );
00497 assert( (vertexCount_ < 0) || (e[ i ] < vertexCount_) );
00498 const GlobalVector &x = vertex( e[ i ] );
00499
00500 const int j = ALBERTA AlbertHelp::MapVertices< 1, dim >::mapVertices( edge, 1 );
00501 assert( (vertexCount_ < 0) || (e[ j ] < vertexCount_) );
00502 const GlobalVector &y = vertex( e[ j ] );
00503
00504 Real sum = (y[ 0 ] - x[ 0 ]) * (y[ 0 ] - x[ 0 ]);
00505 for( int i = 1; i < dimWorld; ++i )
00506 sum += (y[ i ] - x[ i ]) * (y[ i ] - x[ i ]);
00507 return sqrt( sum );
00508 }
00509
00510
00511 template< int dim >
00512 inline int MacroData< dim >::longestEdge ( const ElementId &e ) const
00513 {
00514 int maxEdge = 0;
00515 Real maxLength = edgeLength( e, 0 );
00516 for( int i = 1; i < numEdges; ++i )
00517 {
00518 const Real length = edgeLength( e, i );
00519 if( length <= maxLength )
00520 continue;
00521 maxEdge = i;
00522 maxLength = length;
00523 }
00524 return maxEdge;
00525 }
00526
00527
00528 #if DUNE_ALBERTA_VERSION >= 0x200
00529 template< int dim >
00530 template< class Type >
00531 inline void MacroData< dim >::rotate ( Type *array, int i, int shift )
00532 {
00533 assert( (i >= 0) && (i < data_->n_macro_elements) );
00534 if( array == NULL )
00535 return;
00536
00537 const int offset = i*numVertices;
00538 Type old[ numVertices ];
00539 for( int j = 0; j < numVertices; ++j )
00540 old[ j ] = array[ offset + j ];
00541 for( int j = 0; j < numVertices; ++j )
00542 array[ offset + j ] = old[ (j+shift) % numVertices ];
00543 }
00544 #endif // #if DUNE_ALBERTA_VERSION >= 0x200
00545
00546 #if DUNE_ALBERTA_VERSION < 0x200
00547 template< int dim >
00548 template< class Type >
00549 inline void MacroData< dim >::rotate ( Type (*array)[ numVertices ], int i, int shift )
00550 {
00551 assert( (i >= 0) && (i < data_->n_macro_elements) );
00552 if( array == NULL )
00553 return;
00554
00555 Type old[ numVertices ];
00556 for( int j = 0; j < numVertices; ++j )
00557 old[ j ] = array[ i ][ j ];
00558 for( int j = 0; j < numVertices; ++j )
00559 array[ i ][ j ] = old[ (j+shift) % numVertices ];
00560 }
00561 #endif // #if DUNE_ALBERTA_VERSION < 0x200
00562
00563
00564 #if DUNE_ALBERTA_VERSION >= 0x200
00565 template< int dim >
00566 inline void MacroData< dim >::resizeElements ( const int newSize )
00567 {
00568 const int oldSize = data_->n_macro_elements;
00569 data_->n_macro_elements = newSize;
00570 data_->mel_vertices = memReAlloc( data_->mel_vertices, oldSize*numVertices, newSize*numVertices );
00571 data_->boundary = memReAlloc( data_->boundary, oldSize*numVertices, newSize*numVertices );
00572 assert( (newSize == 0) || (data_->mel_vertices != NULL) );
00573 }
00574 #endif // #if DUNE_ALBERTA_VERSION >= 0x200
00575
00576 #if DUNE_ALBERTA_VERSION < 0x200
00577 template< int dim >
00578 inline void MacroData< dim >::resizeElements ( const int newSize )
00579 {
00580 const int oldSize = data_->n_macro_elements;
00581 data_->n_macro_elements = newSize;
00582 data_->mel_vertices = memReAlloc( data_->mel_vertices, oldSize, newSize );
00583 assert( data_->mel_vertices != NULL );
00584 }
00585 #endif // #if DUNE_ALBERTA_VERSION < 0x200
00586
00587 }
00588
00589 }
00590
00591 #endif // #if HAVE_ALBERTA
00592
00593 #endif