/*
 *              Philips Electronics N.V. 2001.
 *  This information is proprietary to Philips Electronics N.V. and is
 *  protected by copyright. If you copy this material you agree to indemnify,
 *  hold harmless and defend Philips Electronics N.V. or any of its
 *  affiliated companies against any claims, lawsuits, including attorney's
 *  fees that arise or result from the use of this material.

  This file is intended for help in implementing software, according to the 
  documentation given in 
    Nat.Lab. Unclassified Report NL-UR 2001/801,
    ``Parameter Extraction for the Bipolar Transistor Model Mextram,
    level 504''
    J.C.J. Paasschens, W.J. Kloosterman, and R.J. Havens.
    see www.semiconductors.philips.com/Philips_Models

  In the report various routines are discussed and explained. This file
  contains code to support these routines in extraction software.
  Since the code in this file is stripped of all parts copyrighted to
  other companies, there is no longer any interaction with an
  extraction software tool coded. 
  The code in this file is therefore not directly usable.
  (In some parts it is more macro code than real c-code.)


  For the model equations of Mextram 504, used in this code, see 
    Nat.Lab. Unclassified Report NL-UR 2000/811,
    ``The Mextram Bipolar Transistor Model, level 504''
    J.C.J. Paasschens and W.J. Kloosterman.
    see www.semiconductors.philips.com/Philips_Models
*/


/*------------------------------------------------*/
/* mxtpardef.h */
/* contains the various definitions of model parameters and some much used
/* quantities */

   double level,mult,tref,dta,exmod,exphi,exavl,is,ik,vef,ver,
          bf,ibf,mlf,xibi,bri,ibr,vlr,xext,wavl,vavl,sfh,
          re,rbc,rbv,rcc,rcv,scrcv,ihc,axi,cje,vde,pe,xcje,cbeo,
          cjc,vdc,pc,xp,mc,xcjc,cbco,mtau,taue,taub,tepi,taur,
          aqbo,ae,ab,aex,aepi,ac,dvgbf,dvgbr,vgb,vgc,vgj,dvgte,
          iss,iks,cjs,vds,ps,vgs,as,
          deg, xrec,rth,cth;

   double isT,ikT,vefT,verT,
          bfT,ibfT,briT,ibrT,
          reT,rbcT,rbvT,rccT,rcvT,cjeT,vdeT,
          cjcT,vdcT,xpT,taueT,taubT,tepiT,
          issT,iksT,cjsT,vdsT, degT;

   double cpcs, bnT_bn;
   double kq,Gmin,aje,vfe,ajc,bjc,vfc,ajs;
   double temp,tk,trk,tn,vt,vtr,inv_vDt;

   double aq0i, deg_vt;

/* end mxtpardef.h */
/*------------------------------------------------*/
/* Giving values to the various parameter is not coded.
   Part of the code that does so, could contain (see Sec. 2.6.3 of
   aforementioned report):
        if (taub < 0) 
          taub = ver * (1-xcje) * cje / ik;
        if (tepi < 0) 
          tepi = taub * is * ik * rcv*rcv * exp(vdc/vtr) / (4*vtr*vtr);
        if (taur < 0) 
          taur = (taub+tepi) * (1-xcjc)/xcjc;
   The constants are defined by
        Gmin = 1e-13;
        aje  = 3.0;
        ajc  = 2.0;
        ajs  = 2.0;
*/
/*------------------------------------------------*/
/* mxtTrules.h */
/* Temperature rules */
/* tk, trk, tn, vt, vtr, inv_vDt must be set. */

        reT =re *pow(tn,ae);
	rbvT=rbv*pow(tn,ab-aqbo);      
	rbcT=rbc*pow(tn,aex);
	rccT=rcc*pow(tn,ac); 
	rcvT=rcv*pow(tn,aepi); 
       
	vdeT=-3*vt*log(tn)+vde*tn+(1-tn)*vgb;
        vdeT = vdeT + vt*log(1+exp((0.05-vdeT)/vt));
	cjeT=cje*pow((vde/vdeT),pe);
  
	vdsT=-3*vt*log(tn)+vds*tn+(1-tn)*vgs;
        vdsT = vdsT + vt*log(1+exp((0.05-vdsT)/vt));
	cjsT=cjs*pow((vds/vdsT),ps);
  
	vdcT =-3*vt*log(tn)+vdc*tn+(1-tn)*vgc;
        vdcT = vdcT + vt*log(1+exp((0.05-vdcT)/vt));
	cjcT =cjc*((1-xp)*pow((vdc/vdcT),pc)+xp);
	xpT  =xp  *(cjc/cjcT);
  
        vefT=vef * pow(tn,aqbo) * cjc/cjcT;
        verT=ver * pow(tn,aqbo) * cje/cjeT;

	bfT  = bf * pow(tn,ae-ab-aqbo) * exp(-dvgbf*inv_vDt);
	briT = bri                     * exp(-dvgbr*inv_vDt);
      
	isT  = is * pow(tn,4.0-ab-aqbo) * exp(-vgb*inv_vDt);
	ikT  = ik * pow(tn,1-ab);
	ibfT = ibf* pow(tn,6-2*mlf) * exp(-vgj*inv_vDt/mlf);
	ibrT = ibr* tn*tn * exp(-0.5*vgc*inv_vDt);

	issT = iss* pow(tn,4.0-as) * exp(-vgs*inv_vDt);
        if ( (issT !=0) && (is !=0) ) {
	  iksT=iks*pow(tn,1-as)* isT/is * iss/issT;
        }
        else {
	  iksT=iks*pow(tn,1-as);
        }

        taueT=taue*pow(tn,ab-2.0) * exp(-dvgte*inv_vDt);
        taubT=taub*pow(tn,aqbo+ab-1.0);
        tepiT =tepi* pow(tn,aepi);

      
	bnT_bn = (1+7.2E-4*(tk-300)-1.6E-6*(tk-300)*(tk-300));


        bjc = (ajc-xpT)/(1-xpT);
        vfc = vdcT * (1-pow(bjc,-1.0/pc));
        vfe = vdeT * (1-pow(aje,-1.0/pe));


        degT = deg * pow(tn,aqbo);
        deg_vt = degT/vt;
        if (degT == 0)
          aq0i = 0.0;
        else 
          aq0i = 1.0 / (exp(deg_vt)-1.0);


        if (axi  < 0.02) axi  = 0.02;

/* end mxtTrules.h */
/*------------------------------------------------*/
/*------------------------------------------------*/
/* Normal functions */

MXT_show_parms
{
#include "mxtpardef.h"

   double taub0, tepi0, taur0, verI, vefI;



   taub0 = verT*cjeT*(1-xcje)/ikT;
   tepi0 = taub * is * ik * rcv*rcv * exp(vdc/vtr) / (4*vtr*vtr)
           * pow(tn,aepi); 
   taur0 = (taub+tepi) * (1-xcjc)/xcjc;

   if (degT == 0) {
     verI = verT;
     vefI = vefT;
   } else { 
     verI  = verT / (deg_vt * aq0i * exp(deg_vt));
     vefI  = vefT / (deg_vt * aq0i);
   }




   printf("level, Temp, vt        : %6.1f %6.1f %9.6f\n", level, tk-273.15,vt);
   printf("mult,exmod,exavl,exphi : %6.3f %6.3f %6.3f %6.3f\n",
           mult,exmod,exavl,exphi);
   printf("Tref,dta,aqbo,dvgbf/br : %6.3f %6.3f %6.3f %6.3f %6.3f\n",
           tref,dta,aqbo,dvgbf,dvgbr);
   printf("ae,ab,ac,aex,aepi,as   : %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n",
           ae,ab,ac,aex,aepi,as);
   printf("dvgte,vgj,vgb,vgc,vgs  : %6.3f %6.3f %6.3f %6.3f %6.3f\n",
           dvgte,vgj,vgb,vgc,vgs);
   printf("wavl,vavl,sfh,axi      : %13.3e %6.3f %6.3f %6.3f\n",
           wavl,vavl,sfh,axi );
   printf("Rth, Cth, deg, xrec    : %9.3f %9.3e  %6.3f %6.3f\n", 
           rth, cth, deg, xrec);

   printf("\n");
   printf("Bf,Ibf,mlf     : %6.2f %9.3e %6.3f\n",
                     bfT, ibfT, mlf);
   printf("Br,Ibr,Vlr     : %6.2f %9.3e %6.3f\n",
                     briT, ibrT, vlr);

   printf("Re,Rbc,Rbv,Rcc : %9.3f %9.3f %9.3f %9.3f\n",
           reT, rbcT, rbvT, rccT);
   printf("Rcv,SCRcv,Ihc  : %9.3f %9.3f %9.3e (%8.3f %8.3f)\n", 
          rcvT, scrcv, ihc, rcvT*ihc, scrcv*ihc);

   printf("\n");
   printf("Is ,Ik ,Iss,Iks  : %9.3e %9.3e %9.3e %9.3e\n",isT, ikT,issT,iksT);
   printf("Ver,Vef,VerI,VefI: %9.3f %9.3f %9.3f %9.3f\n",verT,vefT,verI,vefI);

   printf("\n");
   printf("xcje,xib1,xcjc,xext    : %6.3f %6.3f %6.3f %6.3f\n",
           xcje,xibi,xcjc,xext);
   printf("Cbeo, Cbco             : %9.3e %9.3e \n", cbeo, cbco);
   printf("Cje,Vde,pe             : %9.3e %6.3f %6.3f\n", cjeT, vdeT, pe);
   printf("Cjc,Vdc,pc,xp,mc       : %9.3e %6.3f %6.3f %6.3f %6.3f\n",
           cjcT, vdcT, pc, xpT, mc );
   printf("Cjs,Vds,ps             : %9.3e %6.3f %6.3f\n", cjsT, vdsT, ps);

   printf("\n");
   printf("Taub,Tepi      : %9.3e (%9.3e) %9.3e (%9.3e)\n",
          taubT,taub0,tepiT,tepi0);
   printf("Taur,Taue,mtau : %9.3e (%9.3e) %9.3e  %9.3f\n",
           taur,taur0,taueT,mtau);



   return 0;

}
  


MXT_ft
{
#include "mxtpardef.h"
  
    double *qqic,*qqvbe,*qqvce;
    double qvbc,qic;
    
    double  
           vb2e1, vb2c1, vb1c1, vbb2, vbb1, vbc1, vb1e1,
           dvb2c1_Dx,
           dvb1c1_dx, dvb1c1_di, dvb1c1_dz, 
           dvbb2_dx, dvbb2_di, dvbb2_dz, 
           dve1e_dx, dve1e_di, dve1e_dz,
           dvbb1_dx, dvbb1_di, dvbb1_dz,
           dvcc1_dx, dvcc1_di, dvcc1_dz,
           dvbc1_dx, dvbc1_di, dvbc1_dz,
           vjunc, dvjunc_di, dvjunc_dz, 
           vec0, dvec0_di, iepi, diepi_di, diepi_dz,
           Dvb2e1, Din, 
           iff, diff_dx, f1, df1,root, n0, dn0_dx, 
           irr, dirr_di, dirr_dz, f2, df2, nb, dnb, dnb_dz, dnb_di, 
           in, din_Dx, din_dx, din_di, din_dz,
           q1, dq1_dx, dq1_di, dq1_dz, 
           qB, dqB_dx, dqB_di, dqB_dz,
           ib, dib_dx, Ib1, dIb1_dx, Ib2, dIb2_dx,
           rb, drb_dx, drb_di, drb_dz, 
           rbvinv, drbvinv_Dx, drbvinv_dx, drbvinv_di, drbvinv_dz, vv, Dvv, 
           vje, dvje_dx, vte, dvte_dx, dvtes_dx, dvtes_dv, 
           vch, dvch_dz, dvch_di,
           vj, dvj_dv, dvj_dvch,
           fI, dfI_dicap,
           vcv, dvcv_dv, dvcv_dvch, dvcv_dicap,
           vjc, dvjc_dy, dvjc_dv, 
           vtc, dvtc_di, dvtc_dz, dvtc_dv, dvtc_dvch, dvtc_dicap,
           icap, dicap_di, 
           qe0, qe, dqe_dx,
           dqte_dx, dqtes_dx, dqtes_di, dqtes_dz, dqtes_dv, 
           dqtc_di, dqtc_dz, qbe, 
           qb0, dqbe_dx, dqbe_di, dqbe_dz, dqbc_dx, dqbc_di, dqbc_dz, 
           qepi0, qepi, dqepi_di, dqepi_dz, 
           qtex, dqtex_dx, dqtex_di, dqtex_dz, dqtex_dv, dxqtex_dv,
           xqtex, xdqtex_dx, xdqtex_di, xdqtex_dz, xdqtex_dv,
           dcbeo_dx, dcbeo_di, dcbeo_dz, dcbco_dx, dcbco_di, dcbco_dz,
           tau, dvce_dx, dvce_di, dvce_dz, dq_dx, dq_di,dq_dz, 
           a, da_dx, da_di, da_dz, da_dv, da,
           b, db_dx, db_di, db_dz, db_dv, db,
           d, dd_dx, e, de_dv, de_di,
           tol, b1, b2;

    double v, dv_dv, dv_dz, dv_di,
           ii, dii_dz, dii_di, alfa, dalfa_di, dalfa_dz,
           a0, a1, da2_dz, da2_di, a2, a3, da3, a4, da4, da4_dv, da4_dvch, a5,
           dz_di, dx_di, denom;
    double alfa0;
    double vqs, dvqs_dz, dvqs_di, 
           iqs, diqs_dz, diqs_di, diqs_dv,
           yi, dyi_dz, dyi_di, dyi_dv,
           xi, dxi_dz, dxi_di,
           g, dg_dz, dg_di,
           p0star, dp0star_di, dp0star_dz;
   
    
    double dt, hard_sat_max, vb2c1max;
    double dum;
    int    itvv, it,itmax, i;
    int FALSE =  0;
    int TRUE = 1;
    
        

        vb2c1max = hard_sat_max * vdcT;

        alfa0 = 1.0/(1.0+ axi * log(1+exp(-1.0/axi)));


	itmax=15;
        tol  =1E-9;



   /* Go through all bias points and calculate current */
  
	for(i = 0; i < imax; i++)
	{
	  qvbc=qqvbe[i]-qqvce[i];
          qic =qqic[i];

	  dt = qqvce[i] * qic * rth;
	    
	  tk =temp+273.15+dt+dta;
	  trk=tref+273.15;
	  tn=tk/trk;
	    
	  vt = kq*tk;
	  vtr= kq*trk;
          inv_vDt= 1/vt - 1/vtr;

#include "mxtTrules.h"

          if (qic <= 0.0) { 
            result = 0.0;
	  } else {

            /* first estimates */
	    if (i==0) {
		vb2e1 = vt*log(qqic[0]/isT);
                vv    = qqic[0] * rbvT/(bfT*vt);      /* vv = vb1b2/vt */
	    } else
	    {
		if (qqic[i]<qqic[i-1]) {
		    vb2e1 = vt*log(qqic[i]/isT);
                    vv    = qqic[i] * rbvT/(bfT*vt);
		} else
                    Dvb2e1 = (qqic[i]-qqic[i-1])/din_Dx;
		    vb2e1 = vb2e1 + Dvb2e1;
	    }

            a        = ihc/(qic+ihc);
            icap     = qic * a;
            dicap_di =  a  * a;

	    b1        = 0.5*scrcv*(qic-ihc);
	    b2        = scrcv*ihc*rcvT*qic;
	    vec0      = b1+sqrt(b1*b1+b2);
            dvec0_di  = scrcv * (vec0+ihc*rcvT)*(vec0+ihc*rcvT)/
                        (vec0*vec0+2*vec0*ihc*rcvT+scrcv*rcvT*ihc*ihc);

	    
            /* find vb2e1 iteratively */
            for ( it=0, Dvb2e1 = 10*tol;
                  (it<itmax) && (fabs(Dvb2e1) > tol);  it++)
	    {
		iff     = isT*exp(vb2e1/vt);
		diff_dx = iff/vt ;

	        Ib1     = isT/bfT*exp(vb2e1/vt);
                dIb1_dx = Ib1/vt;

	        Ib2     = ibfT*exp(vb2e1/(mlf*vt));
                dIb2_dx = Ib2/(mlf*vt);

                ib      = Ib1     + Ib2;
                dib_dx  = dIb1_dx + dIb2_dx;


	        a        = 1.0 + (1-xibi)*rbvT/bfT;
	        vbb2     = rbcT*ib + vt * log(1.0 + a*qic/vt);
	        dvbb2_dx = rbcT*dib_dx;
	        dvbb2_di = a / (1.0 + a*qic/vt);
                dvbb2_dz = 0.0;


                vb2c1     = qvbc + qic*rccT -  vbb2;
                dvb2c1_Dx =                 - dvbb2_dx;

                a         = qic*rcvT/(2*vt)+1;
                b         = vdcT - vb2c1 + 2*vt * log(a);
                root      = sqrt(b*b + 4*0.01*vdcT*vdcT);
                vqs       = (b + root) / 2.0 ;
                dvqs_dz   = -0.5 * (1.0 + b / root) ;
                dvqs_di   =  0.5 * (1.0 + b / root) * rcvT/a;

                a         = vqs+ihc*rcvT;
                iqs       = vqs/scrcv * (vqs+ihc*scrcv)/ a;
                diqs_dv   = 1.0/scrcv + (scrcv-rcvT)*rcvT*ihc*ihc/(scrcv*a*a);
                diqs_dz   = diqs_dv * dvqs_dz;
                diqs_di   = diqs_dv * dvqs_di;


/* Calculation of yi */
                ii =     qic/iqs;
                dii_dz = (    - ii * diqs_dz)/iqs;
                dii_di = (1.0 - ii * diqs_di)/iqs;

                if (ii < 1) {
                  a0 = exp((ii-1)/axi);
                  a1 = axi * log(1+a0);
                  alfa     = alfa0 * (1+a1);
                  dalfa_dz = alfa0 * a0 * dii_dz/ (1+a0); 
                  dalfa_di = alfa0 * a0 * dii_di/ (1+a0);
                } else { 
                  a  = (1-ii)/axi;
                  if (a > -40) 
                    a0 = exp(a);
                  else
                    a0 = 0.0;
                  a1 = axi * log(1+a0);
                  alfa     = alfa0 * (ii+a1);
                  dalfa_dz = alfa0 * dii_dz/ (1+a0);
                  dalfa_di = alfa0 * dii_di/ (1+a0);
                }

                dv_dv = 1.0 / (ihc * scrcv);
                v     =  vqs    * dv_dv;
                dv_dz = dvqs_dz * dv_dv;
                dv_di = dvqs_di * dv_dv;


                a2     = alfa * (1+v);
                da2_dz = dalfa_dz * (1+v) + alfa * dv_dv * dvqs_dz;
                da2_di = dalfa_di * (1+v) + alfa * dv_dv * dvqs_di;

                yi        = (1.0 + sqrt(1.0+4.0 * v * a2))/(2 * a2);
                dyi_dv   =  1.0 / (2 * a2 * yi - 1.0);
                /* dyi_da2 = - yi*yi * dyi_dv; */

                dyi_dz = dyi_dv * (dv_dz - yi*yi*da2_dz);
                dyi_di = dyi_dv * (dv_di - yi*yi*da2_di);

/* END of Calculation of yi */

                xi        = 1 - yi;
                dxi_dz    = -dyi_dz;
                dxi_di    = -dyi_di;

                g         = rcvT * qic * xi           / (2*vt);
                dg_dz     = rcvT * qic * dxi_dz       / (2*vt);
                dg_di     = rcvT *(qic * dxi_di + xi) / (2*vt);

                a         = 0.25 * (g-1) * (g-1) + 2.0*g;
                da        = 0.5  * (g-1)         + 2.0;
                root      = sqrt(a);
                p0star    = 0.5 * (g-1) + root;
                dp0star_dz= 0.5 * (1.0 + da/root) * dg_dz;
                dp0star_di= 0.5 * (1.0 + da/root) * dg_di;



                a      = isT*exp(vdcT/vt);
		irr    = a * p0star * (p0star+1);
                dirr_dz= a * (2*p0star + 1) * dp0star_dz;
                dirr_di= a * (2*p0star + 1) * dp0star_di;

		df2    = 4/ikT;
		f2     = df2 * irr;

                root   = sqrt(1+f2);
                nb     = f2  / (1+root);
                dnb    = df2 / (2*root);
                dnb_dz = dnb * dirr_dz;
                dnb_di = dnb * dirr_di;



                /* continue with other quantities */
                e       = exp((vb2e1-vfe)/(0.1*vdeT));
                vje     = vb2e1  - 0.1*vdeT*log(1+e);
                dvje_dx = 1/(1+e);
                vte     = vdeT/(1-pe)*(1-pow(1-vje/vdeT,1-pe))+aje*(vb2e1-vje);
                dvte_dx = (pow(1-vje/vdeT,-pe) - aje) * dvje_dx + aje;

                vjunc     = vb2c1 + vec0;
                dvjunc_dz = 1.0;
                dvjunc_di = dvec0_di;
                
                a         = 1.0 / (qic + iqs);
                vch       = vdcT * (0.1 + 2.0 * qic * a);
                dvch_dz   = vdcT * 2.0 * (     - diqs_dz * qic) * a * a;
                dvch_di   = vdcT * 2.0 * (iqs  - diqs_di * qic) * a * a;

                if (vjunc <= vfc) {
                  a2     = exp((vjunc-vfc)/vch);
                  a3     = log(1.0+a2);
                  vj     = vjunc - vch * a3;
                  dvj_dv = 1.0 / (1.0 + a2) ;
                  dvj_dvch=(a2/(1.0+a2) * (vjunc-vfc)/vch - a3);
                } else {
                  a2     = exp((vfc-vjunc)/vch);
                  a3     = log(1.0+a2);
                  vj     = vfc  - vch * a3;
                  dvj_dv = a2  / (1.0 + a2) ;
                  dvj_dvch=(a2/(1.0+a2) * (vfc-vjunc)/vch - a3);
                }

                a1        = 1 - icap/ihc;
                fI        = pow(a1, mc);
                dfI_dicap = -mc * fI / (a1 * ihc);

                a3      = 1 - vj / vdcT;
                a4      = pow(a3, 1.0-pc);
                da4_dv  = - (1.0-pc) * a4 * dvj_dv   / (a3 * vdcT);
                da4_dvch= - (1.0-pc) * a4 * dvj_dvch / (a3 * vdcT);

                a5        = vdcT / (1-pc);
                vcv       = a5  * (1- fI * a4);
                dvcv_dv   = - a5 * fI * da4_dv  ;
                dvcv_dvch = - a5 * fI * da4_dvch;
                dvcv_dicap= - a5 * dfI_dicap * a4  ;

                vtc       = (1-xpT) * (vcv + fI * bjc * (vjunc-vj))
                          + xpT * vb2c1;
                dvtc_dz   = xpT;
                dvtc_dv   = (1-xpT) * (dvcv_dv   + fI * bjc * (1-dvj_dv));
                dvtc_dvch = (1-xpT) * (dvcv_dvch - fI * bjc * dvj_dvch);
                dvtc_dicap= (1-xpT) * (dvcv_dicap+ dfI_dicap*bjc*(vjunc-vj));

                dvtc_dz   = dvtc_dv * dvjunc_dz 
                          + dvtc_dvch * dvch_dz + dvtc_dz;
                dvtc_di   = dvtc_dv * dvjunc_di + dvtc_dicap * dicap_di 
                          + dvtc_dvch * dvch_di;

                if (degT == 0) {
		  q1     = 1.0+vte   /verT +  vtc   /vefT;
		  dq1_dx =    dvte_dx/verT; 
		  dq1_dz =                    dvtc_dz/vefT;
		  dq1_di =                    dvtc_di/vefT;
                } else {
                  a      = exp( deg_vt*(vte/verT+1));
		  b      = exp(-deg_vt * vtc/vefT);
                  q1     = aq0i * (a-b);
                  dq1_dx = aq0i * a * deg_vt * dvte_dx/verT;
                  dq1_dz = aq0i * b * deg_vt * dvtc_dz/vefT;
                  dq1_di = aq0i * b * deg_vt * dvtc_di/vefT;
                }


		df1    = 4/ikT;
		f1     = df1*iff;

                root   = sqrt(1+f1);
                n0     = f1  / (1+root);
                dn0_dx = df1 / (2*root) * diff_dx;

                qB     =  q1    * (1.0 + 0.5 * (n0 + nb));
                dqB_dx = dq1_dx * (1.0 + 0.5 * (n0 + nb)) + q1 * 0.5 * dn0_dx;
                dqB_dz = dq1_dz * (1.0 + 0.5 * (n0 + nb)) + q1 * 0.5 * dnb_dz;
                dqB_di = dq1_di * (1.0 + 0.5 * (n0 + nb)) + q1 * 0.5 * dnb_di;

		in     = (iff-irr)/qB;
		din_dx = ( diff_dx -in*dqB_dx)/qB;
		din_dz = (-dirr_dz -in*dqB_dz)/qB;
		din_di = (-dirr_di -in*dqB_di)/qB;

                din_Dx = din_dx + din_dz * dvb2c1_Dx;

		Din    = qic - in;
		Dvb2e1 = Din/din_Dx;
		/* for better convergence when starting at high end*/
		if (Dvb2e1 > 1.5*vt) Dvb2e1= 1.5*vt;
                if (Dvb2e1 <-2.0*vt) Dvb2e1=-2.0*vt;

		vb2e1  = vb2e1+Dvb2e1;
              

    	    } /* end loop determining vb2e1 */
 

/* post processing: all voltages are known */   
	    if (vb2c1 > vb2c1max)
		result=0;
	    else
	    {
                /* voltages */
                vbb1     = rbcT* ib;
	        dvbb1_dx = rbcT*dib_dx;
	        dvbb1_dz = 0.0;      
	        dvbb1_di = 0.0;      

		vb1c1     = vb2c1 +  vbb2     -  vbb1 ;
		dvb1c1_dx =         dvbb2_dx  - dvbb1_dx;
		dvb1c1_dz = 1.0   + dvbb2_dz  - dvbb1_dz;
		dvb1c1_di =         dvbb2_di  - dvbb1_di;

		vbc1     = vb2c1 +  vbb2   ;
		dvbc1_dx =         dvbb2_dx; 
		dvbc1_dz = 1.0   + dvbb2_dz;
		dvbc1_di =         dvbb2_di; 

            /*  vcc1      = qic * rccT */
                dvcc1_dx  = 0.0;
                dvcc1_dz  = 0.0;
                dvcc1_di  = rccT; 

            /*  ve1e      = (qic + ib) * reT ; */
                dve1e_dx  = dib_dx*reT; 
                dve1e_dz  = 0.0;
                dve1e_di  = reT; 
   
            /*  vce      =  vcc1 - vb2c1 + vb2e1 + ve1e ; */
		dvce_dx  = dvcc1_dx + 1  + dve1e_dx;
		dvce_dz  = dvcc1_dz - 1  + dve1e_dz;
		dvce_di  = dvcc1_di      + dve1e_di;


                /* charges */
                vb1e1   = vb1c1 - vb2c1 + vb2e1;
                e       = exp((vb1e1-vfe)/(0.1*vdeT));
                vje     = vb1e1  - 0.1*vdeT*log(1+e);
                dvje_dx = 1/(1+e);
             /* vtes  = vdeT/(1-pe)*(1-pow(1-vje/vdeT,1-pe))+aje*(vb2e1-vje);*/
                dvtes_dv = (pow(1-vje/vdeT,-pe) - aje) * dvje_dx + aje;

                dqtes_dv = xcje * cjeT * dvtes_dv;
                dqtes_dx = dqtes_dv * ( 1.0 + dvb1c1_dx);
                dqtes_dz = dqtes_dv * (-1.0 + dvb1c1_dz);
                dqtes_di = dqtes_dv * (       dvb1c1_di);

                dqte_dx   = (1.0-xcje)*cjeT*dvte_dx;

             /* qtc       = xcjc*cjcT*vtc; */
                dqtc_dz   = xcjc*cjcT*dvtc_dz;
                dqtc_di   = xcjc*cjcT*dvtc_di;

		q1     = 1.0+vte   /verT +  vtc   /vefT;
		dq1_dx =    dvte_dx/verT; 
		dq1_dz =                    dvtc_dz/vefT;
		dq1_di =                    dvtc_di/vefT;

                qb0       = taubT * ikT;
             /* qbe       = 0.5 * qb0 *   q1    * n0;  */
                dqbe_dx   = 0.5 * qb0 * (dq1_dx * n0 + q1 * dn0_dx);
                dqbe_dz   = 0.5 * qb0 *  dq1_dz * n0;
                dqbe_di   = 0.5 * qb0 *  dq1_di * n0;

             /* qbc       = 0.5 * qb0 *   q1    * nb;  */
                dqbc_dx   = 0.5 * qb0 *  dq1_dx * nb;
                dqbc_dz   = 0.5 * qb0 * (dq1_dz * nb + q1 * dnb_dz);
                dqbc_di   = 0.5 * qb0 * (dq1_di * nb + q1 * dnb_di);

                qepi0    = tepiT * 4 * vt / rcvT;
            /*  qepi     = 0.5*qepi0 * xi * (p0star + 2); */
                dqepi_dz = 0.5*qepi0 * (dxi_dz * (p0star+2) + xi * dp0star_dz);
                dqepi_di = 0.5*qepi0 * (dxi_di * (p0star+2) + xi * dp0star_di);


		qe0     = taueT*ikT * pow(isT/ikT, 1/mtau );
		qe      = qe0*exp(vb2e1/(mtau*vt));
		dqe_dx  = qe/(mtau*vt);


                e       = exp((vb1c1-vfc)/(0.1*vdcT));
                vjc     = vb1c1  - 0.1*vdcT*log(1+e);
                dvjc_dv = 1/(1+e);
             /* vcv     = vdcT/(1-pc)*(1-pow(1-vjc/vdcT,1-pc))+bjc*(vb1c1-vjc);
              * qtex    = (1-xcjc)*cjcT * ((1-xpT) * vcv     + xpT * vb1c1); */
                dvcv_dv = (pow(1-vjc/vdcT,-pc) - bjc) * dvjc_dv  + bjc;
                dqtex_dv= (1-xcjc)*cjcT * ((1-xpT) * dvcv_dv + xpT);

                e       = exp((vbc1-vfc)/(0.1*vdcT));
                vjc     = vbc1  - 0.1*vdcT*log(1+e);
                dvjc_dv = 1/(1+e);
             /* vcv     = vdcT/(1-pc)*(1-pow(1-vjc/vdcT,1-pc))+bjc*(vbc1-vjc);
              * xqtex    = (1-xcjc)*cjcT * ((1-xpT) * vcv     + xpT * vbc1); */
                dvcv_dv = (pow(1-vjc/vdcT,-pc) - bjc) * dvjc_dv  + bjc;
                dxqtex_dv= (1-xcjc)*cjcT * ((1-xpT) * dvcv_dv + xpT);

		dqtex_dx = (1-xext)* dqtex_dv * dvb1c1_dx + 
                              xext *dxqtex_dv * dvbc1_dx   ;
		dqtex_dz = (1-xext)* dqtex_dv * dvb1c1_dz + 
                              xext *dxqtex_dv * dvbc1_dz   ;
		dqtex_di = (1-xext)* dqtex_dv * dvb1c1_di + 
                              xext *dxqtex_dv * dvbc1_di   ;

 
             /* qbeo     = cbeo * (  vbb2 + vb2e1 + ve1e ); */
		dcbeo_dx = cbeo * ( dvbb2_dx +  1 + dve1e_dx);
		dcbeo_dz = cbeo * ( dvbb2_dz      + dve1e_dz);
		dcbeo_di = cbeo * ( dvbb2_di      + dve1e_di);
   
             /* qbco     = cbco * (  vbb2 + vb2c1 + vc1c ); */
		dcbco_dx = cbco * (dvbb2_dx       - dvcc1_dx);
		dcbco_dz = cbco * (dvbb2_dz + 1.0 - dvcc1_dz); 
		dcbco_di = cbco * (dvbb2_di       - dvcc1_di); 



		dq_dx   =            dqtex_dx + dqtes_dx + dqte_dx + 
                          dqbe_dx  + dqbc_dx  + dqe_dx +
                          dcbeo_dx + dcbco_dx;       
		dq_dz   = dqtc_dz  + dqtex_dz + dqtes_dz +
                          dqbe_dz  + dqbc_dz          + dqepi_dz +
                          dcbeo_dz + dcbco_dz;
		dq_di   = dqtc_di  + dqtex_di + dqtes_di +
                          dqbe_di  + dqbc_di          + dqepi_di +
                          dcbeo_di + dcbco_di;
                break;



   /* Now we solve the equations
    * dvce = dvce_dx dx + dvce_dz dz + dvce_di di = 0
    * din  = din_dx  dx + din_dz dz  + din_di di  = di
    * This gives us dx_di and dz_di: */

                denom = dvce_dx * din_dz - dvce_dz * din_dx;
                dx_di = (dvce_dz * (din_di-1) - dvce_di * din_dz) / denom;
                dz_di =-(dvce_dx * (din_di-1) - dvce_di * din_dx) / denom;
                

		tau     = ( dq_di +  dq_dx * dx_di +  dq_dz * dz_di);


		result= 1 /( 2*M_PI*tau);       

	    }
	  }
	}  
    }

}



MXT_ic_vce
{
#include "mxtpardef.h"

    double vb2e1, vb2c1, Dvb2e1, vb1b2, dvb2c1_dx,
           Ib1, dIb1_dx, dIb1_di, Ib2, dIb2_dx,  Ib1S, dIb1S_dx, 
           Ib, dIb_dx, dIb_di, Ibmin, dIbmin_dx,
           vje, dvje_dx, vte, dvte_dx, 
           ic1c2, Dic1c2, ic1c2prev,
           vqs, dvqs_dx, dvqs_di, iqs, diqs_dx, diqs_di, diqs_dv,
           i_i, di_i_dx, di_i_di,
           alfa0, alfa, dalfa_dx, dalfa_di, v, dv_dx,  dv_di, 
           yi, dyi_dv, dyi_dx, dyi_di, xi, dxi_dx, dxi_di,
           g, dg, dg_dx, dg_di,
           p0star, dp0star_dx, dp0star_di,
           iff, diff_dx, irr, dirr_dx, dirr_di, in, din_dx, din_di,
           q1, dq1_dx, dq1_di, qB, dqB_dx, dqB_di,
           root, f1, df1, f2, df2,
           nb, dnb_dx, dnb_di, n0, dn0_dx,
           vec0, vjunc, dvjunc_dx, dvjunc_di, icap, dicap_di, b1, b2,
           vch, dvch_dx, dvch_di, vj, dvj_dv, dvj_dvch, fI, dfI_dicap,
           vcv, dvcv_dv, dvcv_dvch, dvcv_dicap, 
           vtc, dvtc_dv, dvtc_dvch, dvtc_dicap, dvtc_dx, dvtc_di;
    double ibm, g1, g2, j11, j12, j21, j22, det;
    double an, bn, bnT, efi, dEdx0, xd0,
           xd, dxd_dvb2c1, dxd_dicap, weff, dweff_dxi,
           wd, dwd_dvb2c1, dwd_dicap, dwd_dxi,
           Eav, dEav_dvb2c1, dEav_dicap, dEav_dxi,
           E0, dE0_dvb2c1, dE0_dicap, dE0_dxi,
           Em, dEm_dvb2c1, dEm_dicap, dEm_dxi, dEm_dic1c2,
           EW, dEW_dvb2c1, dEW_dicap, dEW_dxi, dEW_dic1c2,
           da1_dvb2c1, da1_dicap, da1_dxi, da1_dic1c2,
           droot_dvb2c1, droot_dicap, droot_dxi, droot_dic1c2,
           lambda, dlambda_dEm, dlambda_dEav, dlambda_dwd,
           dlambda_dicap, dlambda_dxi, dlambda_dic1c2,dlambda_dvb2c1,
           SHW, dSHW_dxi,
           Gem, dGem_dx, dGem_di,dGem_dvb2c1,dGem_dic1c2,
           dGem_dEm, dGem_dlambda, dGem_dweff, dGem_dicap, dGem_dxi;
    double a, da, da_dx, da_di, b, db, db_dx, db_di, 
           d, dd, e,
           a0, a1, a2, da2_dx, da2_di, a3, a4, da4_dv, da4_dvch, a5;
    double dt, vbe, q1Q;
    double tol,tolvbe;
  
    double hard_sat_max, vb2c1max;
    double *qqic,*qqib,*qqvce,*qqvbe,*qqis; 
    double qic,qib, qvce, qvbe;


    
    double npn=1;   /* for pnp set npn to -1 */
    int FALSE =  0;
    int TRUE = 1;
    int includeAVL = FALSE;
    int NotValid = FALSE;
    
    int    ind,ir,itmax,it,ip,ii,intt,inti;
    
        alfa0 = 1.0/(1.0+ axi * log(1+exp(-1.0/axi)));

        vb2c1max = hard_sat_max * vdcT;


	if (npn==1)
	{
	    an=7.03E7;
	    bn=1.23E8;
	}
	else 
	{
	    an=1.58E8;
	    bn=2.04E8;
	}

      
    }   
	tol=1E-3;
	tolvbe=1E-6;
	itmax=50;

	/* go through all the points */
	for (ir = irmax-1 ; ir > -1; ir--)
	{
	    qic=qqic[ir];
	    qib=qqib[ir];
	    qvce=qqvce[ir];
	    
	    dt = qvce*qic*rth;
	    
	    tk =temp+273.15+dt+dta;
	    trk=tref+273.15;
	    tn=tk/trk;
	    
	    vt = kq*tk;
	    vtr= kq*trk;
            inv_vDt = 1.0/vt - 1.0/vtr;

#include "mxtTrules.h"
            bnT = bn * bnT_bn;

            efi = (1+sfh)/(1+2*sfh);
            dEdx0 = 2*vavl/(wavl*wavl);
            xd0   = wavl * sqrt(vdcT/vavl);
	    

/* Solve vb2e1 and ic1c2 simultanously */

/* initial values */
            if ( qib <= 0.0 )  /* Extra check for noisy data */
                vb2e1 = qqvbe[ir];
            else 
	        vb2e1= vt*log(qib*bfT/isT); 

            if ( <start of new curve>  )
            {
                ic1c2=qic;
            } /* otherwise keep the previous value as initial guess */


/* Check on validity: we demand that vb2c1 < vb2e1. Later a more
 * stringent test will be used */
            if (qvce <= qic*rccT+(qic+qib)*reT) {
              NotValid=TRUE;
            } else {

/* The loop */

	        for (it=0, Dvb2e1=10*tolvbe, Dic1c2=ic1c2;  
                      (it<itmax) && (fabs(Dvb2e1) > tolvbe)
                                 && (fabs(Dic1c2) > tol*fabs(ic1c2))  ;
                      it++) {

	            iff     = isT * exp(vb2e1/vt); 
                    diff_dx = iff/vt;

		    df1    = 4/ikT;
		    f1     = df1*iff;

                    root   = sqrt(1+f1);
                    n0     = f1  / (1+root);
                    dn0_dx = df1 / (2*root) * diff_dx;


                    e       = exp((vb2e1-vfe)/(0.1*vdeT));
                    vje     = vb2e1  - 0.1*vdeT*log(1+e);
                    dvje_dx = 1/(1+e);
                    vte     = vdeT/(1-pe)*(1-pow(1-vje/vdeT,1-pe))
                             +aje*(vb2e1-vje);
                    dvte_dx = (pow(1-vje/vdeT,-pe) - aje) * dvje_dx + aje;


	            vb2c1     = vb2e1+qic*rccT+(qic+qib)*reT-qvce;
                    dvb2c1_dx = 1.0;

                    a       = ic1c2*rcvT/(2*vt)+1;
                    b       = vdcT - vb2c1 + 2*vt * log(a);
                    root    = sqrt(b*b + 4*0.01*vdcT*vdcT);
                    vqs     = (b + root) / 2.0 ;
                    dvqs_dx = -0.5 * (1.0 + b / root) * dvb2c1_dx ;
                    dvqs_di =  0.5 * (1.0 + b / root) * rcvT/a;

                    a       = vqs+ihc*rcvT;
                    iqs     = vqs/scrcv * (vqs+ihc*scrcv)/ a;
                    diqs_dv = 1.0/scrcv +(scrcv-rcvT)*rcvT*ihc*ihc/(scrcv*a*a);
                    diqs_dx = diqs_dv * dvqs_dx;
                    diqs_di = diqs_dv * dvqs_di;

/* Calculation of yi */
                    i_i =     ic1c2/iqs;
                    di_i_dx = (    - i_i * diqs_dx)/iqs;
                    di_i_di = (1.0 - i_i * diqs_di)/iqs;

                    if (i_i < 1) {
                      a0 = exp((i_i-1)/axi);
                      a1 = axi * log(1+a0);
                      alfa     = alfa0 * (1+a1);
                      dalfa_dx = alfa0 * a0 * di_i_dx/ (1+a0);
                      dalfa_di = alfa0 * a0 * di_i_di/ (1+a0);
                    } else { 
                      a  = (1-i_i)/axi;
                      if (a>-40)
                        a0 = exp(a);
                      else
                        a0 = 0.0;
                      a1 = axi * log(1+a0);
                      alfa     = alfa0 * (i_i+a1);
                      dalfa_dx = alfa0 * di_i_dx/ (1+a0);
                      dalfa_di = alfa0 * di_i_di/ (1+a0);
                    }

                    a     = 1.0 / (ihc * scrcv);
                    v     =  vqs    * a;
                    dv_dx = dvqs_dx * a;
                    dv_di = dvqs_di * a;


                    a2     = alfa * (1+v);
                    da2_dx = dalfa_dx * (1+v) + alfa * dv_dx;
                    da2_di = dalfa_di * (1+v) + alfa * dv_di;

                    yi        = (1.0 + sqrt(1.0+4.0 * v * a2))/(2 * a2);
                    dyi_dv   =  1.0 / (2 * a2 * yi - 1.0);
                    /* dyi_da2 = - yi*yi * dyi_dv; */

                    dyi_dx = dyi_dv * (dv_dx - yi*yi*da2_dx);
                    dyi_di = dyi_dv * (dv_di - yi*yi*da2_di);

/* END of Calculation of yi */

                    xi        = 1 - yi;
                    dxi_dx    = -dyi_dx;
                    dxi_di    = -dyi_di;

                    g         = rcvT * ic1c2 * xi           / (2*vt);
                    dg_dx     = rcvT *(ic1c2 * dxi_dx     ) / (2*vt);
                    dg_di     = rcvT *(ic1c2 * dxi_di + xi) / (2*vt);

                    a         = 0.25 * (g-1) * (g-1) + 2.0*g;
                    da        = 0.5  * (g-1)         + 2.0;
                    root      = sqrt(a);
                    p0star    = 0.5 * (g-1) + root;
                    dp0star_dx= 0.5 * (1.0 + da/root) * dg_dx;
                    dp0star_di= 0.5 * (1.0 + da/root) * dg_di;


                    a      = isT*exp(vdcT/vt);
		    irr    = a * p0star * (p0star+1);
                    dirr_dx= a * (2*p0star + 1) * dp0star_dx;
                    dirr_di= a * (2*p0star + 1) * dp0star_di;

		    df2    = 4/ikT;
		    f2     = df2 * irr;

                    root   = sqrt(1+f2);
                    nb     = f2  / (1+root);
                    dnb_dx = df2 / (2*root) * dirr_dx;
                    dnb_di = df2 / (2*root) * dirr_di;

                    a        = ihc/(ic1c2+ihc);
                    icap     = ic1c2 * a;
                    dicap_di =  a  * a;

	            b1        = 0.5*scrcv*(ic1c2-ihc);
	            b2        = scrcv*ihc*rcvT*ic1c2;
	            vec0      = b1+sqrt(b1*b1+b2);
	            vjunc     = vb2c1 + vec0;
                    dvjunc_dx = dvb2c1_dx;
                    dvjunc_di = scrcv * (vec0+ihc*rcvT)*(vec0+ihc*rcvT)/
                                (vec0*vec0+2*vec0*ihc*rcvT+scrcv*rcvT*ihc*ihc);

                    a         = 1.0 / (ic1c2 + iqs);
                    vch       = vdcT * (0.1 + 2.0 * ic1c2 * a);
                    dvch_dx   = vdcT * 2.0 * (     - diqs_dx * ic1c2) * a * a;
                    dvch_di   = vdcT * 2.0 * (iqs  - diqs_di * ic1c2) * a * a;

                    if (vjunc <= vfc) {
                      a2     = exp((vjunc-vfc)/vch);
                      a3     = log(1.0+a2);
                      vj     = vjunc - vch * a3;
                      dvj_dv = 1.0 / (1.0 + a2) ;
                      dvj_dvch=(a2/(1.0+a2) * (vjunc-vfc)/vch - a3);
                    } else {
                      a2     = exp((vfc-vjunc)/vch);
                      a3     = log(1.0+a2);
                      vj     = vfc  - vch * a3;
                      dvj_dv = a2  / (1.0 + a2) ;
                      dvj_dvch=(a2/(1.0+a2) * (vfc-vjunc)/vch - a3);
                    }

                    a1        = 1 - icap/ihc;
                    fI        = pow(a1, mc);
                    dfI_dicap = -mc * fI / (a1 * ihc);

                    a3      = 1 - vj / vdcT;
                    a4      = pow(a3, 1.0-pc);
                    da4_dv  = - (1.0-pc) * a4 * dvj_dv   / (a3 * vdcT);
                    da4_dvch= - (1.0-pc) * a4 * dvj_dvch / (a3 * vdcT);

                    a5        = vdcT / (1-pc);
                    vcv       = a5  * (1- fI * a4);
                    dvcv_dv   = - a5 * fI * da4_dv  ;
                    dvcv_dvch = - a5 * fI * da4_dvch;
                    dvcv_dicap= - a5 * dfI_dicap * a4  ;

                    vtc       = (1-xpT) * (vcv + fI * bjc * (vjunc-vj))
                              + xpT * vb2c1;
                    dvtc_dv   = (1-xpT) * (dvcv_dv   + fI * bjc * (1-dvj_dv));
                    dvtc_dvch = (1-xpT) * (dvcv_dvch - fI * bjc * dvj_dvch);
                    dvtc_dicap= (1-xpT) * (dvcv_dicap+ dfI_dicap*bjc*(vjunc-vj));

                    dvtc_dx   = dvtc_dv * dvjunc_dx
                              + dvtc_dvch * dvch_dx;
                    dvtc_di   = dvtc_dv * dvjunc_di + dvtc_dicap * dicap_di 
                              + dvtc_dvch * dvch_di;

                    if (degT == 0) {
                      q1     = 1+vte/verT+vtc/vefT;
                      dq1_dx = dvte_dx/verT + dvtc_dx/vefT;
                      dq1_di =                dvtc_di/vefT;
                    } else {
                      a      = exp( deg_vt*(vte/verT+1));
		      b      = exp(-deg_vt * vtc/vefT);
                      q1     = aq0i * (a-b);
                      dq1_dx = aq0i * deg_vt * ( a *  dvte_dx/verT
                                                +b *  dvtc_dx/vefT);
                      dq1_di = aq0i * deg_vt * b *  dvtc_di/vefT;
                    }


                    qB     =  q1    * (1.0 + 0.5 * (n0 + nb) );
                    dqB_dx = dq1_dx * (1.0 + 0.5 * (n0 + nb) ) 
                               + q1*0.5*(dn0_dx + dnb_dx);
                    dqB_di = dq1_di * (1.0 + 0.5 * (n0 + nb) ) + q1*0.5*dnb_di;

		    in     = (iff-irr)/qB;
		    din_dx = (diff_dx -dirr_dx - in*dqB_dx)/qB;
		    din_di = (        -dirr_di - in*dqB_di)/qB;

/* now the base current */

                    if (xrec == 0 ) {
	                Ib1     = (1-xibi) * iff/bfT;
                        dIb1_dx = (1-xibi) * diff_dx/bfT;
                        dIb1_di = 0.0;
                    } else {
   
                        b     = (1+vtc/vefT);
                        db_dx = dvtc_dx/vefT;
                        db_di = dvtc_di/vefT;

                        if ( b > 0 ) {
                          a     = (iff     + irr);
                          da_dx = (diff_dx + dirr_dx);
                          da_di = (          dirr_di);

                          Ib1    = (1-xibi)/bfT * (
                                     (1-xrec)*iff +
                                     xrec * a * b  );
                          dIb1_dx = (1-xibi)/bfT * (
                                     (1-xrec)*diff_dx +
                                     xrec*(da_dx*b + a*db_dx ));
                          dIb1_di = (1-xibi)/bfT * (
                                     xrec*(da_di*b + a*db_di ));
                         } else {
                           Ib1  = 0.0;
                           dIb1_dx = 0.0;
                           dIb1_di = 0.0;
                         }
                    }

	            Ib1S    = xibi * iff / bfT;
                    dIb1S_dx= xibi * diff_dx / bfT;


	            Ib2     = ibfT*exp(vb2e1/(mlf*vt));
                    dIb2_dx = Ib2/(mlf*vt);

                    /* for use at low currents */
                    Ibmin     = Gmin * (vb2e1 + vb2c1);
                    dIbmin_dx = Gmin * (1.0   + dvb2c1_dx);

                    Ib      = Ib1     + Ib2     + Ib1S     + Ibmin;
		    if (Ib<0) { 
                            /* for very small currents this is possible,
                               i.e. in an iteration */
                       Ib -= Ibmin;
                       dIbmin_dx=0.0;
                    }
                    dIb_dx  = dIb1_dx + dIb2_dx + dIb1S_dx + dIbmin_dx;
                    dIb_di  = dIb1_di;

/* now we add avalanche */

if ( includeAVL && (vb2c1<vdcT) ) {
   a1         = sqrt(1-vb2c1/vdcT);
   a2         = sqrt(1-icap/ihc);
   xd         = xd0 * a1/a2;
   dxd_dvb2c1 =- xd0 / (2 * vdcT * a1 * a2);
   dxd_dicap  = xd / (2 * (ihc - icap));

   if (exavl == 0.0) { /* simple model */
        weff         =  wavl;
        dweff_dxi    =  0.0;
   } else {           /* extended avalanche model */
        a1   = (1 - 0.5 * xi);
        weff         =  wavl * a1 * a1;
        dweff_dxi    = -wavl * a1;
   } /* fi */

   a1         = 1.0/ sqrt(xd*xd + weff*weff);
   wd         = xd * weff * a1;
   dwd_dvb2c1 = pow(weff * a1, 3) * dxd_dvb2c1;
   dwd_dicap  = pow(weff * a1, 3) * dxd_dicap ;
   dwd_dxi    = pow(xd   * a1, 3) * dweff_dxi ;

   Eav          = (vdcT - vb2c1) / wd;
   dEav_dvb2c1  = -1.0/wd - Eav * dwd_dvb2c1 / wd;
   dEav_dicap   =         - Eav * dwd_dicap  / wd;
   dEav_dxi     =         - Eav * dwd_dxi/ wd;

   a1           = 0.5 * dEdx0 * (1-icap/ihc);
   E0           =  Eav        + a1 *  wd        ;
   dE0_dvb2c1   = dEav_dvb2c1 + a1 * dwd_dvb2c1 ;
   dE0_dicap    = dEav_dicap  + a1 * dwd_dicap  - 0.5 * dEdx0 * wd / ihc;
   dE0_dxi      = dEav_dxi+ a1 * dwd_dxi;

   if (bnT/E0 < 25) { /* Otherwise Gem will be negligible */

	if (exavl == 0.0) { /* simple model */
            Em          = E0;
            dEm_dvb2c1  = dE0_dvb2c1 ;
            dEm_dicap   = dE0_dicap  ;
            dEm_dxi     = dE0_dxi;
            dEm_dic1c2  = 0.0;
	} else {           /* extended avalanche model */
   	    SHW          = 1.0 + 2.0 * sfh * (1.0 + 2.0 * xi);
            dSHW_dxi     = 4.0 * sfh;

            a1           = 0.5 * dEdx0 * (efi-ic1c2/(ihc * SHW));
            EW           =  Eav        - a1 *  wd;
            dEW_dvb2c1   = dEav_dvb2c1 - a1 * dwd_dvb2c1;
            dEW_dicap    = dEav_dicap  - a1 * dwd_dicap ;
            dEW_dxi      = dEav_dxi- a1 * dwd_dxi
                          + 0.5*dEdx0 * wd * ic1c2/(ihc*SHW*SHW) * dSHW_dxi;
            dEW_dic1c2   = 0.5*dEdx0 * wd        /(ihc*SHW);

            a1         =  EW - E0;
	    da1_dvb2c1 =  dEW_dvb2c1  - dE0_dvb2c1;
	    da1_dic1c2 =  dEW_dic1c2;
	    da1_dicap  =  dEW_dicap   - dE0_dicap;
	    da1_dxi    =  dEW_dxi - dE0_dxi;

	    a3         =  0.1 * Eav * icap / ihc;

	    root       =  sqrt(a1 * a1 + a3 * Eav);
	    droot_dvb2c1 =  (a1 * da1_dvb2c1  + a3 * dEav_dvb2c1 ) / root;
	    droot_dic1c2 =   a1 * da1_dic1c2                       / root;
	    droot_dicap  =  (a1 * da1_dicap   + a3 * dEav_dicap 
                                       + 0.05 * Eav * Eav/ ihc) / root;
	    droot_dxi    =  (a1 * da1_dxi + a3 * dEav_dxi) / root;

   	    Em         =  0.5 * ( E0 + EW + root ); 
	    dEm_dvb2c1 =  0.5 * (dE0_dvb2c1  + dEW_dvb2c1  + droot_dvb2c1 );
	    dEm_dic1c2 =  0.5 * (              dEW_dic1c2  + droot_dic1c2 );
	    dEm_dicap  =  0.5 * (dE0_dicap   + dEW_dicap   + droot_dicap  );
	    dEm_dxi    =  0.5 * (dE0_dxi + dEW_dxi + droot_dxi);
	} /* fi */


	a1      =  1.0 / (Em - Eav);
	a2      =  0.5 * wd * a1;
	lambda      =  a2  * Em;
	dlambda_dEm = -a2  * Eav * a1;
	dlambda_dEav=  a2  * Em  * a1;
	dlambda_dwd =  0.5 * a1 * Em;

	dlambda_dvb2c1 = dlambda_dEm*dEm_dvb2c1  + dlambda_dEav*dEav_dvb2c1
                        + dlambda_dwd*dwd_dvb2c1;
	dlambda_dicap  = dlambda_dEm*dEm_dicap   + dlambda_dEav*dEav_dicap
                        + dlambda_dwd*dwd_dicap;
	dlambda_dxi    = dlambda_dEm*dEm_dxi + dlambda_dEav*dEav_dxi
                        + dlambda_dwd*dwd_dxi;
	dlambda_dic1c2 = dlambda_dEm*dEm_dic1c2;

	a1         =  bnT / Em;
	a2         =  a1 * (1.0 + weff / lambda);
	a3         =  (a1 < 20) ? exp(-a1) : 0;
	a4         =  (a2 < 20) ? exp(-a2) : 0;
	Gem           =  an/bnT * Em * lambda * (a3 - a4);
	dGem_dEm      =  an/bnT *      lambda * 
                      ( (1.0 + a1) * a3 - (1.0 + a2) * a4 ) ;
	dGem_dlambda  =  an * (Em/bnT*(a3-a4) - weff/lambda*a4);
	dGem_dweff    =  an * a4;
   
	dGem_dvb2c1  = dGem_dEm      *      dEm_dvb2c1 
                      + dGem_dlambda * dlambda_dvb2c1; 
	dGem_dic1c2  = dGem_dEm      *      dEm_dic1c2 
                      + dGem_dlambda * dlambda_dic1c2; 
	dGem_dicap   = dGem_dEm      *      dEm_dicap
                      + dGem_dlambda * dlambda_dicap; 
	dGem_dxi     = dGem_dEm      *      dEm_dxi
                      + dGem_dlambda * dlambda_dxi
                      + dGem_dweff   *    dweff_dxi; 

        dGem_dx      = dGem_dvb2c1 * dvb2c1_dx + dGem_dxi    * dxi_dx;
        dGem_di      = dGem_dic1c2             + dGem_dxi    * dxi_di
                     + dGem_dicap  * dicap_di;

        /* making sure Gem < 1. We do neglect Gmax */
        a         = 1.0/(1+Gem);
        Gem       = 1-a;
        dGem_dx  *= a*a;
        dGem_di  *= a*a;

        if (Ib - Gem*ic1c2 <= 0) {
            Gem     = Ib/(2*ic1c2);
            dGem_dx = 0.0;
            dGem_di = 0.0;
        }

   } else { /* bnT/E_0 < 25 */
           Gem     = 0.0;
           dGem_dx = 0.0;
           dGem_di = 0.0;
   }
} else { /* includeAVL */
        Gem     = 0.0;
        dGem_dx = 0.0;
        dGem_di = 0.0;
}

Ib     -= Gem * ic1c2;
dIb_dx -= dGem_dx * ic1c2;
dIb_di -= dGem_di * ic1c2 + Gem;



/* This is the part where we calculate new values of vb2e1 and ic1c2 */

		    ic1c2prev = ic1c2;

                    /* Extra check for noisy data */
                    /* if qib<=0, don't change vb2e1 */
                    if ( qib <= 0.0 )  
	                ibm = Ib;
                    else 
                        ibm = qib;

                    /* We need to solve g1=0 and g2=0 */
                    g1 = log(Ib) - log(ibm);
                    g2 = in - ic1c2*(1.0-Gem);

                    /* jacobian calculation */
                    j11 = dIb_dx / Ib;
                    j12 = dIb_di / Ib;
                    j21 = din_dx + ic1c2*dGem_dx ;
                    j22 = din_di + ic1c2*dGem_di - (1.0-Gem) ;
                    det = j11*j22-j12*j21;

                    Dvb2e1 = - ( j22 * g1 - j12 * g2)/det;
                    Dic1c2 = - (-j21 * g1 + j11 * g2)/det;

                    vb2e1 += Dvb2e1;
                    ic1c2 += Dic1c2;

		    if (ic1c2<=0.0)
			ic1c2 = 0.5 * fabs(ic1c2prev);


		} /* end forloop iteration for finding vb2e1 and ic1c2 */
            } /* end if  vb2e1 < vb2c1 */

	    if ( vb2c1 > vb2c1max )
		NotValid=True;

	    switch  /*actual code depends on extraction tool */
	    {
	      case 0: /* ic */
                if (NotValid)
	        {
	          result = 0.0;
	        } else {
		  result=npn*ic1c2;
		}
		break;
		
	      case 1: /* vbe */
                if (NotValid)
		  result=<first vbe point>;
                }
                else { /* determine vbe */
                  q1Q    = 1+vte/verT+vtc/vefT;
                  vb1b2 = vt * log(1.0 + (1-xibi)*rbvT*qib*q1/(vt*q1Q*qB));
		  vbe = vb2e1 + vb1b2 + (qic+qib) * reT + qib*rbcT;

		  result=npn*vbe;
                }
		break;

	    }   /*   end switch */   

	 
	} /* end  for(ir = 0; ir < irmax; ir++)  */
    }

}


MXT_rev_currents
{
#include "mxtpardef.h"
  
    double *qqvbc, *qqvbe, *qqie;
    double qvbc, qvbe, qie, ie, ib, is_sub;
    double vb2e1, vb2c2, vb2c1, vb1c1, vbc1;
    double dvb2c2, dvb2c1, dvbc, dvb2c1_dy, dvb1c1_dy, dvbc1_dy ;
    double vbcs, dvbcs_dy;
    double vje, vte, vjc, dvjc_dy, vcv, dvcv_dy, vtc, dvtc_dy;
    double q1, dq1_dy, qB, dqB_dy;
    double ir, dir_dy, dir_dz, irex, in, din_dy, iepi, diepi_dy, diepi_dz;
    double ib3, dib3_dy, ib1, dib1_dy;
    double exp0, k0, dk0_dy, expw, kw, dkw_dz, ec, dec_dz, dec_dy;
    double iex, diex_dy, jex, djex_dy, xiex, dxiex_dy;
    double isub, disub_dy, jsub, djsub_dy, xisub, dxisub_dy;
    double arg, sqarg, vex, vbex, dvbex_dy, t1, fex, dfex_dy;
    double f2, df2_dy, g1, dg1_dy, nb, dnb_dy, nbex, dnbex_dy;
    double a, b, c, d, e, da_dz, root;
    double tol;
  
    int    ind   , irw    , itmax , it    ,  ip    , intt   i;
    int    TRUE = 1;
    int    FALSE= 0;




    {
	itmax= 100;
	tol  = 1E-5;
	
	/* go through all the points */
	for (irw = 0; irw < irwmax; irw++)
	{
            qvbe = qqvbe[irw];
	    qvbc = qqvbc[irw];
	    qie  = qqie[irw];
	    if (irw >0) {
		dvb2c2 = (qvbc-qqvbc[irw-1])/dvbcs_dy;
		vb2c2  = vb2c2 +           dvb2c2;
		vb2c1  = vb2c1 + dvb2c1_dy*dvb2c2;
	        vb2e1  = qvbe + qie*reT - rbcT*(iex+isub);  
	    }
            else {
                dvb2c2 = 2*tol;
	        vb2c2 = qqvbc[0];
	        vb2c1 = vb2c2;
	        vb2e1 = qvbe;  
            }
	    
            for( it=0 ; (it<itmax) && (fabs(dvb2c2)>tol) ; it++)
	    { 
		if (it>0)
		{
		    vb2e1=qvbe+(in-ib1)*reT-(iex+isub+ib3+ib1)*rbcT;
		}
                e   = exp((vb2e1-vfe)/(0.1*vdeT));
                vje = vb2e1  - 0.1*vdeT*log(1+e);
                vte = vdeT/(1-pe) * (1-pow(1-vje/vdeT,1-pe)) + aje*(vb2e1-vje);
		
		ir     = isT*exp(vb2c2/vt);
		dir_dy = ir/vt;
                           /* Note that vjunc = vb2c2 */
                e       = exp((vb2c2-vfc)/(0.1*vdcT));
                vjc     = vb2c2  - 0.1*vdcT*log(1+e);
                dvjc_dy = 1/(1+e);
                vcv     = vdcT/(1-pc)*(1-pow(1-vjc/vdcT,1-pc))+bjc*(vb2c2-vjc);
                dvcv_dy = (pow(1-vjc/vdcT,-pc) - bjc) * dvjc_dy  + bjc;
                vtc     = (1-xpT) * vcv     + xpT * vb2c1;
                dvtc_dy = (1-xpT) * dvcv_dy + xpT;

                if (degT == 0) {
                  q1     = 1+vte/verT+vtc/vefT;
                  dq1_dy = dvtc_dy/vefT;
                } else {
                  a      = exp( deg_vt*(vte/verT+1));
		  b      = exp(-deg_vt * vtc/vefT);
                  q1     = aq0i * (a-b);
                  dq1_dy = aq0i * b * deg_vt * dvtc_dy/vefT;
                }
		
		f2     = 4* ir   /ikT;
		df2_dy = 4*dir_dy/ikT;

                root   = sqrt(1+f2);
                nb     = f2     / (1+root);
                dnb_dy = df2_dy / (2*root);

                qB     =   q1    * (1.0 + 0.5 * nb);
                dqB_dy =  dq1_dy * (1.0 + 0.5 * nb) + q1 * 0.5 * dnb_dy;

                in     = ir/qB;
                din_dy = (dir_dy - in*dqB_dy)/qB;
		


		/* solve Vb2c1 from: In = Iepi=-(Ec+vc1c2)/Rcv */
		
		exp0   = exp((vb2c2-vdcT)/vt);
		k0     = sqrt(1+4*exp0);
		dk0_dy = 2*exp0/(k0*vt);

		
                for ( intt=0,         dvb2c1=2*tol; 
                     (intt<5) && (fabs(dvb2c1)>0.1*tol); intt++)
		{
		    expw   = exp((vb2c1-vdcT)/vt);
		    kw     = sqrt(1+4*expw);
		    dkw_dz = 2*expw/(kw*vt);

		    ec     = vt*(k0-kw-log((k0+1)/(kw+1)));
		    dec_dz = -vt*kw/(kw+1)*dkw_dz;
		    iepi   = -(ec+vb2c2-vb2c1)/rcvT ; 
		    diepi_dz = (1-dec_dz)/rcvT;
		    dvb2c1 = (in-iepi)/diepi_dz;
		    /* For better convergence */
		    if (dvb2c1 > 1.5*vt) dvb2c1= 1.5*vt;
		    if (dvb2c1 <-1.0*vt) dvb2c1=-1.0*vt;
		    vb2c1  = vb2c1 + dvb2c1;
 
		}  /* end for (intt<5) */
		
		dec_dy    = vt*k0/(k0+1)*dk0_dy;
		diepi_dy  = -(dec_dy+1)/rcvT;
		dvb2c1_dy = (din_dy-diepi_dy)/diepi_dz; 

		vb1c1     = vb2c1;
		dvb1c1_dy = dvb2c1_dy;
		
	        a       = exp(vb1c1/(2*vt));
                e       = exp(vlr/(2*vt));
	        ib3     = ibrT *(a*a-1)/(a+e);
                dib3_dy = ibrT * a*dvb1c1_dy*(a*(a+2*e)+1)/(2*vt*(a+e)*(a+e));

		irex   = isT*exp(vb1c1/vt);
		a      = sqrt(1+4*irex/iksT);
		da_dz  = 2*irex/(a*iksT*vt);
		isub   = 2*(issT/isT)*(irex-isT)/(1+a);
		if (exmod>0.0)
		    isub = (1-xext)*isub;
		disub_dy = isub*(1/vt - da_dz/(1+a))*dvb1c1_dy;
		
		g1     = 4*irex/ikT;
		dg1_dy = g1*dvb1c1_dy/vt;

                root     = sqrt(1+g1);
                nbex     = g1     / (1+root);
                dnbex_dy = dg1_dy / (2*root);

		iex    = (1/briT)* ( 0.5*ikT*nbex - isT);
		diex_dy= (1/briT)*   0.5*ikT*dnbex_dy;
		if (exmod>0.0) {
		    iex     = (1-xext)* iex;
		    diex_dy = (1-xext)* diex_dy;
		}

		a     = isT/bfT*(1-xibi)*xrec;
                b     = exp(vb2c2/vt);
                ib1   = a*b*(1+vtc/vefT);
                dib1_dy =a*b*(dvtc_dy/vefT + (1+vtc/vefT)/vt);
                
		
		vbc1     = vb1c1     + rbcT*(isub    +iex    +ib3    +ib1);
		dvbc1_dy = dvb1c1_dy + rbcT*(disub_dy+diex_dy+dib3_dy+dib1_dy); 
		
		if (exmod>0.0)
                /* repeat the above for another voltage */
                /* temporary currents are denoted by jex, instead of iex */
		{
		    irex   = isT*exp(vbc1/vt);
		    a      = sqrt(1+4*irex/iksT);
		    da_dz  = 2*irex/(a*iksT*vt);
		    jsub   = xext * 2*(issT/isT)*(irex-isT)/(1+a);
		    djsub_dy = jsub*(1/vt - da_dz/(1+a))*dvbc1_dy;
		    
		    g1     = 4*irex/ikT;
		    dg1_dy = g1*dvbc1_dy/vt;
    
                    root     = sqrt(1+g1);
                    nbex     = g1     / (1+root);
                    dnbex_dy = dg1_dy / (2*root);
    
		    jex    = (xext/briT)* ( 0.5*ikT*nbex- isT);
		    djex_dy= (xext/briT)*   0.5*ikT*dnbex_dy;
	
		    a        = xext*((isT/briT)+issT)*rccT;
		    vex      = vt*(2+log(vt/a));
		    arg      = vex-vbc1;
		    sqarg    = sqrt(arg*arg+0.0121);
		    vbex     = (-arg+sqarg)/2;
		    dvbex_dy = (1-(arg/sqarg))*dvbc1_dy/2;
		    t1       = a+rccT*(jex+jsub)+vbex;
		    fex      = vbex/t1;
		    dfex_dy  = (dvbex_dy-
                        fex*(rccT*(djex_dy+djsub_dy)+dvbex_dy))/t1;

		    xisub    = fex*jsub;
		    dxisub_dy= dfex_dy*jsub+fex*djsub_dy;
		    xiex     = fex*jex;
		    dxiex_dy = dfex_dy*jex+fex*djex_dy;
		}
		else
		{ 
		    xiex     = 0.0;
		    dxiex_dy = 0.0;
		    xisub    = 0.0;
		    dxisub_dy= 0.0;
		}
		
		vbcs     = vbc1     + rccT*( in   + ib3    + iex   + xiex   ); 
		dvbcs_dy = dvbc1_dy + rccT*(din_dy+dib3_dy +diex_dy+dxiex_dy);
		dvbc     = qvbc - vbcs;
		dvb2c2   = dvbc/dvbcs_dy;
		/* Needed when starting at high vbe */
		if (dvb2c2 > 0.5*vt) dvb2c2= 0.5*vt;
		if (dvb2c2 <-0.6*vt) dvb2c2=-0.6*vt;
		vb2c2    = vb2c2 + dvb2c2;
		
		
	    } /* end for(it) (end of iteration) */
	    
	    ie    = in-ib1;
	    ib    = ib3 + iex + xiex + isub + xisub+ib1;
	    is_sub=-isub-xisub;
	    
	    
	} /* end  for(irw = 0; irw < irwmax; irw++)  */
    }

}


MXT_forward_ic
{
#include "mxtpardef.h"
   double *qqvcb,*qqveb,*qqic; 
   double vbe,vbc;
   double e, vje, vte, vjc, vcv, vtc, q0, q1, If;
   double npn=1;   /* for pnp set npn to -1 */
   int    i;
   int    TRUE = 1;
   int    FALSE= 0;



   {
        /* go through all the points */
	for (i = 0; i < imax; i++)
	{
            vbc  =-qqvcb[i];
            vbe  =-qqveb[i];

            e    = exp((vbc-vfc)/(0.1*vdcT));
            vjc  = vbc  - 0.1*vdcT*log(1+e);
            vcv  = vdcT/(1-pc) * (1-pow(1-vjc/vdcT,1-pc)) + bjc * (vbc-vjc);
            vtc  = (1-xpT) * vcv + xpT * vbc;

            e    = exp((vbe-vfe)/(0.1*vdeT));
            vje  = vbe  - 0.1*vdeT*log(1+e);
            vte  = vdeT/(1-pe) * (1-pow(1-vje/vdeT,1-pe)) + aje * (vbe-vje);

            if (degT == 0) {
              q0  = 1+vte/verT+vtc/vefT;
            } else {
              q0  = aq0i*(exp(deg_vt*(vte/verT+1)) - exp(-deg_vt * vtc/vefT));
            }
            q1 = 0.5*(q0 + sqrt(q0*q0+0.01) );
	   
	    If=isT*(exp(vbe/vt)-1);

            result=npn* If / q1;

	} /* end  for(i = 0; i < imax; i++)  */
   }
   
}


MXT_forward_hfe
{
#include "mxtpardef.h"
  
    double *qqvcb,*qqveb,*qqic; 
    double vbe,vbc,qic;
    double e, vje, vte, vjc, vcv, vtc, q0, q1, If;
    double Ib1, Ib2, Ibmin, Vb2e1, a, b, c;
    int    i;
    int    TRUE = 1;
    int    FALSE= 0;
    
	
    {

	for (i = 0; i < imax; i++)
	{
            vbc  =-qqvcb[i];
            e    = exp((vbc-vfc)/(0.1*vdcT));
            vjc  = vbc  - 0.1*vdcT*log(1+e);
            vcv  = vdcT/(1-pc) * (1-pow(1-vjc/vdcT,1-pc)) + bjc * (vbc-vjc);
            vtc  = (1-xpT) * vcv + xpT * vbc;

	    vbe =-qqveb[i];
	    qic = qqic[i];
	    
            e    = exp((vbe-vfe)/(0.1*vdeT));
            vje  = vbe  - 0.1*vdeT*log(1+e);
            vte  = vdeT/(1-pe) * (1-pow(1-vje/vdeT,1-pe)) + aje * (vbe-vje);

            if (degT == 0) {
              q0  = 1+vte/verT+vtc/vefT;
            } else {
              q0  = aq0i*(exp(deg_vt*(vte/verT+1)) - exp(-deg_vt * vtc/vefT));
            }
            q1 = 0.5*(q0 + sqrt(q0*q0+0.01) );
	    
	    Vb2e1=vt*log(qic*q1/isT);
	    
	    Ib1  = isT/bfT*(exp(Vb2e1/vt)-1);
	    Ib2  = ibfT*(exp(Vb2e1/(mlf*vt))-1);
            Ibmin = Gmin*vbe + Gmin*vbc;
	    
	    result = qic/(Ib1+Ib2 + Ibmin); 
	    
	} /* end  for(i = 0; i < imax; i++)  */
    }
    
}
   
   
MXT_forward_vbe
{
#include "mxtpardef.h"
  
    double *qqic,*qqib,*qqveb; 
    double ib,ic;
    double npn=1;   /* for pnp set npn to -1 */
    double a,b,c,d,g,da,db,dc,dd,dg, rbvinv, vv, dvv,
           Ib1,Ib2,dIb1,dIb2, Voff_Rbc,Tdut,Vb2e1,dVb2e1,Ve1e,Vbb2;
    int    i,it;
    int    TRUE = 1;
    int    FALSE= 0;
    
    {
	Vb2e1= 0.5;
        vv   = qqib[0] * rbvT/vt;          /* vv = vb1b2/vt */

	for (i = 0; i < imax; i++)
	{
	    ic  = qqic[i];
	    ib  = qqib[i];
            if (ib<=0) ib=1.e-20;

	    for (it =0,dVb2e1=0.1;  (it<10) && (fabs(dVb2e1) > 1.0E-6) ; it++)
            {
	      Ib1  = isT/bfT*exp(Vb2e1/vt);
              dIb1 = Ib1/vt;

	      Ib2  = ibfT*exp(Vb2e1/(mlf*vt));
              dIb2 = Ib2/(mlf*vt);

              g     =  Ib1+ Ib2;
              dg    = dIb1+dIb2;
              dVb2e1= -(log(g) - log(ib)) * g / dg;
              Vb2e1 = Vb2e1 + dVb2e1;
            }

	    Ve1e    = (ic+ib)*reT;
	    Vbb2 = ib*rbcT + vt * log(1.0 + (1-xibi)*rbvT*ic/(vt*bfT));
	    
	    result=npn*(Ve1e+Vb2e1+Vbb2+Voff_Rbc);
	    
	} /* end  for(i = 0; i < imax; i++)  */
    }

}


MXT_reverse_isub
{
#include "mxtpardef.h"
   double *qqvbc,*qqis; 
   double vbc;
   double npn=1;   /* for pnp set npn to -1 */
   int    i;
   int    TRUE = 1;
   int    FALSE= 0;

   {
	for (i = 0; i < imax; i++)
	{

	/* Calculate  the substrate current in reverse-bias
	   condition with small Vbc ( small and medium current) */

            result=-npn* issT*(exp(qqvbc[i]/vt)-1);

	} /* end  for(i = 0; i < imax; i++)  */
   }
   
}


MXT_hard_sat_isub
{
#include "mxtpardef.h"
   double *qqvbc,*qqic,*qqib; 
   double vb1c1, e, isub;
   double npn=1;   /* for pnp set npn to -1 */
   int    i;
   int    TRUE = 1;
   int    FALSE= 0;

       }

   {

	for (i = 0; i < imax; i++)
	{
            vb1c1 = qqvbc[i] + qqic[i] * rccT - qqib[i] * rbcT;

            e    = exp(vb1c1/vt);
            isub = -2.0 * issT * (e-1) / (1+sqrt(1+4*isT*e/iksT));

            result=npn*isub;

	} /* end  for(i = 0; i < imax; i++)  */
   }
   
}
 
MXT_reverse_hfc_sub
{
#include "mxtpardef.h"
  
    double *qqvcb,*qqveb,*qqie,*qqis; 
    double vbe,vbc;
    double e, vje, vte, vjc, vcv, vtc, q0, q1;
    int    i;
    int    TRUE = 1;
    int    FALSE= 0;
    
   {
       for (i = 0; i < imax; i++)
       {
           vbe  =-qqveb[i];
	   vbc  =-qqvcb[i];
	   
           e    = exp((vbe-vfe)/(0.1*vdeT));
           vje  = vbe  - 0.1*vdeT*log(1+e);
           vte  = vdeT/(1-pe) * (1-pow(1-vje/vdeT,1-pe)) + aje * (vbe-vje);

           e    = exp((vbc-vfc)/(0.1*vdcT));
           vjc  = vbc  - 0.1*vdcT*log(1+e);
           vcv  = vdcT/(1-pc) * (1-pow(1-vjc/vdcT,1-pc)) + bjc * (vbc-vjc);
           vtc  = (1-xpT) * vcv + xpT * vbc;
 
           if (degT == 0) {
             q0  = 1+vte/verT+vtc/vefT;
           } else {
             q0  = aq0i*(exp(deg_vt*(vte/verT+1)) - exp(-deg_vt * vtc/vefT));
           }
           q1 = 0.5*(q0 + sqrt(q0*q0+0.01) );

           if (issT == 0) {
	     result=1.0;
           } else {
	     result=isT/(q1*issT);
           }
	   
       } /* end  for(i = 0; i < imax; i++)  */
   }       

}


MXT_reverse_hfc
{
#include "mxtpardef.h"
  
   double *qqvcb,*qqveb,*qqie; 
   double vbe,vbc,ie;
   double e, vje, vte, vjc, vcv, vtc, q0, q1;
   double a, b, c, d, Ib3, Iex, Isub, Ibmin, Vb1c1, corr, Ib1;
   int    i;
   int    TRUE = 1;
   int    FALSE= 0;
   
   {
       
       for (i = 0; i < imax; i++)
       {
           vbe =-qqveb[i];
	   vbc =-qqvcb[i];
	   ie  = fabs(qqie[i]);
	   
           e    = exp((vbe-vfe)/(0.1*vdeT));
           vje  = vbe  - 0.1*vdeT*log(1+e);
           vte  = vdeT/(1-pe) * (1-pow(1-vje/vdeT,1-pe)) + aje * (vbe-vje);

           e    = exp((vbc-vfc)/(0.1*vdcT));
           vjc  = vbc  - 0.1*vdcT*log(1+e);
           vcv  = vdcT/(1-pc) * (1-pow(1-vjc/vdcT,1-pc)) + bjc * (vbc-vjc);
           vtc  = (1-xpT) * vcv + xpT * vbc;

           if (degT == 0) {
             q0  = 1+vte/verT+vtc/vefT;
           } else {
             q0  = aq0i*(exp(deg_vt*(vte/verT+1)) - exp(-deg_vt * vtc/vefT));
           }
           q1 = 0.5*(q0 + sqrt(q0*q0+0.01) );

           corr = (1-xibi)/bfT*xrec*(1+vtc/vefT);
    
	/* Vb1c1 = vt*log(ie*q1/isT);
	/* a     = exp(Vb1c1/(2*vt)); */
           a     = sqrt(ie/isT/(1.0/q1-corr));

	   Ib3   = ibrT * (a*a-1)/(a+exp(vlr/(2*vt)));
	   Ibmin = Gmin*vbc + Gmin*vbe;  

	   c     = 2*issT*(a*a-1);
	   d     = sqrt(1+4*(isT/iksT)*a*a);
	   Isub = c/(1+d);

	   Iex   = (isT/briT)*(a*a-1);

           Ib1   = corr * isT*(a*a-1);

	   if (<including substrate>)
	       result=ie/(Ib3+Iex+Ibmin+Isub+Ib1);
	   else 
	       result=ie/(Ib3+Iex+Ibmin+Ib1);
 
       } /* end  for(i = 0; i < imax; i++)  */
   }

}


MXT_veaf_ic

{
#include "mxtpardef.h"
  
    double *qqvcb,*qqveb,*qqib; 
    double vbe,vbc;
    
    double e, vje, vte, vjc, vcv, vtc, Ic0, q00, q0,q10,q1;
    int    i;
    
    int TRUE = 1;
    int FALSE = 0;
    
   {

       e    = exp((vbe-vfe)/(0.1*vdeT));
       vje  = vbe  - 0.1*vdeT*log(1+e);
       vte  = vdeT/(1-pe) * (1-pow(1-vje/vdeT,1-pe)) + aje * (vbe-vje);

       for (i = 0; i < imax; i++)
       {
           vbc  =-qqvcb[i];

           e    = exp((vbc-vfc)/(0.1*vdcT));
           vjc  = vbc  - 0.1*vdcT*log(1+e);
           vcv  = vdcT/(1-pc) * (1-pow(1-vjc/vdcT,1-pc)) + bjc * (vbc-vjc);
           vtc  = (1-xpT) * vcv + xpT * vbc;
	   
           if (degT == 0) {
             q00 = 1+vte/verT;
             q0  = 1+vte/verT+vtc/vefT;
           } else {
             q00 = aq0i*(exp(deg_vt*(vte/verT+1)) - 1.0);
             q0  = aq0i*(exp(deg_vt*(vte/verT+1)) - exp(-deg_vt * vtc/vefT));
           }
           q10 = 0.5*(q00 + sqrt(q00*q00+0.01) );
           q1  = 0.5*(q0  + sqrt(q0 *q0 +0.01) );

	   result=Ic0* q10 / q1;
	   
       } /* end  for(i = 0; i < imax; i++)  */
   }

}

MXT_veaf_ib

{
#include "mxtpardef.h"
  
    double *qqvcb,*qqic; 
    double vbc,ic;
    
    double dEdx0, xd0, xd, wd, Eav, Em, lambda, a, b, an, bn, bnT, Ib0, Gem;
    double e, vjc, vcv, vtc;
    int    i;
    
    double npn=1;   /* for pnp set npn to -1 */
    int    TRUE = 1;
    int    FALSE= 0;


	if (npn == 1)
	{
	    an=7.03E7;
	    bn=1.23E8;
	}
	else 
	{
	    an=1.58E8;
	    bn=2.04E8;
	}
        bnT = bn * bnT_bn;

        dEdx0 = 2*vavl/(wavl*wavl);
        xd0   = wavl * sqrt(vdcT/vavl);

	for (i = 0; i < imax; i++)
	{
	    vbc = -qqvcb[i];
	    ic  =  qqic[i];

            if (vbc < vdcT) {
              xd  = xd0 * sqrt(1-vbc/vdcT);
              wd  = xd * wavl / sqrt(xd*xd + wavl*wavl);

              Eav = (vdcT-vbc)/wd;
              Em  = Eav + 0.5 * wd * dEdx0;
 
	      lambda = Em * wd / (2*(Em-Eav));
	      a      = exp(-bnT/Em);
	      b      = exp(-bnT*(1+wavl/lambda)/Em);
	      Gem    = (an/bnT) * Em * lambda * (a-b);

	      if (xrec == 0) {
	        result=Ib0 - ic*Gem*npn;  
	      } else {
        	e    = exp((vbc-vfc)/(0.1*vdcT));
        	vjc  = vbc  - 0.1*vdcT*log(1+e);
        	vcv  = vdcT/(1-pc) * (1-pow(1-vjc/vdcT,1-pc)) + bjc*(vbc-vjc);
        	vtc  = (1-xpT) * vcv + xpT * vbc;
	        result=Ib0*(1+xrec*vtc/vefT) - ic*Gem*npn;  
	      }
            } else {
	      result=Ib0 ;  
            }
  
	} /* end  for(i = 0; i < imax; i++)  */
    }

}

MXT_vear_ie 
{
#include "mxtpardef.h"
  
    double *qqvcb,*qqveb,*qqic; 
    double vbe,vbc;
 
    double e, vje, vte, vjc, vcv, vtc, Ie0, q00, q0, q10, q1;
    int    i;
    
    int    TRUE = 1;
    int    FALSE= 0;


        vbc  =-qqvcb[0];

        e    = exp((vbc-vfc)/(0.1*vdcT));
        vjc  = vbc  - 0.1*vdcT*log(1+e);
        vcv  = vdcT/(1-pc) * (1-pow(1-vjc/vdcT,1-pc)) + bjc * (vbc-vjc);
        vtc  = (1-xpT) * vcv + xpT * vbc;

	for (i = 0; i < imax; i++)
	{
            vbe  =-qqveb[i];

            e    = exp((vbe-vfe)/(0.1*vdeT));
            vje  = vbe  - 0.1*vdeT*log(1+e);
            vte  = vdeT/(1-pe) * (1-pow(1-vje/vdeT,1-pe)) + aje * (vbe-vje);

            if (degT == 0) {
              q00 = 1+vtc/vefT;
              q0  = 1+vtc/vefT+vte/verT;
            } else {
              q00 = aq0i*(exp(deg_vt)              - exp(-deg_vt * vtc/vefT));
              q0  = aq0i*(exp(deg_vt*(vte/verT+1)) - exp(-deg_vt * vtc/vefT));
            }
            q10 = 0.5*(q00 + sqrt(q00*q00+0.01) );
            q1  = 0.5*(q0  + sqrt(q0 *q0 +0.01) );

	    result=Ie0*q10/q1;
   
	} /* end  for(i = 0; i < imax; i++)  */
    }
}


MXT_jun_cap

{
#include "mxtpardef.h"
  
    double *qqvjun; 
    double vjun;
    
    double vf, vjj, e, dvjj_dv, dvtt_dv;
    int    i;
    

    int    TRUE = 1;
    int    FALSE= 0;

    

    

 
	switch   /*actual code depends on extraction tool */
	{ 
	  case 0:/* cbe */
	    for (i = 0; i < imax; i++)
	    {
		vjun=qqvjun[i];
                vf        = vdeT * (1-pow(aje,-1.0/pe));
                e         = exp((vjun-vf )/(0.1*vdeT));
                vjj       = vjun  - 0.1*vdeT*log(1+e);
                dvjj_dv = 1.0/(1.0+e);
                dvtt_dv = ( pow(1-vjj/vdeT,-pe)-aje ) * dvjj_dv + aje;
	        result = cjeT*dvtt_dv + cbeo;
	    } 
	    break;
	  case 1:  /* cbc */
       
	    for (i = 0; i < imax; i++)
	    {
		vjun=-qqvjun[i];
                bjc       = (ajc-xpT)/(1-xpT);
                vf        = vdcT * (1-pow(bjc,-1.0/pc));
                e         = exp((vjun-vf )/(0.1*vdcT));
                vjj       = vjun  - 0.1*vdcT*log(1+e);
                dvjj_dv = 1.0/(1.0+e);
                dvtt_dv = ( pow(1-vjj/vdcT,-pc)-bjc ) * dvjj_dv + bjc;
	        result = cjcT*( (1-xpT)*dvtt_dv + xpT) + cbco;
	    }   
	    break;
       
	  case 2:   /* csc */
       
	    for (i = 0; i < imax; i++)
	    {
		vjun=qqvjun[i];
                vf        = vdsT * (1-pow(ajs,-1.0/ps));
                e         = exp((vjun-vf )/(0.1*vdsT));
                vjj       = vjun  - 0.1*vdsT*log(1+e);
                dvjj_dv = 1.0/(1.0+e);
                dvtt_dv = ( pow(1-vjj/vdsT,-ps)-ajs ) * dvjj_dv + ajs;
	        result = cjsT*dvtt_dv + cpcs;
	    }
	    break;
       
	}   /*   end switch */  
    

}

MXT_cbe
{
#include "mxtpardef.h"

  
    double *vj;
    double vje, e, dvje_dvbe, dvte_dvbe;
    int    i;
    int    TRUE = 1;
    int    FALSE= 0;

    {
	for(i=0;i<imax;i++)
	{
            e         = exp((vj[i]-vfe)/(0.1*vdeT));
            vje       = vj[i]  - 0.1*vdeT*log(1+e);
            dvje_dvbe = 1.0/(1.0+e);
            dvte_dvbe = ( pow(1-vje/vdeT,-pe)-aje ) * dvje_dvbe + aje;
	    result = cjeT*dvte_dvbe + cbeo;
	}
    }
}

MXT_cbc
{
#include "mxtpardef.h"
  
    double *vj;
    double vjc, e, dvjc_dvbc, dvtc_dvbc;
    int    i;
    int    TRUE = 1;
    int    FALSE= 0;
    
       
       for(i = 0; i < imax; i++)
       {
            e         = exp((vj[i]-vfc)/(0.1*vdcT));
            vjc       = vj[i]  - 0.1*vdcT*log(1+e);
            dvjc_dvbc = 1.0/(1.0+e);
            dvtc_dvbc = ( pow(1-vjc/vdcT,-pc)-bjc ) * dvjc_dvbc + bjc;
	    result = cjcT*( (1-xpT)*dvtc_dvbc + xpT) + cbco;
       }
   }

}

MXT_csc 
{
#include "mxtpardef.h"
  
    double *vj;
    double vfs, vjs, e, dvjs_dvsc, dvts_dvsc;
    int    i;
    int    TRUE = 1;
    int    FALSE= 0;

	
        vfs = vdsT * (1-pow(ajs,-1.0/ps));
	for (i=0; i < imax;i++)
	{
            e         = exp((vj[i]-vfs)/(0.1*vdsT));
            vjs       = vj[i]  - 0.1*vdsT*log(1+e);
            dvjs_dvsc = 1.0/(1.0+e);
            dvts_dvsc = ( pow(1-vjs/vdsT,-ps)-ajs ) * dvjs_dvsc + ajs;
	    result = cjsT*dvts_dvsc + cpcs;
	}
    }

}


/******************************************************************
 This function calculates VER based on the following formula:

   VER = (ie * dvbe/die @ vbe=0)

 The function requires ie and vbe as inputs and the model
 variable DEG and TREF
******************************************************************/

MXT_ver
{
    double *ie_data, *veb_data, ie0, ver, deg, vt, tref;
    double delta_veb, delta_ie;
    int    i;
    double npn=1;   /* for pnp set npn to -1 */
    int    TRUE = 1;
    int    FALSE= 0;
    
    
    {
	ie0 = ie@(data point 1);
	delta_veb = veb@(data point 3) - veb@(data point 1);
	delta_ie = ie@(data point 3) - ie@(data point 1);
	
	if (delta_ie != 0.0) {
	    ver = npn * ie0 * (delta_veb/delta_ie);
            if (deg != 0) {
	      <get vt from program>
              ver *= deg/vt/(1-exp(-deg/vt));
            }
        }
	else {
            ver = 2.5;
	    /* set to the default value */
        }
	
    }

}


/******************************************************************
 This function calculates VEF based on the following formula:

   VEF = (ic * dvbc/dic @ vbc=0)

 The function requires ic and vbc as inputs and the model
 variable DEG and TREF. 
******************************************************************/
MXT_vef
{
    double *ic_data, *vcb_data, ic0, vef,deg,tref,vt;
    double delta_vcb, delta_ic;
    int    i;
    double npn=1;   /* for pnp set npn to -1 */
    int    TRUE = 1;
    int    FALSE= 0;
    
    {
	ic0 = ic@(data point 1);
	delta_vcb = vcb@(data point 3) - vcb[0]@(data point 1);
	delta_ic = ic@(data point 3) - ic@(data point 1);
	
	if (delta_ic != 0.0) {
	    vef = npn * ic0 * (delta_vcb/delta_ic);
            if (deg != 0) {
	      <get vt from program>
              vef *= deg/vt/(exp(deg/vt)-1);
            }

        }
	else {
            vef  = 44.0; /* default value */
        }
	
    }



