Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #pragma once
11 :
12 : #include <cstddef>
13 :
14 : namespace CompileTimeDerivativesMaterialInternal
15 : {
16 : namespace details
17 : {
18 :
19 : /**
20 : * Check if the given index sequence is sorted ()internal function)
21 : */
22 : template <std::size_t first, std::size_t second, std::size_t... tail>
23 : constexpr bool
24 : is_sorted()
25 : {
26 : if constexpr (first <= second)
27 : {
28 : if constexpr (sizeof...(tail) == 0)
29 : return true;
30 : else
31 : return is_sorted<second, tail...>();
32 : }
33 : else
34 : return false;
35 : }
36 :
37 : /**
38 : * Compile time evaluation of the factorial of N
39 : */
40 : template <std::size_t N>
41 : constexpr std::size_t
42 : factorial()
43 : {
44 : if constexpr (N == 0)
45 : return 1;
46 : else if constexpr (N == 1)
47 : return 1;
48 : else
49 : return N * factorial<N - 1>();
50 : }
51 :
52 : /**
53 : * Number of distinct order N derivatives of a function with M variables
54 : */
55 : template <std::size_t N, std::size_t M>
56 : constexpr std::size_t
57 : num_derivatives()
58 : {
59 : return factorial<N + M - 1>() / (factorial<N>() * factorial<M - 1>());
60 : }
61 :
62 : /**
63 : * Merge two index sequences into one
64 : */
65 : template <std::size_t... first, std::size_t... second>
66 : constexpr auto
67 8265 : merge(std::index_sequence<first...>, std::index_sequence<second...>)
68 : {
69 8265 : return std::index_sequence<first..., second...>{};
70 : }
71 :
72 : /**
73 : * Increment the first number in an index sequence, but roll over into the next number if it reaches
74 : * Nmax. This basically increments a base-Nmax number with its digits in reverse!
75 : */
76 : template <std::size_t Nmax, std::size_t first, std::size_t... tail>
77 : constexpr auto
78 29754 : increment(std::index_sequence<first, tail...>)
79 : {
80 : if constexpr (first + 1 == Nmax)
81 : {
82 : if constexpr (sizeof...(tail) == 0)
83 1653 : return std::index_sequence<>{};
84 : else
85 8265 : return merge(std::index_sequence<0>{}, increment<Nmax>(std::index_sequence<tail...>{}));
86 : }
87 : else
88 19836 : return std::index_sequence<first + 1, tail...>{};
89 : }
90 :
91 : /**
92 : * Compute the total number of distinct derivatives for all orders N
93 : */
94 : template <std::size_t M, std::size_t... N>
95 : constexpr std::size_t
96 : total_derivatives(std::index_sequence<N...>)
97 : {
98 : return (num_derivatives<N, M>() + ...);
99 : }
100 :
101 : /**
102 : * Take an index sequence and return an index sequence of the same length with all entries replaced
103 : * by zeroes
104 : */
105 : template <std::size_t... Ns>
106 : constexpr auto
107 551 : zeroes(std::index_sequence<Ns...>)
108 : {
109 551 : return std::index_sequence<(void(Ns), 0)...>{};
110 : }
111 :
112 : } // namespace details
113 :
114 : /**
115 : * Check if the given index sequence is sorted
116 : */
117 : template <std::size_t first, std::size_t second, std::size_t... tail>
118 : constexpr bool
119 : is_sorted(std::index_sequence<first, second, tail...>)
120 : {
121 : return details::is_sorted<first, second, tail...>();
122 : }
123 :
124 : /**
125 : * A sequence of size 1 is always sorted
126 : */
127 : template <std::size_t first>
128 : constexpr bool
129 : is_sorted(std::index_sequence<first>)
130 : {
131 : return true;
132 : }
133 :
134 : /**
135 : * Compute the total number of distinct derivatives for all orders 1 through N
136 : */
137 : template <std::size_t N, std::size_t M>
138 : constexpr std::size_t
139 : total_derivatives()
140 : {
141 : // we compute derivatives of orders 0 up to and including N, and subtract 1 for
142 : // the 0th order derivative (underived original function)
143 : return details::total_derivatives<M>(std::make_index_sequence<N + 1>{}) - 1;
144 : }
145 :
146 : // shim for C++20 std::type_identity
147 : template <class T>
148 : struct type_identity
149 : {
150 : using type = T;
151 : };
152 :
153 : /**
154 : * Create a tuple with sizeof...(Ns) entries, containing CTArrayRefs with tags given by the Ns...
155 : */
156 : template <typename T, std::size_t... Ns>
157 : constexpr auto
158 : make_tuple_array(std::index_sequence<Ns...>)
159 : {
160 : // we cannot default construct the tuple, so we wrap it in the type_identity template
161 : return type_identity<std::tuple<CompileTimeDerivatives::CTArrayRef<Ns, T, unsigned int>...>>{};
162 : }
163 :
164 : /**
165 : * Create an index sequence containing N zeroes
166 : */
167 : template <std::size_t N>
168 : constexpr auto
169 551 : zeroes()
170 : {
171 551 : return details::zeroes(std::make_index_sequence<N>{});
172 : }
173 :
174 : /**
175 : * Take all derivatives of expression listed in the index sequence
176 : */
177 : template <typename T, std::size_t first, std::size_t... tags>
178 : auto
179 23040 : take_derivatives(const T & expression, std::index_sequence<first, tags...>)
180 : {
181 : if constexpr (sizeof...(tags) == 0)
182 9728 : return expression.template D<static_cast<CompileTimeDerivatives::CTTag>(first)>();
183 : else
184 13312 : return take_derivatives(
185 26624 : expression.template D<static_cast<CompileTimeDerivatives::CTTag>(first)>(),
186 26624 : std::index_sequence<tags...>{});
187 : }
188 :
189 : } // namespace CompileTimeDerivativesMaterialInternal
|