Serac  0.1
Serac is an implicit thermal strucural mechanics simulation code.
dual.hpp
Go to the documentation of this file.
1 // Copyright (c) 2019-2024, Lawrence Livermore National Security, LLC and
2 // other Serac Project Developers. See the top-level LICENSE file for
3 // details.
4 //
5 // SPDX-License-Identifier: (BSD-3-Clause)
6 
13 #pragma once
14 
15 #include <iostream>
16 
17 #include <cmath>
18 
20 
21 namespace serac {
22 
28 template <typename gradient_type>
29 struct dual {
30  double value;
31  gradient_type gradient;
32 
39  SERAC_HOST_DEVICE constexpr auto& operator=(double b)
40  {
41  value = b;
42  gradient = {};
43  return *this;
44  }
45 };
46 
55 template <typename T>
56 dual(double, T) -> dual<T>;
57 
59 template <typename gradient_type>
60 SERAC_HOST_DEVICE constexpr auto operator+(dual<gradient_type> a, double b)
61 {
62  return dual{a.value + b, a.gradient};
63 }
64 
66 template <typename gradient_type>
67 SERAC_HOST_DEVICE constexpr auto operator+(double a, dual<gradient_type> b)
68 {
69  return dual{a + b.value, b.gradient};
70 }
71 
73 template <typename gradient_type_a, typename gradient_type_b>
75 {
76  return dual{a.value + b.value, a.gradient + b.gradient};
77 }
78 
80 template <typename gradient_type>
81 constexpr auto operator-(dual<gradient_type> x)
82 {
83  return dual{-x.value, -x.gradient};
84 }
85 
87 template <typename gradient_type>
88 SERAC_HOST_DEVICE constexpr auto operator-(dual<gradient_type> a, double b)
89 {
90  return dual{a.value - b, a.gradient};
91 }
92 
94 template <typename gradient_type>
95 SERAC_HOST_DEVICE constexpr auto operator-(double a, dual<gradient_type> b)
96 {
97  return dual{a - b.value, -b.gradient};
98 }
99 
101 template <typename gradient_type_a, typename gradient_type_b>
103 {
104  return dual{a.value - b.value, a.gradient - b.gradient};
105 }
106 
108 template <typename gradient_type>
109 SERAC_HOST_DEVICE constexpr auto operator*(const dual<gradient_type>& a, double b)
110 {
111  return dual{a.value * b, a.gradient * b};
112 }
113 
115 template <typename gradient_type>
116 SERAC_HOST_DEVICE constexpr auto operator*(double a, const dual<gradient_type>& b)
117 {
118  return dual{a * b.value, a * b.gradient};
119 }
120 
122 template <typename gradient_type_a, typename gradient_type_b>
124 {
125  return dual{a.value * b.value, b.value * a.gradient + a.value * b.gradient};
126 }
127 
129 template <typename gradient_type>
130 SERAC_HOST_DEVICE constexpr auto operator/(const dual<gradient_type>& a, double b)
131 {
132  return dual{a.value / b, a.gradient / b};
133 }
134 
136 template <typename gradient_type>
137 SERAC_HOST_DEVICE constexpr auto operator/(double a, const dual<gradient_type>& b)
138 {
139  return dual{a / b.value, -(a / (b.value * b.value)) * b.gradient};
140 }
141 
143 template <typename gradient_type_a, typename gradient_type_b>
145 {
146  return dual{a.value / b.value, (a.gradient / b.value) - (a.value * b.gradient) / (b.value * b.value)};
147 }
148 
154 #define binary_comparator_overload(x) \
155  template <typename T> \
156  SERAC_HOST_DEVICE constexpr bool operator x(const dual<T>& a, double b) \
157  { \
158  return a.value x b; \
159  } \
160  \
161  template <typename T> \
162  SERAC_HOST_DEVICE constexpr bool operator x(double a, const dual<T>& b) \
163  { \
164  return a x b.value; \
165  }; \
166  \
167  template <typename T, typename U> \
168  SERAC_HOST_DEVICE constexpr bool operator x(const dual<T>& a, const dual<U>& b) \
169  { \
170  return a.value x b.value; \
171  };
172 
178 
179 #undef binary_comparator_overload
180 
182 template <typename gradient_type>
184 {
185  a.value += b.value;
186  a.gradient += b.gradient;
187  return a;
188 }
189 
191 template <typename gradient_type>
193 {
194  a.value -= b.value;
195  a.gradient -= b.gradient;
196  return a;
197 }
198 
200 template <typename gradient_type>
201 SERAC_HOST_DEVICE constexpr auto& operator+=(dual<gradient_type>& a, double b)
202 {
203  a.value += b;
204  return a;
205 }
206 
208 template <typename gradient_type>
209 SERAC_HOST_DEVICE constexpr auto& operator-=(dual<gradient_type>& a, double b)
210 {
211  a.value -= b;
212  return a;
213 }
214 
219 template <typename gradient_type>
221 {
222  return (x.value >= 0) ? x : -x;
223 }
224 
229 template <typename gradient_type>
231 {
232  dual<gradient_type> b_dual{b, 0.0 * a.gradient};
233  return (a > b_dual) ? a : b_dual;
234 }
235 
237 template <typename gradient_type>
239 {
240  dual<gradient_type> a_dual{a, 0.0 * b.gradient};
241  return (a_dual > b) ? a_dual : b;
242 }
243 
245 template <typename gradient_type>
247 {
248  return (a > b) ? a : b;
249 }
250 
255 template <typename gradient_type>
257 {
258  dual<gradient_type> b_dual{b, 0.0 * a.gradient};
259  return (a < b_dual) ? a : b_dual;
260 }
261 
263 template <typename gradient_type>
265 {
266  dual<gradient_type> a_dual{a, 0.0 * b.gradient};
267  return (a_dual < b) ? a_dual : b;
268 }
269 
271 template <typename gradient_type>
273 {
274  return (a < b) ? a : b;
275 }
276 
278 template <typename gradient_type>
280 {
281  using std::sqrt;
282  return dual<gradient_type>{sqrt(x.value), x.gradient / (2.0 * sqrt(x.value))};
283 }
284 
286 template <typename gradient_type>
288 {
289  using std::cos, std::sin;
290  return dual<gradient_type>{cos(a.value), -a.gradient * sin(a.value)};
291 }
292 
294 template <typename gradient_type>
296 {
297  using std::cos, std::sin;
298  return dual<gradient_type>{sin(a.value), a.gradient * cos(a.value)};
299 }
300 
302 template <typename gradient_type>
304 {
305  using std::atan, std::pow;
306  return dual<gradient_type>{atan(a.value), a.gradient / (1.0 + pow(a.value, 2))};
307 }
308 
310 template <typename gradient_type>
312 {
313  using std::atan2, std::pow;
314  return dual<gradient_type>{atan2(y.value, x.value), y.gradient * x.value / (pow(x.value, 2) + pow(y.value, 2)) -
315  x.gradient * y.value / (pow(x.value, 2) + pow(y.value, 2))};
316 }
317 
319 template <typename gradient_type>
321 {
322  using std::atan2, std::pow;
323  return dual<gradient_type>{atan2(y, x.value), -x.gradient * y / (pow(x.value, 2) + pow(y, 2))};
324 }
325 
327 template <typename gradient_type>
329 {
330  using std::atan2, std::pow;
331  return dual<gradient_type>{atan2(y.value, x), y.gradient * x / (pow(x, 2) + pow(y.value, 2))};
332 }
333 
335 template <typename gradient_type>
337 {
338  using std::asin, std::pow, std::sqrt;
339  return dual<gradient_type>{asin(a.value), a.gradient / sqrt(1.0 - pow(a.value, 2))};
340 }
341 
343 template <typename gradient_type>
345 {
346  using std::acos, std::pow, std::sqrt;
347  return dual<gradient_type>{acos(a.value), -a.gradient / sqrt(1.0 - pow(a.value, 2))};
348 }
349 
351 template <typename gradient_type>
353 {
354  using std::exp;
355  return dual<gradient_type>{exp(a.value), exp(a.value) * a.gradient};
356 }
357 
359 template <typename gradient_type>
361 {
362  using std::log;
363  return dual<gradient_type>{log(a.value), a.gradient / a.value};
364 }
365 
367 template <typename gradient_type>
369 {
370  using std::log1p;
371  return dual<gradient_type>{log1p(a.value), a.gradient / (1.0 + a.value)};
372 }
373 
375 template <typename gradient_type>
377 {
378  using std::pow, std::log;
379  double value = pow(a.value, b.value);
380  gradient_type grad = pow(a.value, b.value - 1) * (a.gradient * b.value + b.gradient * a.value * log(a.value));
381  return dual<gradient_type>{value, grad};
382 }
383 
385 template <typename gradient_type>
387 {
388  using std::pow, std::log;
389  double value = pow(a, b.value);
390  return dual<gradient_type>{value, value * b.gradient * log(a)};
391 }
392 
394 template <typename gradient_type>
396 {
397  using std::pow;
398  double value = pow(a.value, b);
399  gradient_type grad = b * pow(a.value, b - 1) * a.gradient;
400  return dual<gradient_type>{value, grad};
401 }
402 
404 template <typename T, int... n>
405 auto& operator<<(std::ostream& out, dual<T> A)
406 {
407  out << '(' << A.value << ' ' << A.gradient << ')';
408  return out;
409 }
410 
412 SERAC_HOST_DEVICE constexpr auto make_dual(double x) { return dual{x, 1.0}; }
413 
415 template <typename T>
416 SERAC_HOST_DEVICE constexpr auto get_value(const T& arg)
417 {
418  return arg;
419 }
420 
422 template <typename T>
424 {
425  return arg.value;
426 }
427 
429 template <typename gradient_type>
431 {
432  return arg.gradient;
433 }
434 
436 template <typename T>
438  static constexpr bool value = false;
439 };
440 
442 template <typename T>
443 struct is_dual_number<dual<T> > {
444  static constexpr bool value = true;
445 };
446 
447 } // namespace serac
448 
449 #include "serac/numerics/functional/tuple_tensor_dual_functions.hpp"
This file contains the interface used for initializing/terminating any hardware accelerator-related f...
#define SERAC_HOST_DEVICE
Macro that evaluates to __host__ __device__ when compiling with nvcc and does nothing on a host compi...
Definition: accelerator.hpp:38
Accelerator functionality.
Definition: serac.cpp:38
constexpr SERAC_HOST_DEVICE auto make_dual(double x)
promote a value to a dual number of the appropriate type
Definition: dual.hpp:412
SERAC_HOST_DEVICE auto atan2(dual< gradient_type > y, dual< gradient_type > x)
implementation of atan2 for dual numbers
Definition: dual.hpp:311
SERAC_HOST_DEVICE auto sin(dual< gradient_type > a)
implementation of sine for dual numbers
Definition: dual.hpp:295
constexpr SERAC_HOST_DEVICE auto operator*(const dual< gradient_type > &a, double b)
multiplication of a dual number and a non-dual number
Definition: dual.hpp:109
SERAC_HOST_DEVICE auto cos(dual< gradient_type > a)
implementation of cosine for dual numbers
Definition: dual.hpp:287
SERAC_HOST_DEVICE auto pow(dual< gradient_type > a, double b)
implementation of a (dual) raised to the b (non-dual) power
Definition: dual.hpp:395
Domain operator-(const Domain &a, const Domain &b)
create a new domain that is the set difference of a and b
Definition: domain.cpp:500
SERAC_HOST_DEVICE auto pow(dual< gradient_type > a, dual< gradient_type > b)
implementation of a (dual) raised to the b (dual) power
Definition: dual.hpp:376
SERAC_HOST_DEVICE auto max(dual< gradient_type > a, double b)
Implementation of max for dual numbers.
Definition: dual.hpp:230
SERAC_HOST_DEVICE auto min(dual< gradient_type > a, double b)
Implementation of min for dual numbers.
Definition: dual.hpp:256
SERAC_HOST_DEVICE auto sqrt(dual< gradient_type > x)
implementation of square root for dual numbers
Definition: dual.hpp:279
constexpr SERAC_HOST_DEVICE auto operator+(dual< gradient_type > a, double b)
addition of a dual number and a non-dual number
Definition: dual.hpp:60
constexpr SERAC_HOST_DEVICE auto & operator-=(dual< gradient_type > &a, const dual< gradient_type > &b)
compound assignment (-) for dual numbers
Definition: dual.hpp:192
SERAC_HOST_DEVICE auto asin(dual< gradient_type > a)
implementation of asin for dual numbers
Definition: dual.hpp:336
constexpr SERAC_HOST_DEVICE auto get_value(const T &arg)
return the "value" part from a given type. For non-dual types, this is just the identity function
Definition: dual.hpp:416
auto & operator<<(std::ostream &out, dual< T > A)
overload of operator<< for dual to work with std::cout and other std::ostreams
Definition: dual.hpp:405
SERAC_HOST_DEVICE auto abs(dual< gradient_type > x)
Implementation of absolute value function for dual numbers.
Definition: dual.hpp:220
SERAC_HOST_DEVICE auto acos(dual< gradient_type > a)
implementation of acos for dual numbers
Definition: dual.hpp:344
constexpr SERAC_HOST_DEVICE auto & operator+=(dual< gradient_type > &a, const dual< gradient_type > &b)
compound assignment (+) for dual numbers
Definition: dual.hpp:183
SERAC_HOST_DEVICE auto atan(dual< gradient_type > a)
implementation of atan for dual numbers
Definition: dual.hpp:303
SERAC_HOST_DEVICE auto log(dual< gradient_type > a)
implementation of the natural logarithm function for dual numbers
Definition: dual.hpp:360
SERAC_HOST_DEVICE auto atan2(dual< gradient_type > y, double x)
implementation of atan2 for dual numbers
Definition: dual.hpp:328
constexpr SERAC_HOST_DEVICE auto get_gradient(dual< gradient_type > arg)
return the "gradient" part from a dual number type
Definition: dual.hpp:430
binary_comparator_overload(<)
implement operator< for dual numbers
constexpr SERAC_HOST_DEVICE auto operator/(const dual< gradient_type > &a, double b)
division of a dual number by a non-dual number
Definition: dual.hpp:130
SERAC_HOST_DEVICE auto log1p(dual< gradient_type > a)
implementation of the natural logarithm of one plus the argument function for dual numbers
Definition: dual.hpp:368
dual(double, T) -> dual< T >
class template argument deduction guide for type dual.
SERAC_HOST_DEVICE auto exp(dual< gradient_type > a)
implementation of exponential function for dual numbers
Definition: dual.hpp:352
Dual number struct (value plus gradient)
Definition: dual.hpp:29
gradient_type gradient
the partial derivatives of value w.r.t. some other quantity
Definition: dual.hpp:31
constexpr SERAC_HOST_DEVICE auto & operator=(double b)
Copy assignment operator.
Definition: dual.hpp:39
double value
the actual numerical value
Definition: dual.hpp:30
class for checking if a type is a dual number or not
Definition: dual.hpp:437
static constexpr bool value
whether or not type T is a dual number
Definition: dual.hpp:438