// obtain local copies of objects
final Quote u = underlying_.currentLink();
final YieldTermStructure dTS = dividendTS_.currentLink();
final YieldTermStructure rTS = riskFreeTS_.currentLink();
final BlackVolTermStructure bTS = blackTS_.currentLink();
final double forwardValue = u.value() * ( dTS.discount(time, true) / rTS.discount(time, true) );
// strike derivatives
/*@Real*/ double strike;
/*@Real*/ double strikem;
/*@Real*/ double strikep;
double y, dy;
double w, wp, wm, dwdy, d2wdy2;
strike = underlyingLevel;
y = Math.log(strike / forwardValue);
dy = ((y != 0.0) ? y * 0.000001 : 0.000001);
strikep = strike * Math.exp(dy);
strikem = strike / Math.exp(dy);
w = bTS.blackVariance(time, strike, true);
wp = bTS.blackVariance(time, strikep, true);
wm = bTS.blackVariance(time, strikem, true);
dwdy = (wp - wm) / (2.0 * dy);
d2wdy2 = (wp - 2.0 * w + wm) / (dy * dy);
// time derivative
/*@Time*/ final double t = time;
/*@Time*/ double dt;
double wpt, wmt, dwdt;
if (t == 0.0) {
dt = 0.0001;
wpt = bTS.blackVariance(/*@Time*/ (t + dt), strike, true);
QL.require(wpt >= w , "decreasing variance at strike"); // TODO: message
dwdt = (wpt - w) / dt;
} else {
dt = Math.min(0.0001, t / 2.0);
wpt = bTS.blackVariance(/*@Time*/ (t + dt), strike, true);
wmt = bTS.blackVariance(/*@Time*/ (t - dt), strike, true);
QL.ensure(wpt >= w , "decreasing variance at strike"); // TODO: message
QL.ensure(w >= wmt , "decreasing variance at strike"); // TODO: message
dwdt = (wpt - wmt) / (2.0 * dt);
}