File: indexset.hh

package info (click to toggle)
dune-grid 2.11.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 8,472 kB
  • sloc: cpp: 60,883; python: 1,438; perl: 191; makefile: 12; sh: 3
file content (323 lines) | stat: -rw-r--r-- 14,058 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root
// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
// -*- tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_PYTHON_GRID_INDEXSET_HH
#define DUNE_PYTHON_GRID_INDEXSET_HH

#include <string>
#include <tuple>
#include <type_traits>
#include <utility>

#include <dune/common/hybridutilities.hh>
#include <dune/common/typeutilities.hh>

#include <dune/geometry/referenceelements.hh>

#include <dune/python/common/typeregistry.hh>
#include <dune/python/pybind11/pybind11.h>

namespace Dune
{

  namespace Python
  {

    namespace detail
    {

      // indexSetSubIndex
      // ----------------

      template< class IndexSet, class Entity >
      inline static int indexSetSubIndex ( const IndexSet &indexSet, const Entity &entity, int i, int c )
      {
        if( !indexSet.contains( entity ) )
          pybind11::value_error( "Entity not contained in index set." );
        if( (c < Entity::codimension) || (c > Entity::dimension) )
          throw pybind11::value_error( "Invalid codimension: " + std::to_string( c ) + " (must be in [" + std::to_string( Entity::codimension ) + ", " + std::to_string( Entity::dimension ) + "])" );
        const int size = entity.subEntities( c );
        if( (i < 0) || (i >= size) )
          throw pybind11::value_error( "Invalid index: " + std::to_string( i ) + " (must be in [0, " + std::to_string( size ) + "))." );
        return static_cast< int >( indexSet.subIndex( entity, i, c ) );
      }



      // registerSubIndex
      // ----------------

      template< class Entity, class IndexSet, class... options >
      inline static std::enable_if_t< Entity::codimension == 0 >
      registerSubIndex ( pybind11::class_< IndexSet, options... > cls, PriorityTag< 1 > )
      {
        using pybind11::operator""_a;

        pybind11::options opts;
        opts.disable_function_signatures();

        cls.def( "subIndex", [] ( const IndexSet &self, const Entity &entity, int i, int c ) {
            return detail::indexSetSubIndex( self, entity, i, c );
          }, "entity"_a, "index"_a, "codim"_a,
          R"doc(
            get index of a subentity

            Numerical codes frequently require only the index of a subentity,
            not the subentity itself.
            This method directly provides the index.

            The subentity is described by a local index and a codimension.
            The exact interpretation of the local index is defined by the
            reference element.

            Calling this method is semantically equivalent to

            self.index(entity.subEntity(index, codim))

            Note: This method is implemented even if the grid does not implement
                  entities of the corresponding codimension.

            Args:
                entity:   entity containing the subentity
                index:    number of the subentity
                codim:    codimension of the subentity (wrt. the grid dimension)

            Returns:  Index of the subentity
          )doc" );
        cls.def( "subIndex", [] ( const IndexSet &self, const Entity &entity, std::tuple< int, int > e ) {
            return detail::indexSetSubIndex( self, entity, std::get< 0 >( e ), std::get< 1 >( e ) );
          }, "entity"_a, "subentity"_a,
          R"doc(
            Args:
                entity:       entity containing the subentity
                subentity:    (index, codim) tuple

            Returns:  Index of the subentity
          )doc" );

        cls.def( "subIndices", [] ( const IndexSet &self, const Entity &entity, int c ) {
            if( !self.contains( entity ) )
              pybind11::value_error( "Entity not contained in index set." );
            if( (c < Entity::codimension) || (c > Entity::dimension) )
              throw pybind11::value_error( "Invalid codimension: " + std::to_string( c ) + " (must be in [" + std::to_string( Entity::codimension ) + ", " + std::to_string( Entity::dimension ) + "])" );
            const int size = entity.subEntities( c );
            pybind11::tuple subIndices( size );
            for( int i = 0; i < size; ++i )
              subIndices[ i ] = pybind11::cast( self.subIndex( entity, i, c ) );
            return subIndices;
          }, "entity"_a, "codim"_a,
          R"doc(
            get indices of all subentities in a codimension

            Numerical codes frequently require all subindices of a codimension,
            e.g., all vertex indices.
            This convenience method provides them in a single call.

            Note: This method is implemented even if the grid does not implement
                  entities of the corresponding codimension.

            Args:
                entity:   entity containing the subentities
                codim:    codimension of the subentities (wrt. the grid dimension)

            Returns:  Tuple of indices, in the order given by the reference element
          )doc" );

      cls.def( "subIndices", [] ( const IndexSet &self, const Entity &entity, int i, int c, int cc ) {
            if( !self.contains( entity ) )
              pybind11::value_error( "Entity not contained in index set." );
            if( (c < Entity::codimension) || (c > Entity::dimension) )
              throw pybind11::value_error( "Invalid codimension: " + std::to_string( c ) + " (must be in [" + std::to_string( Entity::codimension ) + ", " + std::to_string( Entity::dimension ) + "])" );
            if( (cc < c) || (cc > Entity::dimension) )
              throw pybind11::value_error( "Invalid codimension: " + std::to_string( cc ) + " (must be in [" + std::to_string( c ) + ", " + std::to_string( Entity::dimension ) + "])" );
            const auto reference = referenceElement< double, Entity::dimension >( entity.type() );
            const int size = reference.size( i, c, cc );
            pybind11::tuple subIndices( size );
            for( int ii = 0; ii < size; ++ii )
              subIndices[ ii ] = pybind11::cast( self.subIndex( entity, reference.subEntity(i, c, ii, cc), cc ) );
            return subIndices;
          }, "entity"_a, "index"_a, "codim"_a, "codim"_a,
          R"doc(
            get indices of all subentities in a codimension

            Numerical codes frequently require all subindices of a subentity of a codimension,
            e.g., all vertex indices of a edge.
            This convenience method provides them in a single call.

            Note: This method is implemented even if the grid does not implement
                  entities of the corresponding codimension.

            Args:
                entity:   entity containing the subentities
                index:    index of the subentity of entity
                codim:    codimension of the subentity of entity
                codim:    codimension of the subentities (wrt. the grid dimension)

            Returns:  Tuple of indices, in the order given by the reference element
          )doc" );

      cls.def( "subIndices", [] ( const IndexSet &self, const Entity &entity, std::pair< int, int > ic, int cc ) {
            int i = ic.first;
            int c = ic.second;
            if( !self.contains( entity ) )
              pybind11::value_error( "Entity not contained in index set." );
            if( (c < Entity::codimension) || (c > Entity::dimension) )
              throw pybind11::value_error( "Invalid codimension: " + std::to_string( c ) + " (must be in [" + std::to_string( Entity::codimension ) + ", " + std::to_string( Entity::dimension ) + "])" );
            if( (cc < c) || (cc > Entity::dimension) )
              throw pybind11::value_error( "Invalid codimension: " + std::to_string( cc ) + " (must be in [" + std::to_string( c ) + ", " + std::to_string( Entity::dimension ) + "])" );
            const auto reference = referenceElement< double, Entity::dimension >( entity.type() );
            const int size = reference.size( i, c, cc );
            pybind11::tuple subIndices( size );
            for( int ii = 0; ii < size; ++ii )
              subIndices[ ii ] = pybind11::cast( self.subIndex( entity, reference.subEntity(i, c, ii, cc), cc ) );
            return subIndices;
          }, "entity"_a, "subentity"_a, "codim"_a,
          R"doc(
            get indices of all subentities in a codimension

            Numerical codes frequently require all subindices of a subentity of a codimension,
            e.g., all vertex indices of a edge.
            This convenience method provides them in a single call.

            Note: This method is implemented even if the grid does not implement
                  entities of the corresponding codimension.

            Args:
                entity:       entity containing the subentities
                subentity:    (index, codim) tuple
                codim:        codimension of the subentities (wrt. the grid dimension)

            Returns:  Tuple of indices, in the order given by the reference element
          )doc" );
      }

      template< class Entity, class IndexSet, class... options >
      inline static void registerSubIndex ( pybind11::class_< IndexSet, options... > cls, PriorityTag< 0 > )
      {}

      template< class Entity, class IndexSet, class... options >
      inline static void registerSubIndex ( pybind11::class_< IndexSet, options... > cls )
      {
        registerSubIndex< Entity >( cls, PriorityTag< 42 >() );
      }

    } // namespace detail



    // registerGridViewIndexSet
    // ------------------------

    template< class IndexSet, class... options >
    inline static void registerGridViewIndexSet ( pybind11::handle scope, pybind11::class_< IndexSet, options... > cls )
    {
      using pybind11::operator""_a;

      pybind11::options opts;
      opts.disable_function_signatures();

      cls.doc() = R"doc(
          The index set maps all entities in a grid view to natural numbers
          (including 0).
          Denoting by E(g) the entities of geometry type g, this map has the
          following properties:
          - It is injective on each E(g).
          - The image of E(g) is consecutive and zero-starting, i.e.,
            { 0, ..., N-1 } for some integer N

          Index sets are used to assign user-defined data (e.g., degrees of
          freedom of a discretization) to entities in the grid view.
          For efficiency reasons, the preferred data structure for user data is
          an array.
          In order to access the data from associated to an entity, its index
          (wrt. an index set) is evaluated and used to access the  array element.

          Usually, the index set is not used directly. Instead, a mapper is used
          to compute the array index from the index provided by an index set.

          Note: The index assigned to an entity may change during grid
                modification (e.g., refinement of dynamic load balancing).
                The user is responsible for reorganizing the information stored
                in the external arrays.
                In order to do this, the concepts of id sets and persistent
                containers are provided.
        )doc";

      cls.def( "size", [] ( IndexSet &self, Dune::GeometryType type ) { return self.size( type ); } );
      cls.def( "size", [] ( IndexSet &self, int codim ) {
          if( (codim < 0) || (codim > IndexSet::dimension) )
            throw pybind11::value_error( "Invalid codimension: " + std::to_string( codim ) + " (must be in [0, " + std::to_string( IndexSet::dimension ) + "])" );
          return self.size( codim );
        } );

      cls.def( "types", [] ( const IndexSet &self, int codim ) {
          pybind11::list types;
          for( GeometryType type : self.types( codim ) )
            types.append( pybind11::cast( type ) );
          return types;
        }, "codim"_a,
        R"doc(
          obtain list of geometry types in the domain of the index set.

          Args:
              codim:    codimension to obtain geometry types for

          Returns:  List of all geometry types of given codimension in the
                    domain of the index set
        )doc" );

      Hybrid::forEach( std::make_integer_sequence< int, IndexSet::dimension+1 >(), [ &cls ] ( auto codim ) {
          typedef typename IndexSet::template Codim< codim >::Entity Entity;

          using pybind11::operator""_a;

          cls.def( "index", [] ( const IndexSet &self, const Entity &entity ) {
              if( !self.contains( entity ) )
                pybind11::value_error( "Entity not contained in index set." );
              return static_cast< int >( self.index( entity ) );
            }, "entity"_a,
            R"doc(
              get index of an entity

              Args:
                  entity:   entity to obtain index for

              Returns:  Index assigned to the entity
            )doc" );
          cls.def( "contains", [] ( const IndexSet &self, const Entity &entity ) {
              return self.contains( entity );
            }, "entity"_a,
            R"doc(
              check whether an entity is in the domain of the index set

              Args:
                  entity:   entity to check for

              Returns: True, if the entity is in the domain, False otherwise
            )doc" );

          detail::registerSubIndex< Entity >( cls );
        } );
    }



    // registerGridViewIndexSet
    // ------------------------

    template< class GridView >
    inline static pybind11::class_< typename GridView::IndexSet > registerGridViewIndexSet ( pybind11::handle scope )
    {
      typedef typename GridView::IndexSet IndexSet;

      auto cls = insertClass< IndexSet >( scope, "IndexSet", GenerateTypeName( MetaType< GridView >(), "IndexSet" ) ).first;
      registerGridViewIndexSet( scope, cls );
      return cls;
    }

  } // namespace Python

} // namespace Dune

#endif // #ifndef DUNE_PYTHON_GRID_INDEXSET_HH