com.opengamma.analytics.financial.model.finitedifference.ExponentialMeshing.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.analytics.financial.model.finitedifference.ExponentialMeshing.java

Source

/**
 * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
 * 
 * Please see distribution for license.
 */
package com.opengamma.analytics.financial.model.finitedifference;

import org.apache.commons.lang.Validate;

import com.opengamma.analytics.math.FunctionUtils;
import com.opengamma.util.ArgumentChecker;

/**
 * 
 */
public class ExponentialMeshing extends MeshingFunction {
    private final double[] _fpValues;
    private final UniformMeshing _um;
    private final double _theta;
    private final double _eta;
    private final double _lambda;
    private final boolean _linear;
    private final double _l;
    private final double _r;

    /**
     * creates a non-uniform set of points according to the formula $x_i = \theta + \eta*\exp(\lambda z_i)$, where the points run from 
     * $x_0$ to $x_{N-1}$ (i.e. there are N points), $\eta = (x_{N-1} - x_0)/(\exp(\lambda) - 1)$ and $\theta = x_0 - \eta$. The points $z_i$ are uniform on (0,1) and 
     * given by $z_i = i/(N-1)$. 
     * @param lowerBound The value of $x_0$
     * @param upperBound The value of $x_{N-1}$
     * @param nPoints Number of Points (equal to N in the above formula)
     * @param lambda Bunching parameter. $\lambda = 0$ is uniform, $\lambda > 0$ gives a high density of points near $x_0$ and $\lambda < 0$ gives a high density
     * of points near $x_{N-1}$
     */
    public ExponentialMeshing(final double lowerBound, final double upperBound, final int nPoints,
            final double lambda) {
        super(nPoints);
        Validate.isTrue(upperBound > lowerBound, "need upperBound>lowerBound");
        _l = lowerBound;
        _r = upperBound;
        _lambda = lambda;

        if (lambda == 0.0) {
            _linear = true;
            _theta = lowerBound;
            _eta = (upperBound - lowerBound);
        } else {
            _linear = false;
            _eta = (upperBound - lowerBound) / (Math.exp(lambda) - 1);
            _theta = lowerBound - _eta;
        }
        _um = new UniformMeshing(nPoints);
        _fpValues = null;
    }

    /**
     * creates a non-uniform set of points according to the formula $x_i = \theta + \eta*\exp(\lambda z_i)$, where the points run from 
     * $x_0$ to $x_{N-1}$ (i.e. there are N points), $\eta = (x_{N-1} - x_0)/(\exp(\lambda) - 1)$ and $\theta = x_0 - \eta$. 
     * The points $z_i$ are are close as possible to uniform on (0,1) while allowing the <em>fixedPoints</em> to be in the set of points.
     * @param lowerBound The value of $x_0$
     * @param upperBound The value of $x_{N-1}$
     * @param nPoints Number of Points (equal to N in the above formula).The number of points must exceed the number of fixed points by at least 2.
     * @param lambda Bunching parameter. $\lambda = 0$ is uniform, $\lambda > 0$ gives a high density of points near $x_0$ and $\lambda < 0$ gives a high density
     * of points near $x_{N-1}$
     * @param fixedPoints set of points that must be included. These must be within the lower and upper bound (exclusive) 
     */
    public ExponentialMeshing(final double lowerBound, final double upperBound, final int nPoints,
            final double lambda, final double[] fixedPoints) {
        super(nPoints);
        Validate.isTrue(upperBound > lowerBound, "need upperBound>lowerBound");
        ArgumentChecker.notNull(fixedPoints, "null fixedPoints");
        _lambda = lambda;
        _l = lowerBound;
        _r = upperBound;

        _fpValues = FunctionUtils.unique(fixedPoints);

        int m = _fpValues.length;
        final double[] fp = new double[m];

        if (lambda == 0.0) {
            _linear = true;
            _theta = lowerBound;
            _eta = (upperBound - lowerBound);
            for (int ii = 0; ii < m; ii++) {
                fp[ii] = (fixedPoints[ii] - _theta) / _eta;
            }
        } else {
            _linear = false;
            _eta = (upperBound - lowerBound) / (Math.exp(lambda) - 1);
            _theta = lowerBound - _eta;
            for (int ii = 0; ii < m; ii++) {
                fp[ii] = Math.log((_fpValues[ii] - _theta) / _eta) / lambda;
            }
        }
        _um = new UniformMeshing(nPoints, fp);
    }

    @Override
    public Double evaluate(final Integer i) {
        Validate.isTrue(i >= 0 && i < getNumberOfPoints(), "i out of range");
        if (i == 0) {
            return _l;
        }
        if (i == getNumberOfPoints() - 1) {
            return _r;
        }

        //short cut if required point is one of the specified fixed points 
        if (_fpValues != null) {
            int index = _um.getFixedPointIndex(i);
            if (index >= 0) {
                return _fpValues[index];
            }
        }

        final double z = _um.evaluate(i);
        if (_linear) {
            return _theta + _eta * z;
        }
        return _theta + _eta * Math.exp(z * _lambda);
    }

}