Serac  0.1
Serac is an implicit thermal strucural mechanics simulation code.
dual.hpp
Go to the documentation of this file.
1 // Copyright (c) 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 #include <cmath>
17 
19 
20 namespace serac {
21 
27 template <typename gradient_type>
28 struct dual {
29  double value;
30  gradient_type gradient;
31 
38  SERAC_HOST_DEVICE constexpr auto& operator=(double b)
39  {
40  value = b;
41  gradient = {};
42  return *this;
43  }
44 };
45 
54 template <typename T>
55 dual(double, T) -> dual<T>;
56 
58 template <typename gradient_type>
59 SERAC_HOST_DEVICE constexpr auto operator+(dual<gradient_type> a, double b)
60 {
61  return dual{a.value + b, a.gradient};
62 }
63 
65 template <typename gradient_type>
66 SERAC_HOST_DEVICE constexpr auto operator+(double a, dual<gradient_type> b)
67 {
68  return dual{a + b.value, b.gradient};
69 }
70 
72 template <typename gradient_type_a, typename gradient_type_b>
74 {
75  return dual{a.value + b.value, a.gradient + b.gradient};
76 }
77 
79 template <typename gradient_type>
80 constexpr auto operator-(dual<gradient_type> x)
81 {
82  return dual{-x.value, -x.gradient};
83 }
84 
86 template <typename gradient_type>
87 SERAC_HOST_DEVICE constexpr auto operator-(dual<gradient_type> a, double b)
88 {
89  return dual{a.value - b, a.gradient};
90 }
91 
93 template <typename gradient_type>
94 SERAC_HOST_DEVICE constexpr auto operator-(double a, dual<gradient_type> b)
95 {
96  return dual{a - b.value, -b.gradient};
97 }
98 
100 template <typename gradient_type_a, typename gradient_type_b>
102 {
103  return dual{a.value - b.value, a.gradient - b.gradient};
104 }
105 
107 template <typename gradient_type>
108 SERAC_HOST_DEVICE constexpr auto operator*(const dual<gradient_type>& a, double b)
109 {
110  return dual{a.value * b, a.gradient * b};
111 }
112 
114 template <typename gradient_type>
115 SERAC_HOST_DEVICE constexpr auto operator*(double a, const dual<gradient_type>& b)
116 {
117  return dual{a * b.value, a * b.gradient};
118 }
119 
121 template <typename gradient_type_a, typename gradient_type_b>
123 {
124  return dual{a.value * b.value, b.value * a.gradient + a.value * b.gradient};
125 }
126 
128 template <typename gradient_type>
129 SERAC_HOST_DEVICE constexpr auto operator/(const dual<gradient_type>& a, double b)
130 {
131  return dual{a.value / b, a.gradient / b};
132 }
133 
135 template <typename gradient_type>
136 SERAC_HOST_DEVICE constexpr auto operator/(double a, const dual<gradient_type>& b)
137 {
138  return dual{a / b.value, -(a / (b.value * b.value)) * b.gradient};
139 }
140 
142 template <typename gradient_type_a, typename gradient_type_b>
144 {
145  return dual{a.value / b.value, (a.gradient / b.value) - (a.value * b.gradient) / (b.value * b.value)};
146 }
147 
153 #define binary_comparator_overload(x) \
154  template <typename T> \
155  SERAC_HOST_DEVICE constexpr bool operator x(const dual<T>& a, double b) \
156  { \
157  return a.value x b; \
158  } \
159  \
160  template <typename T> \
161  SERAC_HOST_DEVICE constexpr bool operator x(double a, const dual<T>& b) \
162  { \
163  return a x b.value; \
164  }; \
165  \
166  template <typename T, typename U> \
167  SERAC_HOST_DEVICE constexpr bool operator x(const dual<T>& a, const dual<U>& b) \
168  { \
169  return a.value x b.value; \
170  };
171 
177 
178 #undef binary_comparator_overload
179 
181 template <typename gradient_type>
183 {
184  a.value += b.value;
185  a.gradient += b.gradient;
186  return a;
187 }
188 
190 template <typename gradient_type>
192 {
193  a.value -= b.value;
194  a.gradient -= b.gradient;
195  return a;
196 }
197 
199 template <typename gradient_type>
200 SERAC_HOST_DEVICE constexpr auto& operator+=(dual<gradient_type>& a, double b)
201 {
202  a.value += b;
203  return a;
204 }
205 
207 template <typename gradient_type>
208 SERAC_HOST_DEVICE constexpr auto& operator-=(dual<gradient_type>& a, double b)
209 {
210  a.value -= b;
211  return a;
212 }
213 
218 template <typename gradient_type>
220 {
221  return (x.value >= 0) ? x : -x;
222 }
223 
228 template <typename gradient_type>
230 {
231  dual<gradient_type> b_dual{b, 0.0 * a.gradient};
232  return (a > b_dual) ? a : b_dual;
233 }
234 
236 template <typename gradient_type>
238 {
239  dual<gradient_type> a_dual{a, 0.0 * b.gradient};
240  return (a_dual > b) ? a_dual : b;
241 }
242 
244 template <typename gradient_type>
246 {
247  return (a > b) ? a : b;
248 }
249 
254 template <typename gradient_type>
256 {
257  dual<gradient_type> b_dual{b, 0.0 * a.gradient};
258  return (a < b_dual) ? a : b_dual;
259 }
260 
262 template <typename gradient_type>
264 {
265  dual<gradient_type> a_dual{a, 0.0 * b.gradient};
266  return (a_dual < b) ? a_dual : b;
267 }
268 
270 template <typename gradient_type>
272 {
273  return (a < b) ? a : b;
274 }
275 
280 template <typename S, typename T>
281 SERAC_HOST_DEVICE constexpr auto inner(const dual<S>& A, const dual<T>& B)
282 {
283  return A * B;
284 }
285 
290 template <typename T>
291 SERAC_HOST_DEVICE constexpr auto inner(double A, const dual<T>& B)
292 {
293  return A * B;
294 }
295 
300 template <typename S>
301 SERAC_HOST_DEVICE constexpr auto inner(const dual<S>& A, double B)
302 {
303  return A * B;
304 }
305 
307 template <typename gradient_type>
309 {
310  using std::sqrt;
311  return dual<gradient_type>{sqrt(x.value), x.gradient / (2.0 * sqrt(x.value))};
312 }
313 
315 template <typename gradient_type>
317 {
318  using std::cos, std::sin;
319  return dual<gradient_type>{cos(a.value), -a.gradient * sin(a.value)};
320 }
321 
323 template <typename gradient_type>
325 {
326  using std::cos, std::sin;
327  return dual<gradient_type>{sin(a.value), a.gradient * cos(a.value)};
328 }
329 
331 template <typename gradient_type>
333 {
334  using std::atan, std::pow;
335  return dual<gradient_type>{atan(a.value), a.gradient / (1.0 + pow(a.value, 2))};
336 }
337 
339 template <typename gradient_type>
341 {
342  using std::atan2, std::pow;
343  return dual<gradient_type>{atan2(y.value, x.value), y.gradient * x.value / (pow(x.value, 2) + pow(y.value, 2)) -
344  x.gradient * y.value / (pow(x.value, 2) + pow(y.value, 2))};
345 }
346 
348 template <typename gradient_type>
350 {
351  using std::atan2, std::pow;
352  return dual<gradient_type>{atan2(y, x.value), -x.gradient * y / (pow(x.value, 2) + pow(y, 2))};
353 }
354 
356 template <typename gradient_type>
358 {
359  using std::atan2, std::pow;
360  return dual<gradient_type>{atan2(y.value, x), y.gradient * x / (pow(x, 2) + pow(y.value, 2))};
361 }
362 
364 template <typename gradient_type>
366 {
367  using std::asin, std::pow, std::sqrt;
368  return dual<gradient_type>{asin(a.value), a.gradient / sqrt(1.0 - pow(a.value, 2))};
369 }
370 
372 template <typename gradient_type>
374 {
375  using std::acos, std::pow, std::sqrt;
376  return dual<gradient_type>{acos(a.value), -a.gradient / sqrt(1.0 - pow(a.value, 2))};
377 }
378 
380 template <typename gradient_type>
382 {
383  using std::exp;
384  return dual<gradient_type>{exp(a.value), exp(a.value) * a.gradient};
385 }
386 
388 template <typename gradient_type>
390 {
391  using std::log;
392  return dual<gradient_type>{log(a.value), a.gradient / a.value};
393 }
394 
396 template <typename gradient_type>
398 {
399  using std::log1p;
400  return dual<gradient_type>{log1p(a.value), a.gradient / (1.0 + a.value)};
401 }
402 
404 template <typename gradient_type>
406 {
407  using std::pow, std::log;
408  double value = pow(a.value, b.value);
409  gradient_type grad = pow(a.value, b.value - 1) * (a.gradient * b.value + b.gradient * a.value * log(a.value));
410  return dual<gradient_type>{value, grad};
411 }
412 
414 template <typename gradient_type>
416 {
417  using std::pow, std::log;
418  double value = pow(a, b.value);
419  return dual<gradient_type>{value, value * b.gradient * log(a)};
420 }
421 
423 template <typename gradient_type>
425 {
426  using std::pow;
427  double value = pow(a.value, b);
428  gradient_type grad = b * pow(a.value, b - 1) * a.gradient;
429  return dual<gradient_type>{value, grad};
430 }
431 
433 template <typename T, int... n>
434 auto& operator<<(std::ostream& out, dual<T> A)
435 {
436  out << '(' << A.value << ' ' << A.gradient << ')';
437  return out;
438 }
439 
441 SERAC_HOST_DEVICE constexpr auto make_dual(double x) { return dual{x, 1.0}; }
442 
444 template <typename T>
445 SERAC_HOST_DEVICE constexpr auto get_value(const T& arg)
446 {
447  return arg;
448 }
449 
451 template <typename T>
453 {
454  return arg.value;
455 }
456 
458 template <typename gradient_type>
460 {
461  return arg.gradient;
462 }
463 
465 template <typename T>
467  static constexpr bool value = false;
468 };
469 
471 template <typename T>
472 struct is_dual_number<dual<T> > {
473  static constexpr bool value = true;
474 };
475 
476 } // namespace serac
477 
478 #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:36
constexpr SERAC_HOST_DEVICE auto inner(const dual< S > &A, const dual< T > &B)
Definition: dual.hpp:281
constexpr SERAC_HOST_DEVICE auto make_dual(double x)
promote a value to a dual number of the appropriate type
Definition: dual.hpp:441
SERAC_HOST_DEVICE auto atan2(dual< gradient_type > y, dual< gradient_type > x)
implementation of atan2 for dual numbers
Definition: dual.hpp:340
SERAC_HOST_DEVICE auto sin(dual< gradient_type > a)
implementation of sine for dual numbers
Definition: dual.hpp:324
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:108
SERAC_HOST_DEVICE auto cos(dual< gradient_type > a)
implementation of cosine for dual numbers
Definition: dual.hpp:316
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:424
Domain operator-(const Domain &a, const Domain &b)
create a new domain that is the set difference of a and b
Definition: domain.cpp:761
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:405
SERAC_HOST_DEVICE auto max(dual< gradient_type > a, double b)
Implementation of max for dual numbers.
Definition: dual.hpp:229
SERAC_HOST_DEVICE auto min(dual< gradient_type > a, double b)
Implementation of min for dual numbers.
Definition: dual.hpp:255
SERAC_HOST_DEVICE auto sqrt(dual< gradient_type > x)
implementation of square root for dual numbers
Definition: dual.hpp:308
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:59
constexpr SERAC_HOST_DEVICE auto & operator-=(dual< gradient_type > &a, const dual< gradient_type > &b)
compound assignment (-) for dual numbers
Definition: dual.hpp:191
SERAC_HOST_DEVICE auto asin(dual< gradient_type > a)
implementation of asin for dual numbers
Definition: dual.hpp:365
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:445
SERAC_HOST_DEVICE auto abs(dual< gradient_type > x)
Implementation of absolute value function for dual numbers.
Definition: dual.hpp:219
SERAC_HOST_DEVICE auto acos(dual< gradient_type > a)
implementation of acos for dual numbers
Definition: dual.hpp:373
constexpr SERAC_HOST_DEVICE auto & operator+=(dual< gradient_type > &a, const dual< gradient_type > &b)
compound assignment (+) for dual numbers
Definition: dual.hpp:182
SERAC_HOST_DEVICE auto atan(dual< gradient_type > a)
implementation of atan for dual numbers
Definition: dual.hpp:332
SERAC_HOST_DEVICE auto log(dual< gradient_type > a)
implementation of the natural logarithm function for dual numbers
Definition: dual.hpp:389
SERAC_HOST_DEVICE auto atan2(dual< gradient_type > y, double x)
implementation of atan2 for dual numbers
Definition: dual.hpp:357
constexpr SERAC_HOST_DEVICE auto get_gradient(dual< gradient_type > arg)
return the "gradient" part from a dual number type
Definition: dual.hpp:459
binary_comparator_overload(<)
implement operator< for dual numbers
std::ostream & operator<<(std::ostream &out, DoF dof)
stream output for DoF
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:129
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:397
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:381
Dual number struct (value plus gradient)
Definition: dual.hpp:28
gradient_type gradient
the partial derivatives of value w.r.t. some other quantity
Definition: dual.hpp:30
constexpr SERAC_HOST_DEVICE auto & operator=(double b)
Copy assignment operator.
Definition: dual.hpp:38
double value
the actual numerical value
Definition: dual.hpp:29
class for checking if a type is a dual number or not
Definition: dual.hpp:466
static constexpr bool value
whether or not type T is a dual number
Definition: dual.hpp:467