File: extended_4D.cpp

package info (click to toggle)
gridtools 2.3.9-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 29,480 kB
  • sloc: cpp: 228,792; python: 17,561; javascript: 9,164; ansic: 4,101; sh: 850; makefile: 231; f90: 201
file content (136 lines) | stat: -rw-r--r-- 6,042 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
/*
 * GridTools
 *
 * Copyright (c) 2014-2023, ETH Zurich
 * All rights reserved.
 *
 * Please, refer to the LICENSE file in the root directory.
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <type_traits>

#include <gridtools/meta.hpp>
#include <gridtools/stencil/cartesian.hpp>
#include <gridtools/stencil/global_parameter.hpp>

#include <stencil_select.hpp>
#include <test_environment.hpp>

namespace {
    using namespace gridtools;
    using namespace stencil;
    using namespace cartesian;
    using namespace expressions;

    /**
      @file
      @brief This file shows a possible usage of the extension to storages with more than 3 space dimensions.

      We recall that the space dimensions simply identify the number of indexes/strides required to access
      a contiguous chunk of storage. The number of space dimensions is fully arbitrary.

      In particular, we show how to perform a nested inner loop on the extra dimension(s). Possible scenarios
      where this can be useful could be:
      * when dealing with arbitrary order integration of a field in the cells.
      * when we want to implement a discretization scheme involving integrals (like all Galerkin-type discretizations,
      i.e. continuous/discontinuous finite elements, isogeometric analysis)
      * if we discretize an equation defined on a manifold with more than 3 dimensions (e.g. space-time)
      * if we want to implement coloring schemes, or access the grid points using exotic (but 'regular') patterns

      In this example we suppose that we aim at projecting a field 'f' on a finite elements space. To each
      i,j,k point corresponds an element (we can e.g. suppose that the i,j,k, nodes are the low-left corner).
      We suppose that the following (4-dimensional) quantities are provided (replaced with stubs)
      * The basis and test functions phi and psi respectively, evaluated on the quadrature points of the
      reference element
      * The Jacobian of the finite elements transformation (from the reference to the current configurations)
      , also evaluated in the quadrature points
      * The quadrature nodes/quadrature rule

      With this information we perform the projection (i.e. perform an integral) by looping on the
      quadrature points in an innermost loop, with stride given by the layout_map (I*J*K in this case).

      Note that the fields phi and psi are passed through as global_parameters and taken in the stencil
      operator as global_accessors. This is the czse since the base functions do not change when the
      iteration point moves, so their values are constant. This is a typical example of global_parameter use.
    */

    struct integration {
        using phi_fun = in_accessor<0>;
        using psi_fun = in_accessor<1>;
        using jac = in_accessor<2, extent<>, 4>;
        using f = in_accessor<3, extent<>, 6>;
        using result = inout_accessor<4, extent<>, 6>;

        using param_list = make_param_list<phi_fun, psi_fun, jac, f, result>;

        template <typename Evaluation>
        GT_FUNCTION static void apply(Evaluation eval) {
            dimension<4> di;
            dimension<5> dj;
            dimension<6> dk;
            dimension<4> qp;
            auto psi = eval(psi_fun());
            auto phi = eval(phi_fun());
            using float_type = std::decay_t<decltype(eval(result()))>;
            for (int I = 0; I < 2; ++I)
                for (int J = 0; J < 2; ++J)
                    for (int K = 0; K < 2; ++K) {
                        float_type res = 0;
                        for (int q = 0; q < 2; ++q) {
                            float_type sum = 0;
                            for (int a = 0; a < 2; ++a)
                                for (int b = 0; b < 2; ++b)
                                    for (int c = 0; c < 2; ++c)
                                        sum += eval(psi(a, b, c, q) * f(di + a, dj + b, dk + c));
                            res += eval(phi(I, J, K, q) * jac(qp + q) * sum);
                        }
                        eval(result(di + I, dj + J, dk + K)) = res / 8;
                    }
        }
    };

    /**
     * this is a user-defined class which will be used from within the user functor
     * by calling its  operator(). It can represent in this case values which are local to the elements
     * e.g. values of the basis functions in the quad points.
     */
    struct elemental {
        GT_FUNCTION double operator()(int, int, int, int) const { return m_val; }

        double m_val;
    };

    GT_REGRESSION_TEST(extended_4d, test_environment<>, stencil_backend_t) {
        static constexpr uint_t nbQuadPt = 2;
        static constexpr uint_t b1 = 2;
        static constexpr uint_t b2 = 2;
        static constexpr uint_t b3 = 2;

        using float_t = typename TypeParam::float_t;
        using storage_traits_t = typename TypeParam::storage_traits_t;

        float_t phi = 10, psi = 11, f = 1.3;
        auto jac = [](int, int, int, int q) { return 1 + q; };
        const auto const_builder = storage::builder<storage_traits_t>.template type<float_t const>();

        elemental ephi = {phi};
        elemental epsi = {psi};

        auto result = storage::builder<storage_traits_t>.template type<float_t>().dimensions(
            TypeParam::d(0), TypeParam::d(1), TypeParam::d(2), b1, b2, b3)();
        run_single_stage(integration(),
            stencil_backend_t(),
            TypeParam::make_grid(),
            global_parameter(ephi),
            global_parameter(epsi),
            const_builder.dimensions(TypeParam::d(0), TypeParam::d(1), TypeParam::d(2), nbQuadPt)
                .initializer(jac)
                .build(),
            const_builder.dimensions(TypeParam::d(0), TypeParam::d(1), TypeParam::d(2), b1, b2, b3).value(f).build(),
            result);
        TypeParam::verify(
            [=](int i, int j, int k, int, int, int) { return (jac(i, j, k, 0) + jac(i, j, k, 1)) * phi * psi * f; },
            result);
    }
} // namespace