dune-grid  2.1.1
albertagrid/gridfactory.hh
Go to the documentation of this file.
00001 // -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002 // vi: set et ts=8 sw=2 sts=2:
00003 
00004 #ifndef DUNE_ALBERTA_GRIDFACTORY_HH
00005 #define DUNE_ALBERTA_GRIDFACTORY_HH
00006 
00012 #include <algorithm>
00013 #include <limits>
00014 #include <map>
00015 
00016 #include <dune/common/array.hh>
00017 
00018 #include <dune/grid/common/gridfactory.hh>
00019 #include <dune/grid/common/genericreferenceelements.hh>
00020 
00021 #include <dune/grid/utility/grapedataioformattypes.hh>
00022 
00023 #include <dune/grid/albertagrid/agrid.hh>
00024 
00025 #if HAVE_ALBERTA
00026 
00027 namespace Dune
00028 {
00029 
00047   template< int dim, int dimworld >
00048   class GridFactory< AlbertaGrid< dim, dimworld > >
00049   : public GridFactoryInterface< AlbertaGrid< dim, dimworld > >
00050   {
00051     typedef GridFactory< AlbertaGrid< dim, dimworld > > This;
00052 
00053   public:
00055     typedef AlbertaGrid< dim, dimworld > Grid;
00056 
00058     typedef typename Grid::ctype ctype;
00059 
00061     static const int dimension = Grid::dimension;
00063     static const int dimensionworld = Grid::dimensionworld;
00064 
00066     typedef FieldVector< ctype, dimensionworld > WorldVector;
00068     typedef FieldMatrix< ctype, dimensionworld, dimensionworld > WorldMatrix;
00069 
00070     typedef DuneBoundaryProjection< dimensionworld > DuneProjection;
00071     typedef Dune::shared_ptr< const DuneProjection > DuneProjectionPtr;
00072     typedef Dune::BoundarySegment< dimension, dimensionworld > BoundarySegment;
00073 
00074     template< int codim >
00075     struct Codim
00076     {
00077       typedef typename Grid::template Codim< codim >::Entity Entity;
00078     };
00079 
00080   private:
00081     typedef Dune::BoundarySegmentWrapper< dimension, dimensionworld > BoundarySegmentWrapper;
00082 
00083     static const int numVertices
00084       = Alberta::NumSubEntities< dimension, dimension >::value;
00085 
00086     typedef Alberta::MacroElement< dimension > MacroElement;
00087     typedef Alberta::ElementInfo< dimension > ElementInfo;
00088     typedef Alberta::MacroData< dimension > MacroData;
00089     typedef Alberta::NumberingMap< dimension, Alberta::Dune2AlbertaNumbering > NumberingMap;
00090     typedef Alberta::DuneBoundaryProjection< dimension > Projection;
00091 
00092     typedef array< unsigned int, dimension > FaceId;
00093     typedef std::map< FaceId, size_t > BoundaryMap;
00094 
00095     class ProjectionFactory;
00096 
00097   public:
00099     static const bool supportsBoundaryIds = true;
00101     static const bool supportPeriodicity = MacroData::supportPeriodicity;
00102 
00104     GridFactory ()
00105     : globalProjection_( (const DuneProjection *)0 )
00106     {
00107       macroData_.create();
00108     }
00109 
00110     virtual ~GridFactory ();
00111 
00116     virtual void insertVertex ( const WorldVector &pos )
00117     {
00118       macroData_.insertVertex( pos );
00119     }
00120 
00126     virtual void insertElement ( const GeometryType &type,
00127                                  const std::vector< unsigned int > &vertices )
00128     {
00129       if( (int)type.dim() != dimension )
00130         DUNE_THROW( AlbertaError, "Inserting element of wrong dimension: " << type.dim() );
00131       if( !type.isSimplex() )
00132         DUNE_THROW( AlbertaError, "Alberta supports only simplices." );
00133 
00134       if( vertices.size() != (size_t)numVertices )
00135         DUNE_THROW( AlbertaError, "Wrong number of vertices passed: " << vertices.size() << "." );
00136 
00137       int array[ numVertices ];
00138       for( int i = 0; i < numVertices; ++i )
00139         array[ i ] = vertices[ numberingMap_.alberta2dune( dimension, i ) ];
00140       macroData_.insertElement( array );
00141     }
00142 
00151     virtual void insertBoundary ( int element, int face, int id )
00152     {
00153       if( (id <= 0) || (id > 127) )
00154         DUNE_THROW( AlbertaError, "Invalid boundary id: " << id << "." );
00155       macroData_.boundaryId( element, numberingMap_.dune2alberta( 1, face ) ) = id;
00156     }
00157 
00166     virtual void
00167     insertBoundaryProjection ( const GeometryType &type,
00168                                const std::vector< unsigned int > &vertices,
00169                                const DuneProjection *projection )
00170     {
00171       if( (int)type.dim() != dimension-1 )
00172         DUNE_THROW( AlbertaError, "Inserting boundary face of wrong dimension: " << type.dim() );
00173       if( !type.isSimplex() )
00174         DUNE_THROW( AlbertaError, "Alberta supports only simplices." );
00175 
00176       FaceId faceId;
00177       if( vertices.size() != faceId.size() )
00178         DUNE_THROW( AlbertaError, "Wrong number of face vertices passed: " << vertices.size() << "." );
00179       for( size_t i = 0; i < faceId.size(); ++i )
00180         faceId[ i ] = vertices[ i ];
00181       std::sort( faceId.begin(), faceId.end() );
00182 
00183       typedef std::pair< typename BoundaryMap::iterator, bool > InsertResult;
00184       const InsertResult result = boundaryMap_.insert( std::make_pair( faceId, boundaryProjections_.size() ) );
00185       if( !result.second )
00186         DUNE_THROW( GridError, "Only one boundary projection can be attached to a face." );
00187       boundaryProjections_.push_back( DuneProjectionPtr( projection ) );
00188     }
00189 
00190 
00197     virtual void insertBoundaryProjection ( const DuneProjection *projection )
00198     {
00199       if( globalProjection_ )
00200         DUNE_THROW( GridError, "Only one global boundary projection can be attached to a grid." );
00201       globalProjection_ = DuneProjectionPtr( projection );
00202     }
00203 
00209     virtual void
00210     insertBoundarySegment ( const std::vector< unsigned int >& vertices )
00211     {
00212       typedef typename GenericGeometry::SimplexTopology< dimension-1 >::type Topology;
00213       insertBoundaryProjection( GeometryType( Topology() ), vertices, 0 );
00214     }
00215 
00221     virtual void
00222     insertBoundarySegment ( const std::vector< unsigned int > &vertices,
00223                             const shared_ptr< BoundarySegment > &boundarySegment )
00224     {
00225       const GenericReferenceElement< ctype, dimension-1 > &refSimplex
00226         = GenericReferenceElements< ctype, dimension-1 >::simplex();
00227 
00228       if( !boundarySegment )
00229         DUNE_THROW( GridError, "Trying to insert null as a boundary segment." );
00230       if( (int)vertices.size() != refSimplex.size( dimension-1 ) )
00231         DUNE_THROW( GridError, "Wrong number of face vertices passed: " << vertices.size() << "." );
00232 
00233       std::vector< WorldVector > coords( refSimplex.size( dimension-1 ) );
00234       for( int i = 0; i < dimension; ++i )
00235       {
00236         Alberta::GlobalVector &x = macroData_.vertex( vertices[ i ] );
00237         for( int j = 0; j < dimensionworld; ++j )
00238           coords[ i ][ j ] = x[ j ];
00239         if( ((*boundarySegment)( refSimplex.position( i, dimension-1 ) ) - coords[ i ]).two_norm() > 1e-6 )
00240           DUNE_THROW( GridError, "Boundary segment does not interpolate the corners." );
00241       }
00242 
00243       const GeometryType gt = refSimplex.type( 0, 0 );
00244       const DuneProjection *prj = new BoundarySegmentWrapper( gt, coords, boundarySegment );
00245       insertBoundaryProjection( gt, vertices, prj );
00246     }
00247 
00261     void insertFaceTransformation ( const WorldMatrix &matrix, const WorldVector &shift );
00262 
00271     void markLongestEdge ()
00272     {
00273       macroData_.markLongestEdge();
00274     }
00275 
00288     Grid *createGrid ()
00289     {
00290       macroData_.finalize();
00291       if( macroData_.elementCount() == 0 )
00292         DUNE_THROW( GridError, "Cannot create empty AlbertaGrid." );
00293       if( dimension < 3 )
00294         macroData_.setOrientation( Alberta::Real( 1 ) );
00295       assert( macroData_.checkNeighbors() );
00296       macroData_.checkCycles();
00297       ProjectionFactory projectionFactory( *this );
00298       return new Grid( macroData_, projectionFactory );
00299     }
00300 
00305     static void destroyGrid ( Grid *grid )
00306     {
00307       delete grid;
00308     }
00309 
00318     template< GrapeIOFileFormatType type >
00319     bool write ( const std::string &filename )
00320     {
00321       dune_static_assert( type != pgm, "AlbertaGridFactory: writing pgm format is not supported." );
00322       macroData_.finalize();
00323       if( dimension < 3 )
00324         macroData_.setOrientation( Alberta::Real( 1 ) );
00325       assert( macroData_.checkNeighbors() );
00326       return macroData_.write( filename, (type == xdr) );
00327     }
00328 
00337     virtual bool write ( const std::string &filename )
00338     {
00339       return write< ascii >( filename );
00340     }
00341 
00342     virtual unsigned int
00343     insertionIndex ( const typename Codim< 0 >::Entity &entity ) const
00344     {
00345       return insertionIndex( Grid::getRealImplementation( entity ).elementInfo() );
00346     }
00347 
00348     virtual unsigned int
00349     insertionIndex ( const typename Codim< dimension >::Entity &entity ) const
00350     {
00351       const int elIndex = insertionIndex( Grid::getRealImplementation( entity ).elementInfo() );
00352       const typename MacroData::ElementId &elementId = macroData_.element( elIndex );
00353       return elementId[ Grid::getRealImplementation( entity ).subEntity() ];
00354     }
00355 
00356     virtual unsigned int
00357     insertionIndex ( const typename Grid::LeafIntersection &intersection ) const
00358     {
00359       const Grid &grid = Grid::getRealImplementation( intersection ).grid();
00360       const ElementInfo &elementInfo = Grid::getRealImplementation( intersection ).elementInfo();
00361       const int face = grid.generic2alberta( 1, intersection.indexInInside() );
00362       return insertionIndex( elementInfo, face );
00363     }
00364 
00365     virtual bool
00366     wasInserted ( const typename Grid::LeafIntersection &intersection ) const
00367     {
00368       return (insertionIndex( intersection ) < std::numeric_limits< unsigned int >::max());
00369     }
00370 
00371   private:
00372     unsigned int insertionIndex ( const ElementInfo &elementInfo ) const;
00373     unsigned int insertionIndex ( const ElementInfo &elementInfo, const int face ) const;
00374 
00375     FaceId faceId ( const ElementInfo &elementInfo, const int face ) const;
00376 
00377     MacroData macroData_;
00378     NumberingMap numberingMap_;
00379     DuneProjectionPtr globalProjection_;
00380     BoundaryMap boundaryMap_;
00381     std::vector< DuneProjectionPtr > boundaryProjections_;
00382   };
00383 
00384 
00385   template< int dim, int dimworld >
00386   GridFactory< AlbertaGrid< dim, dimworld > >::~GridFactory ()
00387   {
00388     macroData_.release();
00389   }
00390 
00391 
00392   template< int dim, int dimworld >
00393   inline void
00394   GridFactory< AlbertaGrid< dim, dimworld > >
00395     ::insertFaceTransformation ( const WorldMatrix &matrix, const WorldVector &shift )
00396   {
00397     // make sure the matrix is orthogonal
00398     for( int i = 0; i < dimworld; ++i )
00399       for( int j = 0; j < dimworld; ++j )
00400       {
00401         const ctype delta = (i == j ? ctype( 1 ) : ctype( 0 ));
00402         const ctype epsilon = (8*dimworld)*std::numeric_limits< ctype >::epsilon();
00403 
00404         if( std::abs( matrix[ i ] * matrix[ j ] - delta ) > epsilon )
00405         {
00406           DUNE_THROW( AlbertaError,
00407                       "Matrix of face transformation is not orthogonal." );
00408         }
00409       }
00410 
00411     // copy matrix
00412     Alberta::GlobalMatrix M;
00413     for( int i = 0; i < dimworld; ++i )
00414       for( int j = 0; j < dimworld; ++j )
00415         M[ i ][ j ] = matrix[ i ][ j ];
00416 
00417     // copy shift
00418     Alberta::GlobalVector t;
00419     for( int i = 0; i < dimworld; ++i )
00420       t[ i ] = shift[ i ];
00421 
00422     // insert into ALBERTA macro data
00423     macroData_.insertWallTrafo( M, t );
00424   }
00425 
00426 
00427   template< int dim, int dimworld >
00428   inline unsigned int
00429   GridFactory< AlbertaGrid< dim, dimworld > >
00430     ::insertionIndex ( const ElementInfo &elementInfo ) const
00431   {
00432     const MacroElement &macroElement = elementInfo.macroElement();
00433     const unsigned int index = macroElement.index;
00434 
00435 #ifndef NDEBUG
00436     const typename MacroData::ElementId &elementId = macroData_.element( index );
00437     for( int i = 0; i <= dimension; ++i )
00438     {
00439       const Alberta::GlobalVector &x = macroData_.vertex( elementId[ i ] );
00440       const Alberta::GlobalVector &y = macroElement.coordinate( i );
00441       for( int j = 0; j < dimensionworld; ++j )
00442       {
00443         if( x[ j ] != y[ j ] )
00444           DUNE_THROW( GridError, "Vertex in macro element does not coincide with same vertex in macro data structure." );
00445       }
00446     }
00447 #endif // #ifndef NDEBUG
00448 
00449     return index;
00450   }
00451 
00452 
00453   template< int dim, int dimworld >
00454   inline unsigned int
00455   GridFactory< AlbertaGrid< dim, dimworld > >
00456     ::insertionIndex ( const ElementInfo &elementInfo, const int face ) const
00457   {
00458     typedef typename BoundaryMap::const_iterator Iterator;
00459     const Iterator it = boundaryMap_.find( faceId( elementInfo, face ) );
00460     if( it != boundaryMap_.end() )
00461       return it->second;
00462     else
00463       return std::numeric_limits< unsigned int >::max();
00464   }
00465 
00466 
00467   template< int dim, int dimworld >
00468   inline typename GridFactory< AlbertaGrid< dim, dimworld > >::FaceId
00469   GridFactory< AlbertaGrid< dim, dimworld > >
00470     ::faceId ( const ElementInfo &elementInfo, const int face ) const
00471   {
00472     const unsigned int index = insertionIndex( elementInfo );
00473     const typename MacroData::ElementId &elementId = macroData_.element( index );
00474 
00475     FaceId faceId;
00476     for( size_t i = 0; i < faceId.size(); ++i )
00477     {
00478       const int k = Alberta::MapVertices< dimension, 1 >::apply( face, i );
00479       faceId[ i ] = elementId[ k ];
00480     }
00481     std::sort( faceId.begin(), faceId.end() );
00482     return faceId;
00483   }
00484 
00485 
00486 
00487   // GridFactory::ProjectionFactory
00488   // ------------------------------
00489 
00490   template< int dim, int dimworld >
00491   class GridFactory< AlbertaGrid< dim, dimworld > >::ProjectionFactory
00492   : public Alberta::ProjectionFactory< Alberta::DuneBoundaryProjection< dim >, ProjectionFactory >
00493   {
00494     typedef ProjectionFactory This;
00495     typedef Alberta::ProjectionFactory< Alberta::DuneBoundaryProjection< dim >, ProjectionFactory > Base;
00496 
00497     typedef typename Dune::GridFactory< AlbertaGrid< dim, dimworld > > Factory;
00498 
00499   public:
00500     typedef typename Base::Projection Projection;
00501     typedef typename Base::ElementInfo ElementInfo;
00502 
00503     typedef typename Projection::Projection DuneProjection;
00504 
00505     ProjectionFactory( const GridFactory &gridFactory )
00506     : gridFactory_( gridFactory )
00507     {}
00508 
00509     bool hasProjection ( const ElementInfo &elementInfo, const int face ) const
00510     {
00511       if( gridFactory().globalProjection_ )
00512         return true;
00513 
00514       const unsigned int index = gridFactory().insertionIndex( elementInfo, face );
00515       if( index < std::numeric_limits< unsigned int >::max() )
00516         return bool( gridFactory().boundaryProjections_[ index ] );
00517       else
00518         return false;
00519     }
00520 
00521     bool hasProjection ( const ElementInfo &elementInfo ) const
00522     {
00523       return bool( gridFactory().globalProjection_ );
00524     }
00525 
00526     Projection projection ( const ElementInfo &elementInfo, const int face ) const
00527     {
00528       const unsigned int index = gridFactory().insertionIndex( elementInfo, face );
00529       if( index < std::numeric_limits< unsigned int >::max() )
00530       {
00531         const DuneProjectionPtr &projection = gridFactory().boundaryProjections_[ index ];
00532         if( projection )
00533           return Projection( projection );
00534       }
00535 
00536       assert( gridFactory().globalProjection_ );
00537       return Projection( gridFactory().globalProjection_ );
00538     };
00539 
00540     Projection projection ( const ElementInfo &elementInfo ) const
00541     {
00542       assert( gridFactory().globalProjection_ );
00543       return Projection( gridFactory().globalProjection_ );
00544     };
00545 
00546     const GridFactory &gridFactory () const
00547     {
00548       return gridFactory_;
00549     }
00550 
00551   private:
00552     const GridFactory &gridFactory_;
00553   };
00554 
00555 }
00556 
00557 #endif // #if HAVE_ALBERTA
00558 
00559 #endif // #ifndef DUNE_ALBERTA_GRIDFACTORY_HH