package mmc; /** * This class provides routines for function interpolation. Include the function to be interpolated * in a class that implements the interface FunctionInt or FunctionInt2 (defined below). * Methods contained here are based on the Numerical Recipes (W. H. Press et al.). *
 * interface FunctionInt{
 *     double functionInt(double x);
 * }
 *
 * interface FunctionInt2{
 *     double functionInt(double x1, double x2);
 * }
 * 
* @author Dmitry Chirkin */ public class Interpolate extends MathModel implements FunctionInt{ private int romberg, rombergY; private double[] iX; private double[] iY; private double[] c; private double[] d; private int max; private double xmin, xmax, step; private boolean rational, relative; private FunctionInt2 function2int; private Interpolate[] I; private int row, starti; private boolean rationalY, relativeY; private boolean reverse, self=true, flag; private boolean isLog, logSubst; public double precision, worstX; public double precision2, worstX2; public double precisionY, worstY; public static boolean fast=true; //----------------------------------------------------------------------------------------------------// /** * initializes class for the 1-dimensional function */ public Interpolate(int max, double xmin, double xmax, FunctionInt function2int, int romberg, boolean rational, boolean relative, boolean isLog, int rombergY, boolean rationalY, boolean relativeY, boolean logSubst){ this(max, xmin, xmax, romberg, rational, relative, isLog, rombergY, rationalY, relativeY, logSubst); int i; double aux, xaux; for(i=0,aux=this.xmin+step/2; i 0, setting to 1"); max=1; } if(isLog){ if(xmin<=0){ Output.err.println("Warning (in Interpolate/Interpolate/1): xmin = "+xmin+" must be > 0, setting to 1"); xmin=1; } if(xmax<=0){ Output.err.println("Warning (in Interpolate/Interpolate/2): xmax = "+xmax+" must be > 0, setting to 1"); xmax=1; } } if(xmin==xmax) max=1; else if(xmin>xmax){ aux=xmin; xmin=xmax; xmax=aux; } if(romberg<=0){ Output.err.println("Warning (in Interpolate/Interpolate/3): romberg = "+romberg+" must be > 0, setting to 1"); romberg=1; } if(romberg>max){ Output.err.println("Warning (in Interpolate/Interpolate/4): romberg = "+romberg+" must be <= max = "+max+", setting to "+max); romberg=max; } if(rombergY<=0){ Output.err.println("Warning (in Interpolate/Interpolate/5): rombergY = "+rombergY+" must be > 0, setting to 1"); rombergY=1; } if(rombergY>max){ Output.err.println("Warning (in Interpolate/Interpolate/6): rombergY = "+rombergY+" must be <= max = "+max+", setting to "+max); rombergY=max; } this.max=max; if(Math.log(max)/Math.log(2)+romberg=max) starti=max-1; start=(int)(aux-0.5*(romberg-1)); if(start<0) start=0; if(start+romberg>max || start>max) start=max-romberg; result=interpolate(x, start); if(logSubst) if(self) result=exp(result); return result; } //----------------------------------------------------------------------------------------------------// /** * interpolates f(x) for 2d function */ public double interpolate(double x1, double x2){ int i, start; double aux, aux2=0, result; if(isLog) x2=Math.log(x2); reverse=true; aux=(x2-xmin)/step; starti=(int)aux; if(starti<0) starti=0; if(starti>=max) starti=max-1; start=(int)(aux-0.5*(romberg-1)); if(start<0) start=0; if(start+romberg>max || start>max) start=max-romberg; for(i=start; iaux){ aux=I[i].precision; aux2=I[i].worstX; } if(aux>precision2){ precision2=aux; worstX2=aux2; } } result=interpolate(x2, start); if(logSubst) result=exp(result); return result; } //----------------------------------------------------------------------------------------------------// /** * interpolates f(x) for 1d function if the arrays already exist. */ public double interpolateArray(double x){ int i, j, m, start, auxdir; boolean dir; reverse=false; i=0; j=max-1; dir=iX[max-1]>iX[0]; while(j-i>1){ m=(i+j)/2; if(x>iX[m]==dir) i=m; else j=m; } if(i+1max || start>max) start=max-romberg; return interpolate(x, start); } //----------------------------------------------------------------------------------------------------// /** * interpolates f(x) based on the values iY[i]=f(iX[i]) in the romberg-vicinity of x */ private double interpolate(double x, int start){ int num, i, k; boolean dd, doLog; double error=0, result=0; double aux, aux2, dx1, dx2; doLog=false; if(logSubst) if(reverse) for(i=0;iaux2-x == aux2>aux) dd=true; else dd=false; } else{ if(Math.abs(x-aux) > Math.abs(x-aux2)) dd=true; else dd=false; } } result=iY[start+num]; if(doLog) result=exp(result); for(k=1;kprecision){ precision=aux; worstX=x; } } if(doLog) result=log(result); return result; } //----------------------------------------------------------------------------------------------------// /** * finds x: f(x)=y, 1d initialization required */ public double findLimit(double y){ int i, j, m, start, auxdir, auxR; boolean dir, rat=false, rel; double result, aux; double[] ii; reverse=false; if(logSubst) y=log(y); i=0; j=max-1; dir=iY[max-1]>iY[0]; while(j-i>1){ m=(i+j)/2; if(y>iY[m]==dir) i=m; else j=m; } ii=iX; iX=iY; iY=ii; if(!fast){ aux=precision; precision=precisionY; precisionY=aux; aux=worstX; worstX=worstY; worstY=aux; rat=rational; rational=rationalY; } auxR=romberg; romberg=rombergY; rombergY=auxR; rel=relative; relative=relativeY; if(i+1max || start>max) start=max-romberg; result=interpolate(y, start); ii=iX; iX=iY; iY=ii; if(!fast){ aux=precision; precision=precisionY; precisionY=aux; aux=worstX; worstX=worstY; worstY=aux; rational=rat; } auxR=romberg; romberg=rombergY; rombergY=auxR; relative=rel; if(resultxmax) result=xmax; if(isLog) result=Math.exp(result); return result; } //----------------------------------------------------------------------------------------------------// /** * flag check helper */ private double IX(int i, double x){ return flag?I[i].interpolate(x):iX[i]; } //----------------------------------------------------------------------------------------------------// /** * flag check helper */ private double IY(int i, double x){ return flag?I[i].interpolate(x):iY[i]; } //----------------------------------------------------------------------------------------------------// /** * finds x: f(a,x)=y, 2d initialization required */ public double findLimit(double x1, double y){ int i, j, m, start, auxdir, auxR; boolean dir, rat=false, rel; double result, aux, aux2=0; double[] ii; reverse=false; if(logSubst) y=log(y); if(!flag) for(i=0; iIY(0, x1); while(j-i>1){ m=(i+j)/2; aux=IY(m, x1); if(y>aux==dir) i=m; else j=m; } ii=iX; iX=iY; iY=ii; if(!fast){ aux=precision; precision=precisionY; precisionY=aux; aux=worstX; worstX=worstY; worstY=aux; rat=rational; rational=rationalY; } auxR=romberg; romberg=rombergY; rombergY=auxR; rel=relative; relative=relativeY; if(i+1max || start>max) start=max-romberg; if(flag) for(i=start; ixmax) result=xmax; if(!fast){ aux=0; for(i=start; iaux){ aux=I[i].precision; aux2=I[i].worstX; } if(aux>precision2){ precision2=aux; worstX2=aux2; } } if(isLog) result=Math.exp(result); return result; } //----------------------------------------------------------------------------------------------------// final protected static double bigNumber=-300; final protected static double aBigNumber=-299; /** * Exp if not zero */ private static double exp(double x){ if(x<=aBigNumber) return 0; else return Math.exp(x); } //----------------------------------------------------------------------------------------------------// /** * Log if not zero */ private static double log(double x){ if(x<=0) return bigNumber; else return Math.log(x); } //----------------------------------------------------------------------------------------------------// private static double x_save=1, y_save=0; /** * Log it again */ private static double slog(double x){ return x==x_save?y_save:(y_save=Math.log(x_save=x)); } }