cleaned up brent solver
parent
9baca24e5e
commit
9aa5c13daa
|
@ -20,6 +20,7 @@
|
|||
#define __BRENT_H
|
||||
|
||||
#include <mitsuba/mitsuba.h>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -27,24 +28,22 @@ MTS_NAMESPACE_BEGIN
|
|||
* \brief Brent's method nonlinear zero finder
|
||||
*
|
||||
* The implementation is transcribed from the Apache Commons
|
||||
* Java implementation. The function \a Func is required to be
|
||||
* Java implementation. The supplied function is required to be
|
||||
* continuous, but not necessarily smooth.
|
||||
*
|
||||
* \ingroup libcore
|
||||
*/
|
||||
template <typename T, typename Func> class BrentSolver {
|
||||
class BrentSolver {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
/// Return value of \ref BrentSolver::solve()
|
||||
struct Result {
|
||||
bool success;
|
||||
int iterations;
|
||||
value_type x;
|
||||
value_type y;
|
||||
Float x;
|
||||
Float y;
|
||||
|
||||
/// Create a new result instance
|
||||
inline Result(bool success, int iterations, value_type x, value_type y)
|
||||
inline Result(bool success, int iterations, Float x, Float y)
|
||||
: success(success), iterations(iterations), x(x), y(y) { }
|
||||
|
||||
/// Return a string representation of the result
|
||||
|
@ -75,10 +74,10 @@ public:
|
|||
* Absolute accuracy requirement of the position -- the
|
||||
* iterations will stop when |minX-maxX|/minX < relAccuracyPos.
|
||||
*/
|
||||
inline BrentSolver(int maxIterations = 100,
|
||||
value_type absAccuracy = 1e-6f,
|
||||
value_type absAccuracyPos = 1e-6f,
|
||||
value_type relAccuracyPos = 1e-6f)
|
||||
inline BrentSolver(size_t maxIterations = 100,
|
||||
Float absAccuracy = 1e-6f,
|
||||
Float absAccuracyPos = 1e-6f,
|
||||
Float relAccuracyPos = 1e-6f)
|
||||
: m_maxIterations(maxIterations),
|
||||
m_absAccuracy(absAccuracy),
|
||||
m_absAccuracyPos(absAccuracyPos),
|
||||
|
@ -94,27 +93,8 @@ public:
|
|||
* \param max the upper bound for the interval.
|
||||
* \return the value where the function is zero
|
||||
*/
|
||||
Result solve(Func &f, value_type min, value_type max) const {
|
||||
// return the first endpoint if it is good enough
|
||||
value_type yMin = f(min);
|
||||
if (std::abs(yMin) <= m_absAccuracy)
|
||||
return Result(true, 0, min, yMin);
|
||||
|
||||
// return the second endpoint if it is good enough
|
||||
value_type yMax = f(max);
|
||||
if (std::abs(yMax) <= m_absAccuracy)
|
||||
return Result(true, 0, max, yMax);
|
||||
|
||||
value_type sign = yMin * yMax;
|
||||
if (sign > 0) {
|
||||
SLog(EWarn, "BrentSolver: Function values at the endpoints do not have different signs -- "
|
||||
"endpoints: [%f, %f], values: [%f, %f]", min, max, yMin, yMax);
|
||||
return Result(false, 0, 0, 0);
|
||||
} else {
|
||||
// solve using only the first endpoint as initial guess
|
||||
return solve(f, min, yMin, max, yMax, min, yMin);
|
||||
}
|
||||
}
|
||||
Result solve(const boost::function<Float (Float)> &func,
|
||||
Float min, Float max) const;
|
||||
|
||||
/**
|
||||
* \brief Find a zero in the given interval with an initial guess
|
||||
|
@ -130,41 +110,8 @@ public:
|
|||
* if no initial point is known)
|
||||
* \return the value where the function is zero
|
||||
*/
|
||||
Result solve(Func &f, value_type min, value_type max, value_type initial) const {
|
||||
if (initial < min || initial > max) {
|
||||
SLog(EWarn, "BrentSolver: Invalid interval: lower=%f, initial=%f, upper=%f",
|
||||
min, max, initial);
|
||||
return Result(false, 0, 0, 0);
|
||||
}
|
||||
|
||||
// return the initial guess if it is good enough
|
||||
value_type yInitial = f(initial);
|
||||
if (std::abs(yInitial) <= m_absAccuracy)
|
||||
return Result(true, 0, initial, yInitial);
|
||||
|
||||
// return the first endpoint if it is good enough
|
||||
value_type yMin = f(min);
|
||||
if (std::abs(yMin) <= m_absAccuracy)
|
||||
return Result(true, 0, min, yMin);
|
||||
|
||||
// reduce interval if min and initial bracket the root
|
||||
if (yInitial * yMin < 0)
|
||||
return solve(f, min, yMin, initial, yInitial, min, yMin);
|
||||
|
||||
// return the second endpoint if it is good enough
|
||||
value_type yMax = f(max);
|
||||
if (std::abs(yMax) <= m_absAccuracy)
|
||||
return Result(true, 0, max, yMax);
|
||||
|
||||
// reduce interval if initial and max bracket the root
|
||||
if (yInitial * yMax < 0)
|
||||
return solve(f, initial, yInitial, max, yMax, initial, yInitial);
|
||||
|
||||
SLog(EWarn, "BrentSolver: Function values at the endpoints do not have different signs -- "
|
||||
"endpoints: [%f, %f], values: [%f, %f]", min, max, yMin, yMax);
|
||||
|
||||
return Result(false, 0, 0, 0);
|
||||
}
|
||||
Result solve(const boost::function<Float (Float)> &func,
|
||||
Float min, Float max, Float initial) const;
|
||||
|
||||
/**
|
||||
* Find a zero starting search according to the three provided points.
|
||||
|
@ -179,105 +126,15 @@ public:
|
|||
* \param y2 function value at the bracket point.
|
||||
* \return the value where the function is zero
|
||||
*/
|
||||
Result solve(Func &f,
|
||||
value_type x0, value_type y0,
|
||||
value_type x1, value_type y1,
|
||||
value_type x2, value_type y2) const {
|
||||
value_type delta = x1 - x0;
|
||||
value_type oldDelta = delta;
|
||||
|
||||
int i = 0;
|
||||
while (i < m_maxIterations) {
|
||||
if (std::abs(y2) < std::abs(y1)) {
|
||||
// use the bracket point if is better than last approximation
|
||||
x0 = x1;
|
||||
x1 = x2;
|
||||
x2 = x0;
|
||||
y0 = y1;
|
||||
y1 = y2;
|
||||
y2 = y0;
|
||||
}
|
||||
if (std::abs(y1) <= m_absAccuracy) {
|
||||
// Avoid division by very small values. Assume
|
||||
// the iteration has converged (the problem may
|
||||
// still be ill conditioned)
|
||||
return Result(true, i, x1, y1);
|
||||
}
|
||||
value_type dx = x2 - x1;
|
||||
value_type tolerance =
|
||||
std::max(m_relAccuracyPos * std::abs(x1), m_absAccuracyPos);
|
||||
|
||||
if (std::abs(dx) <= tolerance)
|
||||
return Result(true, i, x1, y1);
|
||||
if ((std::abs(oldDelta) < tolerance) ||
|
||||
(std::abs(y0) <= std::abs(y1))) {
|
||||
// Force bisection.
|
||||
delta = (value_type) 0.5f * dx;
|
||||
oldDelta = delta;
|
||||
} else {
|
||||
value_type r3 = y1 / y0;
|
||||
value_type p;
|
||||
value_type p1;
|
||||
// the equality test (x0 == x2) is intentional,
|
||||
// it is part of the original Brent's method,
|
||||
// it should NOT be replaced by proximity test
|
||||
if (x0 == x2) {
|
||||
// Linear interpolation.
|
||||
p = dx * r3;
|
||||
p1 = 1 - r3;
|
||||
} else {
|
||||
// Inverse quadratic interpolation.
|
||||
value_type r1 = y0 / y2;
|
||||
value_type r2 = y1 / y2;
|
||||
p = r3 * (dx * r1 * (r1 - r2) - (x1 - x0) * (r2 - 1));
|
||||
p1 = (r1 - 1) * (r2 - 1) * (r3 - 1);
|
||||
}
|
||||
if (p > 0) {
|
||||
p1 = -p1;
|
||||
} else {
|
||||
p = -p;
|
||||
}
|
||||
if (2 * p >= (value_type) 1.5f * dx * p1 - std::abs(tolerance * p1) ||
|
||||
p >= std::abs((value_type) 0.5f * oldDelta * p1)) {
|
||||
// Inverse quadratic interpolation gives a value
|
||||
// in the wrong direction, or progress is slow.
|
||||
// Fall back to bisection.
|
||||
delta = (value_type) 0.5f * dx;
|
||||
oldDelta = delta;
|
||||
} else {
|
||||
oldDelta = delta;
|
||||
delta = p / p1;
|
||||
}
|
||||
}
|
||||
// Save old X1, Y1
|
||||
x0 = x1;
|
||||
y0 = y1;
|
||||
// Compute new X1, Y1
|
||||
if (std::abs(delta) > tolerance) {
|
||||
x1 = x1 + delta;
|
||||
} else if (dx > 0) {
|
||||
x1 = x1 + (value_type) 0.5f * tolerance;
|
||||
} else if (dx <= 0) {
|
||||
x1 = x1 - (value_type) 0.5f * tolerance;
|
||||
}
|
||||
y1 = f(x1);
|
||||
if ((y1 > 0) == (y2 > 0)) {
|
||||
x2 = x0;
|
||||
y2 = y0;
|
||||
delta = x1 - x0;
|
||||
oldDelta = delta;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
SLog(EWarn, "BrentSolver: Maximum number of iterations (%i) exceeded!",
|
||||
m_maxIterations);
|
||||
return Result(false, i, x1, y1);
|
||||
}
|
||||
private:
|
||||
int m_maxIterations;
|
||||
value_type m_absAccuracy;
|
||||
value_type m_absAccuracyPos;
|
||||
value_type m_relAccuracyPos;
|
||||
Result solve(const boost::function<Float (Float)> &func,
|
||||
Float x0, Float y0,
|
||||
Float x1, Float y1,
|
||||
Float x2, Float y2) const;
|
||||
protected:
|
||||
size_t m_maxIterations;
|
||||
Float m_absAccuracy;
|
||||
Float m_absAccuracyPos;
|
||||
Float m_relAccuracyPos;
|
||||
};
|
||||
|
||||
MTS_NAMESPACE_END
|
||||
|
|
|
@ -25,7 +25,7 @@ if coreEnv.has_key('JPEGLIB'):
|
|||
|
||||
coreEnv.Prepend(CPPDEFINES = [['MTS_BUILD_MODULE', 'MTS_MODULE_CORE']])
|
||||
libcore_objects = [
|
||||
'class.cpp', 'object.cpp', 'statistics.cpp', 'thread.cpp',
|
||||
'class.cpp', 'object.cpp', 'statistics.cpp', 'thread.cpp', 'brent.cpp',
|
||||
'logger.cpp', 'appender.cpp', 'formatter.cpp', 'lock.cpp',
|
||||
'random.cpp', 'timer.cpp', 'util.cpp', 'properties.cpp',
|
||||
'transform.cpp', 'spectrum.cpp', 'aabb.cpp', 'stream.cpp',
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
This file is part of Mitsuba, a physically based rendering system.
|
||||
|
||||
Copyright (c) 2007-2010 by Wenzel Jakob and others.
|
||||
|
||||
Mitsuba is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License Version 3
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
Mitsuba is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <mitsuba/core/brent.h>
|
||||
|
||||
/**
|
||||
* \file brent.cpp
|
||||
* \brief Brent's method nonlinear zero finder
|
||||
*
|
||||
* The implementation is transcribed from the Apache Commons
|
||||
* Java implementation.
|
||||
*/
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
BrentSolver::Result BrentSolver::solve(const boost::function<Float (Float)> &f,
|
||||
Float min, Float max) const {
|
||||
// return the first endpoint if it is good enough
|
||||
Float yMin = f(min);
|
||||
if (std::abs(yMin) <= m_absAccuracy)
|
||||
return Result(true, 0, min, yMin);
|
||||
|
||||
// return the second endpoint if it is good enough
|
||||
Float yMax = f(max);
|
||||
if (std::abs(yMax) <= m_absAccuracy)
|
||||
return Result(true, 0, max, yMax);
|
||||
|
||||
Float sign = yMin * yMax;
|
||||
if (sign > 0) {
|
||||
SLog(EWarn, "BrentSolver: Function values at the endpoints do not have different signs -- "
|
||||
"endpoints: [%f, %f], values: [%f, %f]", min, max, yMin, yMax);
|
||||
return Result(false, 0, 0, 0);
|
||||
} else {
|
||||
// solve using only the first endpoint as initial guess
|
||||
return solve(f, min, yMin, max, yMax, min, yMin);
|
||||
}
|
||||
}
|
||||
|
||||
BrentSolver::Result BrentSolver::solve(const boost::function<Float (Float)> &f,
|
||||
Float min, Float max, Float initial) const {
|
||||
if (initial < min || initial > max) {
|
||||
SLog(EWarn, "BrentSolver: Invalid interval: lower=%f, initial=%f, upper=%f",
|
||||
min, max, initial);
|
||||
return Result(false, 0, 0, 0);
|
||||
}
|
||||
|
||||
// return the initial guess if it is good enough
|
||||
Float yInitial = f(initial);
|
||||
if (std::abs(yInitial) <= m_absAccuracy)
|
||||
return Result(true, 0, initial, yInitial);
|
||||
|
||||
// return the first endpoint if it is good enough
|
||||
Float yMin = f(min);
|
||||
if (std::abs(yMin) <= m_absAccuracy)
|
||||
return Result(true, 0, min, yMin);
|
||||
|
||||
// reduce interval if min and initial bracket the root
|
||||
if (yInitial * yMin < 0)
|
||||
return solve(f, min, yMin, initial, yInitial, min, yMin);
|
||||
|
||||
// return the second endpoint if it is good enough
|
||||
Float yMax = f(max);
|
||||
if (std::abs(yMax) <= m_absAccuracy)
|
||||
return Result(true, 0, max, yMax);
|
||||
|
||||
// reduce interval if initial and max bracket the root
|
||||
if (yInitial * yMax < 0)
|
||||
return solve(f, initial, yInitial, max, yMax, initial, yInitial);
|
||||
|
||||
SLog(EWarn, "BrentSolver: Function values at the endpoints do not have different signs -- "
|
||||
"endpoints: [%f, %f], values: [%f, %f]", min, max, yMin, yMax);
|
||||
|
||||
return Result(false, 0, 0, 0);
|
||||
}
|
||||
|
||||
BrentSolver::Result BrentSolver::solve(const boost::function<Float (Float)> &f,
|
||||
Float x0, Float y0,
|
||||
Float x1, Float y1,
|
||||
Float x2, Float y2) const {
|
||||
Float delta = x1 - x0;
|
||||
Float oldDelta = delta;
|
||||
|
||||
size_t i = 0;
|
||||
while (i < m_maxIterations) {
|
||||
if (std::abs(y2) < std::abs(y1)) {
|
||||
// use the bracket point if is better than last approximation
|
||||
x0 = x1;
|
||||
x1 = x2;
|
||||
x2 = x0;
|
||||
y0 = y1;
|
||||
y1 = y2;
|
||||
y2 = y0;
|
||||
}
|
||||
if (std::abs(y1) <= m_absAccuracy) {
|
||||
// Avoid division by very small values. Assume
|
||||
// the iteration has converged (the problem may
|
||||
// still be ill conditioned)
|
||||
return Result(true, i, x1, y1);
|
||||
}
|
||||
Float dx = x2 - x1;
|
||||
Float tolerance =
|
||||
std::max(m_relAccuracyPos * std::abs(x1), m_absAccuracyPos);
|
||||
|
||||
if (std::abs(dx) <= tolerance)
|
||||
return Result(true, i, x1, y1);
|
||||
if ((std::abs(oldDelta) < tolerance) ||
|
||||
(std::abs(y0) <= std::abs(y1))) {
|
||||
// Force bisection.
|
||||
delta = (Float) 0.5f * dx;
|
||||
oldDelta = delta;
|
||||
} else {
|
||||
Float r3 = y1 / y0;
|
||||
Float p;
|
||||
Float p1;
|
||||
// the equality test (x0 == x2) is intentional,
|
||||
// it is part of the original Brent's method,
|
||||
// it should NOT be replaced by proximity test
|
||||
if (x0 == x2) {
|
||||
// Linear interpolation.
|
||||
p = dx * r3;
|
||||
p1 = 1 - r3;
|
||||
} else {
|
||||
// Inverse quadratic interpolation.
|
||||
Float r1 = y0 / y2;
|
||||
Float r2 = y1 / y2;
|
||||
p = r3 * (dx * r1 * (r1 - r2) - (x1 - x0) * (r2 - 1));
|
||||
p1 = (r1 - 1) * (r2 - 1) * (r3 - 1);
|
||||
}
|
||||
if (p > 0) {
|
||||
p1 = -p1;
|
||||
} else {
|
||||
p = -p;
|
||||
}
|
||||
if (2 * p >= (Float) 1.5f * dx * p1 - std::abs(tolerance * p1) ||
|
||||
p >= std::abs((Float) 0.5f * oldDelta * p1)) {
|
||||
// Inverse quadratic interpolation gives a value
|
||||
// in the wrong direction, or progress is slow.
|
||||
// Fall back to bisection.
|
||||
delta = (Float) 0.5f * dx;
|
||||
oldDelta = delta;
|
||||
} else {
|
||||
oldDelta = delta;
|
||||
delta = p / p1;
|
||||
}
|
||||
}
|
||||
// Save old X1, Y1
|
||||
x0 = x1;
|
||||
y0 = y1;
|
||||
// Compute new X1, Y1
|
||||
if (std::abs(delta) > tolerance) {
|
||||
x1 = x1 + delta;
|
||||
} else if (dx > 0) {
|
||||
x1 = x1 + (Float) 0.5f * tolerance;
|
||||
} else if (dx <= 0) {
|
||||
x1 = x1 - (Float) 0.5f * tolerance;
|
||||
}
|
||||
y1 = f(x1);
|
||||
if ((y1 > 0) == (y2 > 0)) {
|
||||
x2 = x0;
|
||||
y2 = y0;
|
||||
delta = x1 - x0;
|
||||
oldDelta = delta;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
SLog(EWarn, "BrentSolver: Maximum number of iterations (" SIZE_T_FMT ") exceeded!",
|
||||
m_maxIterations);
|
||||
return Result(false, i, x1, y1);
|
||||
}
|
||||
|
||||
MTS_NAMESPACE_END
|
|
@ -3,5 +3,6 @@ Import('env', 'plugins')
|
|||
plugins += env.SharedLibrary('#plugins/isotropic', ['isotropic.cpp'])
|
||||
plugins += env.SharedLibrary('#plugins/hg', ['hg.cpp'])
|
||||
plugins += env.SharedLibrary('#plugins/kkay', ['kkay.cpp'])
|
||||
plugins += env.SharedLibrary('#plugins/microflake', ['microflake.cpp'])
|
||||
|
||||
Export('plugins')
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
This file is part of Mitsuba, a physically based rendering system.
|
||||
|
||||
Copyright (c) 2007-2010 by Wenzel Jakob and others.
|
||||
|
||||
Mitsuba is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License Version 3
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
Mitsuba is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <mitsuba/render/phase.h>
|
||||
#include <mitsuba/render/sampler.h>
|
||||
#include "microflake.h"
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
class MicroflakePhaseFunction : public PhaseFunction {
|
||||
public:
|
||||
MicroflakePhaseFunction(const Properties &props)
|
||||
: PhaseFunction(props) {
|
||||
}
|
||||
|
||||
MicroflakePhaseFunction(Stream *stream, InstanceManager *manager)
|
||||
: PhaseFunction(stream, manager) {
|
||||
}
|
||||
|
||||
virtual ~MicroflakePhaseFunction() { }
|
||||
|
||||
void serialize(Stream *stream, InstanceManager *manager) const {
|
||||
PhaseFunction::serialize(stream, manager);
|
||||
}
|
||||
|
||||
void configure() {
|
||||
}
|
||||
|
||||
Spectrum sample(PhaseFunctionQueryRecord &pRec,
|
||||
Sampler *sampler) const {
|
||||
Point2 sample(sampler->next2D());
|
||||
pRec.wo = squareToSphere(sample);
|
||||
return Spectrum(1.0f);
|
||||
}
|
||||
|
||||
Spectrum sample(PhaseFunctionQueryRecord &pRec,
|
||||
Float &pdf, Sampler *sampler) const {
|
||||
pRec.wo = squareToSphere(sampler->next2D());
|
||||
pdf = 1/(4 * (Float) M_PI);
|
||||
return Spectrum(pdf);
|
||||
}
|
||||
|
||||
Spectrum f(const PhaseFunctionQueryRecord &pRec) const {
|
||||
return Spectrum(1/(4 * (Float) M_PI));
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
return "MicroflakePhaseFunction[]";
|
||||
}
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
};
|
||||
|
||||
|
||||
MTS_IMPLEMENT_CLASS_S(MicroflakePhaseFunction, false, PhaseFunction)
|
||||
MTS_EXPORT_PLUGIN(MicroflakePhaseFunction, "Microflake phase function");
|
||||
MTS_NAMESPACE_END
|
|
@ -19,6 +19,11 @@
|
|||
#if !defined(__MICROFLAKE_SIGMA_T_H)
|
||||
#define __MICROFLAKE_SIGMA_T_H
|
||||
|
||||
#include <mitsuba/core/statistics.h>
|
||||
#include <mitsuba/core/brent.h>
|
||||
#include <boost/math/special_functions/erf.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
#define SIGMA_T_RANGE_MIN 4e-08
|
||||
|
@ -166,6 +171,61 @@ double sigmaT_fiberGaussian(double stddev, double sinTheta) {
|
|||
return result;
|
||||
}
|
||||
|
||||
static StatsCounter brentSolves("Micro-flake model",
|
||||
"Brent solver calls");
|
||||
static StatsCounter avgBrentFunEvals("Micro-flake model",
|
||||
"Average Brent solver function evaluations", EAverage);
|
||||
|
||||
struct GaussianFiberDistribution {
|
||||
public:
|
||||
inline GaussianFiberDistribution(Float stddev) : m_stddev(stddev) {
|
||||
m_normalization = 1/(std::sqrt(2*M_PI) * m_stddev *
|
||||
boost::math::erf<Float>(1/(SQRT_TWO * m_stddev)));
|
||||
m_c1 = 1.0f/boost::math::erf<Float>(1/(SQRT_TWO * m_stddev));
|
||||
}
|
||||
|
||||
/// Evaluate \sigma_t as a function of \cos\theta
|
||||
Float sigmaT(Float cosTheta) const {
|
||||
return sigmaT_fiberGaussian(m_stddev,
|
||||
std::sqrt(std::max((Float) 0, 1-cosTheta*cosTheta)));
|
||||
}
|
||||
|
||||
/// Evaluate the longitudinal density as a function of \cos\theta
|
||||
Float pdfCosTheta(Float cosTheta) const {
|
||||
return std::exp(-cosTheta*cosTheta/(2*m_stddev*m_stddev)) * m_normalization;
|
||||
}
|
||||
|
||||
/// Evaluate the longitudinal CDF as a function of \cos\theta
|
||||
inline Float cdf(Float theta) const {
|
||||
return 0.5f * (1.0f -
|
||||
boost::math::erf<Float>(std::cos(theta)/(SQRT_TWO * m_stddev))*m_c1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the inversion method to sample \theta given
|
||||
* a uniformly distributed \xi on [0, 1]
|
||||
*/
|
||||
Float sample(Float xi) const {
|
||||
BrentSolver brentSolver(100, 1e-6f);
|
||||
BrentSolver::Result result = brentSolver.solve(
|
||||
boost::bind(&GaussianFiberDistribution::cdfFunctor, this, xi, _1), 0, M_PI);
|
||||
SAssert(result.success);
|
||||
avgBrentFunEvals.incrementBase();
|
||||
++brentSolves;
|
||||
return result.x;
|
||||
}
|
||||
private:
|
||||
Float cdfFunctor(Float theta, Float xi) const {
|
||||
++avgBrentFunEvals;
|
||||
return cdf(theta)-xi;
|
||||
}
|
||||
|
||||
Float m_stddev;
|
||||
Float m_normalization;
|
||||
Float m_c1;
|
||||
};
|
||||
|
||||
|
||||
MTS_NAMESPACE_END
|
||||
|
||||
#endif /* __MICROFLAKE_SIGMA_T_H */
|
||||
|
|
Loading…
Reference in New Issue