/* $Id: d_bjt.model,v 26.136 2009/12/08 02:03:49 al Exp $ -*- C++ -*-
 * Copyright (C) 2002 Albert Davis
 * Author: Albert Davis <aldavis@gnu.org>
 *
 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 *------------------------------------------------------------------
 * Berkeley BJT model
 * Derived from Spice code, both from 2g6 and 3f4
 * Recoded for Gnucap model compiler, Al Davis, 2002
 *------------------------------------------------------------------
 * data structures and defaults for bjt model.
 *
 * netlist syntax:
 * device:  qxxxx c b e s mname <device args>
 * model:   .model mname NPN <args>
 *	or  .model mname PNP <args>
 *
 * known BUGs
 * 1. excess phase partially implemented, disabled, as if PTF == 0.
 */
/* This file is automatically generated. DO NOT EDIT */

#include "u_limit.h"
#include "globals.h"
#include "e_elemnt.h"
#include "d_bjt.h"
/*--------------------------------------------------------------------------*/
const double NA(NOT_INPUT);
const double INF(BIGBIG);
/*--------------------------------------------------------------------------*/
int MODEL_BUILT_IN_BJT::_count = 0;
/*--------------------------------------------------------------------------*/
const int LEVEL(1);
/*--------------------------------------------------------------------------*/
namespace MODEL_BUILT_IN_BJT_DISPATCHER { 
  static DEV_BUILT_IN_BJT p1d;
  static MODEL_BUILT_IN_BJT p1(&p1d);
  static DISPATCHER<MODEL_CARD>::INSTALL
    d1(&model_dispatcher, "npn|pnp|npn1|pnp1", &p1);
}
/*--------------------------------------------------------------------------*/
void SDP_BUILT_IN_BJT::init(const COMMON_COMPONENT* cc)
{
  assert(cc);
  SDP_BUILT_IN_DIODE::init(cc);
}
/*--------------------------------------------------------------------------*/
TDP_BUILT_IN_BJT::TDP_BUILT_IN_BJT(const DEV_BUILT_IN_BJT* d)
{
  assert(d);
  const COMMON_BUILT_IN_BJT* c = prechecked_cast<const COMMON_BUILT_IN_BJT*>(d->common());
  assert(c);
  const SDP_BUILT_IN_BJT* s = prechecked_cast<const SDP_BUILT_IN_BJT*>(c->sdp());
  assert(s);
  const MODEL_BUILT_IN_BJT* m = prechecked_cast<const MODEL_BUILT_IN_BJT*>(c->model());
  assert(m);
  const CARD_LIST* par_scope = d->scope();
  assert(par_scope);
    // final adjust: code_pre

      const double reftemp = 300.15;
      double temp_k = 
	((has_hard_value(c->temp_c)) ? c->temp_c : d->_sim->_temp_c) + P_CELSIUS0;
      double fact1 = m->tnom_k / reftemp;
      double fact2 = temp_k / reftemp;
      double tempratio  = temp_k / m->tnom_k; // fact2/fact1
      double kt = temp_k * P_K;
      vt = temp_k * P_K_Q;
      double egap = 1.16 - (7.02e-4*temp_k*temp_k) / (temp_k+1108.); // egfet
      // double arg = (m->eg*tempratio - egap) / (2*kt);
      double arg = -egap/(2 * kt) + 1.1150877 / (P_K * (reftemp+reftemp));
      double pbfact = -2 * vt * (1.5 * log(fact2) + P_Q * arg);
      double ratlog = log(tempratio);
      double ratio1 = tempratio - 1;
      double factlog = ratio1 * m->eg / vt + m->xti * ratlog;
      double factor = exp(factlog);
      double bfactor = exp(ratlog * m->xtb);

    // final adjust: override
    // final adjust: raw
    // final adjust: mid
    // final adjust: calculated
    ibc = m->ibc * factor;
    ibe = m->ibe * factor;
    BetaF = m->bf * bfactor;
    BetaR = m->br * bfactor;
    BEleakCur = m->ise * exp(factlog/m->ne) / bfactor;
    BCleakCur = m->isc * exp(factlog/m->nc) / bfactor;
    Vcrit = vt * log(vt / (M_SQRT2 * m->ibe));
    // final adjust: post

      {
	double pbo = (m->vje - pbfact) / fact1;
	BEpot = fact2 * pbo + pbfact;
	double gmaold = (m->vje - pbo) / pbo;
	double gmanew = (BEpot - pbo) / pbo;
	BEcap = (m->cje / (1 + m->mje * (4e-4*(m->tnom_k-reftemp)-gmaold)))
	  * (1 + m->mje * (4e-4*(temp_k-reftemp)-gmanew));
	DepCap = m->fc * BEpot;
	f1 = BEpot * (1 - exp((1 - m->mje) * m->xfc)) / (1 - m->mje);
      }
      {
	double pbo = (m->vjc - pbfact) / fact1;
	BCpot = fact2 * pbo + pbfact;
	double gmaold = (m->vjc - pbo) / pbo;
	double gmanew = (BCpot - pbo) / pbo;
	BCcap = (m->cjc / (1 + m->mjc 
			   * (4e-4*(m->tnom_k-reftemp)-gmaold)))
	  * (1 + m->mjc * (4e-4*(temp_k-reftemp)-gmanew));
	f4 = m->fc * BCpot;
	f5 = BCpot * (1 - exp((1 - m->mjc) * m->xfc)) / (1 - m->mjc);
      }
    // final adjust: done
}
/*--------------------------------------------------------------------------*/
MODEL_BUILT_IN_BJT::MODEL_BUILT_IN_BJT(const BASE_SUBCKT* p)
  :MODEL_BUILT_IN_DIODE(p),
   level(1),
   bf(100.),
   br(1.),
   ibc(NA),
   ibe(NA),
   i_s(NA),
   nf(1.),
   nr(1.),
   vaf(NA),
   var(NA),
   isc(NA),
   c4(0.),
   nc(2.),
   ise(NA),
   c2(0.),
   ne(1.5),
   ikf(NA),
   ikr(NA),
   irb(NA),
   rb(0.),
   rbm(NA),
   re(0.),
   rc(0.),
   cbcp(0.),
   cbep(0.),
   cbsp(0.),
   ccsp(0.),
   cjc(0.),
   cje(0.),
   cjs(0.),
   fc(NA),
   mjc(.33),
   mje(.33),
   mjs(0.),
   vjc(.75),
   vje(.75),
   vjs(.75),
   xcjc(1.),
   itf(0.),
   ptf(0.),
   tf(0.),
   tr(0.),
   vtf(NA),
   xtf(0.),
   xtb(0.),
   xti(3.),
   eg(1.11),
   tnom_k(NA),
   polarity(pN),
   invearlyvoltf(NA),
   invearlyvoltr(NA),
   invrollofff(NA),
   invrolloffr(NA),
   transtimevbcfact(NA),
   excessphasefactor(NA),
   xfc(NA),
   f2(NA),
   f3(NA),
   f6(NA),
   f7(NA)
{
  if (ENV::run_mode != rPRE_MAIN) {
    ++_count;
  }else{
  }
  set_default(&kf, 0.);
  set_default(&af, 1.);
}
/*--------------------------------------------------------------------------*/
MODEL_BUILT_IN_BJT::MODEL_BUILT_IN_BJT(const MODEL_BUILT_IN_BJT& p)
  :MODEL_BUILT_IN_DIODE(p),
   level(p.level),
   bf(p.bf),
   br(p.br),
   ibc(p.ibc),
   ibe(p.ibe),
   i_s(p.i_s),
   nf(p.nf),
   nr(p.nr),
   vaf(p.vaf),
   var(p.var),
   isc(p.isc),
   c4(p.c4),
   nc(p.nc),
   ise(p.ise),
   c2(p.c2),
   ne(p.ne),
   ikf(p.ikf),
   ikr(p.ikr),
   irb(p.irb),
   rb(p.rb),
   rbm(p.rbm),
   re(p.re),
   rc(p.rc),
   cbcp(p.cbcp),
   cbep(p.cbep),
   cbsp(p.cbsp),
   ccsp(p.ccsp),
   cjc(p.cjc),
   cje(p.cje),
   cjs(p.cjs),
   fc(p.fc),
   mjc(p.mjc),
   mje(p.mje),
   mjs(p.mjs),
   vjc(p.vjc),
   vje(p.vje),
   vjs(p.vjs),
   xcjc(p.xcjc),
   itf(p.itf),
   ptf(p.ptf),
   tf(p.tf),
   tr(p.tr),
   vtf(p.vtf),
   xtf(p.xtf),
   xtb(p.xtb),
   xti(p.xti),
   eg(p.eg),
   tnom_k(p.tnom_k),
   polarity(p.polarity),
   invearlyvoltf(p.invearlyvoltf),
   invearlyvoltr(p.invearlyvoltr),
   invrollofff(p.invrollofff),
   invrolloffr(p.invrolloffr),
   transtimevbcfact(p.transtimevbcfact),
   excessphasefactor(p.excessphasefactor),
   xfc(p.xfc),
   f2(p.f2),
   f3(p.f3),
   f6(p.f6),
   f7(p.f7)
{
  if (ENV::run_mode != rPRE_MAIN) {
    ++_count;
  }else{untested();//194
  }
}
/*--------------------------------------------------------------------------*/
std::string MODEL_BUILT_IN_BJT::dev_type()const
{
  if (polarity == pN) {
    return "npn";
  }else if (polarity == pP) {
    return "pnp";
  }else if (polarity == pN) {
    return "npn1";
  }else if (polarity == pP) {
    return "pnp1";
  }else{untested();//235
    return MODEL_BUILT_IN_DIODE::dev_type();
  }
}
/*--------------------------------------------------------------------------*/
void MODEL_BUILT_IN_BJT::set_dev_type(const std::string& new_type)
{
  if (Umatch(new_type, "npn ")) {
    polarity = pN;
  }else if (Umatch(new_type, "pnp ")) {
    polarity = pP;
  }else if (Umatch(new_type, "npn1 ")) {
    polarity = pN;
  }else if (Umatch(new_type, "pnp1 ")) {
    polarity = pP;
  }else{
    MODEL_CARD::set_dev_type(new_type);
  }
}
/*--------------------------------------------------------------------------*/
void MODEL_BUILT_IN_BJT::precalc_first()
{
    const CARD_LIST* par_scope = scope();
    assert(par_scope);
    MODEL_CARD::precalc_first();
    e_val(&(this->level), 1, par_scope);
    e_val(&(this->bf), 100., par_scope);
    e_val(&(this->br), 1., par_scope);
    e_val(&(this->ibc), NA, par_scope);
    e_val(&(this->ibe), NA, par_scope);
    e_val(&(this->i_s), NA, par_scope);
    e_val(&(this->nf), 1., par_scope);
    e_val(&(this->nr), 1., par_scope);
    e_val(&(this->vaf), NA, par_scope);
    e_val(&(this->var), NA, par_scope);
    e_val(&(this->isc), NA, par_scope);
    e_val(&(this->c4), 0., par_scope);
    e_val(&(this->nc), 2., par_scope);
    e_val(&(this->ise), NA, par_scope);
    e_val(&(this->c2), 0., par_scope);
    e_val(&(this->ne), 1.5, par_scope);
    e_val(&(this->ikf), NA, par_scope);
    e_val(&(this->ikr), NA, par_scope);
    e_val(&(this->irb), NA, par_scope);
    e_val(&(this->rb), 0., par_scope);
    e_val(&(this->rbm), NA, par_scope);
    e_val(&(this->re), 0., par_scope);
    e_val(&(this->rc), 0., par_scope);
    e_val(&(this->cbcp), 0., par_scope);
    e_val(&(this->cbep), 0., par_scope);
    e_val(&(this->cbsp), 0., par_scope);
    e_val(&(this->ccsp), 0., par_scope);
    e_val(&(this->cjc), 0., par_scope);
    e_val(&(this->cje), 0., par_scope);
    e_val(&(this->cjs), 0., par_scope);
    e_val(&(this->fc), NA, par_scope);
    e_val(&(this->mjc), .33, par_scope);
    e_val(&(this->mje), .33, par_scope);
    e_val(&(this->mjs), 0., par_scope);
    e_val(&(this->vjc), .75, par_scope);
    e_val(&(this->vje), .75, par_scope);
    e_val(&(this->vjs), .75, par_scope);
    e_val(&(this->xcjc), 1., par_scope);
    e_val(&(this->itf), 0., par_scope);
    e_val(&(this->ptf), 0., par_scope);
    e_val(&(this->tf), 0., par_scope);
    e_val(&(this->tr), 0., par_scope);
    e_val(&(this->vtf), NA, par_scope);
    e_val(&(this->xtf), 0., par_scope);
    e_val(&(this->xtb), 0., par_scope);
    e_val(&(this->xti), 3., par_scope);
    e_val(&(this->eg), 1.11, par_scope);
    // final adjust: code_pre
    // final adjust: override
    // final adjust: raw
    e_val(&(this->level), 1, par_scope);
    e_val(&(this->bf), 100., par_scope);
    e_val(&(this->br), 1., par_scope);
    e_val(&(this->ibc), ((has_hard_value(i_s)) ? i_s : 1e-16), par_scope);
    e_val(&(this->ibe), ((has_hard_value(i_s)) ? i_s : 1e-16), par_scope);
    e_val(&(this->i_s), ((ibe == ibc) ? ibe : NA), par_scope);
    e_val(&(this->nf), 1., par_scope);
    e_val(&(this->nr), 1., par_scope);
    e_val(&(this->vaf), NA, par_scope);
    e_val(&(this->var), NA, par_scope);
    e_val(&(this->isc), (c4*ibc), par_scope);
    e_val(&(this->c4), 0., par_scope);
    e_val(&(this->nc), 2., par_scope);
    e_val(&(this->ise), (c2*ibe), par_scope);
    e_val(&(this->c2), 0., par_scope);
    e_val(&(this->ne), 1.5, par_scope);
    e_val(&(this->ikf), NA, par_scope);
    e_val(&(this->ikr), NA, par_scope);
    e_val(&(this->irb), NA, par_scope);
    e_val(&(this->rb), 0., par_scope);
    e_val(&(this->rbm), rb, par_scope);
    e_val(&(this->re), 0., par_scope);
    e_val(&(this->rc), 0., par_scope);
    e_val(&(this->cbcp), 0., par_scope);
    e_val(&(this->cbep), 0., par_scope);
    e_val(&(this->cbsp), 0., par_scope);
    e_val(&(this->ccsp), 0., par_scope);
    e_val(&(this->cjc), 0., par_scope);
    e_val(&(this->cje), 0., par_scope);
    e_val(&(this->cjs), 0., par_scope);
    e_val(&(this->fc), .5, par_scope);
    //this->fc = std::min(fc, .9999);
    e_val(&(this->mjc), .33, par_scope);
    e_val(&(this->mje), .33, par_scope);
    e_val(&(this->mjs), 0., par_scope);
    e_val(&(this->vjc), .75, par_scope);
    e_val(&(this->vje), .75, par_scope);
    e_val(&(this->vjs), .75, par_scope);
    e_val(&(this->xcjc), 1., par_scope);
    e_val(&(this->itf), 0., par_scope);
    e_val(&(this->ptf), 0., par_scope);
    e_val(&(this->tf), 0., par_scope);
    e_val(&(this->tr), 0., par_scope);
    e_val(&(this->vtf), NA, par_scope);
    e_val(&(this->xtf), 0., par_scope);
    e_val(&(this->xtb), 0., par_scope);
    e_val(&(this->xti), 3., par_scope);
    e_val(&(this->eg), 1.11, par_scope);
    // final adjust: mid
    // final adjust: calculated
    tnom_k = _tnom_c + P_CELSIUS0;
    invearlyvoltf = (has_nz_value(vaf)) ? 1./vaf : 0.;
    invearlyvoltr = (has_nz_value(var)) ? 1./var : 0.;
    invrollofff = (has_nz_value(ikf)) ? 1./ikf : 0.;
    invrolloffr = (has_nz_value(ikr)) ? 1./ikr : 0.;
    transtimevbcfact = (has_nz_value(vtf)) ? 1./(vtf*1.44) : 0.;
    excessphasefactor = (ptf * DTOR) * tf;
    xfc = log(1 - fc);
    f2 = exp((1 + mje) * xfc);
    f3 = 1 - fc * (1 + mje);
    f6 = exp((1 + mjc) * xfc);
    f7 = 1 - fc * (1 + mjc);
    // final adjust: post
    // final adjust: done
}
/*--------------------------------------------------------------------------*/
void MODEL_BUILT_IN_BJT::precalc_last()
{
    MODEL_CARD::precalc_last();
}
/*--------------------------------------------------------------------------*/
SDP_CARD* MODEL_BUILT_IN_BJT::new_sdp(COMMON_COMPONENT* c)const
{
  assert(c);
  if (COMMON_BUILT_IN_BJT* cc = dynamic_cast<COMMON_BUILT_IN_BJT*>(c)) {
    if (cc->_sdp) {
      cc->_sdp->init(cc);
      return cc->_sdp;
    }else{
      delete cc->_sdp;
      return new SDP_BUILT_IN_BJT(c);
    }
  }else{
    return MODEL_BUILT_IN_DIODE::new_sdp(c);
  }
}
/*--------------------------------------------------------------------------*/
void MODEL_BUILT_IN_BJT::set_param_by_index(int i, std::string& value, int offset)
{
  switch (MODEL_BUILT_IN_BJT::param_count() - 1 - i) {
  case 0: level = value; break; //1
  case 1: kf = value; break;
  case 2: af = value; break;
  case 3: level = value; break;
  case 4: bf = value; break;
  case 5: br = value; break;
  case 6: ibc = value; break;
  case 7: ibe = value; break;
  case 8: i_s = value; break;
  case 9: nf = value; break;
  case 10: nr = value; break;
  case 11: vaf = value; break;
  case 12: var = value; break;
  case 13: isc = value; break;
  case 14: c4 = value; break;
  case 15: nc = value; break;
  case 16: ise = value; break;
  case 17: c2 = value; break;
  case 18: ne = value; break;
  case 19: ikf = value; break;
  case 20: ikr = value; break;
  case 21: irb = value; break;
  case 22: rb = value; break;
  case 23: rbm = value; break;
  case 24: re = value; break;
  case 25: rc = value; break;
  case 26: cbcp = value; break;
  case 27: cbep = value; break;
  case 28: cbsp = value; break;
  case 29: ccsp = value; break;
  case 30: cjc = value; break;
  case 31: cje = value; break;
  case 32: cjs = value; break;
  case 33: fc = value; break;
  case 34: mjc = value; break;
  case 35: mje = value; break;
  case 36: mjs = value; break;
  case 37: vjc = value; break;
  case 38: vje = value; break;
  case 39: vjs = value; break;
  case 40: xcjc = value; break;
  case 41: itf = value; break;
  case 42: ptf = value; break;
  case 43: tf = value; break;
  case 44: tr = value; break;
  case 45: vtf = value; break;
  case 46: xtf = value; break;
  case 47: xtb = value; break;
  case 48: xti = value; break;
  case 49: eg = value; break;
  default: throw Exception_Too_Many(i, 49, offset); break;
  }
}
/*--------------------------------------------------------------------------*/
bool MODEL_BUILT_IN_BJT::param_is_printable(int i)const
{
  switch (MODEL_BUILT_IN_BJT::param_count() - 1 - i) {
  case 0:  return (true);
  case 1:  return (true);
  case 2:  return (true);
  case 3:  return (false);
  case 4:  return (true);
  case 5:  return (true);
  case 6:  return (ibe != ibc);
  case 7:  return (ibe != ibc);
  case 8:  return (ibe == ibc);
  case 9:  return (true);
  case 10:  return (true);
  case 11:  return (vaf.has_hard_value());
  case 12:  return (var.has_hard_value());
  case 13:  return (isc.has_hard_value());
  case 14:  return (true);
  case 15:  return (true);
  case 16:  return (ise.has_hard_value());
  case 17:  return (true);
  case 18:  return (true);
  case 19:  return (ikf.has_hard_value());
  case 20:  return (ikr.has_hard_value());
  case 21:  return (irb.has_hard_value());
  case 22:  return (true);
  case 23:  return (rbm.has_hard_value());
  case 24:  return (true);
  case 25:  return (true);
  case 26:  return (cbcp!=0.);
  case 27:  return (cbep!=0.);
  case 28:  return (cbsp!=0.);
  case 29:  return (ccsp!=0.);
  case 30:  return (true);
  case 31:  return (true);
  case 32:  return (true);
  case 33:  return (fc.has_hard_value());
  case 34:  return (true);
  case 35:  return (true);
  case 36:  return (true);
  case 37:  return (true);
  case 38:  return (true);
  case 39:  return (true);
  case 40:  return (true);
  case 41:  return (true);
  case 42:  return (true);
  case 43:  return (true);
  case 44:  return (true);
  case 45:  return (vtf.has_hard_value());
  case 46:  return (true);
  case 47:  return (true);
  case 48:  return (true);
  case 49:  return (true);
  default: return false;
  }
}
/*--------------------------------------------------------------------------*/
std::string MODEL_BUILT_IN_BJT::param_name(int i)const
{
  switch (MODEL_BUILT_IN_BJT::param_count() - 1 - i) {
  case 0:  return "level";
  case 1:  return "kf";
  case 2:  return "af";
  case 3:  return "level";
  case 4:  return "bf";
  case 5:  return "br";
  case 6:  return "ibc";
  case 7:  return "ibe";
  case 8:  return "is";
  case 9:  return "nf";
  case 10:  return "nr";
  case 11:  return "vaf";
  case 12:  return "var";
  case 13:  return "isc";
  case 14:  return "c4";
  case 15:  return "nc";
  case 16:  return "ise";
  case 17:  return "c2";
  case 18:  return "ne";
  case 19:  return "ikf";
  case 20:  return "ikr";
  case 21:  return "irb";
  case 22:  return "rb";
  case 23:  return "rbm";
  case 24:  return "re";
  case 25:  return "rc";
  case 26:  return "cbcp";
  case 27:  return "cbep";
  case 28:  return "cbsp";
  case 29:  return "ccsp";
  case 30:  return "cjc";
  case 31:  return "cje";
  case 32:  return "cjs";
  case 33:  return "fc";
  case 34:  return "mjc";
  case 35:  return "mje";
  case 36:  return "mjs";
  case 37:  return "vjc";
  case 38:  return "vje";
  case 39:  return "vjs";
  case 40:  return "xcjc";
  case 41:  return "itf";
  case 42:  return "ptf";
  case 43:  return "tf";
  case 44:  return "tr";
  case 45:  return "vtf";
  case 46:  return "xtf";
  case 47:  return "xtb";
  case 48:  return "xti";
  case 49:  return "eg";
  default: return "";
  }
}
/*--------------------------------------------------------------------------*/
std::string MODEL_BUILT_IN_BJT::param_name(int i, int j)const
{
  if (j == 0) {
    return param_name(i);
  }else if (j == 1) {
    switch (MODEL_BUILT_IN_BJT::param_count() - 1 - i) {
    case 0:  return "";
    case 1:  return "";
    case 2:  return "";
    case 3:  return "";
    case 4:  return "bfm";
    case 5:  return "brm";
    case 6:  return "";
    case 7:  return "";
    case 8:  return "";
    case 9:  return "";
    case 10:  return "";
    case 11:  return "va\0vbf";
    case 12:  return "vb";
    case 13:  return "";
    case 14:  return "jlc";
    case 15:  return "";
    case 16:  return "";
    case 17:  return "jle";
    case 18:  return "";
    case 19:  return "ik\0jbf";
    case 20:  return "jbr";
    case 21:  return "jrb\0iob";
    case 22:  return "";
    case 23:  return "";
    case 24:  return "";
    case 25:  return "";
    case 26:  return "";
    case 27:  return "";
    case 28:  return "";
    case 29:  return "";
    case 30:  return "";
    case 31:  return "";
    case 32:  return "ccs\0csub";
    case 33:  return "";
    case 34:  return "mc\0mj";
    case 35:  return "me";
    case 36:  return "msub\0ms\0esub";
    case 37:  return "pc";
    case 38:  return "pe";
    case 39:  return "psub\0ps";
    case 40:  return "cdis";
    case 41:  return "jtf";
    case 42:  return "";
    case 43:  return "";
    case 44:  return "";
    case 45:  return "";
    case 46:  return "";
    case 47:  return "tb";
    case 48:  return "";
    case 49:  return "";
    default: return "";
    }
  }else{
    return "";
  }
}
/*--------------------------------------------------------------------------*/
std::string MODEL_BUILT_IN_BJT::param_value(int i)const
{
  switch (MODEL_BUILT_IN_BJT::param_count() - 1 - i) {
  case 0:  return "1";
  case 1:  return kf.string();
  case 2:  return af.string();
  case 3:  return level.string();
  case 4:  return bf.string();
  case 5:  return br.string();
  case 6:  return ibc.string();
  case 7:  return ibe.string();
  case 8:  return i_s.string();
  case 9:  return nf.string();
  case 10:  return nr.string();
  case 11:  return vaf.string();
  case 12:  return var.string();
  case 13:  return isc.string();
  case 14:  return c4.string();
  case 15:  return nc.string();
  case 16:  return ise.string();
  case 17:  return c2.string();
  case 18:  return ne.string();
  case 19:  return ikf.string();
  case 20:  return ikr.string();
  case 21:  return irb.string();
  case 22:  return rb.string();
  case 23:  return rbm.string();
  case 24:  return re.string();
  case 25:  return rc.string();
  case 26:  return cbcp.string();
  case 27:  return cbep.string();
  case 28:  return cbsp.string();
  case 29:  return ccsp.string();
  case 30:  return cjc.string();
  case 31:  return cje.string();
  case 32:  return cjs.string();
  case 33:  return fc.string();
  case 34:  return mjc.string();
  case 35:  return mje.string();
  case 36:  return mjs.string();
  case 37:  return vjc.string();
  case 38:  return vje.string();
  case 39:  return vjs.string();
  case 40:  return xcjc.string();
  case 41:  return itf.string();
  case 42:  return ptf.string();
  case 43:  return tf.string();
  case 44:  return tr.string();
  case 45:  return vtf.string();
  case 46:  return xtf.string();
  case 47:  return xtb.string();
  case 48:  return xti.string();
  case 49:  return eg.string();
  default: return "";
  }
}
/*--------------------------------------------------------------------------*/
bool MODEL_BUILT_IN_BJT::is_valid(const COMPONENT* d)const
{
  assert(d);
  return MODEL_BUILT_IN_DIODE::is_valid(d);
}
/*--------------------------------------------------------------------------*/
void MODEL_BUILT_IN_BJT::tr_eval(COMPONENT* brh)const
{
  DEV_BUILT_IN_BJT* d = prechecked_cast<DEV_BUILT_IN_BJT*>(brh);
  assert(d);
  const COMMON_BUILT_IN_BJT* c = prechecked_cast<const COMMON_BUILT_IN_BJT*>(d->common());
  assert(c);
  const SDP_BUILT_IN_BJT* s = prechecked_cast<const SDP_BUILT_IN_BJT*>(c->sdp());
  assert(s);
  const MODEL_BUILT_IN_BJT* m = this;
  const TDP_BUILT_IN_BJT T(d);
  const TDP_BUILT_IN_BJT* t = &T;

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    trace0("--------------------------");
    trace1(d->long_label().c_str(), d->evaliter());
    trace4("", d->vbe, d->vbc, d->vbx, d->vcs);
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    double cbe, gbe;
    { // d->cpi, d->gpi, d->cpixxx
      // uses: d->vbe
      double cben, gben;
      double vtn = t->vt * m->nf;
      double csat = t->ibe * c->area;
      double C2 = t->BEleakCur * c->area;
      if (d->vbe > -5 * vtn) {
	double evbe = exp(d->vbe / vtn);
	cbe = csat * (evbe-1) + OPT::gmin * d->vbe;
	gbe = csat * evbe/vtn + OPT::gmin;
	if (C2 == 0.) {
	  cben = 0.;
	  gben = 0.;
	}else{
	  double vte = m->ne * t->vt;
	  double evben = exp(d->vbe / vte);
	  cben = C2 * (evben-1);
	  gben = C2 * evben/vte;
	}
	trace4("vbe on", cbe, gbe, cben, gben);
      }else{
	gbe = -csat/d->vbe + OPT::gmin;
	cbe = gbe * d->vbe;
	gben = -C2 / d->vbe;
	cben = gben * d->vbe;
	trace4("vbe off", cbe, gbe, cben, gben);
      }
      d->cpi = cbe / t->BetaF + cben;
      d->gpi = gbe / t->BetaF + gben;
      d->cpixxx = d->cpi - d->vbe * d->gpi;
      trace3("", t->BetaF, d->cpi, d->gpi);
    }
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    double cbc, gbc, cbcn;
    { // d->cmu, d->gmu, d->cmuxxx
      // uses: d->vbc
      double gbcn;
      double vtn = t->vt * m->nr;
      double csat = t->ibc * c->area;
      double C4 = t->BCleakCur * c->area;
      if (d->vbc > -5 * vtn) {
	double evbc = exp(d->vbc / vtn);
	cbc = csat * (evbc-1) + OPT::gmin * d->vbc;
	gbc = csat * evbc/vtn + OPT::gmin;
	if (C4 == 0.) {
	  cbcn = 0.;
	  gbcn = 0.;
	}else{
	  double vtc = m->nc * t->vt;
	  double evbcn = exp(d->vbc / vtc);
	  cbcn = C4 * (evbcn-1);
	  gbcn = C4 * evbcn/vtc;
	}
	trace4("vbc on", cbc, gbc, cbcn, gbcn);
      }else{
	gbc = -csat/d->vbc + OPT::gmin;
	cbc = gbc * d->vbc;
	gbcn = -C4 / d->vbc;
	cbcn = gbcn * d->vbc;
	trace4("vbc off", cbc, gbc, cbcn, gbcn);
      }
      d->cmu = cbc / t->BetaR + cbcn;
      d->gmu = gbc / t->BetaR + gbcn;
      d->cmuxxx = d->cmu - d->vbc * d->gmu;
      trace3("", t->BetaR, d->cmu, d->gmu);
    }
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //   determine base charge terms
    double qb, dqbdve, dqbdvc;
    {
      double q1 = 1 / (1 - m->invearlyvoltf*d->vbc - m->invearlyvoltr*d->vbe);
      if(c->oik == 0. && c->oikr == 0.) {
	qb = q1;
	dqbdve = q1 * qb * m->invearlyvoltr;
	dqbdvc = q1 * qb * m->invearlyvoltf;
	trace4("!oik", q1, qb, dqbdve, dqbdvc);
      }else{
	double q2 = c->oik * cbe + c->oikr * cbc;
	double arg = std::max(0., 1+4*q2);
	double sqarg = (arg == 0.) ? 1 : sqrt(arg);
	qb = q1 * (1+sqarg) / 2;
	dqbdve = q1 * (qb * m->invearlyvoltr + c->oik  * gbe / sqarg);
	dqbdvc = q1 * (qb * m->invearlyvoltf + c->oikr * gbc / sqarg);
	trace2("", c->oik, c->oikr);
	trace4("oik", q1, qb, dqbdve, dqbdvc);
      }
    }
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // weil's approx. for excess phase applied with backward-euler integration
    {
      double cc = 0.;
      double cex = cbe;
      double gex = gbe;
      if (0 && m->excessphasefactor != 0.) {
	unreachable();
	incomplete(); // doesn't save old values of cexbc, so disabled
	double arg1 = d->_dt_0 / m->excessphasefactor;
	double arg2 = 3 * arg1;
	arg1 *= arg2;
	double denom = 1 + arg1 + arg2;
	double arg3 = arg1 / denom;
	if (_sim->is_initial_step()) {
	  d->cexbc_2 = d->cexbc_1 = cbe / qb;
	}else{
	}
	cc = (d->cexbc_1 * (1 + d->_dt_0/d->_dt_1 + arg2)
	      - d->cexbc_2 * d->_dt_0/d->_dt_1) / denom;
	cex *= arg3;
	gex *= arg3;
      }
      d->cexbc_0 = cc + cex / qb;

      d->cce = cc + (cex-cbc)/qb - cbc/t->BetaR - cbcn;
      d->go = (gbc + (cex-cbc)*dqbdvc / qb) / qb;
      d->gm = (gex - (cex-cbc)*dqbdve / qb) / qb - d->go;
      d->ccexxx = d->cce - ((d->vbe - d->vbc) * d->go + d->vbe * d->gm);
      trace4("", d->cce, d->go, d->gm, d->cce/t->vt);
    }
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // d->gx
    // should be moved to a private eval
    // may use d->cpi, d->cmu, qb
    {
      if (!OPT::rstray || (!has_nz_value(m->rb) && !has_nz_value(m->rbm))) {
	trace3("", m->rb, m->irb, d->gx);
	assert(d->gx == NA);
      }else{
	double rx = NA;
	double rbpr = m->rbm / c->area;
	double rbpi = m->rb / c->area - rbpr;
	if (has_nz_value(m->irb)) {itested();//554
	  // base resistance lowering at high current
	  double cb = d->cpi + d->cmu;
	  double xjrb = m->irb * c->area;
	  double arg1 = std::max(cb/xjrb, 1e-9);
	  double arg2 = (-1 + sqrt(1+14.59025*arg1)) / 2.4317 / sqrt(arg1);
	  arg1 = tan(arg2);
	  rx = rbpr + 3 * rbpi * (arg1-arg2) / arg2 / arg1 / arg1;
	}else{
	  rx = rbpr + rbpi / qb;
	}
	trace3("", m->rb, m->irb, rx);
	assert(rx != NA);
	assert(rx != 0.);
	d->gx = 1 / rx;
	trace1("", d->gx);
      }
    }
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    const bool charge_computation_needed = OPT::cstray;
    if (charge_computation_needed) {
      if (has_nz_value(m->tf) && d->vbe > 0.) {
	double argtf = NA;
	double arg2  = NA;
	double arg3  = NA;
	if (has_nz_value(m->xtf)) {itested();//579
	  if (m->transtimevbcfact != 0.) {
	    argtf = m->xtf * exp(d->vbc * m->transtimevbcfact);
	  }else{untested();
	    argtf = m->xtf;
	  }
	  arg2 = argtf;
	  if(has_nz_value(m->itf)) {
	    double temp = cbe / (cbe + m->itf * c->area);
	    argtf *= temp*temp;
	    arg2  *= (3-temp-temp);
	  }else{
	  }
	  arg3 = cbe * argtf * m->transtimevbcfact;
	}else{
	  arg3 = arg2 = argtf = 0.;
	}
	assert(argtf != NA);
	assert(arg2  != NA);
	assert(arg3  != NA);
	cbe *= (1+argtf) / qb;
	gbe = (gbe * (1+arg2) - cbe * dqbdve) / qb;
	d->geqcb=m->tf*(arg3-cbe*dqbdvc)/qb;
      }else{
	d->geqcb=0.;
      }
      { // d->qbe, d->cqbe
	// uses: d->vbe, cbe, gbe
	double czbe = t->BEcap * c->area;
	if (d->vbe < t->DepCap) {
	  double arg = 1 - d->vbe / t->BEpot;
	  double sarg = pow(arg, -m->mje);
	  d->qbe = m->tf * cbe + t->BEpot * czbe * (1-arg*sarg) / (1 - m->mje);
	  d->cqbe = m->tf * gbe + czbe * sarg;
	}else{
	  double czbef2 = czbe / m->f2;
	  d->qbe = m->tf * cbe + czbe * t->f1 
	    + czbef2 * (m->f3 * (d->vbe - t->DepCap)
			+ (m->mje / (2. * t->BEpot))
			* (d->vbe * d->vbe - t->DepCap * t->DepCap));
	  d->cqbe = m->tf * gbe + czbef2 * (m->f3 + m->mje*d->vbe / t->BEpot);
	}
      }
      { // d->qbc, d->cqbc
	// uses: d->vbc, cbc, gbc
	double czbc = t->BCcap * c->area * m->xcjc;
	if (d->vbc < t->f4) {
	  double arg = 1 - d->vbc / t->BCpot;
	  double sarg = pow(arg, -m->mjc);
	  d->qbc = m->tr *cbc + t->BCpot *czbc * (1 - arg*sarg) / (1 - m->mjc);
	  d->cqbc = m->tr * gbc + czbc * sarg;
	}else{
	  double czbcf2 = czbc / m->f6;
	  d->qbc = m->tr * cbc + czbc * t->f5
	    + czbcf2 * (m->f7 * (d->vbc-t->f4) 
		+ (m->mjc/(t->BCpot+t->BCpot)) * (d->vbc*d->vbc-t->f4*t->f4));
	  d->cqbc = m->tr * gbc + czbcf2 * (m->f7 + m->mjc * d->vbc/t->BCpot);
	}
      }
      { // d->qbx, d->cqbx
	// uses: d->vbx
	double czbx = t->BCcap * c->area * (1 - m->xcjc);
	if (d->vbx < t->f4) {
	  double arg = 1 - d->vbx / t->BCpot;
	  double sarg = pow(arg, -m->mjc);
	  d->qbx = t->BCpot * czbx * (1 - arg*sarg) / (1 - m->mjc);
	  d->cqbx = czbx * sarg;
	}else{
	  double czbxf2 = czbx / m->f6;
	  d->qbx = czbx * t->f5 + czbxf2 
	    * (m->f7 * (d->vbx-t->f4)
	      + (m->mjc / (t->BCpot+t->BCpot)) * (d->vbx*d->vbx-t->f4*t->f4));
	  d->cqbx = czbxf2 * (m->f7 + m->mjc * d->vbx / t->BCpot);
	}
      }
      { // d->qcs, d->cqcs
	// uses: d->vcs
	double czcs = m->cjs * c->area;
	if (d->vcs < 0.) {
	  double arg = 1 - d->vcs / m->vjs;
	  double sarg = pow(arg, -m->mjs);
	  d->qcs = m->vjs * czcs * (1 - arg*sarg) / (1 - m->mjs);
	  d->cqcs = czcs * sarg;
	}else{
	  d->qcs = d->vcs * czcs * (1 + m->mjs * d->vcs / (2 * m->vjs));
	  d->cqcs = czcs * (1 + m->mjs * d->vcs / m->vjs);
	}
      }
    }
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
int DEV_BUILT_IN_BJT::_count = -1;
int COMMON_BUILT_IN_BJT::_count = -1;
static COMMON_BUILT_IN_BJT Default_BUILT_IN_BJT(CC_STATIC);
/*--------------------------------------------------------------------------*/
COMMON_BUILT_IN_BJT::COMMON_BUILT_IN_BJT(int c)
  :COMMON_COMPONENT(c),
   area(1.),
   off(false),
   icvbe(NA),
   icvce(NA),
   temp_c(NA),
   _sdp(0),
   oik(NA),
   oikr(NA)
{
  ++_count;
}
/*--------------------------------------------------------------------------*/
COMMON_BUILT_IN_BJT::COMMON_BUILT_IN_BJT(const COMMON_BUILT_IN_BJT& p)
  :COMMON_COMPONENT(p),
   area(p.area),
   off(p.off),
   icvbe(p.icvbe),
   icvce(p.icvce),
   temp_c(p.temp_c),
   _sdp(0),
   oik(p.oik),
   oikr(p.oikr)
{
  ++_count;
}
/*--------------------------------------------------------------------------*/
COMMON_BUILT_IN_BJT::~COMMON_BUILT_IN_BJT()
{
  --_count;
  delete _sdp;
}
/*--------------------------------------------------------------------------*/
bool COMMON_BUILT_IN_BJT::operator==(const COMMON_COMPONENT& x)const
{
  const COMMON_BUILT_IN_BJT* p = dynamic_cast<const COMMON_BUILT_IN_BJT*>(&x);
  return (p
    && area == p->area
    && off == p->off
    && icvbe == p->icvbe
    && icvce == p->icvce
    && temp_c == p->temp_c
    && _sdp == p->_sdp
    && COMMON_COMPONENT::operator==(x));
}
/*--------------------------------------------------------------------------*/
void COMMON_BUILT_IN_BJT::set_param_by_index(int I, std::string& Value, int Offset)
{
  switch (COMMON_BUILT_IN_BJT::param_count() - 1 - I) {
  case 0:  area = Value; break;
  case 1:  off = Value; break;
  case 2:  icvbe = Value; break;
  case 3:  icvce = Value; break;
  case 4:  temp_c = Value; break;
  default: COMMON_COMPONENT::set_param_by_index(I, Value, Offset);
  }
}
/*--------------------------------------------------------------------------*/
bool COMMON_BUILT_IN_BJT::param_is_printable(int i)const
{
  switch (COMMON_BUILT_IN_BJT::param_count() - 1 - i) {
  case 0:  return (true);
  case 1:  return (off);
  case 2:  return (icvbe != NA);
  case 3:  return (icvce != NA);
  case 4:  return (temp_c != NA);
  default: return COMMON_COMPONENT::param_is_printable(i);
  }
}
/*--------------------------------------------------------------------------*/
std::string COMMON_BUILT_IN_BJT::param_name(int i)const
{
  switch (COMMON_BUILT_IN_BJT::param_count() - 1 - i) {
  case 0:  return "area";
  case 1:  return "off";
  case 2:  return "icvbe";
  case 3:  return "icvce";
  case 4:  return "temp";
  default: return COMMON_COMPONENT::param_name(i);
  }
}
/*--------------------------------------------------------------------------*/
std::string COMMON_BUILT_IN_BJT::param_name(int i, int j)const
{
  if (j == 0) {
    return param_name(i);
  }else if (j == 1) {
    switch (COMMON_BUILT_IN_BJT::param_count() - 1 - i) {
    case 0:  return "";
    case 1:  return "";
    case 2:  return "";
    case 3:  return "";
    case 4:  return "";
    default: return "";
    }
  }else{untested();//281
    return COMMON_COMPONENT::param_name(i, j);
  }
}
/*--------------------------------------------------------------------------*/
std::string COMMON_BUILT_IN_BJT::param_value(int i)const
{
  switch (COMMON_BUILT_IN_BJT::param_count() - 1 - i) {
  case 0:  return area.string();
  case 1:  return off.string();
  case 2:  return icvbe.string();
  case 3:  return icvce.string();
  case 4:  return temp_c.string();
  default: return COMMON_COMPONENT::param_value(i);
  }
}
/*--------------------------------------------------------------------------*/
void COMMON_BUILT_IN_BJT::expand(const COMPONENT* d)
{
  COMMON_COMPONENT::expand(d);
  attach_model(d);
  COMMON_BUILT_IN_BJT* c = this;
  const MODEL_BUILT_IN_BJT* m = dynamic_cast<const MODEL_BUILT_IN_BJT*>(model());
  if (!m) {
    throw Exception_Model_Type_Mismatch(d->long_label(), modelname(), "bjt");
  }else{
  }
  // size dependent
  //delete _sdp;
  _sdp = m->new_sdp(this);
  assert(_sdp);
  const SDP_BUILT_IN_BJT* s = prechecked_cast<const SDP_BUILT_IN_BJT*>(_sdp);
  assert(s);

  // subcircuit commons, recursive
  assert(c == this);
}
/*--------------------------------------------------------------------------*/
void COMMON_BUILT_IN_BJT::precalc_first(const CARD_LIST* par_scope)
{
  assert(par_scope);
  COMMON_COMPONENT::precalc_first(par_scope);
    e_val(&(this->area), 1., par_scope);
    e_val(&(this->off), false, par_scope);
    e_val(&(this->icvbe), NA, par_scope);
    e_val(&(this->icvce), NA, par_scope);
    e_val(&(this->temp_c), NA, par_scope);
}
/*--------------------------------------------------------------------------*/
void COMMON_BUILT_IN_BJT::precalc_last(const CARD_LIST* par_scope)
{
  assert(par_scope);
  COMMON_COMPONENT::precalc_last(par_scope);
  COMMON_BUILT_IN_BJT* c = this;
  const MODEL_BUILT_IN_BJT* m = prechecked_cast<const MODEL_BUILT_IN_BJT*>(model());
    // final adjust: code_pre
    // final adjust: override
    // final adjust: raw
    e_val(&(this->area), 1., par_scope);
    e_val(&(this->off), false, par_scope);
    e_val(&(this->icvbe), NA, par_scope);
    e_val(&(this->icvce), NA, par_scope);
    e_val(&(this->temp_c), NA, par_scope);
    // final adjust: mid
    // final adjust: calculated
    oik = m->invrollofff / c->area;
    oikr = m->invrolloffr / c->area;
    // final adjust: post
    // final adjust: done

  // size dependent
  //delete _sdp;
  _sdp = m->new_sdp(this);
  assert(_sdp);
  const SDP_BUILT_IN_BJT* s = prechecked_cast<const SDP_BUILT_IN_BJT*>(_sdp);
  assert(s);

  // subcircuit commons, recursive
  assert(c == this);
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
namespace DEV_BUILT_IN_BJT_DISPATCHER { 
  static DEV_BUILT_IN_BJT p0;
  static DISPATCHER<CARD>::INSTALL
    d0(&device_dispatcher, "Q|bjt", &p0);
}
/*--------------------------------------------------------------------------*/
DEV_BUILT_IN_BJT::DEV_BUILT_IN_BJT()
  :BASE_SUBCKT(),
   // input parameters,
   // calculated parameters,
   vbe(NA),
   vbc(NA),
   vbx(NA),
   vcs(NA),
   cce(NA),
   ccexxx(NA),
   go(NA),
   gm(NA),
   cpi(NA),
   cpixxx(NA),
   gpi(NA),
   cmu(NA),
   cmuxxx(NA),
   gmu(NA),
   ixxxx(0.),
   gx(NA),
   qbx(NA),
   cqbx(NA),
   qbc(NA),
   cqbc(NA),
   qcs(NA),
   cqcs(NA),
   qbe(NA),
   cqbe(NA),
   geqcb(NA),
   cexbc_0(NA),
   cexbc_1(NA),
   cexbc_2(NA),
   _dt_0(NA),
   _dt_1(NA),
   // netlist,
   _Ice(0),
   _Ipi(0),
   _Imu(0),
   _Cbx(0),
   _Cbc(0),
   _Ccs(0),
   _Cbe(0),
   _Rc(0),
   _Re(0),
   _Yb(0),
   _Cbcp(0),
   _Cbep(0),
   _Cbs(0)
{
  _n = _nodes;
  attach_common(&Default_BUILT_IN_BJT);
  ++_count;
  // overrides
}
/*--------------------------------------------------------------------------*/
DEV_BUILT_IN_BJT::DEV_BUILT_IN_BJT(const DEV_BUILT_IN_BJT& p)
  :BASE_SUBCKT(p),
   // input parameters,
   // calculated parameters,
   vbe(p.vbe),
   vbc(p.vbc),
   vbx(p.vbx),
   vcs(p.vcs),
   cce(p.cce),
   ccexxx(p.ccexxx),
   go(p.go),
   gm(p.gm),
   cpi(p.cpi),
   cpixxx(p.cpixxx),
   gpi(p.gpi),
   cmu(p.cmu),
   cmuxxx(p.cmuxxx),
   gmu(p.gmu),
   ixxxx(p.ixxxx),
   gx(p.gx),
   qbx(p.qbx),
   cqbx(p.cqbx),
   qbc(p.qbc),
   cqbc(p.cqbc),
   qcs(p.qcs),
   cqcs(p.cqcs),
   qbe(p.qbe),
   cqbe(p.cqbe),
   geqcb(p.geqcb),
   cexbc_0(p.cexbc_0),
   cexbc_1(p.cexbc_1),
   cexbc_2(p.cexbc_2),
   _dt_0(p._dt_0),
   _dt_1(p._dt_1),
   // netlist,
   _Ice(0),
   _Ipi(0),
   _Imu(0),
   _Cbx(0),
   _Cbc(0),
   _Ccs(0),
   _Cbe(0),
   _Rc(0),
   _Re(0),
   _Yb(0),
   _Cbcp(0),
   _Cbep(0),
   _Cbs(0)
{
  _n = _nodes;
  for (int ii = 0; ii < max_nodes() + int_nodes(); ++ii) {
    _n[ii] = p._n[ii];
  }
  ++_count;
  // overrides
}
/*--------------------------------------------------------------------------*/
void DEV_BUILT_IN_BJT::expand()
{
  BASE_SUBCKT::expand(); // calls common->expand, attached model
  assert(_n);
  assert(common());
  const COMMON_BUILT_IN_BJT* c = static_cast<const COMMON_BUILT_IN_BJT*>(common());
  assert(c);
  assert(c->model());
  const MODEL_BUILT_IN_BJT* m = prechecked_cast<const MODEL_BUILT_IN_BJT*>(c->model());
  assert(m);
  assert(c->sdp());
  const SDP_BUILT_IN_BJT* s = prechecked_cast<const SDP_BUILT_IN_BJT*>(c->sdp());
  assert(s);
  if (!subckt()) {
    new_subckt();
  }else{
  }

  if (_sim->is_first_expand()) {
    precalc_first();
    precalc_last();
    // local nodes
    //assert(!(_n[n_ic].n_()));
    //BUG// this assert fails on a repeat elaboration after a change.
    //not sure of consequences when new_model_node called twice.
    if (!(_n[n_ic].n_())) {
      if (!OPT::rstray || m->rc == 0.) {
        _n[n_ic] = _n[n_c];
      }else{
        _n[n_ic].new_model_node("." + long_label() + ".ic", this);
      }
    }else{
      if (!OPT::rstray || m->rc == 0.) {
        assert(_n[n_ic] == _n[n_c]);
      }else{
        //_n[n_ic].new_model_node("ic." + long_label(), this);
      }
    }
    //assert(!(_n[n_ib].n_()));
    //BUG// this assert fails on a repeat elaboration after a change.
    //not sure of consequences when new_model_node called twice.
    if (!(_n[n_ib].n_())) {
      if (!OPT::rstray || (m->rb == 0. && m->rbm == 0.)) {
        _n[n_ib] = _n[n_b];
      }else{
        _n[n_ib].new_model_node("." + long_label() + ".ib", this);
      }
    }else{
      if (!OPT::rstray || (m->rb == 0. && m->rbm == 0.)) {
        assert(_n[n_ib] == _n[n_b]);
      }else{
        //_n[n_ib].new_model_node("ib." + long_label(), this);
      }
    }
    //assert(!(_n[n_ie].n_()));
    //BUG// this assert fails on a repeat elaboration after a change.
    //not sure of consequences when new_model_node called twice.
    if (!(_n[n_ie].n_())) {
      if (!OPT::rstray || m->re == 0.) {
        _n[n_ie] = _n[n_e];
      }else{
        _n[n_ie].new_model_node("." + long_label() + ".ie", this);
      }
    }else{
      if (!OPT::rstray || m->re == 0.) {
        assert(_n[n_ie] == _n[n_e]);
      }else{
        //_n[n_ie].new_model_node("ie." + long_label(), this);
      }
    }

    // clone subckt elements
    {
      if (!_Ice) {
        const CARD* p = device_dispatcher["cpoly_g"];
        assert(p);
        _Ice = dynamic_cast<COMPONENT*>(p->clone());
        assert(_Ice);
        subckt()->push_front(_Ice);
      }else{
      }
      {
        node_t nodes[] = {_n[n_ic], _n[n_ie], _n[n_ib], _n[n_ie]};
      _Ice->set_parameters("Ice", this, NULL, 0., 3, &ccexxx, 4, nodes);
      }
    }
    {
      if (!_Ipi) {
        const CARD* p = device_dispatcher["cpoly_g"];
        assert(p);
        _Ipi = dynamic_cast<COMPONENT*>(p->clone());
        assert(_Ipi);
        subckt()->push_front(_Ipi);
      }else{
      }
      {
        node_t nodes[] = {_n[n_ib], _n[n_ie]};
      _Ipi->set_parameters("Ipi", this, NULL, 0., 2, &cpixxx, 2, nodes);
      }
    }
    {
      if (!_Imu) {
        const CARD* p = device_dispatcher["cpoly_g"];
        assert(p);
        _Imu = dynamic_cast<COMPONENT*>(p->clone());
        assert(_Imu);
        subckt()->push_front(_Imu);
      }else{
      }
      {
        node_t nodes[] = {_n[n_ib], _n[n_ic]};
      _Imu->set_parameters("Imu", this, NULL, 0., 2, &cmuxxx, 2, nodes);
      }
    }
    {
      if (!_Cbx) {
        const CARD* p = device_dispatcher["fpoly_cap"];
        assert(p);
        _Cbx = dynamic_cast<COMPONENT*>(p->clone());
        assert(_Cbx);
        subckt()->push_front(_Cbx);
      }else{
      }
      {
        node_t nodes[] = {_n[n_b], _n[n_ic]};
      _Cbx->set_parameters("Cbx", this, NULL, 0., 2, &qbx, 2, nodes);
      }
    }
    {
      if (!_Cbc) {
        const CARD* p = device_dispatcher["fpoly_cap"];
        assert(p);
        _Cbc = dynamic_cast<COMPONENT*>(p->clone());
        assert(_Cbc);
        subckt()->push_front(_Cbc);
      }else{
      }
      {
        node_t nodes[] = {_n[n_ib], _n[n_ic]};
      _Cbc->set_parameters("Cbc", this, NULL, 0., 2, &qbc, 2, nodes);
      }
    }
    if (!(_n[n_s].n_())) {
      if (_Ccs) {
        subckt()->erase(_Ccs);
        _Ccs = NULL;
      }else{
      }
    }else{
      if (!_Ccs) {
        const CARD* p = device_dispatcher["fpoly_cap"];
        assert(p);
        _Ccs = dynamic_cast<COMPONENT*>(p->clone());
        assert(_Ccs);
        subckt()->push_front(_Ccs);
      }else{
      }
      {
        node_t nodes[] = {_n[n_s], _n[n_ic]};
      _Ccs->set_parameters("Ccs", this, NULL, 0., 2, &qcs, 2, nodes);
      }
    }
    {
      if (!_Cbe) {
        const CARD* p = device_dispatcher["fpoly_cap"];
        assert(p);
        _Cbe = dynamic_cast<COMPONENT*>(p->clone());
        assert(_Cbe);
        subckt()->push_front(_Cbe);
      }else{
      }
      {
        node_t nodes[] = {_n[n_ib], _n[n_ie], _n[n_ib], _n[n_ic]};
      _Cbe->set_parameters("Cbe", this, NULL, 0., 3, &qbe, 4, nodes);
      }
    }
    if (!OPT::rstray || m->rc == 0.) {
      if (_Rc) {
        subckt()->erase(_Rc);
        _Rc = NULL;
      }else{
      }
    }else{
      if (!_Rc) {
        const CARD* p = device_dispatcher["resistor"];
        assert(p);
        _Rc = dynamic_cast<COMPONENT*>(p->clone());
        assert(_Rc);
        subckt()->push_front(_Rc);
      }else{
      }
      {
        node_t nodes[] = {_n[n_c], _n[n_ic]};
      _Rc->set_parameters("Rc", this, NULL, m->rc / c->area, 0, NULL, 2, nodes);
      }
    }
    if (!OPT::rstray || m->re == 0.) {
      if (_Re) {
        subckt()->erase(_Re);
        _Re = NULL;
      }else{
      }
    }else{
      if (!_Re) {
        const CARD* p = device_dispatcher["resistor"];
        assert(p);
        _Re = dynamic_cast<COMPONENT*>(p->clone());
        assert(_Re);
        subckt()->push_front(_Re);
      }else{
      }
      {
        node_t nodes[] = {_n[n_e], _n[n_ie]};
      _Re->set_parameters("Re", this, NULL, m->re / c->area, 0, NULL, 2, nodes);
      }
    }
    if (!OPT::rstray || (m->rb == 0. && m->rbm == 0.)) {
      if (_Yb) {
        subckt()->erase(_Yb);
        _Yb = NULL;
      }else{
      }
    }else{
      if (!_Yb) {
        const CARD* p = device_dispatcher["cpoly_g"];
        assert(p);
        _Yb = dynamic_cast<COMPONENT*>(p->clone());
        assert(_Yb);
        subckt()->push_front(_Yb);
      }else{
      }
      {
        node_t nodes[] = {_n[n_b], _n[n_ib]};
      _Yb->set_parameters("Yb", this, NULL, 0., 2, &ixxxx, 2, nodes);
      }
    }
    if (!OPT::cstray || m->cbcp == 0.) {
      if (_Cbcp) {
        subckt()->erase(_Cbcp);
        _Cbcp = NULL;
      }else{
      }
    }else{
      if (!_Cbcp) {
        const CARD* p = device_dispatcher["capacitor"];
        assert(p);
        _Cbcp = dynamic_cast<COMPONENT*>(p->clone());
        assert(_Cbcp);
        subckt()->push_front(_Cbcp);
      }else{
      }
      {
        node_t nodes[] = {_n[n_b], _n[n_c]};
      _Cbcp->set_parameters("Cbcp", this, NULL, m->cbcp * c->area, 0, NULL, 2, nodes);
      }
    }
    if (!OPT::cstray || m->cbep == 0.) {
      if (_Cbep) {
        subckt()->erase(_Cbep);
        _Cbep = NULL;
      }else{
      }
    }else{
      if (!_Cbep) {
        const CARD* p = device_dispatcher["capacitor"];
        assert(p);
        _Cbep = dynamic_cast<COMPONENT*>(p->clone());
        assert(_Cbep);
        subckt()->push_front(_Cbep);
      }else{
      }
      {
        node_t nodes[] = {_n[n_b], _n[n_e]};
      _Cbep->set_parameters("Cbep", this, NULL, m->cbep * c->area, 0, NULL, 2, nodes);
      }
    }
    if (!OPT::cstray || ((m->cbsp + m->ccsp) == 0.)) {
      if (_Cbs) {
        subckt()->erase(_Cbs);
        _Cbs = NULL;
      }else{
      }
    }else{
      if (!_Cbs) {
        const CARD* p = device_dispatcher["capacitor"];
        assert(p);
        _Cbs = dynamic_cast<COMPONENT*>(p->clone());
        assert(_Cbs);
        subckt()->push_front(_Cbs);
      }else{
      }
      {
        node_t nodes[] = {_n[n_b], _n[n_s]};
      _Cbs->set_parameters("Cbs", this, NULL, (m->cbsp + m->ccsp) * c->area, 0, NULL, 2, nodes);
      }
    }
  }else{
    //precalc();
  }
  //precalc();
  subckt()->expand();
  //subckt()->precalc();
  assert(!is_constant());
  subckt()->set_slave();
}
/*--------------------------------------------------------------------------*/
double DEV_BUILT_IN_BJT::tr_probe_num(const std::string& x)const
{
  assert(_n);
  const COMMON_BUILT_IN_BJT* c = prechecked_cast<const COMMON_BUILT_IN_BJT*>(common());
  assert(c);
  const MODEL_BUILT_IN_BJT* m = prechecked_cast<const MODEL_BUILT_IN_BJT*>(c->model());
  assert(m);
  const SDP_BUILT_IN_BJT* s = prechecked_cast<const SDP_BUILT_IN_BJT*>(c->sdp());
  assert(s);

  if (Umatch(x, "v ")) {
    return  _n[n_c].v0() - _n[n_e].v0();
  }else if (Umatch(x, "vbei{nt} ")) {
    return  vbe;
  }else if (Umatch(x, "vbci{nt} ")) {
    return  vbc;
  }else if (Umatch(x, "vbxi{nt} ")) {
    return  vbx;
  }else if (Umatch(x, "vcsi{nt} ")) {
    return  vcs;
  }else if (Umatch(x, "vbs ")) {
    return  _n[n_b].v0() - _n[n_s].v0();
  }else if (Umatch(x, "vbe ")) {
    return  _n[n_b].v0() - _n[n_e].v0();
  }else if (Umatch(x, "vbc ")) {
    return  _n[n_b].v0() - _n[n_c].v0();
  }else if (Umatch(x, "vbx ")) {
    return  _n[n_b].v0() - _n[n_ib].v0();
  }else if (Umatch(x, "vcs ")) {
    return  _n[n_c].v0() - _n[n_s].v0();
  }else if (Umatch(x, "vcb ")) {
    return  _n[n_c].v0() - _n[n_b].v0();
  }else if (Umatch(x, "vce ")) {
    return  _n[n_c].v0() - _n[n_e].v0();
  }else if (Umatch(x, "ves ")) {
    return  _n[n_e].v0() - _n[n_s].v0();
  }else if (Umatch(x, "veb ")) {
    return  _n[n_e].v0() - _n[n_b].v0();
  }else if (Umatch(x, "vec ")) {
    return  _n[n_e].v0() - _n[n_c].v0();
  }else if (Umatch(x, "vb ")) {
    return  _n[n_b].v0();
  }else if (Umatch(x, "vc ")) {
    return  _n[n_c].v0();
  }else if (Umatch(x, "ve ")) {
    return  _n[n_e].v0();
  }else if (Umatch(x, "vs ")) {
    return  _n[n_s].v0();
  }else if (Umatch(x, "vbi ")) {
    return  _n[n_ib].v0();
  }else if (Umatch(x, "vci ")) {
    return  _n[n_ic].v0();
  }else if (Umatch(x, "vei ")) {
    return  _n[n_ie].v0();
  }else if (Umatch(x, "i ")) {
    return  cce;
  }else if (Umatch(x, "ice ")) {
    return  cce;
  }else if (Umatch(x, "iceo{ffset} ")) {
    return  ccexxx;
  }else if (Umatch(x, "hoe ")) {
    return  go;
  }else if (Umatch(x, "ro{e} ")) {
    return  (go != 0.) ? 1/go : BIGBIG;
  }else if (Umatch(x, "ipi ")) {
    return  cpi;
  }else if (Umatch(x, "ipio{ffset} ")) {
    return  cpixxx;
  }else if (Umatch(x, "rpi ")) {
    return  (gpi != 0.) ? 1/gpi : BIGBIG;
  }else if (Umatch(x, "hie ")) {
    return  (gpi != 0.) ? 1/gpi : BIGBIG;
  }else if (Umatch(x, "imu ")) {
    return  cmu;
  }else if (Umatch(x, "imuo{ffset} ")) {
    return  cmuxxx;
  }else if (Umatch(x, "rmu ")) {
    return  (gmu != 0.) ? 1/gmu : BIGBIG;
  }else if (Umatch(x, "ib ")) {
    return  cpi + cmu;
  }else if (Umatch(x, "rx ")) {
    return  (gx != NA) ? 1/gx : 0.;
  }else if (Umatch(x, "ic ")) {
    return  cce - cmu;
  }else if (Umatch(x, "ie ")) {
    return  -cce -cpi;
  }else if (Umatch(x, "cbx ")) {
    return  cqbx;
  }else if (Umatch(x, "cbc ")) {
    return  cqbc;
  }else if (Umatch(x, "cmu ")) {
    return  cqbc;
  }else if (Umatch(x, "ccs ")) {
    return  cqcs;
  }else if (Umatch(x, "cbe ")) {
    return  cqbe;
  }else if (Umatch(x, "cpi ")) {
    return  cqbe;
  }else if (Umatch(x, "p ")) {
    return  CARD::probe(_Ice,"P") + CARD::probe(_Ipi,"P") + CARD::probe(_Imu,"P") + CARD::probe(_Rc,"P") + CARD::probe(_Re,"P") + CARD::probe(_Yb,"P") + CARD::probe(_Cbx,"P") + CARD::probe(_Cbc,"P") + CARD::probe(_Ccs,"P") + CARD::probe(_Cbe,"P");
  }else if (Umatch(x, "pd ")) {
    return  CARD::probe(_Ice,"PD") + CARD::probe(_Ipi,"PD") + CARD::probe(_Imu,"PD") + CARD::probe(_Rc,"PD") + CARD::probe(_Re,"PD") + CARD::probe(_Yb,"PD") + CARD::probe(_Cbx,"PD") + CARD::probe(_Cbc,"PD") + CARD::probe(_Ccs,"PD") + CARD::probe(_Cbe,"PD");
  }else if (Umatch(x, "ps ")) {
    return  CARD::probe(_Ice,"PS") + CARD::probe(_Ipi,"PS") + CARD::probe(_Imu,"PS") + CARD::probe(_Rc,"PS") + CARD::probe(_Re,"PS") + CARD::probe(_Yb,"PS") + CARD::probe(_Cbx,"PS") + CARD::probe(_Cbc,"PS") + CARD::probe(_Ccs,"PS") + CARD::probe(_Cbe,"PS");
  }else if (Umatch(x, "status ")) {
    return  static_cast<double>(converged() * 2);
  }else if (Umatch(x, "vbe ")) {
    return vbe;
  }else if (Umatch(x, "vbc ")) {
    return vbc;
  }else if (Umatch(x, "vbx ")) {
    return vbx;
  }else if (Umatch(x, "vcs ")) {
    return vcs;
  }else if (Umatch(x, "cce ")) {
    return cce;
  }else if (Umatch(x, "ccexxx ")) {
    return ccexxx;
  }else if (Umatch(x, "go ")) {
    return go;
  }else if (Umatch(x, "gm ")) {
    return gm;
  }else if (Umatch(x, "cpi ")) {
    return cpi;
  }else if (Umatch(x, "cpixxx ")) {
    return cpixxx;
  }else if (Umatch(x, "gpi ")) {
    return gpi;
  }else if (Umatch(x, "cmu ")) {
    return cmu;
  }else if (Umatch(x, "cmuxxx ")) {
    return cmuxxx;
  }else if (Umatch(x, "gmu ")) {
    return gmu;
  }else if (Umatch(x, "ixxxx ")) {
    return ixxxx;
  }else if (Umatch(x, "gx ")) {
    return gx;
  }else if (Umatch(x, "qbx ")) {
    return qbx;
  }else if (Umatch(x, "cqbx ")) {
    return cqbx;
  }else if (Umatch(x, "qbc ")) {
    return qbc;
  }else if (Umatch(x, "cqbc ")) {
    return cqbc;
  }else if (Umatch(x, "qcs ")) {
    return qcs;
  }else if (Umatch(x, "cqcs ")) {
    return cqcs;
  }else if (Umatch(x, "qbe ")) {
    return qbe;
  }else if (Umatch(x, "cqbe ")) {
    return cqbe;
  }else if (Umatch(x, "geqcb ")) {
    return geqcb;
  }else if (Umatch(x, "cexbc_0 ")) {
    return cexbc_0;
  }else if (Umatch(x, "cexbc_1 ")) {
    return cexbc_1;
  }else if (Umatch(x, "cexbc_2 ")) {
    return cexbc_2;
  }else if (Umatch(x, "_dt_0 ")) {
    return _dt_0;
  }else if (Umatch(x, "_dt_1 ")) {
    return _dt_1;
  }else {
    return BASE_SUBCKT::tr_probe_num(x);
  }
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------*/
bool DEV_BUILT_IN_BJT::tr_needs_eval()const
{
  if (is_q_for_eval()) {
    untested();
    return false;
  }else if (!converged()) {
    return true;
  }else{
    const COMMON_BUILT_IN_BJT* c = prechecked_cast<const COMMON_BUILT_IN_BJT*>(common());
    assert(c);
    const MODEL_BUILT_IN_BJT* m=prechecked_cast<const MODEL_BUILT_IN_BJT*>(c->model());
    assert(m);
    polarity_t polarity = m->polarity;
    return !(conchk(vbc, polarity*(_n[n_ib].v0()-_n[n_ic].v0()),
		    OPT::vntol)
	     && conchk(vbe, polarity*(_n[n_ib].v0()-_n[n_ie].v0()),
		       OPT::vntol)
	     && conchk(vcs, polarity*(_n[n_ic].v0()-_n[n_s].v0()),
		       OPT::vntol));
  }
}
/*--------------------------------------------------------------------------*/
bool DEV_BUILT_IN_BJT::do_tr()
{
  const COMMON_BUILT_IN_BJT* c = prechecked_cast<const COMMON_BUILT_IN_BJT*>(common());
  assert(c);
  const MODEL_BUILT_IN_BJT* m = prechecked_cast<const MODEL_BUILT_IN_BJT*>(c->model());
  assert(m);
  const TDP_BUILT_IN_BJT T(this);
  const TDP_BUILT_IN_BJT* t = &T;

  if(_sim->is_initial_step()) {	// initial guess
    if (c->off) {
      vbe = 0.;
    }else{
      double vt = (_sim->_temp_c + P_CELSIUS0) * P_K_Q;
      vbe = vt * log(vt / (M_SQRT2 * m->ibe));
    }
    vbc = 0.;
    /* ERROR:  need to initialize VCS, VBX here */
    vcs = vbx = 0.;
  }else{				// normal gather
    vbe = pnj_limit((m->polarity * volts_limited(_n[n_ib], _n[n_ie])),
		    vbe, t->vt, t->Vcrit);
    vbc = pnj_limit((m->polarity * volts_limited(_n[n_ib], _n[n_ic])),
		    vbc, t->vt, t->Vcrit);
    vbx = m->polarity * volts_limited(_n[n_b], _n[n_ic]);
    vcs = m->polarity * volts_limited(_n[n_s], _n[n_ic]);
  }
 
  if (_sim->uic_now()) {itested();//736
    if (has_good_value(c->icvbe)) {untested();//737
      vbe = m->polarity * c->icvbe;
    }else{itested();//739
    }
    if (has_good_value(c->icvce)) {untested();//741
      vbc = vbe - m->polarity * c->icvce;
      vbx = vbc;
    }else{itested();//744
    }
  }else{
  }

  m->tr_eval(this);
  switch (m->polarity) {
  case pP:
    cce = -cce;
    ccexxx = -ccexxx;
    cpi = -cpi;
    cpixxx = -cpixxx;
    cmu = -cmu;
    cmuxxx = -cmuxxx;
    assert(ixxxx == 0.);
    qbx = -qbx;
    qbc = -qbc;
    qcs = -qcs;
    qbe = -qbe;
    break;
  case pN:
    // leave it as is
    break;
  }
  
  assert(subckt());
  set_converged(subckt()->do_tr());
  return converged();
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
