/**********
Copyright 1992 Regents of the University of California.  All rights reserved.
Author:	1987 Kartikeya Mayaram, U. C. Berkeley CAD Group
Author:	1992 David A. Gates, U. C. Berkeley CAD Group
**********/

/*
 * Miscellaneous routines culled from the oned directory so that the twod
 * code will run without having to compile the oned code
 */

#include "ngspice/ngspice.h"
#include "ngspice/numglobs.h"
#include "ngspice/numenum.h"
#include "ngspice/spmatrix.h"
#include "ngspice/cidersupt.h"


/* Used in Solution Projection Calculations */
double guessNewConc(double conc, double delta)
{
    BOOLEAN acceptable = FALSE;
    double fib, newConc, lambda, fibn, fibp;
    lambda = 1.0;
    fibn = 1.0;
    fibp = 1.0;
    newConc = 0.0;
    for ( ; !acceptable ; ) {
        fib = fibp;
        fibp = fibn;
        fibn += fib;
        lambda *= fibp / fibn;
        newConc = conc + delta * lambda;
        if( newConc > 0.0 ) {
            acceptable = TRUE;
        }
        else {
            /* newConc is still negative but fibp and fibn are large */
            if ( (fibp > 1e6) || (fibn > 1e6) ) {
                acceptable = TRUE;
                newConc = conc;
            }
        }
    }
    return( newConc );
}

/* Used in Doping Calculation */
/* compute the concentration at x given an array of data.
 * The data is stored in a two-dimensional array x, N(x).
 * x is assumed to be in ascending order. given an x
 * a search is performed to determine the data points closest
 * to it and linear interpolation is performed to generate N(x)
 */

/*
#define LOGSUPREM
*/
double lookup(double **dataTable, double x)
{
    double conc=0.0, x0, x1, y0, y1;
#ifdef LOGSUPREM
    double lnconc, lny0, lny1;
#endif
    int index, numPoints;
    BOOLEAN done = FALSE;

    numPoints = (int)dataTable[ 0 ][ 0 ];
    for( index = 2; index <= numPoints && (!done); index++ ) {
	x1 = dataTable[ 0 ][ index ];
	/* check if x1 > x */
	if( x1 >= x ) {
	    /* found an x1 larger than x, so linear interpolate */
	    x0 = dataTable[ 0 ][ index - 1 ];
	    y0 = dataTable[ 1 ][ index - 1 ];
	    y1 = dataTable[ 1 ][ index ];
#ifdef LOGSUPREM
	    /* Ignore concentrations below 1.0 */
	    if ( ABS(y0) < 1.0 )
		lny0 = 0.0;
	    else
	        lny0 = SGN(y0) * log( ABS(y0) );
	    if ( ABS(y1) < 1.0 )
		lny1 = 0.0;
	    else
	        lny1 = SGN(y0) * log( ABS(y0) );
	    lnconc = lny0 + (lny1 - lny0) * (x - x0) / (x1 - x0);
	    conc = SGN(lnconc) * exp( ABS(lnconc) );
#else
	    conc = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
#endif /* LOGSUPREM */
	    done = TRUE;
	} else {
	    if( index == numPoints ) {
		/* set to concentration of last node - due to roundoff errors */
		conc = dataTable[ 1 ][ numPoints ];
	    }
	}
    }
    return ( conc );
}

/* Used in admittance calculations */
/* this function returns TRUE is SOR iteration converges otherwise FALSE */

BOOLEAN hasSORConverged(double *oldSolution, double *newSolution,
                        int numEqns)
{
    BOOLEAN converged = TRUE;
    int index;
    double xOld, xNew, tol;
    double absTol = 1e-12;
    double relTol = 1e-3;
    for( index = 1 ; index <= numEqns ; index++ ) {
	xOld = oldSolution[ index ];
	xNew = newSolution[ index ];
	tol = absTol + relTol * MAX( ABS( xOld ), ABS( xNew ));
	if( ABS( xOld - xNew ) > tol ) {
	    converged = FALSE;
	    printf("hasSORconverged failed\n");
	    break;
	}
    }
    return( converged ); 
}

/* Used to Check Sparse Matrix Errors */
BOOLEAN
foundError(int error)
{
    BOOLEAN matrixError;

    switch( error ) {
	/*  Removed for Spice3e1 Compatibility 
	case spSMALL_PIVOT:
	    printf( "Warning: LU Decomposition Problem - SMALL PIVOT\n" );
	    matrixError = FALSE;
	    break;
	*/
	case spPANIC:
	    printf( "Error: LU Decomposition Failed - PANIC\n" );
	    matrixError = TRUE;
	    break;
	case spSINGULAR:
	    printf( "Error: LU Decomposition Failed - SINGULAR\n" );
	    matrixError = TRUE;
	    break;
	/*  Removed for Spice3e1 Compatibility 
	case spZERO_DIAG:
	    printf( "Error: LU Decomposition Failed - ZERO PIVOT\n" );
	    matrixError = TRUE;
	    break;
	*/
	case spNO_MEMORY:
	    printf( "Error: LU Decomposition Failed - NO MEMORY\n" );
	    matrixError = TRUE;
	    break;
	default:
	    matrixError = FALSE;
	    break;
    }
    return( matrixError );
}
