/**** BSIM3v3.3.0, Released by Xuemei Xi 07/29/2005 ****/

/**********
 * Copyright 2004 Regents of the University of California. All rights reserved.
 * File: b3temp.c of BSIM3v3.3.0
 * Author: 1995 Min-Chie Jeng and Mansun Chan.
 * Author: 1997-1999 Weidong Liu.
 * Author: 2001  Xuemei Xi
 **********/

/* Lmin, Lmax, Wmin, Wmax */

#include "ngspice/ngspice.h"
#include "ngspice/smpdefs.h"
#include "ngspice/cktdefs.h"
#include "bsim3def.h"
#include "ngspice/const.h"
#include "ngspice/sperror.h"
#include "ngspice/devdefs.h"
#include "ngspice/suffix.h"

#define Kb 1.3806226e-23
#define KboQ 8.617087e-5  /* Kb / q  where q = 1.60219e-19 */
#define EPSOX 3.453133e-11
#define EPSSI 1.03594e-10
#define PI 3.141592654
#define MAX_EXP 5.834617425e14
#define MIN_EXP 1.713908431e-15
#define EXP_THRESHOLD 34.0
#define Charge_q 1.60219e-19

/* ARGSUSED */
int
BSIM3temp(
GENmodel *inModel,
CKTcircuit *ckt)
{
BSIM3model *model = (BSIM3model*) inModel;
BSIM3instance *here;
struct bsim3SizeDependParam *pSizeDependParamKnot, *pLastKnot, *pParam=NULL;
double tmp, tmp1, tmp2, tmp3, Eg, Eg0, ni, T0, T1, T2, T3, T4, T5, Ldrn, Wdrn;
double delTemp, Temp, TRatio, Inv_L, Inv_W, Inv_LW, Vtm0, Tnom;
double Nvtm, SourceSatCurrent, DrainSatCurrent;
int Size_Not_Found, error;

/*  loop through all the BSIM3 device models */
    for (; model != NULL; model = model->BSIM3nextModel)
    {    Temp = ckt->CKTtemp;
         if (model->BSIM3bulkJctPotential < 0.1)
         {   model->BSIM3bulkJctPotential = 0.1;
             fprintf(stderr, "Given pb is less than 0.1. Pb is set to 0.1.\n");
         }
         if (model->BSIM3sidewallJctPotential < 0.1)
         {   model->BSIM3sidewallJctPotential = 0.1;
             fprintf(stderr, "Given pbsw is less than 0.1. Pbsw is set to 0.1.\n");
         }
         if (model->BSIM3GatesidewallJctPotential < 0.1)
         {   model->BSIM3GatesidewallJctPotential = 0.1;
             fprintf(stderr, "Given pbswg is less than 0.1. Pbswg is set to 0.1.\n");
         }
         model->pSizeDependParamKnot = NULL;
         pLastKnot = NULL;

         Tnom = model->BSIM3tnom;
         TRatio = Temp / Tnom;

         model->BSIM3vcrit = CONSTvt0 * log(CONSTvt0 / (CONSTroot2 * 1.0e-14));
         model->BSIM3factor1 = sqrt(EPSSI / EPSOX * model->BSIM3tox);

         Vtm0 = KboQ * Tnom;
         Eg0 = 1.16 - 7.02e-4 * Tnom * Tnom / (Tnom + 1108.0);
         ni = 1.45e10 * (Tnom / 300.15) * sqrt(Tnom / 300.15)
            * exp(21.5565981 - Eg0 / (2.0 * Vtm0));

         model->BSIM3vtm = KboQ * Temp;
         Eg = 1.16 - 7.02e-4 * Temp * Temp / (Temp + 1108.0);
         if (Temp != Tnom)
         {   T0 = Eg0 / Vtm0 - Eg / model->BSIM3vtm + model->BSIM3jctTempExponent
                * log(Temp / Tnom);
             T1 = exp(T0 / model->BSIM3jctEmissionCoeff);
             model->BSIM3jctTempSatCurDensity = model->BSIM3jctSatCurDensity
                                              * T1;
             model->BSIM3jctSidewallTempSatCurDensity
                         = model->BSIM3jctSidewallSatCurDensity * T1;
         }
         else
         {   model->BSIM3jctTempSatCurDensity = model->BSIM3jctSatCurDensity;
             model->BSIM3jctSidewallTempSatCurDensity
                        = model->BSIM3jctSidewallSatCurDensity;
         }

         if (model->BSIM3jctTempSatCurDensity < 0.0)
             model->BSIM3jctTempSatCurDensity = 0.0;
         if (model->BSIM3jctSidewallTempSatCurDensity < 0.0)
             model->BSIM3jctSidewallTempSatCurDensity = 0.0;

         /* Temperature dependence of D/B and S/B diode capacitance begins */
         delTemp = ckt->CKTtemp - model->BSIM3tnom;
         T0 = model->BSIM3tcj * delTemp;
         if (T0 >= -1.0)
         {   model->BSIM3unitAreaTempJctCap = model->BSIM3unitAreaJctCap * (1.0 + T0);
         }
         else if (model->BSIM3unitAreaJctCap > 0.0)
         {   model->BSIM3unitAreaTempJctCap = 0.0;
             fprintf(stderr, "Temperature effect has caused cj to be negative. Cj is clamped to zero.\n");
         }
         T0 = model->BSIM3tcjsw * delTemp;
         if (T0 >= -1.0)
         {   model->BSIM3unitLengthSidewallTempJctCap = model->BSIM3unitLengthSidewallJctCap * (1.0 + T0);
         }
         else if (model->BSIM3unitLengthSidewallJctCap > 0.0)
         {   model->BSIM3unitLengthSidewallTempJctCap = 0.0;
             fprintf(stderr, "Temperature effect has caused cjsw to be negative. Cjsw is clamped to zero.\n");
         }
         T0 = model->BSIM3tcjswg * delTemp;
         if (T0 >= -1.0)
         {   model->BSIM3unitLengthGateSidewallTempJctCap = model->BSIM3unitLengthGateSidewallJctCap * (1.0 + T0);
         }
         else if (model->BSIM3unitLengthGateSidewallJctCap > 0.0)
         {   model->BSIM3unitLengthGateSidewallTempJctCap = 0.0;
             fprintf(stderr, "Temperature effect has caused cjswg to be negative. Cjswg is clamped to zero.\n");
         }

         model->BSIM3PhiB = model->BSIM3bulkJctPotential
                          - model->BSIM3tpb * delTemp;
         if (model->BSIM3PhiB < 0.01)
         {   model->BSIM3PhiB = 0.01;
             fprintf(stderr, "Temperature effect has caused pb to be less than 0.01. Pb is clamped to 0.01.\n");
         }
         model->BSIM3PhiBSW = model->BSIM3sidewallJctPotential
                            - model->BSIM3tpbsw * delTemp;
         if (model->BSIM3PhiBSW <= 0.01)
         {   model->BSIM3PhiBSW = 0.01;
             fprintf(stderr, "Temperature effect has caused pbsw to be less than 0.01. Pbsw is clamped to 0.01.\n");
         }
         model->BSIM3PhiBSWG = model->BSIM3GatesidewallJctPotential
                             - model->BSIM3tpbswg * delTemp;
         if (model->BSIM3PhiBSWG <= 0.01)
         {   model->BSIM3PhiBSWG = 0.01;
             fprintf(stderr, "Temperature effect has caused pbswg to be less than 0.01. Pbswg is clamped to 0.01.\n");
         }
         /* End of junction capacitance */

         /* loop through all the instances of the model */
         /* MCJ: Length and Width not initialized */
         for (here = model->BSIM3instances; here != NULL;
              here = here->BSIM3nextInstance)
         {
              pSizeDependParamKnot = model->pSizeDependParamKnot;
              Size_Not_Found = 1;
              while ((pSizeDependParamKnot != NULL) && Size_Not_Found)
              {   if ((here->BSIM3l == pSizeDependParamKnot->Length)
                      && (here->BSIM3w == pSizeDependParamKnot->Width))
                  {   Size_Not_Found = 0;
                      here->pParam = pSizeDependParamKnot;
                      pParam = here->pParam; /*bug-fix  */
                  }
                  else
                  {   pLastKnot = pSizeDependParamKnot;
                      pSizeDependParamKnot = pSizeDependParamKnot->pNext;
                  }
              }

              if (Size_Not_Found)
              {   pParam = TMALLOC(struct bsim3SizeDependParam, 1);
                  if (pLastKnot == NULL)
                      model->pSizeDependParamKnot = pParam;
                  else
                      pLastKnot->pNext = pParam;
                  pParam->pNext = NULL;
                  here->pParam = pParam;

                  Ldrn = here->BSIM3l;
                  Wdrn = here->BSIM3w;
                  pParam->Length = Ldrn;
                  pParam->Width = Wdrn;

                  T0 = pow(Ldrn, model->BSIM3Lln);
                  T1 = pow(Wdrn, model->BSIM3Lwn);
                  tmp1 = model->BSIM3Ll / T0 + model->BSIM3Lw / T1
                       + model->BSIM3Lwl / (T0 * T1);
                  pParam->BSIM3dl = model->BSIM3Lint + tmp1;
                  tmp2 = model->BSIM3Llc / T0 + model->BSIM3Lwc / T1
                       + model->BSIM3Lwlc / (T0 * T1);
                  pParam->BSIM3dlc = model->BSIM3dlc + tmp2;

                  T2 = pow(Ldrn, model->BSIM3Wln);
                  T3 = pow(Wdrn, model->BSIM3Wwn);
                  tmp1 = model->BSIM3Wl / T2 + model->BSIM3Ww / T3
                       + model->BSIM3Wwl / (T2 * T3);
                  pParam->BSIM3dw = model->BSIM3Wint + tmp1;
                  tmp2 = model->BSIM3Wlc / T2 + model->BSIM3Wwc / T3
                       + model->BSIM3Wwlc / (T2 * T3);
                  pParam->BSIM3dwc = model->BSIM3dwc + tmp2;

                  pParam->BSIM3leff = here->BSIM3l + model->BSIM3xl - 2.0 * pParam->BSIM3dl;
                  if (pParam->BSIM3leff <= 0.0)
                  {   IFuid namarray[2];
                      namarray[0] = model->BSIM3modName;
                      namarray[1] = here->BSIM3name;
                      SPfrontEnd->IFerror (ERR_FATAL,
                      "BSIM3: mosfet %s, model %s: Effective channel length <= 0",
                       namarray);
                      return(E_BADPARM);
                  }

                  pParam->BSIM3weff = here->BSIM3w + model->BSIM3xw - 2.0 * pParam->BSIM3dw;
                  if (pParam->BSIM3weff <= 0.0)
                  {   IFuid namarray[2];
                      namarray[0] = model->BSIM3modName;
                      namarray[1] = here->BSIM3name;
                      SPfrontEnd->IFerror (ERR_FATAL,
                      "BSIM3: mosfet %s, model %s: Effective channel width <= 0",
                       namarray);
                      return(E_BADPARM);
                  }

                  pParam->BSIM3leffCV = here->BSIM3l + model->BSIM3xl - 2.0 * pParam->BSIM3dlc;
                  if (pParam->BSIM3leffCV <= 0.0)
                  {   IFuid namarray[2];
                      namarray[0] = model->BSIM3modName;
                      namarray[1] = here->BSIM3name;
                      SPfrontEnd->IFerror (ERR_FATAL,
                      "BSIM3: mosfet %s, model %s: Effective channel length for C-V <= 0",
                       namarray);
                      return(E_BADPARM);
                  }

                  pParam->BSIM3weffCV = here->BSIM3w + model->BSIM3xw - 2.0 * pParam->BSIM3dwc;
                  if (pParam->BSIM3weffCV <= 0.0)
                  {   IFuid namarray[2];
                      namarray[0] = model->BSIM3modName;
                      namarray[1] = here->BSIM3name;
                      SPfrontEnd->IFerror (ERR_FATAL,
                      "BSIM3: mosfet %s, model %s: Effective channel width for C-V <= 0",
                       namarray);
                      return(E_BADPARM);
                  }


                  if (model->BSIM3binUnit == 1)
                  {   Inv_L = 1.0e-6 / pParam->BSIM3leff;
                      Inv_W = 1.0e-6 / pParam->BSIM3weff;
                      Inv_LW = 1.0e-12 / (pParam->BSIM3leff
                             * pParam->BSIM3weff);
                  }
                  else
                  {   Inv_L = 1.0 / pParam->BSIM3leff;
                      Inv_W = 1.0 / pParam->BSIM3weff;
                      Inv_LW = 1.0 / (pParam->BSIM3leff
                             * pParam->BSIM3weff);
                  }
                  pParam->BSIM3cdsc = model->BSIM3cdsc
                                    + model->BSIM3lcdsc * Inv_L
                                    + model->BSIM3wcdsc * Inv_W
                                    + model->BSIM3pcdsc * Inv_LW;
                  pParam->BSIM3cdscb = model->BSIM3cdscb
                                     + model->BSIM3lcdscb * Inv_L
                                     + model->BSIM3wcdscb * Inv_W
                                     + model->BSIM3pcdscb * Inv_LW;

                  pParam->BSIM3cdscd = model->BSIM3cdscd
                                     + model->BSIM3lcdscd * Inv_L
                                     + model->BSIM3wcdscd * Inv_W
                                     + model->BSIM3pcdscd * Inv_LW;

                  pParam->BSIM3cit = model->BSIM3cit
                                   + model->BSIM3lcit * Inv_L
                                   + model->BSIM3wcit * Inv_W
                                   + model->BSIM3pcit * Inv_LW;
                  pParam->BSIM3nfactor = model->BSIM3nfactor
                                       + model->BSIM3lnfactor * Inv_L
                                       + model->BSIM3wnfactor * Inv_W
                                       + model->BSIM3pnfactor * Inv_LW;
                  pParam->BSIM3xj = model->BSIM3xj
                                  + model->BSIM3lxj * Inv_L
                                  + model->BSIM3wxj * Inv_W
                                  + model->BSIM3pxj * Inv_LW;
                  pParam->BSIM3vsat = model->BSIM3vsat
                                    + model->BSIM3lvsat * Inv_L
                                    + model->BSIM3wvsat * Inv_W
                                    + model->BSIM3pvsat * Inv_LW;
                  pParam->BSIM3at = model->BSIM3at
                                  + model->BSIM3lat * Inv_L
                                  + model->BSIM3wat * Inv_W
                                  + model->BSIM3pat * Inv_LW;
                  pParam->BSIM3a0 = model->BSIM3a0
                                  + model->BSIM3la0 * Inv_L
                                  + model->BSIM3wa0 * Inv_W
                                  + model->BSIM3pa0 * Inv_LW;

                  pParam->BSIM3ags = model->BSIM3ags
                                  + model->BSIM3lags * Inv_L
                                  + model->BSIM3wags * Inv_W
                                  + model->BSIM3pags * Inv_LW;

                  pParam->BSIM3a1 = model->BSIM3a1
                                  + model->BSIM3la1 * Inv_L
                                  + model->BSIM3wa1 * Inv_W
                                  + model->BSIM3pa1 * Inv_LW;
                  pParam->BSIM3a2 = model->BSIM3a2
                                  + model->BSIM3la2 * Inv_L
                                  + model->BSIM3wa2 * Inv_W
                                  + model->BSIM3pa2 * Inv_LW;
                  pParam->BSIM3keta = model->BSIM3keta
                                    + model->BSIM3lketa * Inv_L
                                    + model->BSIM3wketa * Inv_W
                                    + model->BSIM3pketa * Inv_LW;
                  pParam->BSIM3nsub = model->BSIM3nsub
                                    + model->BSIM3lnsub * Inv_L
                                    + model->BSIM3wnsub * Inv_W
                                    + model->BSIM3pnsub * Inv_LW;
                  pParam->BSIM3npeak = model->BSIM3npeak
                                     + model->BSIM3lnpeak * Inv_L
                                     + model->BSIM3wnpeak * Inv_W
                                     + model->BSIM3pnpeak * Inv_LW;
                  pParam->BSIM3ngate = model->BSIM3ngate
                                     + model->BSIM3lngate * Inv_L
                                     + model->BSIM3wngate * Inv_W
                                     + model->BSIM3pngate * Inv_LW;
                  pParam->BSIM3gamma1 = model->BSIM3gamma1
                                      + model->BSIM3lgamma1 * Inv_L
                                      + model->BSIM3wgamma1 * Inv_W
                                      + model->BSIM3pgamma1 * Inv_LW;
                  pParam->BSIM3gamma2 = model->BSIM3gamma2
                                      + model->BSIM3lgamma2 * Inv_L
                                      + model->BSIM3wgamma2 * Inv_W
                                      + model->BSIM3pgamma2 * Inv_LW;
                  pParam->BSIM3vbx = model->BSIM3vbx
                                   + model->BSIM3lvbx * Inv_L
                                   + model->BSIM3wvbx * Inv_W
                                   + model->BSIM3pvbx * Inv_LW;
                  pParam->BSIM3vbm = model->BSIM3vbm
                                   + model->BSIM3lvbm * Inv_L
                                   + model->BSIM3wvbm * Inv_W
                                   + model->BSIM3pvbm * Inv_LW;
                  pParam->BSIM3xt = model->BSIM3xt
                                   + model->BSIM3lxt * Inv_L
                                   + model->BSIM3wxt * Inv_W
                                   + model->BSIM3pxt * Inv_LW;
                  pParam->BSIM3vfb = model->BSIM3vfb
                                   + model->BSIM3lvfb * Inv_L
                                   + model->BSIM3wvfb * Inv_W
                                   + model->BSIM3pvfb * Inv_LW;
                  pParam->BSIM3k1 = model->BSIM3k1
                                  + model->BSIM3lk1 * Inv_L
                                  + model->BSIM3wk1 * Inv_W
                                  + model->BSIM3pk1 * Inv_LW;
                  pParam->BSIM3kt1 = model->BSIM3kt1
                                   + model->BSIM3lkt1 * Inv_L
                                   + model->BSIM3wkt1 * Inv_W
                                   + model->BSIM3pkt1 * Inv_LW;
                  pParam->BSIM3kt1l = model->BSIM3kt1l
                                    + model->BSIM3lkt1l * Inv_L
                                    + model->BSIM3wkt1l * Inv_W
                                    + model->BSIM3pkt1l * Inv_LW;
                  pParam->BSIM3k2 = model->BSIM3k2
                                  + model->BSIM3lk2 * Inv_L
                                  + model->BSIM3wk2 * Inv_W
                                  + model->BSIM3pk2 * Inv_LW;
                  pParam->BSIM3kt2 = model->BSIM3kt2
                                   + model->BSIM3lkt2 * Inv_L
                                   + model->BSIM3wkt2 * Inv_W
                                   + model->BSIM3pkt2 * Inv_LW;
                  pParam->BSIM3k3 = model->BSIM3k3
                                  + model->BSIM3lk3 * Inv_L
                                  + model->BSIM3wk3 * Inv_W
                                  + model->BSIM3pk3 * Inv_LW;
                  pParam->BSIM3k3b = model->BSIM3k3b
                                   + model->BSIM3lk3b * Inv_L
                                   + model->BSIM3wk3b * Inv_W
                                   + model->BSIM3pk3b * Inv_LW;
                  pParam->BSIM3w0 = model->BSIM3w0
                                  + model->BSIM3lw0 * Inv_L
                                  + model->BSIM3ww0 * Inv_W
                                  + model->BSIM3pw0 * Inv_LW;
                  pParam->BSIM3nlx = model->BSIM3nlx
                                   + model->BSIM3lnlx * Inv_L
                                   + model->BSIM3wnlx * Inv_W
                                   + model->BSIM3pnlx * Inv_LW;
                  pParam->BSIM3dvt0 = model->BSIM3dvt0
                                    + model->BSIM3ldvt0 * Inv_L
                                    + model->BSIM3wdvt0 * Inv_W
                                    + model->BSIM3pdvt0 * Inv_LW;
                  pParam->BSIM3dvt1 = model->BSIM3dvt1
                                    + model->BSIM3ldvt1 * Inv_L
                                    + model->BSIM3wdvt1 * Inv_W
                                    + model->BSIM3pdvt1 * Inv_LW;
                  pParam->BSIM3dvt2 = model->BSIM3dvt2
                                    + model->BSIM3ldvt2 * Inv_L
                                    + model->BSIM3wdvt2 * Inv_W
                                    + model->BSIM3pdvt2 * Inv_LW;
                  pParam->BSIM3dvt0w = model->BSIM3dvt0w
                                    + model->BSIM3ldvt0w * Inv_L
                                    + model->BSIM3wdvt0w * Inv_W
                                    + model->BSIM3pdvt0w * Inv_LW;
                  pParam->BSIM3dvt1w = model->BSIM3dvt1w
                                    + model->BSIM3ldvt1w * Inv_L
                                    + model->BSIM3wdvt1w * Inv_W
                                    + model->BSIM3pdvt1w * Inv_LW;
                  pParam->BSIM3dvt2w = model->BSIM3dvt2w
                                    + model->BSIM3ldvt2w * Inv_L
                                    + model->BSIM3wdvt2w * Inv_W
                                    + model->BSIM3pdvt2w * Inv_LW;
                  pParam->BSIM3drout = model->BSIM3drout
                                     + model->BSIM3ldrout * Inv_L
                                     + model->BSIM3wdrout * Inv_W
                                     + model->BSIM3pdrout * Inv_LW;
                  pParam->BSIM3dsub = model->BSIM3dsub
                                    + model->BSIM3ldsub * Inv_L
                                    + model->BSIM3wdsub * Inv_W
                                    + model->BSIM3pdsub * Inv_LW;
                  pParam->BSIM3vth0 = model->BSIM3vth0
                                    + model->BSIM3lvth0 * Inv_L
                                    + model->BSIM3wvth0 * Inv_W
                                    + model->BSIM3pvth0 * Inv_LW;
                  pParam->BSIM3ua = model->BSIM3ua
                                  + model->BSIM3lua * Inv_L
                                  + model->BSIM3wua * Inv_W
                                  + model->BSIM3pua * Inv_LW;
                  pParam->BSIM3ua1 = model->BSIM3ua1
                                   + model->BSIM3lua1 * Inv_L
                                   + model->BSIM3wua1 * Inv_W
                                   + model->BSIM3pua1 * Inv_LW;
                  pParam->BSIM3ub = model->BSIM3ub
                                  + model->BSIM3lub * Inv_L
                                  + model->BSIM3wub * Inv_W
                                  + model->BSIM3pub * Inv_LW;
                  pParam->BSIM3ub1 = model->BSIM3ub1
                                   + model->BSIM3lub1 * Inv_L
                                   + model->BSIM3wub1 * Inv_W
                                   + model->BSIM3pub1 * Inv_LW;
                  pParam->BSIM3uc = model->BSIM3uc
                                  + model->BSIM3luc * Inv_L
                                  + model->BSIM3wuc * Inv_W
                                  + model->BSIM3puc * Inv_LW;
                  pParam->BSIM3uc1 = model->BSIM3uc1
                                   + model->BSIM3luc1 * Inv_L
                                   + model->BSIM3wuc1 * Inv_W
                                   + model->BSIM3puc1 * Inv_LW;
                  pParam->BSIM3u0 = model->BSIM3u0
                                  + model->BSIM3lu0 * Inv_L
                                  + model->BSIM3wu0 * Inv_W
                                  + model->BSIM3pu0 * Inv_LW;
                  pParam->BSIM3ute = model->BSIM3ute
                                   + model->BSIM3lute * Inv_L
                                   + model->BSIM3wute * Inv_W
                                   + model->BSIM3pute * Inv_LW;
                  pParam->BSIM3voff = model->BSIM3voff
                                    + model->BSIM3lvoff * Inv_L
                                    + model->BSIM3wvoff * Inv_W
                                    + model->BSIM3pvoff * Inv_LW;
                  pParam->BSIM3delta = model->BSIM3delta
                                     + model->BSIM3ldelta * Inv_L
                                     + model->BSIM3wdelta * Inv_W
                                     + model->BSIM3pdelta * Inv_LW;
                  pParam->BSIM3rdsw = model->BSIM3rdsw
                                    + model->BSIM3lrdsw * Inv_L
                                    + model->BSIM3wrdsw * Inv_W
                                    + model->BSIM3prdsw * Inv_LW;
                  pParam->BSIM3prwg = model->BSIM3prwg
                                    + model->BSIM3lprwg * Inv_L
                                    + model->BSIM3wprwg * Inv_W
                                    + model->BSIM3pprwg * Inv_LW;
                  pParam->BSIM3prwb = model->BSIM3prwb
                                    + model->BSIM3lprwb * Inv_L
                                    + model->BSIM3wprwb * Inv_W
                                    + model->BSIM3pprwb * Inv_LW;
                  pParam->BSIM3prt = model->BSIM3prt
                                    + model->BSIM3lprt * Inv_L
                                    + model->BSIM3wprt * Inv_W
                                    + model->BSIM3pprt * Inv_LW;
                  pParam->BSIM3eta0 = model->BSIM3eta0
                                    + model->BSIM3leta0 * Inv_L
                                    + model->BSIM3weta0 * Inv_W
                                    + model->BSIM3peta0 * Inv_LW;
                  pParam->BSIM3etab = model->BSIM3etab
                                    + model->BSIM3letab * Inv_L
                                    + model->BSIM3wetab * Inv_W
                                    + model->BSIM3petab * Inv_LW;
                  pParam->BSIM3pclm = model->BSIM3pclm
                                    + model->BSIM3lpclm * Inv_L
                                    + model->BSIM3wpclm * Inv_W
                                    + model->BSIM3ppclm * Inv_LW;
                  pParam->BSIM3pdibl1 = model->BSIM3pdibl1
                                      + model->BSIM3lpdibl1 * Inv_L
                                      + model->BSIM3wpdibl1 * Inv_W
                                      + model->BSIM3ppdibl1 * Inv_LW;
                  pParam->BSIM3pdibl2 = model->BSIM3pdibl2
                                      + model->BSIM3lpdibl2 * Inv_L
                                      + model->BSIM3wpdibl2 * Inv_W
                                      + model->BSIM3ppdibl2 * Inv_LW;
                  pParam->BSIM3pdiblb = model->BSIM3pdiblb
                                      + model->BSIM3lpdiblb * Inv_L
                                      + model->BSIM3wpdiblb * Inv_W
                                      + model->BSIM3ppdiblb * Inv_LW;
                  pParam->BSIM3pscbe1 = model->BSIM3pscbe1
                                      + model->BSIM3lpscbe1 * Inv_L
                                      + model->BSIM3wpscbe1 * Inv_W
                                      + model->BSIM3ppscbe1 * Inv_LW;
                  pParam->BSIM3pscbe2 = model->BSIM3pscbe2
                                      + model->BSIM3lpscbe2 * Inv_L
                                      + model->BSIM3wpscbe2 * Inv_W
                                      + model->BSIM3ppscbe2 * Inv_LW;
                  pParam->BSIM3pvag = model->BSIM3pvag
                                    + model->BSIM3lpvag * Inv_L
                                    + model->BSIM3wpvag * Inv_W
                                    + model->BSIM3ppvag * Inv_LW;
                  pParam->BSIM3wr = model->BSIM3wr
                                  + model->BSIM3lwr * Inv_L
                                  + model->BSIM3wwr * Inv_W
                                  + model->BSIM3pwr * Inv_LW;
                  pParam->BSIM3dwg = model->BSIM3dwg
                                   + model->BSIM3ldwg * Inv_L
                                   + model->BSIM3wdwg * Inv_W
                                   + model->BSIM3pdwg * Inv_LW;
                  pParam->BSIM3dwb = model->BSIM3dwb
                                   + model->BSIM3ldwb * Inv_L
                                   + model->BSIM3wdwb * Inv_W
                                   + model->BSIM3pdwb * Inv_LW;
                  pParam->BSIM3b0 = model->BSIM3b0
                                  + model->BSIM3lb0 * Inv_L
                                  + model->BSIM3wb0 * Inv_W
                                  + model->BSIM3pb0 * Inv_LW;
                  pParam->BSIM3b1 = model->BSIM3b1
                                  + model->BSIM3lb1 * Inv_L
                                  + model->BSIM3wb1 * Inv_W
                                  + model->BSIM3pb1 * Inv_LW;
                  pParam->BSIM3alpha0 = model->BSIM3alpha0
                                      + model->BSIM3lalpha0 * Inv_L
                                      + model->BSIM3walpha0 * Inv_W
                                      + model->BSIM3palpha0 * Inv_LW;
                  pParam->BSIM3alpha1 = model->BSIM3alpha1
                                      + model->BSIM3lalpha1 * Inv_L
                                      + model->BSIM3walpha1 * Inv_W
                                      + model->BSIM3palpha1 * Inv_LW;
                  pParam->BSIM3beta0 = model->BSIM3beta0
                                     + model->BSIM3lbeta0 * Inv_L
                                     + model->BSIM3wbeta0 * Inv_W
                                     + model->BSIM3pbeta0 * Inv_LW;
                  /* CV model */
                  pParam->BSIM3elm = model->BSIM3elm
                                  + model->BSIM3lelm * Inv_L
                                  + model->BSIM3welm * Inv_W
                                  + model->BSIM3pelm * Inv_LW;
                  pParam->BSIM3cgsl = model->BSIM3cgsl
                                    + model->BSIM3lcgsl * Inv_L
                                    + model->BSIM3wcgsl * Inv_W
                                    + model->BSIM3pcgsl * Inv_LW;
                  pParam->BSIM3cgdl = model->BSIM3cgdl
                                    + model->BSIM3lcgdl * Inv_L
                                    + model->BSIM3wcgdl * Inv_W
                                    + model->BSIM3pcgdl * Inv_LW;
                  pParam->BSIM3ckappa = model->BSIM3ckappa
                                      + model->BSIM3lckappa * Inv_L
                                      + model->BSIM3wckappa * Inv_W
                                      + model->BSIM3pckappa * Inv_LW;
                  pParam->BSIM3cf = model->BSIM3cf
                                  + model->BSIM3lcf * Inv_L
                                  + model->BSIM3wcf * Inv_W
                                  + model->BSIM3pcf * Inv_LW;
                  pParam->BSIM3clc = model->BSIM3clc
                                   + model->BSIM3lclc * Inv_L
                                   + model->BSIM3wclc * Inv_W
                                   + model->BSIM3pclc * Inv_LW;
                  pParam->BSIM3cle = model->BSIM3cle
                                   + model->BSIM3lcle * Inv_L
                                   + model->BSIM3wcle * Inv_W
                                   + model->BSIM3pcle * Inv_LW;
                  pParam->BSIM3vfbcv = model->BSIM3vfbcv
                                     + model->BSIM3lvfbcv * Inv_L
                                     + model->BSIM3wvfbcv * Inv_W
                                     + model->BSIM3pvfbcv * Inv_LW;
                  pParam->BSIM3acde = model->BSIM3acde
                                    + model->BSIM3lacde * Inv_L
                                    + model->BSIM3wacde * Inv_W
                                    + model->BSIM3pacde * Inv_LW;
                  pParam->BSIM3moin = model->BSIM3moin
                                    + model->BSIM3lmoin * Inv_L
                                    + model->BSIM3wmoin * Inv_W
                                    + model->BSIM3pmoin * Inv_LW;
                  pParam->BSIM3noff = model->BSIM3noff
                                    + model->BSIM3lnoff * Inv_L
                                    + model->BSIM3wnoff * Inv_W
                                    + model->BSIM3pnoff * Inv_LW;
                  pParam->BSIM3voffcv = model->BSIM3voffcv
                                      + model->BSIM3lvoffcv * Inv_L
                                      + model->BSIM3wvoffcv * Inv_W
                                      + model->BSIM3pvoffcv * Inv_LW;

                  pParam->BSIM3abulkCVfactor = 1.0 + pow((pParam->BSIM3clc
                                             / pParam->BSIM3leffCV),
                                             pParam->BSIM3cle);

                  T0 = (TRatio - 1.0);
                  pParam->BSIM3ua = pParam->BSIM3ua + pParam->BSIM3ua1 * T0;
                  pParam->BSIM3ub = pParam->BSIM3ub + pParam->BSIM3ub1 * T0;
                  pParam->BSIM3uc = pParam->BSIM3uc + pParam->BSIM3uc1 * T0;
                  if (pParam->BSIM3u0 > 1.0)
                      pParam->BSIM3u0 = pParam->BSIM3u0 / 1.0e4;

                  pParam->BSIM3u0temp = pParam->BSIM3u0
                                      * pow(TRatio, pParam->BSIM3ute);
                  pParam->BSIM3vsattemp = pParam->BSIM3vsat - pParam->BSIM3at
                                        * T0;
                  pParam->BSIM3rds0 = (pParam->BSIM3rdsw + pParam->BSIM3prt * T0)
                                    / pow(pParam->BSIM3weff * 1E6, pParam->BSIM3wr);

                  if (BSIM3checkModel(model, here, ckt))
                  {   IFuid namarray[2];
                      namarray[0] = model->BSIM3modName;
                      namarray[1] = here->BSIM3name;
                      SPfrontEnd->IFerror (ERR_FATAL, "Fatal error(s) detected during BSIM3V3.3 parameter checking for %s in model %s", namarray);
                      return(E_BADPARM);
                  }

                  pParam->BSIM3cgdo = (model->BSIM3cgdo + pParam->BSIM3cf)
                                    * pParam->BSIM3weffCV;
                  pParam->BSIM3cgso = (model->BSIM3cgso + pParam->BSIM3cf)
                                    * pParam->BSIM3weffCV;
                  pParam->BSIM3cgbo = model->BSIM3cgbo * pParam->BSIM3leffCV;

                  T0 = pParam->BSIM3leffCV * pParam->BSIM3leffCV;
                  pParam->BSIM3tconst = pParam->BSIM3u0temp * pParam->BSIM3elm / (model->BSIM3cox
                                      * pParam->BSIM3weffCV * pParam->BSIM3leffCV * T0);

                  if (!model->BSIM3npeakGiven && model->BSIM3gamma1Given)
                  {   T0 = pParam->BSIM3gamma1 * model->BSIM3cox;
                      pParam->BSIM3npeak = 3.021E22 * T0 * T0;
                  }

                  pParam->BSIM3phi = 2.0 * Vtm0
                                   * log(pParam->BSIM3npeak / ni);

                  pParam->BSIM3sqrtPhi = sqrt(pParam->BSIM3phi);
                  pParam->BSIM3phis3 = pParam->BSIM3sqrtPhi * pParam->BSIM3phi;

                  pParam->BSIM3Xdep0 = sqrt(2.0 * EPSSI / (Charge_q
                                     * pParam->BSIM3npeak * 1.0e6))
                                     * pParam->BSIM3sqrtPhi;
                  pParam->BSIM3sqrtXdep0 = sqrt(pParam->BSIM3Xdep0);
                  pParam->BSIM3litl = sqrt(3.0 * pParam->BSIM3xj
                                    * model->BSIM3tox);
                  pParam->BSIM3vbi = Vtm0 * log(1.0e20
                                   * pParam->BSIM3npeak / (ni * ni));
                  pParam->BSIM3cdep0 = sqrt(Charge_q * EPSSI
                                     * pParam->BSIM3npeak * 1.0e6 / 2.0
                                     / pParam->BSIM3phi);

                  pParam->BSIM3ldeb = sqrt(EPSSI * Vtm0 / (Charge_q
                                    * pParam->BSIM3npeak * 1.0e6)) / 3.0;
                  pParam->BSIM3acde *= pow((pParam->BSIM3npeak / 2.0e16), -0.25);


                  if (model->BSIM3k1Given || model->BSIM3k2Given)
                  {   if (!model->BSIM3k1Given)
                      {
                          if ((!ckt->CKTcurJob) || (ckt->CKTcurJob->JOBtype < 9)) /* don't print in sensitivity */
                              fprintf(stdout, "Warning: k1 should be specified with k2.\n");
                          pParam->BSIM3k1 = 0.53;
                      }
                      if (!model->BSIM3k2Given)
                      {
                          if ((!ckt->CKTcurJob) || (ckt->CKTcurJob->JOBtype < 9)) /* don't print in sensitivity */
                              fprintf(stdout, "Warning: k2 should be specified with k1.\n");
                          pParam->BSIM3k2 = -0.0186;
                      }
                      if ((!ckt->CKTcurJob) || (ckt->CKTcurJob->JOBtype < 9)) { /* don't print in sensitivity */
                          if (model->BSIM3nsubGiven)
                              fprintf(stdout, "Warning: nsub is ignored because k1 or k2 is given.\n");
                          if (model->BSIM3xtGiven)
                              fprintf(stdout, "Warning: xt is ignored because k1 or k2 is given.\n");
                          if (model->BSIM3vbxGiven)
                              fprintf(stdout, "Warning: vbx is ignored because k1 or k2 is given.\n");
                          if (model->BSIM3gamma1Given)
                              fprintf(stdout, "Warning: gamma1 is ignored because k1 or k2 is given.\n");
                          if (model->BSIM3gamma2Given)
                              fprintf(stdout, "Warning: gamma2 is ignored because k1 or k2 is given.\n");
                      }
                  }
                  else
                  {   if (!model->BSIM3vbxGiven)
                          pParam->BSIM3vbx = pParam->BSIM3phi - 7.7348e-4
                                           * pParam->BSIM3npeak
                                           * pParam->BSIM3xt * pParam->BSIM3xt;
                      if (pParam->BSIM3vbx > 0.0)
                          pParam->BSIM3vbx = -pParam->BSIM3vbx;
                      if (pParam->BSIM3vbm > 0.0)
                          pParam->BSIM3vbm = -pParam->BSIM3vbm;

                      if (!model->BSIM3gamma1Given)
                          pParam->BSIM3gamma1 = 5.753e-12
                                              * sqrt(pParam->BSIM3npeak)
                                              / model->BSIM3cox;
                      if (!model->BSIM3gamma2Given)
                          pParam->BSIM3gamma2 = 5.753e-12
                                              * sqrt(pParam->BSIM3nsub)
                                              / model->BSIM3cox;

                      T0 = pParam->BSIM3gamma1 - pParam->BSIM3gamma2;
                      T1 = sqrt(pParam->BSIM3phi - pParam->BSIM3vbx)
                         - pParam->BSIM3sqrtPhi;
                      T2 = sqrt(pParam->BSIM3phi * (pParam->BSIM3phi
                         - pParam->BSIM3vbm)) - pParam->BSIM3phi;
                      pParam->BSIM3k2 = T0 * T1 / (2.0 * T2 + pParam->BSIM3vbm);
                      pParam->BSIM3k1 = pParam->BSIM3gamma2 - 2.0
                                      * pParam->BSIM3k2 * sqrt(pParam->BSIM3phi
                                      - pParam->BSIM3vbm);
                  }

                  if (pParam->BSIM3k2 < 0.0)
                  {   T0 = 0.5 * pParam->BSIM3k1 / pParam->BSIM3k2;
                      pParam->BSIM3vbsc = 0.9 * (pParam->BSIM3phi - T0 * T0);
                      if (pParam->BSIM3vbsc > -3.0)
                          pParam->BSIM3vbsc = -3.0;
                      else if (pParam->BSIM3vbsc < -30.0)
                          pParam->BSIM3vbsc = -30.0;
                  }
                  else
                  {   pParam->BSIM3vbsc = -30.0;
                  }
                  if (pParam->BSIM3vbsc > pParam->BSIM3vbm)
                      pParam->BSIM3vbsc = pParam->BSIM3vbm;

                  if (!model->BSIM3vfbGiven)
                  {   if (model->BSIM3vth0Given)
                      {   pParam->BSIM3vfb = model->BSIM3type * pParam->BSIM3vth0
                                           - pParam->BSIM3phi - pParam->BSIM3k1
                                           * pParam->BSIM3sqrtPhi;
                      }
                      else
                      {   pParam->BSIM3vfb = -1.0;
                      }
                  }
                  if (!model->BSIM3vth0Given)
                  {   pParam->BSIM3vth0 = model->BSIM3type * (pParam->BSIM3vfb
                                        + pParam->BSIM3phi + pParam->BSIM3k1
                                        * pParam->BSIM3sqrtPhi);
                  }

                  pParam->BSIM3k1ox = pParam->BSIM3k1 * model->BSIM3tox
                                    / model->BSIM3toxm;
                  pParam->BSIM3k2ox = pParam->BSIM3k2 * model->BSIM3tox
                                    / model->BSIM3toxm;

                  T1 = sqrt(EPSSI / EPSOX * model->BSIM3tox
                     * pParam->BSIM3Xdep0);
                  T0 = exp(-0.5 * pParam->BSIM3dsub * pParam->BSIM3leff / T1);
                  pParam->BSIM3theta0vb0 = (T0 + 2.0 * T0 * T0);

                  T0 = exp(-0.5 * pParam->BSIM3drout * pParam->BSIM3leff / T1);
                  T2 = (T0 + 2.0 * T0 * T0);
                  pParam->BSIM3thetaRout = pParam->BSIM3pdibl1 * T2
                                         + pParam->BSIM3pdibl2;

                  tmp = sqrt(pParam->BSIM3Xdep0);
                  tmp1 = pParam->BSIM3vbi - pParam->BSIM3phi;
                  tmp2 = model->BSIM3factor1 * tmp;

                  T0 = -0.5 * pParam->BSIM3dvt1w * pParam->BSIM3weff
                     * pParam->BSIM3leff / tmp2;
                  if (T0 > -EXP_THRESHOLD)
                  {   T1 = exp(T0);
                      T2 = T1 * (1.0 + 2.0 * T1);
                  }
                  else
                  {   T1 = MIN_EXP;
                      T2 = T1 * (1.0 + 2.0 * T1);
                  }
                  T0 = pParam->BSIM3dvt0w * T2;
                  T2 = T0 * tmp1;

                  T0 = -0.5 * pParam->BSIM3dvt1 * pParam->BSIM3leff / tmp2;
                  if (T0 > -EXP_THRESHOLD)
                  {   T1 = exp(T0);
                      T3 = T1 * (1.0 + 2.0 * T1);
                  }
                  else
                  {   T1 = MIN_EXP;
                      T3 = T1 * (1.0 + 2.0 * T1);
                  }
                  T3 = pParam->BSIM3dvt0 * T3 * tmp1;

                  T4 = model->BSIM3tox * pParam->BSIM3phi
                     / (pParam->BSIM3weff + pParam->BSIM3w0);

                  T0 = sqrt(1.0 + pParam->BSIM3nlx / pParam->BSIM3leff);
                  T5 = pParam->BSIM3k1ox * (T0 - 1.0) * pParam->BSIM3sqrtPhi
                     + (pParam->BSIM3kt1 + pParam->BSIM3kt1l / pParam->BSIM3leff)
                     * (TRatio - 1.0);

                  tmp3 = model->BSIM3type * pParam->BSIM3vth0
                       - T2 - T3 + pParam->BSIM3k3 * T4 + T5;
                  pParam->BSIM3vfbzb = tmp3 - pParam->BSIM3phi - pParam->BSIM3k1
                                     * pParam->BSIM3sqrtPhi;
                  /* End of vfbzb */
              }

              /* adding delvto  */
              here->BSIM3vth0 = pParam->BSIM3vth0 + here->BSIM3delvto;
              here->BSIM3vfb = pParam->BSIM3vfb + model->BSIM3type * here->BSIM3delvto;
              here->BSIM3vfbzb = pParam->BSIM3vfbzb + model->BSIM3type * here->BSIM3delvto;

              /* low field mobility multiplier */
              here->BSIM3u0temp = pParam->BSIM3u0temp * here->BSIM3mulu0;
              here->BSIM3tconst = here->BSIM3u0temp * pParam->BSIM3elm / (model->BSIM3cox
                                    * pParam->BSIM3weffCV * pParam->BSIM3leffCV * T0);

              /* process source/drain series resistance */
              /* ACM model */
              if (model->BSIM3acmMod == 0)
              {
                  here->BSIM3drainConductance = model->BSIM3sheetResistance
                                                  * here->BSIM3drainSquares;
                  here->BSIM3sourceConductance = model->BSIM3sheetResistance
                                               * here->BSIM3sourceSquares;
              }
              else /* ACM > 0 */
              {
                  error = ACM_SourceDrainResistances(
                  model->BSIM3acmMod,
                  model->BSIM3ld,
                  model->BSIM3ldif,
                  model->BSIM3hdif,
                  model->BSIM3wmlt,
                  here->BSIM3w,
                  model->BSIM3xw,
                  model->BSIM3sheetResistance,
                  here->BSIM3drainSquaresGiven,
                  model->BSIM3rd,
                  model->BSIM3rdc,
                  here->BSIM3drainSquares,
                  here->BSIM3sourceSquaresGiven,
                  model->BSIM3rs,
                  model->BSIM3rsc,
                  here->BSIM3sourceSquares,
                  &(here->BSIM3drainConductance),
                  &(here->BSIM3sourceConductance)
                  );
                  if (error)
                      return(error);
              }
              if (here->BSIM3drainConductance > 0.0)
                  here->BSIM3drainConductance = 1.0
                                              / here->BSIM3drainConductance;
              else
                  here->BSIM3drainConductance = 0.0;

              if (here->BSIM3sourceConductance > 0.0)
                  here->BSIM3sourceConductance = 1.0
                                               / here->BSIM3sourceConductance;
              else
                  here->BSIM3sourceConductance = 0.0;
              here->BSIM3cgso = pParam->BSIM3cgso;
              here->BSIM3cgdo = pParam->BSIM3cgdo;

              Nvtm = model->BSIM3vtm * model->BSIM3jctEmissionCoeff;
              if ((here->BSIM3sourceArea <= 0.0) &&
                  (here->BSIM3sourcePerimeter <= 0.0))
              {   SourceSatCurrent = 1.0e-14;
              }
              else
              {   SourceSatCurrent = here->BSIM3sourceArea
                                   * model->BSIM3jctTempSatCurDensity
                                   + here->BSIM3sourcePerimeter
                                   * model->BSIM3jctSidewallTempSatCurDensity;
              }
              if ((SourceSatCurrent > 0.0) && (model->BSIM3ijth > 0.0))
              {   here->BSIM3vjsm = Nvtm * log(model->BSIM3ijth
                                  / SourceSatCurrent + 1.0);
                  here->BSIM3IsEvjsm = SourceSatCurrent * exp(here->BSIM3vjsm
                                     / Nvtm);
              }

              if ((here->BSIM3drainArea <= 0.0) &&
                  (here->BSIM3drainPerimeter <= 0.0))
              {   DrainSatCurrent = 1.0e-14;
              }
              else
              {   DrainSatCurrent = here->BSIM3drainArea
                                  * model->BSIM3jctTempSatCurDensity
                                  + here->BSIM3drainPerimeter
                                  * model->BSIM3jctSidewallTempSatCurDensity;
              }
              if ((DrainSatCurrent > 0.0) && (model->BSIM3ijth > 0.0))
              {   here->BSIM3vjdm = Nvtm * log(model->BSIM3ijth
                                  / DrainSatCurrent + 1.0);
                  here->BSIM3IsEvjdm = DrainSatCurrent * exp(here->BSIM3vjdm
                                     / Nvtm);
              }
         }
    }
    return(OK);
}

