File: geometry.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 (377 lines) | stat: -rw-r--r-- 15,067 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
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
// 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_GEOMETRY_HH
#define DUNE_PYTHON_GRID_GEOMETRY_HH

#include <cstddef>

#include <array>
#include <string>
#include <type_traits>
#include <utility>

#include <dune/common/fmatrix.hh>
#include <dune/common/fvector.hh>
#include <dune/common/rangeutilities.hh>
#include <dune/common/visibility.hh>

#include <dune/python/common/fvecmatregistry.hh>

#include <dune/geometry/referenceelements.hh>

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

namespace Dune
{

  namespace Python
  {

    namespace detail
    {

      // registerGridGeometry
      // --------------------

      template< class Geometry, class Array >
      inline static pybind11::array_t< double >
      pushForwardGradients ( const Geometry &geo, Array xVec, pybind11::array_t< double > gVec )
      {
        typedef typename Geometry::LocalCoordinate LocalCoordinate;
        typedef typename Geometry::GlobalCoordinate GlobalCoordinate;

        // x = (localCoord,nofQuad)
        auto x = xVec.unchecked();
        // g = (dimRange,localCoord,nofQuad)
        auto g = gVec.unchecked();
        // ret = (dimRange,globalCoord,nofQuad)
        pybind11::array_t< double > ret( std::array< ssize_t, 3 >{{ g.shape( 0 ), static_cast< ssize_t >( Geometry::GlobalCoordinate::size() ), g.shape( 2 ) }} );
        auto y = ret.template mutable_unchecked< 3 >();
        if( x.shape( 1 ) != g.shape( 2 ) )
          std::cout << x.shape( 1 ) << " " << g.shape( 2 ) << std::endl;
        if( x.shape( 0 ) != ssize_t(LocalCoordinate::size()) )
          std::cout << x.shape( 0 ) << " " << Geometry::LocalCoordinate::size() << std::endl;

        for( ssize_t p = 0; p < g.shape( 2 ); ++p )
        {
          LocalCoordinate xLocal;
          for( std::size_t l = 0; l < LocalCoordinate::size(); ++l )
            xLocal[ l ] = x( l, p );
          const auto jit = geo.jacobianInverseTransposed( xLocal );

          for( ssize_t range = 0; range < g.shape( 0 ); ++range )
          {
            // Performance Issue:
            // The copies gradLocal and gradGlobal can be avoided by providing
            // a DenseVector implementation based on a single axis of the
            // pybind11::array accessor, because the `jit.mv` method is required
            // to take arbitrary implementations of the dense vector interface.
            LocalCoordinate gradLocal;
            for( std::size_t l = 0; l < LocalCoordinate::size(); ++l )
              gradLocal[ l ] = g(range, l, p );

            GlobalCoordinate gradGlobal;
            jit.mv( gradLocal, gradGlobal );

            for( std::size_t r = 0; r < GlobalCoordinate::size(); ++r )
              y( range, r, p ) = gradGlobal[ r ];
          }
        }
        return ret;
      }

      template< class Geometry, class... options >
      void registerGridGeometry ( pybind11::handle scope, pybind11::class_<Geometry, options...> cls )
      {
        const int mydimension = Geometry::mydimension;
        const int coorddimension = Geometry::coorddimension;

        typedef typename Geometry::ctype ctype;
        typedef FieldVector< ctype, mydimension > LocalCoordinate;
        typedef FieldVector< ctype, coorddimension > GlobalCoordinate;
        typedef FieldMatrix< ctype, coorddimension, mydimension > Jacobian;
        typedef FieldMatrix< ctype, mydimension, coorddimension > JacobianTransposed;
        typedef FieldMatrix< ctype, mydimension, coorddimension > JacobianInverse;
        typedef FieldMatrix< ctype, coorddimension, mydimension > JacobianInverseTransposed;
        registerFieldVecMat<LocalCoordinate>::apply();
        registerFieldVecMat<GlobalCoordinate>::apply();
        registerFieldVecMat<Jacobian>::apply();
        registerFieldVecMat<JacobianTransposed>::apply();
        registerFieldVecMat<JacobianInverse>::apply();
        registerFieldVecMat<JacobianInverseTransposed>::apply();

        typedef pybind11::array_t< ctype > Array;

        using pybind11::operator""_a;

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

        cls.doc() = R"doc(
            A geometry describes a map from the reference domain into a
            Euclidean space, where the reference domain is given by the
            reference element.
            The mapping is required to be one-to-one.

            We refer to points within the reference domain as "local" points.
            The image of a local point is called its (global) position.

            Note: The image of the mapping may be a submanifold of the
                  Euclidean space.
          )doc";

        cls.def( "corner", [] ( const Geometry &self, int i ) {
            const int size = self.corners();
            if( (i < 0) || (i >= size) )
              throw pybind11::value_error( "Invalid index: " + std::to_string( i ) + " (must be in [0, " + std::to_string( size ) + "))." );
            return self.corner( i );
          }, "index"_a,
          R"doc(
            get global position a reference corner

            Args:
                index:    index of the reference corner

            Returns:
                global position of the reference corner

            Note: If the argument "index" is omitted, this method returns a
                  NumPy array containing the global position of all corners.
                  This version may be used to vectorize the code.
          )doc" );
        cls.def( "corner", [] ( const Geometry &self ) {
            const int size = self.corners();
            pybind11::array_t< ctype > cornersArray( { static_cast< ssize_t >( coorddimension ), static_cast< ssize_t >( size ) } );
            auto corners = cornersArray.template mutable_unchecked< 2 >();
            for( int i = 0; i < size; ++i )
            {
              const auto corner = self.corner( i );
              for( int j = 0; j < coorddimension; ++j )
                corners( j, i ) = corner[ j ];
            }
            return cornersArray;
          } );
        cls.def_property_readonly( "corners", [] ( const Geometry &self ) {
            const int size = self.corners();
            pybind11::tuple corners( size );
            for( int i = 0; i < size; ++i )
              corners[ i ] = pybind11::cast( self.corner( i ) );
            return corners;
          },
          R"doc(
            get global positions of all reference corners

            Note:
                This function differs from the vectorized version of 'corner'
                in the way the corners are returned. This method returns a
                tuple of global positions of type FieldVector.

            Returns:
                tuple of global positions, in the order given by the reference element
          )doc" );


        cls.def_property_readonly( "center", [] ( const Geometry &self ) { return self.center(); },
          R"doc(
            global position of the barycenter of the reference element
          )doc" );
        cls.def_property_readonly( "volume", [] ( const Geometry &self ) { return self.volume(); },
          R"doc(
            volume of the map's image

            The volume is measured using the Hausdorff measure of the corresponding dimension.
          )doc" );

        cls.def_property_readonly( "affine", [] ( const Geometry &self ) { return self.affine(); },
          R"doc(
            True, if the map is affine-linear, False otherwise
          )doc" );
        cls.def_property_readonly( "referenceElement", []( const Geometry &self ) {
            return referenceElement< double, mydimension >( self.type() );
          }, pybind11::keep_alive< 0, 1 >(),
          R"doc(
            corresponding reference element, describing the domain of the map
          )doc" );

        cls.def( "toGlobal", [] ( const Geometry &self, const LocalCoordinate &x ) { return self.global( x ); }, "x"_a,
          R"doc(
            obtain global position of a local point

            Args:
                x:    local point

            Returns:
                global position of x

            Note: This method may be used in vectorized form by passing in a
                  NumPy array for 'x'.
          )doc" );
        cls.def( "toGlobal", [] ( const Geometry &self, Array x ) {
            return vectorize( [ &self ] ( const LocalCoordinate &x ) { return self.global( x ); }, x );
          } );

        cls.def( "toLocal", [] ( const Geometry &self, const GlobalCoordinate &y ) { return self.local( y ); }, "y"_a,
          R"doc(
            obtain local point mapped to a global position

            Args:
                y:    global position

            Returns:
                local point mapped to y

            Note: This method may be used in vectorized form by passing in a
                  NumPy array for 'y'.
          )doc" );
        cls.def( "toLocal", [] ( const Geometry &self, Array y ) {
            return vectorize( [ &self ] ( const GlobalCoordinate &y ) { return self.local( y ); }, y );
          } );

        cls.def( "integrationElement", [] ( const Geometry &self, const LocalCoordinate &x ) { return self.integrationElement( x ); }, "x"_a,
          R"doc(
            obtain integration element in a local point

            The integration element is the factor appearing in the integral
            transformation formula.
            It describes the weight factor when transforming a quadrature rule
            on the reference element into a quadrature rule on the image of this
            map.

            Args:
                x:    local point

            Returns:
                integration element in x

            Note: This method may be used in vectorized form by passing in a
                  NumPy array for 'x'.
          )doc" );
        cls.def( "integrationElement", [] ( const Geometry &self, Array x ) {
            return vectorize( [ &self ] ( const LocalCoordinate &x ) { return self.integrationElement( x ); }, x );
          } );

        cls.def( "jacobian", [] ( const Geometry &self, const LocalCoordinate &x ) {
            return static_cast< Jacobian >( self.jacobian( x ) );
          }, "x"_a,
          R"doc(
            obtain the Jacobian of this mapping in a local point

            The Jacobian describes the push-forward for tangential
            vectors from the reference domain to the image of this map.

            Args:
                x:    local point

            Returns:
                Jacobian matrix in x

            Note: This method may be used in vectorized form by passing in a
                  NumPy array for 'x'.
          )doc" );
        cls.def( "jacobian", [] ( const Geometry &self, Array x ) {
            return vectorize( [ &self ] ( const LocalCoordinate &x ) { return static_cast< Jacobian >( self.jacobian( x ) ); }, x );
          } );

        cls.def( "jacobianTransposed", [] ( const Geometry &self, const LocalCoordinate &x ) {
            return static_cast< JacobianTransposed >( self.jacobianTransposed( x ) );
          }, "x"_a,
          R"doc(
            obtain transposed of the Jacobian of this mapping in a local point

            The rows of the returned matrix describe the tangential vectors in
            the global position of the local point.

            The Jacobian itself describes the push-forward for tangential
            vectors from the reference domain to the image of this map.

            Args:
                x:    local point

            Returns:
                transposed of the Jacobian matrix in x

            Note: This method may be used in vectorized form by passing in a
                  NumPy array for 'x'.
          )doc" );
        cls.def( "jacobianTransposed", [] ( const Geometry &self, Array x ) {
            return vectorize( [ &self ] ( const LocalCoordinate &x ) { return static_cast< JacobianTransposed >( self.jacobianTransposed( x ) ); }, x );
          } );

        cls.def( "jacobianInverse", [] ( const Geometry &self, const LocalCoordinate &x ) {
            return static_cast< JacobianInverse >( self.jacobianInverse( x ) );
          }, "x"_a,
          R"doc(
            obtain inverse Jacobian of this mapping in a local point

            The inverse Jacobian describes the push-forward of cotangential
            vectors from the reference domain to the image of this map.

            Args:
                x:    local point

            Returns:
                Inverse Jacobian matrix in x

            Note: This method may be used in vectorized form by passing in a
                  NumPy array for 'x'.
          )doc" );
        cls.def( "jacobianInverse", [] ( const Geometry &self, Array x ) {
            return vectorize( [ &self ] ( const LocalCoordinate &x ) { return static_cast< JacobianInverse >( self.jacobianInverse( x ) ); }, x );
          } );

        cls.def( "jacobianInverseTransposed", [] ( const Geometry &self, const LocalCoordinate &x ) {
            return static_cast< JacobianInverseTransposed >( self.jacobianInverseTransposed( x ) );
          }, "x"_a,
          R"doc(
            obtain transposed of the inverse Jacobian of this mapping in a local point

            This matrix describes the push-forward for local function gradients
            to the image of this map.

            The inverse Jacobian itself describes the push-forward of cotangential
            vectors from the reference domain to the image of this map.

            Args:
                x:    local point

            Returns:
                transposed of the Jacobian matrix in x

            Note: This method may be used in vectorized form by passing in a
                  NumPy array for 'x'.
          )doc" );
        cls.def( "jacobianInverseTransposed", [] ( const Geometry &self, Array x ) {
            return vectorize( [ &self ] ( const LocalCoordinate &x ) { return static_cast< JacobianInverseTransposed >( self.jacobianInverseTransposed( x ) ); }, x );
          } );

        cls.def( "pushForwardGradients", [] ( const Geometry &self, Array x, pybind11::array_t<double> g ) {
            return pushForwardGradients(self,x,g);
          } );
      }

    } // namespace detail



    // registerGridGeometry
    // --------------------

    template< class Base, class Geometry = typename Base::Geometry >
    inline static pybind11::class_< Geometry > registerGridGeometry ( pybind11::handle scope )
    {
      auto entry = insertClass< Geometry >( scope, "Geometry", GenerateTypeName( scope, "Geometry" ) );
      if ( entry.second )
        detail::registerGridGeometry( scope, entry.first );
      return entry.first;
    }

  } // namespace Python

} // namespace Dune

#endif // #ifndef DUNE_PYTHON_GRID_GEOMETRY_HH