Math.hpp
Go to the documentation of this file.
1 // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 // vi: set et ts=4 sw=4 sts=4:
3 /*
4  Copyright (C) 2015 by Andreas Lauser
5 
6  This file is part of the Open Porous Media project (OPM).
7 
8  OPM is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 2 of the License, or
11  (at your option) any later version.
12 
13  OPM is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with OPM. If not, see <http://www.gnu.org/licenses/>.
20 */
30 #ifndef OPM_LOCAL_AD_MATH_HPP
31 #define OPM_LOCAL_AD_MATH_HPP
32 
33 #include "Evaluation.hpp"
34 
36 
37 namespace Opm {
38 namespace LocalAd {
39 // provide some algebraic functions
40 template <class Scalar, class VarSetTag, int numVars>
42 {
44 
45  result.value = std::abs(x.value);
46 
47  // derivatives use the chain rule
48  if (x.value < 0.0) {
49  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx)
50  result.derivatives[curVarIdx] = -x.derivatives[curVarIdx];
51  }
52  else {
53  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx)
54  result.derivatives[curVarIdx] = x.derivatives[curVarIdx];
55  }
56 
57  return result;
58 }
59 
60 template <class Scalar, class VarSetTag, int numVars>
63 {
65 
66  if (x1.value < x2.value) {
67  result.value = x1.value;
68 
69  std::copy(x1.derivatives.begin(),
70  x1.derivatives.end(),
71  result.derivatives.begin());
72  }
73  else {
74  result.value = x2.value;
75 
76  std::copy(x2.derivatives.begin(),
77  x2.derivatives.end(),
78  result.derivatives.begin());
79  }
80 
81  return result;
82 }
83 
84 template <class ScalarA, class Scalar, class VarSetTag, int numVars>
87 {
89 
90  if (x1 < x2.value) {
91  result.value = x1;
92 
93  std::fill(result.derivatives.begin(),
94  result.derivatives.end(),
95  0.0);
96  }
97  else {
98  result.value = x2.value;
99 
100  std::copy(x2.derivatives.begin(),
101  x2.derivatives.end(),
102  result.derivatives.begin());
103  }
104 
105  return result;
106 }
107 
108 template <class ScalarB, class Scalar, class VarSetTag, int numVars>
110  ScalarB x1)
111 { return min(x1, x2); }
112 
113 template <class Scalar, class VarSetTag, int numVars>
116 {
118 
119  if (x1.value > x2.value) {
120  result.value = x1.value;
121 
122  std::copy(x1.derivatives.begin(),
123  x1.derivatives.end(),
124  result.derivatives.begin());
125  }
126  else {
127  result.value = x2.value;
128 
129  std::copy(x2.derivatives.begin(),
130  x2.derivatives.end(),
131  result.derivatives.begin());
132  }
133 
134  return result;
135 }
136 
137 template <class ScalarA, class Scalar, class VarSetTag, int numVars>
140 {
142 
143  if (x1 > x2.value) {
144  result.value = x1;
145 
146  std::fill(result.derivatives.begin(),
147  result.derivatives.end(),
148  0.0);
149  }
150  else {
151  result.value = x2.value;
152 
153  std::copy(x2.derivatives.begin(),
154  x2.derivatives.end(),
155  result.derivatives.begin());
156  }
157 
158  return result;
159 }
160 
161 template <class ScalarB, class Scalar, class VarSetTag, int numVars>
163  ScalarB x1)
164 { return max(x1, x2); }
165 
166 template <class Scalar, class VarSetTag, int numVars>
168 {
170 
171  Scalar tmp = std::tan(x.value);
172  result.value = tmp;
173 
174  // derivatives use the chain rule
175  Scalar df_dx = 1 + tmp*tmp;
176  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx)
177  result.derivatives[curVarIdx] = df_dx*x.derivatives[curVarIdx];
178 
179  return result;
180 }
181 
182 template <class Scalar, class VarSetTag, int numVars>
184 {
186 
187  result.value = std::atan(x.value);
188 
189  // derivatives use the chain rule
190  Scalar df_dx = 1/(1 + x.value*x.value);
191  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx)
192  result.derivatives[curVarIdx] = df_dx*x.derivatives[curVarIdx];
193 
194  return result;
195 }
196 
197 template <class Scalar, class VarSetTag, int numVars>
200 {
202 
203  result.value = std::atan2(x.value, y.value);
204 
205  // derivatives use the chain rule
206  Scalar alpha = 1/(1 + (x.value*x.value)/(y.value*y.value));
207  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx) {
208  result.derivatives[curVarIdx] =
209  alpha
210  /(y.value*y.value)
211  *(x.derivatives[curVarIdx]*y.value - x.value*y.derivatives[curVarIdx]);
212  }
213 
214  return result;
215 }
216 
217 template <class Scalar, class VarSetTag, int numVars>
219 {
221 
222  result.value = std::sin(x.value);
223 
224  // derivatives use the chain rule
225  Scalar df_dx = std::cos(x.value);
226  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx)
227  result.derivatives[curVarIdx] = df_dx*x.derivatives[curVarIdx];
228 
229  return result;
230 }
231 
232 template <class Scalar, class VarSetTag, int numVars>
234 {
236 
237  result.value = std::asin(x.value);
238 
239  // derivatives use the chain rule
240  Scalar df_dx = 1.0/std::sqrt(1 - x.value*x.value);
241  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx)
242  result.derivatives[curVarIdx] = df_dx*x.derivatives[curVarIdx];
243 
244  return result;
245 }
246 
247 template <class Scalar, class VarSetTag, int numVars>
249 {
251 
252  result.value = std::cos(x.value);
253 
254  // derivatives use the chain rule
255  Scalar df_dx = -std::sin(x.value);
256  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx)
257  result.derivatives[curVarIdx] = df_dx*x.derivatives[curVarIdx];
258 
259  return result;
260 }
261 
262 template <class Scalar, class VarSetTag, int numVars>
264 {
266 
267  result.value = std::acos(x.value);
268 
269  // derivatives use the chain rule
270  Scalar df_dx = - 1.0/std::sqrt(1 - x.value*x.value);
271  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx)
272  result.derivatives[curVarIdx] = df_dx*x.derivatives[curVarIdx];
273 
274  return result;
275 }
276 
277 template <class Scalar, class VarSetTag, int numVars>
279 {
281 
282  Scalar sqrt_x = std::sqrt(x.value);
283  result.value = sqrt_x;
284 
285  // derivatives use the chain rule
286  Scalar df_dx = 0.5/sqrt_x;
287  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx) {
288  result.derivatives[curVarIdx] = df_dx*x.derivatives[curVarIdx];
289  }
290 
291  return result;
292 }
293 
294 template <class Scalar, class VarSetTag, int numVars>
296 {
298 
299  Scalar exp_x = std::exp(x.value);
300  result.value = exp_x;
301 
302  // derivatives use the chain rule
303  Scalar df_dx = exp_x;
304  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx)
305  result.derivatives[curVarIdx] = df_dx*x.derivatives[curVarIdx];
306 
307  return result;
308 }
309 
310 // exponentiation of arbitrary base with a fixed constant
311 template <class Scalar, class VarSetTag, int numVars>
313 {
315 
316  Scalar pow_x = std::pow(base.value, exp);
317  result.value = pow_x;
318 
319  // derivatives use the chain rule
320  Scalar df_dx = pow_x/base.value*exp;
321  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx)
322  result.derivatives[curVarIdx] = df_dx*base.derivatives[curVarIdx];
323 
324  return result;
325 }
326 
327 // exponentiation of constant base with an arbitrary exponent
328 template <class Scalar, class VarSetTag, int numVars>
330 {
332 
333  Scalar lnBase = std::log(base);
334  result.value = std::exp(lnBase*exp.value);
335 
336  // derivatives use the chain rule
337  Scalar df_dx = lnBase*result.value;
338  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx)
339  result.derivatives[curVarIdx] = df_dx*exp.derivatives[curVarIdx];
340 
341  return result;
342 }
343 
344 // this is the most expensive power function. Computationally it is pretty expensive, so
345 // one of the above two variants above should be preferred if possible.
346 template <class Scalar, class VarSetTag, int numVars>
348 {
350 
351  Scalar valuePow = std::pow(base.value, exp.value);
352  result.value = valuePow;
353 
354  // use the chain rule for the derivatives. since both, the base and the exponent can
355  // potentially depend on the variable set, calculating these is quite elaborate...
356  Scalar f = base.value;
357  Scalar g = exp.value;
358  Scalar logF = std::log(f);
359  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx) {
360  Scalar fPrime = base.derivatives[curVarIdx];
361  Scalar gPrime = exp.derivatives[curVarIdx];
362  result.derivatives[curVarIdx] = (g*fPrime/f + logF*gPrime) * valuePow;
363  }
364 
365  return result;
366 }
367 
368 template <class Scalar, class VarSetTag, int numVars>
370 {
372 
373  result.value = std::log(x.value);
374 
375  // derivatives use the chain rule
376  Scalar df_dx = 1/x.value;
377  for (unsigned curVarIdx = 0; curVarIdx < result.derivatives.size(); ++curVarIdx)
378  result.derivatives[curVarIdx] = df_dx*x.derivatives[curVarIdx];
379 
380  return result;
381 }
382 
383 } // namespace LocalAd
384 
385 // a kind of traits class for the automatic differentiation case. (The toolbox for the
386 // scalar case is provided by the MathToolbox.hpp header file.)
387 template <class ScalarT, class VariableSetTag, int numVars>
388 struct MathToolbox<Opm::LocalAd::Evaluation<ScalarT, VariableSetTag, numVars>, false>
389 {
390 private:
391 public:
392  typedef ScalarT Scalar;
394 
395  static Scalar value(const Evaluation& eval)
396  { return eval.value; }
397 
398  static Evaluation createConstant(Scalar value)
399  { return Evaluation::createConstant(value); }
400 
401  static Evaluation createVariable(Scalar value, int varIdx)
402  { return Evaluation::createVariable(value, varIdx); }
403 
404  template <class LhsEval>
405  static LhsEval toLhs(const Evaluation& eval)
407 
408  static const Evaluation passThroughOrCreateConstant(Scalar value)
409  { return createConstant(value); }
410 
411  static const Evaluation& passThroughOrCreateConstant(const Evaluation& eval)
412  { return eval; }
413 
414 
415  // arithmetic functions
416  template <class Arg1Eval, class Arg2Eval>
417  static Evaluation max(const Arg1Eval& arg1, const Arg2Eval& arg2)
418  { return Opm::LocalAd::max(arg1, arg2); }
419 
420  template <class Arg1Eval, class Arg2Eval>
421  static Evaluation min(const Arg1Eval& arg1, const Arg2Eval& arg2)
422  { return Opm::LocalAd::min(arg1, arg2); }
423 
424  static Evaluation abs(const Evaluation& arg)
425  { return Opm::LocalAd::abs(arg); }
426 
427  static Evaluation tan(const Evaluation& arg)
428  { return Opm::LocalAd::tan(arg); }
429 
430  static Evaluation atan(const Evaluation& arg)
431  { return Opm::LocalAd::atan(arg); }
432 
433  static Evaluation atan2(const Evaluation& arg1, const Evaluation& arg2)
434  { return Opm::LocalAd::atan2(arg1, arg2); }
435 
436  static Evaluation sin(const Evaluation& arg)
437  { return Opm::LocalAd::sin(arg); }
438 
439  static Evaluation asin(const Evaluation& arg)
440  { return Opm::LocalAd::asin(arg); }
441 
442  static Evaluation cos(const Evaluation& arg)
443  { return Opm::LocalAd::cos(arg); }
444 
445  static Evaluation acos(const Evaluation& arg)
446  { return Opm::LocalAd::acos(arg); }
447 
448  static Evaluation sqrt(const Evaluation& arg)
449  { return Opm::LocalAd::sqrt(arg); }
450 
451  static Evaluation exp(const Evaluation& arg)
452  { return Opm::LocalAd::exp(arg); }
453 
454  static Evaluation log(const Evaluation& arg)
455  { return Opm::LocalAd::log(arg); }
456 
457  static Evaluation pow(const Evaluation& arg1, typename Evaluation::Scalar arg2)
458  { return Opm::LocalAd::pow(arg1, arg2); }
459 
460  static Evaluation pow(typename Evaluation::Scalar arg1, const Evaluation& arg2)
461  { return Opm::LocalAd::pow(arg1, arg2); }
462 
463  static Evaluation pow(const Evaluation& arg1, const Evaluation& arg2)
464  { return Opm::LocalAd::pow(arg1, arg2); }
465 };
466 
467 }
468 
469 #endif
static Scalar value(const Evaluation &eval)
Definition: Math.hpp:395
std::array< Scalar, size > derivatives
Definition: Evaluation.hpp:342
static LhsEval toLhs(const Evaluation &eval)
Definition: Math.hpp:405
Definition: MathToolbox.hpp:39
Definition: Air_Mesitylene.hpp:31
static Evaluation max(const Arg1Eval &arg1, const Arg2Eval &arg2)
Definition: Math.hpp:417
static Evaluation pow(const Evaluation &arg1, const Evaluation &arg2)
Definition: Math.hpp:463
Evaluation< Scalar, VarSetTag, numVars > max(const Evaluation< Scalar, VarSetTag, numVars > &x1, const Evaluation< Scalar, VarSetTag, numVars > &x2)
Definition: Math.hpp:114
Evaluation< Scalar, VarSetTag, numVars > sqrt(const Evaluation< Scalar, VarSetTag, numVars > &x)
Definition: Math.hpp:278
Evaluation< Scalar, VarSetTag, numVars > cos(const Evaluation< Scalar, VarSetTag, numVars > &x)
Definition: Math.hpp:248
Scalar value
Definition: Evaluation.hpp:341
Evaluation< Scalar, VarSetTag, numVars > atan2(const Evaluation< Scalar, VarSetTag, numVars > &x, const Evaluation< Scalar, VarSetTag, numVars > &y)
Definition: Math.hpp:198
static Evaluation asin(const Evaluation &arg)
Definition: Math.hpp:439
static Evaluation pow(const Evaluation &arg1, typename Evaluation::Scalar arg2)
Definition: Math.hpp:457
static Evaluation atan(const Evaluation &arg)
Definition: Math.hpp:430
static Evaluation abs(const Evaluation &arg)
Definition: Math.hpp:424
static Evaluation pow(typename Evaluation::Scalar arg1, const Evaluation &arg2)
Definition: Math.hpp:460
Evaluation< Scalar, VarSetTag, numVars > atan(const Evaluation< Scalar, VarSetTag, numVars > &x)
Definition: Math.hpp:183
Opm::LocalAd::Evaluation< ScalarT, VariableSetTag, numVars > Evaluation
Definition: Math.hpp:393
static Evaluation sqrt(const Evaluation &arg)
Definition: Math.hpp:448
Evaluation< Scalar, VarSetTag, numVars > pow(const Evaluation< Scalar, VarSetTag, numVars > &base, const Evaluation< Scalar, VarSetTag, numVars > &exp)
Definition: Math.hpp:347
Evaluation< Scalar, VarSetTag, numVars > log(const Evaluation< Scalar, VarSetTag, numVars > &x)
Definition: Math.hpp:369
Evaluation< Scalar, VarSetTag, numVars > exp(const Evaluation< Scalar, VarSetTag, numVars > &x)
Definition: Math.hpp:295
static Evaluation cos(const Evaluation &arg)
Definition: Math.hpp:442
static Evaluation sin(const Evaluation &arg)
Definition: Math.hpp:436
Evaluation< Scalar, VarSetTag, numVars > abs(const Evaluation< Scalar, VarSetTag, numVars > &)
Definition: Math.hpp:41
static Evaluation createVariable(Scalar value, int varIdx)
Definition: Math.hpp:401
static const Evaluation passThroughOrCreateConstant(Scalar value)
Definition: Math.hpp:408
Evaluation< Scalar, VarSetTag, numVars > min(const Evaluation< Scalar, VarSetTag, numVars > &x1, const Evaluation< Scalar, VarSetTag, numVars > &x2)
Definition: Math.hpp:61
static Evaluation tan(const Evaluation &arg)
Definition: Math.hpp:427
static Evaluation acos(const Evaluation &arg)
Definition: Math.hpp:445
static Evaluation createConstant(Scalar value)
Definition: Math.hpp:398
static Evaluation min(const Arg1Eval &arg1, const Arg2Eval &arg2)
Definition: Math.hpp:421
Evaluation< Scalar, VarSetTag, numVars > asin(const Evaluation< Scalar, VarSetTag, numVars > &x)
Definition: Math.hpp:233
Definition: MathToolbox.hpp:44
static Evaluation log(const Evaluation &arg)
Definition: Math.hpp:454
ScalarT Scalar
Definition: Evaluation.hpp:47
Evaluation< Scalar, VarSetTag, numVars > sin(const Evaluation< Scalar, VarSetTag, numVars > &x)
Definition: Math.hpp:218
Evaluation< Scalar, VarSetTag, numVars > pow(const Evaluation< Scalar, VarSetTag, numVars > &base, Scalar exp)
Definition: Math.hpp:312
Represents a function evaluation and its derivatives w.r.t. a fixed set of variables.
Definition: Evaluation.hpp:44
static Evaluation exp(const Evaluation &arg)
Definition: Math.hpp:451
static const Evaluation & passThroughOrCreateConstant(const Evaluation &eval)
Definition: Math.hpp:411
Evaluation< Scalar, VarSetTag, numVars > tan(const Evaluation< Scalar, VarSetTag, numVars > &x)
Definition: Math.hpp:167
static Evaluation atan2(const Evaluation &arg1, const Evaluation &arg2)
Definition: Math.hpp:433
Evaluation< Scalar, VarSetTag, numVars > acos(const Evaluation< Scalar, VarSetTag, numVars > &x)
Definition: Math.hpp:263
Representation of an evaluation of a function and its derivatives w.r.t. a set of variables in the lo...
A traits class which provides basic mathematical functions for arbitrary scalar floating point values...