//package maestro.lib.math;


public  class MaestroA{
    MaestroA(){}
    
    // polinomial approximation of Bessel function J_0(xin)
    public static final double J0(double xin){
        double x;
        double value = 1.0;
        double f0, theta0;
        double par = 0.0;
        
        x = Math.abs(xin);
        
        if(x == 0.0){
            value = 1.0;
        }
        else if(x > 0.0 && x < 3.0){
            par = x/3;
            value = 1.0 - 2.2499997*Math.pow(par,2)+1.2656208*Math.pow(par,4)
                    -0.3163866*Math.pow(par,6)+0.0444479*Math.pow(par,8)
                    -0.0039444*Math.pow(par,10)+0.0002100*Math.pow(par,12);
        }
        else if(x >= 3.0){
            par = 3/x;
            f0 = 0.79788456 - 0.00000077*par-0.00552740*Math.pow(par,2)
                -0.00009512*Math.pow(par,3)+0.00137237*Math.pow(par,4)
                -0.00072805*Math.pow(par,5)+0.00014476*Math.pow(par,6);

            theta0 = x-0.78539816-0.04166397*par-0.00003954*Math.pow(par,2)
                    +0.00262573*Math.pow(par,3)-0.00054125*Math.pow(par,4)
                    -0.00029333*Math.pow(par,5)+0.00013558*Math.pow(par,6);

            value = f0*Math.cos(theta0)/Math.sqrt(x);
        }
        
        if(xin < 0.0){value = - value;}
        
        return value;
    }
    
    // series expansion of Bessel function J_1(xin)
    /*
    public static final double J1(double xin){
        double x;
        double value = 1.0;
        
        x = Math.abs(xin);
        value = 0.5*x - Math.pow(x,3)/16.0 + Math.pow(x,5)/384.0
                - Math.pow(x,7)/18432.0 + Math.pow(x,9)/1474560.0 
                - Math.pow(x,11)/176947200.0; 
        
        if(xin < 0.0){value = - value;}
        
        return value;
    }
    */
     
    public static final double J1(double xin){
        double x;
        double value = 1.0;
        double f1, theta1;
        double par = 0.0;
        
        x = Math.abs(xin);
        
        if(x == 0.0){
            value = 0.0;
        }
        else if(x > 0.0 && x < 3.0){
            par = x/3;
            value = (0.5 - 0.56249985*Math.pow(par,2)+0.21093573*Math.pow(par,4)
                    -0.3954289*Math.pow(par,6)+0.00443319*Math.pow(par,8)
                    -0.00031761*Math.pow(par,10)+0.00001109*Math.pow(par,12))/x;
        }
        else if(x >= 3.0){
            par = 3/x;
            f1 = 0.79788456 + 0.00000156*par+0.01659667*Math.pow(par,2)
                +0.00017105*Math.pow(par,3)-0.00249511*Math.pow(par,4)
                +0.00113653*Math.pow(par,5)-0.00020033*Math.pow(par,6);

            theta1 = x-2.35619449+0.12499612*par+0.00005650*Math.pow(par,2)
                    -0.00637879*Math.pow(par,3)+0.00074348*Math.pow(par,4)
                    +0.00079824*Math.pow(par,5)-0.00029166*Math.pow(par,6);

            value = f1*Math.cos(theta1)/Math.sqrt(x);
        }
        
        if(xin < 0.0){value = - value;}
        
        return value;
    }
    
    public static final double getMin(double x[]){
	double min;
	min = x[0];
	for(int i=1;i<x.length;i++){
	    if(min>x[i]) {min = x[i];}
	}	
	return min;        
    }
    
    public static final double getMax(double x[]){
	double max;
	max = x[0];
	for(int i=1;i<x.length;i++){
	    if(max<x[i]) {max = x[i];}
	}
	return max;
    }
    
    public static final double getMin(double x[][], int M, int N){
	double min;
	min = x[0][0];
	for(int j=0;j<N;j++){
	for(int i=0;i<M;i++){
	    if(min>x[i][j]) {min = x[i][j];}
	}}	
	return min;        
    }
    
    public static final double getMax(double x[][], int M, int N){
	double max;
	max = x[0][0];
	for(int j=0;j<N;j++){
	for(int i=0;i<M;i++){
	    if(max<x[i][j]) {max = x[i][j];}
	}}
	return max;
    }
    
     public static final double getMin(double x[][], int M, int N, int j){
	double min;
	min = x[0][j];
	for(int i=0;i<M;i++){
	    if(min>x[i][j]) {min = x[i][j];}
	}
	return min;        
    }
    
    public static final double getMax(double x[][], int M, int N, int j){
	double max;
	max = x[0][j];
	for(int i=0;i<M;i++){
	    if(max<x[i][j]) {max = x[i][j];}
	}
	return max;
    }
    
    public static double rounder(double x, int res){
	if(Math.abs(x)*Math.pow(10,res)>1.0*Integer.MAX_VALUE){
	    return x;
	}
	if(x>=0.0){
	    return (int)(Math.abs(x)*Math.pow(10,res)+0.5)/Math.pow(10,res);
	}
	else{
	    return -(int)(Math.abs(x)*Math.pow(10,res)+0.5)/Math.pow(10,res);
	}
    }
    
    public static double rounder(double x, int res, boolean roundoff){
	double tmp;
	if(roundoff){ tmp = 0.5; }
	else{ tmp = 0.0; }
	if(Math.abs(x)*Math.pow(10,res)>1.0*Integer.MAX_VALUE){
	    return x;
	}
	if(x>=0.0){
	    return (int)(Math.abs(x)*Math.pow(10,res)+tmp)/Math.pow(10,res);
	}
	else{
	    return -(int)(Math.abs(x)*Math.pow(10,res)+tmp)/Math.pow(10,res);
	}
    }
    
    public static double mapper(double x, double ymax, double ymin, double xmax, double xmin){
	double a, b;
	if(xmax == xmin){return xmin;}
	a = (ymax-ymin)/(xmax-xmin);
	b = ymax - a * xmax;
	return a*x+b;
    }
    
    public static void confiner(double x[], double xmax, double xmin){
	for(int i = 0 ; i < x.length; i++){
	    if(x[i] < xmin){x[i] = xmin; }
	    if(x[i] > xmax){x[i] = xmax; }
	}
    }
    
    public static void confiner(double x[][], int N, int M, double xmax, double xmin){
	for(int j = 0; j < M; j++){
	for(int i = 0 ; i < N; i++){
	    if(x[i][j] < xmin){x[i][j] = xmin; }
	    if(x[i][j] > xmax){x[i][j] = xmax; }
	}}
    }
    
     public static void confiner(double x[][], int N, int M, double xmax, double xmin, int j){
	for(int i = 0 ; i < N; i++){
	    if(x[i][j] < xmin){x[i][j] = xmin; }
	    if(x[i][j] > xmax){x[i][j] = xmax; }
	}
    }
    
    public static void randomizer(double x[], double xmax, double xmin,int tipo){
	switch(tipo){
	    case 1: //totally random
		for(int i = 0; i < x.length; i++){
		    x[i] = xmin+(xmax-xmin)*Math.random();
		}
		break;
	    case 2: //noise sine
		for(int i = 0; i< x.length; i++){
		    x[i] = (xmax-xmin)*(Math.sin(2.0*Math.PI*i/x.length)+0.2*Math.random());
		}
		break;
	}
    }
    
    public static void signal_stir(double x[],double wt, double xmax, double xmin,int tipo){
	switch(tipo){
	    case 1://sin function
		for(int i = 0; i < x.length; i++){
		    x[i] = (xmax - xmin) * Math.sin(wt+2.0*Math.PI*i/x.length);
		}
		break;
	    case 2://noisy sin function
		for(int i = 0; i < x.length; i++){
		    x[i] = (xmax - xmin) * (Math.sin(wt+2.0*Math.PI*i/x.length)+0.2*Math.random());
		}
		break;
	} 
    }
    
    public static double[] rotation(double x[],double theta){
	double tmp[] = new double[2];
	tmp[0] = x[0] * ( Math.cos(theta) ) + x[1] * ( Math.sin(theta) );
	tmp[1] = x[0] * (-Math.sin(theta) ) + x[1] * ( Math.cos(theta) );
	return tmp;
    }
    
    public static double[] inv_rotation(double x[],double theta){
	double tmp[] = new double[2];
	tmp[0] = x[0] * ( Math.cos(theta) ) + x[1] * (-Math.sin(theta) );
	tmp[1] = x[0] * ( Math.sin(theta) ) + x[1] * ( Math.cos(theta) );
	return tmp;
    } 
    
    
}