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