Evaluation.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 */
27 #ifndef OPM_LOCAL_AD_EVALUATION_HPP
28 #define OPM_LOCAL_AD_EVALUATION_HPP
29 
30 #include <iostream>
31 #include <array>
32 #include <cassert>
34 
35 #include <dune/common/version.hh>
36 
37 namespace Opm {
38 namespace LocalAd {
43 template <class ScalarT, class VarSetTag, int numVars>
45 {
46 public:
47  typedef ScalarT Scalar;
48 
49  enum { size = numVars };
50 
52  {}
53 
54  // copy other function evaluation
55  Evaluation(const Evaluation& other)
56  {
57  // copy evaluated function value and derivatives
58  value = other.value;
59  std::copy(other.derivatives.begin(), other.derivatives.end(), derivatives.begin());
60  }
61 
62  // create an evaluation which represents a constant function
63  //
64  // i.e., f(x) = c. this implies an evaluation with the given value and all
65  // derivatives being zero.
66  Evaluation(Scalar c)
67  {
68  value = c;
69  std::fill(derivatives.begin(), derivatives.end(), 0.0);
70  }
71 
72  // create a function evaluation for a "naked" depending variable (i.e., f(x) = x)
73  static Evaluation createVariable(Scalar value, unsigned varPos)
74  {
75  // The variable position must be in represented by the given variable descriptor
76  assert(0 <= varPos && varPos < size);
77 
78  Evaluation result;
79 
80  // copy function value and set all derivatives to 0, except for the variable
81  // which is represented by the value (which is set to 1.0)
82  result.value = value;
83  std::fill(result.derivatives.begin(), result.derivatives.end(), 0.0);
84  result.derivatives[varPos] = 1.0;
85 
86  return result;
87  }
88 
89  // "evaluate" a constant function (i.e. a function that does not depend on the set of
90  // relevant variables, f(x) = c).
92  {
93  Evaluation result;
94  result.value = value;
95  std::fill(result.derivatives.begin(), result.derivatives.end(), 0.0);
98  return result;
99  }
100 
101  // print the value and the derivatives of the function evaluation
102  void print(std::ostream& os = std::cout) const
103  {
104  os << "v: " << value << " / d:";
105  for (int varIdx = 0; varIdx < derivatives.size(); ++varIdx)
106  os << " " << derivatives[varIdx];
107  }
108 
109 
111  {
112  // value and derivatives are added
113  this->value += other.value;
114  for (unsigned varIdx = 0; varIdx < size; ++varIdx)
115  this->derivatives[varIdx] += other.derivatives[varIdx];
116 
117  return *this;
118  }
119 
120  Evaluation& operator+=(Scalar other)
121  {
122  // value is added, derivatives stay the same
123  this->value += other;
124 
125  return *this;
126  }
127 
129  {
130  // value and derivatives are subtracted
131  this->value -= other.value;
132  for (unsigned varIdx = 0; varIdx < size; ++varIdx)
133  this->derivatives[varIdx] -= other.derivatives[varIdx];
134 
135  return *this;
136  }
137 
138  Evaluation& operator-=(Scalar other)
139  {
140  // for constants, values are subtracted, derivatives stay the same
141  this->value -= other;
142 
143  return *this;
144  }
145 
147  {
148  // while the values are multiplied, the derivatives follow the product rule,
149  // i.e., (u*v)' = (v'u + u'v).
150  Scalar u = this->value;
151  Scalar v = other.value;
152  this->value *= v;
153  for (unsigned varIdx = 0; varIdx < size; ++varIdx) {
154  Scalar uPrime = this->derivatives[varIdx];
155  Scalar vPrime = other.derivatives[varIdx];
156 
157  this->derivatives[varIdx] = (v*uPrime + u*vPrime);
158  }
159 
160  return *this;
161  }
162 
163  Evaluation& operator*=(Scalar other)
164  {
165  // values and derivatives are multiplied
166  this->value *= other;
167  for (unsigned varIdx = 0; varIdx < size; ++varIdx)
168  this->derivatives[varIdx] *= other;
169 
170  return *this;
171  }
172 
174  {
175  // values are divided, derivatives follow the rule for division, i.e., (u/v)' = (v'u -
176  // u'v)/v^2.
177  Scalar u = this->value;
178  Scalar v = other.value;
179  this->value /= v;
180  for (unsigned varIdx = 0; varIdx < size; ++varIdx) {
181  Scalar uPrime = this->derivatives[varIdx];
182  Scalar vPrime = other.derivatives[varIdx];
183 
184  this->derivatives[varIdx] = (v*uPrime - u*vPrime)/(v*v);
185  }
186 
187  return *this;
188  }
189 
190  Evaluation& operator/=(Scalar other)
191  {
192  // values and derivatives are divided
193  other = 1.0/other;
194  this->value *= other;
195  for (unsigned varIdx = 0; varIdx < size; ++varIdx)
196  this->derivatives[varIdx] *= other;
197 
198  return *this;
199  }
200 
201  Evaluation operator+(const Evaluation& other) const
202  {
203  Evaluation result(*this);
204  result += other;
205  return result;
206  }
207 
208  Evaluation operator+(Scalar other) const
209  {
210  Evaluation result(*this);
211  result += other;
212  return result;
213  }
214 
215  Evaluation operator-(const Evaluation& other) const
216  {
217  Evaluation result(*this);
218  result -= other;
219  return result;
220  }
221 
222  Evaluation operator-(Scalar other) const
223  {
224  Evaluation result(*this);
225  result -= other;
226  return result;
227  }
228 
229  // negation (unary minus) operator
231  {
232  Evaluation result;
233  result.value = -this->value;
234  for (unsigned varIdx = 0; varIdx < size; ++varIdx)
235  result.derivatives[varIdx] = - this->derivatives[varIdx];
236 
237  return result;
238  }
239 
240  Evaluation operator*(const Evaluation& other) const
241  {
242  Evaluation result(*this);
243  result *= other;
244  return result;
245  }
246 
247  Evaluation operator*(Scalar other) const
248  {
249  Evaluation result(*this);
250  result *= other;
251  return result;
252  }
253 
254  Evaluation operator/(const Evaluation& other) const
255  {
256  Evaluation result(*this);
257  result /= other;
258  return result;
259  }
260 
261  Evaluation operator/(Scalar other) const
262  {
263  Evaluation result(*this);
264  result /= other;
265  return result;
266  }
267 
268  Evaluation& operator=(Scalar other)
269  {
270  this->value = other;
271  std::fill(this->derivatives.begin(), this->derivatives.end(), 0.0);
272  return *this;
273  }
274 
275  // copy assignment from evaluation
277  {
278  this->value = other.value;
279  std::copy(other.derivatives.begin(), other.derivatives.end(), this->derivatives.begin());
280  return *this;
281  }
282 
283  bool operator==(Scalar other) const
284  { return this->value == other; }
285 
286  bool operator==(const Evaluation& other) const
287  {
288  if (this->value != other.value)
289  return false;
290 
291  for (unsigned varIdx = 0; varIdx < size; ++varIdx)
292  if (this->derivatives[varIdx] != other.derivatives[varIdx])
293  return false;
294 
295  return true;
296  }
297 
298  bool isSame(const Evaluation& other, Scalar tolerance) const
299  {
300  Scalar value_diff = other.value - other.value;
301  if (std::abs(value_diff) > tolerance && std::abs(value_diff)/tolerance > 1.0)
302  return false;
303 
304  for (unsigned varIdx = 0; varIdx < size; ++varIdx) {
305  Scalar deriv_diff = other.derivatives[varIdx] - this->derivatives[varIdx];
306  if (std::abs(deriv_diff) > tolerance && std::abs(deriv_diff)/tolerance > 1.0)
307  return false;
308  }
309 
310  return true;
311  }
312 
313  bool operator!=(const Evaluation& other) const
314  { return !operator==(other); }
315 
316  bool operator>(Scalar other) const
317  { return this->value > other; }
318 
319  bool operator>(const Evaluation& other) const
320  { return this->value > other.value; }
321 
322  bool operator<(Scalar other) const
323  { return this->value < other; }
324 
325  bool operator<(const Evaluation& other) const
326  { return this->value < other.value; }
327 
328  bool operator>=(Scalar other) const
329  { return this->value >= other; }
330 
331  bool operator>=(const Evaluation& other) const
332  { return this->value >= other.value; }
333 
334  bool operator<=(Scalar other) const
335  { return this->value <= other; }
336 
337  bool operator<=(const Evaluation& other) const
338  { return this->value <= other.value; }
339 
340  // maybe this should be made 'private'...
341  Scalar value;
342  std::array<Scalar, size> derivatives;
343 };
344 
345 template <class ScalarA, class Scalar, class VarSetTag, int numVars>
346 bool operator<(const ScalarA& a, const Evaluation<Scalar, VarSetTag, numVars> &b)
347 { return b > a; }
348 
349 template <class ScalarA, class Scalar, class VarSetTag, int numVars>
350 bool operator>(const ScalarA& a, const Evaluation<Scalar, VarSetTag, numVars> &b)
351 { return b < a; }
352 
353 template <class ScalarA, class Scalar, class VarSetTag, int numVars>
354 bool operator<=(const ScalarA& a, const Evaluation<Scalar, VarSetTag, numVars> &b)
355 { return b >= a; }
356 
357 template <class ScalarA, class Scalar, class VarSetTag, int numVars>
358 bool operator>=(const ScalarA& a, const Evaluation<Scalar, VarSetTag, numVars> &b)
359 { return b <= a; }
360 
361 template <class ScalarA, class Scalar, class VarSetTag, int numVars>
362 bool operator!=(const ScalarA& a, const Evaluation<Scalar, VarSetTag, numVars> &b)
363 { return a != b.value; }
364 
365 template <class ScalarA, class Scalar, class VarSetTag, int numVars>
367 {
369 
370  result += a;
371 
372  return result;
373 }
374 
375 template <class ScalarA, class Scalar, class VarSetTag, int numVars>
377 {
379 
380  result.value = a - b.value;
381  for (unsigned varIdx = 0; varIdx < numVars; ++varIdx)
382  result.derivatives[varIdx] = - b.derivatives[varIdx];
383 
384  return result;
385 }
386 
387 template <class ScalarA, class Scalar, class VarSetTag, int numVars>
389 {
391 
392  result.value = a/b.value;
393 
394  // outer derivative
395  Scalar df_dg = - a/(b.value*b.value);
396  for (unsigned varIdx = 0; varIdx < numVars; ++varIdx)
397  result.derivatives[varIdx] = df_dg*b.derivatives[varIdx];
398 
399  return result;
400 }
401 
402 template <class ScalarA, class Scalar, class VarSetTag, int numVars>
404 {
406 
407  result.value = a*b.value;
408  for (unsigned varIdx = 0; varIdx < numVars; ++varIdx)
409  result.derivatives[varIdx] = a*b.derivatives[varIdx];
410 
411  return result;
412 }
413 
414 template <class Scalar, class VarSetTag, int numVars>
415 std::ostream& operator<<(std::ostream& os, const Evaluation<Scalar, VarSetTag, numVars>& eval)
416 {
417  os << eval.value;
418  return os;
419 }
420 
421 } // namespace LocalAd
422 } // namespace Opm
423 
424 // In Dune 2.3, the Evaluation.hpp header must be included before the fmatrix.hh
425 // header. Dune 2.4+ does not suffer from this because of some c++-foo.
426 //
427 // for those who are wondering: in C++ function templates cannot be partially
428 // specialized, and function argument overloads must be known _before_ they are used. The
429 // latter is what we do for the 'Dune::fvmeta::absreal()' function.
430 //
431 // consider the following test program:
432 //
433 // double foo(double i)
434 // { return i; }
435 //
436 // void bar()
437 // { std::cout << foo(0) << "\n"; }
438 //
439 // int foo(int i)
440 // { return i + 1; }
441 //
442 // void foobar()
443 // { std::cout << foo(0) << "\n"; }
444 //
445 // this will print '0' for bar() and '1' for foobar()...
446 #if !(DUNE_VERSION_NEWER(DUNE_COMMON, 2,4))
447 
448 namespace Opm {
449 namespace LocalAd {
450 template <class Scalar, class VarSetTag, int numVars>
451 Evaluation<Scalar, VarSetTag, numVars> abs(const Evaluation<Scalar, VarSetTag, numVars>&);
452 }}
453 
454 namespace std {
455 template <class Scalar, class VarSetTag, int numVars>
457 { return Opm::LocalAd::abs(x); }
458 
459 } // namespace std
460 
461 #if defined DUNE_DENSEMATRIX_HH
462 #warning \
463  "Due to some C++ peculiarity regarding function overloads, the 'Evaluation.hpp'" \
464  "header file must be included before Dune's 'densematrix.hh' for Dune < 2.4. " \
465  "(If Evaluations are to be used in conjunction with a dense matrix.)"
466 #endif
467 
468 #endif
469 
470 // this makes the Dune matrix/vector classes happy...
471 #include <dune/common/ftraits.hh>
472 
473 namespace Dune {
474 template <class Scalar, class VarSetTag, int numVars>
475 struct FieldTraits<Opm::LocalAd::Evaluation<Scalar, VarSetTag, numVars> >
476 {
477 public:
479  // setting real_type to field_type here potentially leads to slightly worse
480  // performance, but at least it makes things compile.
481  typedef field_type real_type;
482 };
483 
484 } // namespace Dune
485 
486 #endif
Evaluation< Scalar, VarSetTag, numVars > operator/(const ScalarA &a, const Evaluation< Scalar, VarSetTag, numVars > &b)
Definition: Evaluation.hpp:388
Evaluation & operator=(const Evaluation &other)
Definition: Evaluation.hpp:276
std::array< Scalar, size > derivatives
Definition: Evaluation.hpp:342
Evaluation< Scalar, VarSetTag, numVars > operator*(const ScalarA &a, const Evaluation< Scalar, VarSetTag, numVars > &b)
Definition: Evaluation.hpp:403
Evaluation & operator+=(const Evaluation &other)
Definition: Evaluation.hpp:110
bool CheckDefined(const T &value OPM_UNUSED)
Make valgrind complain if any of the memory occupied by an object is undefined.
Definition: Valgrind.hpp:74
Evaluation operator-(Scalar other) const
Definition: Evaluation.hpp:222
bool operator<(const Evaluation &other) const
Definition: Evaluation.hpp:325
Definition: Air_Mesitylene.hpp:31
Evaluation operator-(const Evaluation &other) const
Definition: Evaluation.hpp:215
Evaluation operator+(const Evaluation &other) const
Definition: Evaluation.hpp:201
Evaluation & operator*=(Scalar other)
Definition: Evaluation.hpp:163
bool operator>=(const Evaluation &other) const
Definition: Evaluation.hpp:331
bool operator<(Scalar other) const
Definition: Evaluation.hpp:322
bool operator>(const Evaluation &other) const
Definition: Evaluation.hpp:319
bool operator>=(const ScalarA &a, const Evaluation< Scalar, VarSetTag, numVars > &b)
Definition: Evaluation.hpp:358
Some templates to wrap the valgrind client request macros.
Evaluation operator*(Scalar other) const
Definition: Evaluation.hpp:247
Scalar value
Definition: Evaluation.hpp:341
Evaluation(Scalar c)
Definition: Evaluation.hpp:66
Evaluation & operator=(Scalar other)
Definition: Evaluation.hpp:268
Evaluation operator+(Scalar other) const
Definition: Evaluation.hpp:208
Evaluation & operator/=(Scalar other)
Definition: Evaluation.hpp:190
static Evaluation createVariable(Scalar value, unsigned varPos)
Definition: Evaluation.hpp:73
Evaluation< Scalar, VarSetTag, numVars > operator+(const ScalarA &a, const Evaluation< Scalar, VarSetTag, numVars > &b)
Definition: Evaluation.hpp:366
bool operator>=(Scalar other) const
Definition: Evaluation.hpp:328
Evaluation operator/(Scalar other) const
Definition: Evaluation.hpp:261
Definition: Evaluation.hpp:473
bool operator<=(const Evaluation &other) const
Definition: Evaluation.hpp:337
bool operator==(const Evaluation &other) const
Definition: Evaluation.hpp:286
bool operator==(Scalar other) const
Definition: Evaluation.hpp:283
STL namespace.
Definition: Evaluation.hpp:49
bool operator!=(const ScalarA &a, const Evaluation< Scalar, VarSetTag, numVars > &b)
Definition: Evaluation.hpp:362
Evaluation< Scalar, VarSetTag, numVars > abs(const Evaluation< Scalar, VarSetTag, numVars > &)
Definition: Math.hpp:41
bool operator>(Scalar other) const
Definition: Evaluation.hpp:316
Evaluation operator*(const Evaluation &other) const
Definition: Evaluation.hpp:240
Evaluation & operator*=(const Evaluation &other)
Definition: Evaluation.hpp:146
Evaluation operator-() const
Definition: Evaluation.hpp:230
void print(std::ostream &os=std::cout) const
Definition: Evaluation.hpp:102
Evaluation & operator/=(const Evaluation &other)
Definition: Evaluation.hpp:173
bool isSame(const Evaluation &other, Scalar tolerance) const
Definition: Evaluation.hpp:298
ScalarT Scalar
Definition: Evaluation.hpp:47
Evaluation & operator-=(const Evaluation &other)
Definition: Evaluation.hpp:128
Opm::LocalAd::Evaluation< Scalar, VarSetTag, numVars > field_type
Definition: Evaluation.hpp:478
Evaluation & operator-=(Scalar other)
Definition: Evaluation.hpp:138
Evaluation operator/(const Evaluation &other) const
Definition: Evaluation.hpp:254
Evaluation()
Definition: Evaluation.hpp:51
Evaluation< Scalar, VarSetTag, numVars > operator-(const ScalarA &a, const Evaluation< Scalar, VarSetTag, numVars > &b)
Definition: Evaluation.hpp:376
Evaluation(const Evaluation &other)
Definition: Evaluation.hpp:55
bool operator>(const ScalarA &a, const Evaluation< Scalar, VarSetTag, numVars > &b)
Definition: Evaluation.hpp:350
Represents a function evaluation and its derivatives w.r.t. a fixed set of variables.
Definition: Evaluation.hpp:44
bool operator<=(Scalar other) const
Definition: Evaluation.hpp:334
bool operator!=(const Evaluation &other) const
Definition: Evaluation.hpp:313
static Evaluation createConstant(Scalar value)
Definition: Evaluation.hpp:91
Evaluation & operator+=(Scalar other)
Definition: Evaluation.hpp:120