13#include <dune/common/exceptions.hh>
14#include <dune/common/float_cmp.hh>
23 return log(T(1.0) + x);
41template <
typename ST =
double>
42ST
lambertW0(ST z,
int maxIterations = 20, ST eps = std::numeric_limits<ST>::epsilon()) {
45 return std::numeric_limits<ST>::quiet_NaN();
50 const ST branchPoint = -1.0 / std::exp(1.0);
53 if (Dune::FloatCmp::eq(z, branchPoint))
58 DUNE_THROW(Dune::InvalidStateException,
"lambertW0: z must be >= -1/e for branch 0");
62 if (Dune::FloatCmp::gt(z, ST(1.0))) {
65 x0 = lx - llx - 0.5 * Impl::log1p<ST>(-llx / lx);
74 for (
int iter = 0; iter < maxIterations; ++iter) {
76 const ST f = x * ex - z;
77 const ST fPrime = ex * (x + 1.0);
78 const ST fPrimePrime = ex * (x + 2.0);
79 const ST denom = fPrime - ((1.0 / 2.0) * (fPrimePrime / fPrime) * f);
81 const ST newX = x - f / denom;
82 const ST diff = abs(newX - x);
85 if (Dune::FloatCmp::le<ST>(diff, 3 * eps * abs(x)) || Dune::FloatCmp::eq<ST>(diff, lastDiff))
92 DUNE_THROW(Dune::MathError,
"lambertW0: failed to converge within the maximum number of iterations");
Definition: lambertw.hh:18
ST lambertW0(ST z, int maxIterations=20, ST eps=std::numeric_limits< ST >::epsilon())
Implementation of the principal branch of the Lambert-W function (branch 0 in the domain ),...
Definition: lambertw.hh:42
Concept to check if the underlying scalar type is a dual type.
Definition: utils/concepts.hh:625