/* $Id: d_diode.model,v 25.92 2006/06/28 15:02:53 al Exp $ -*- C++ -*-
 * Copyright (C) 2001 Albert Davis
 * Author: Albert Davis <aldavis@ieee.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 2, 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.
 *------------------------------------------------------------------
 * diode model.
 * netlist syntax:
 * device:  dxxxx n+ n- mname <area> <off> <ic=vd> <model-card-args>
 * model:   .model mname D <args>
 *
 * The section "eval Yj" is a big mess.
 * It will be redone using multiple files, like the MOS models.
 */
/* This file is automatically generated. DO NOT EDIT */

#include "e_aux.h"
#include "d_admit.h"
#include "d_cap.h"
#include "d_res.h"
  static bool dummy=false;
  enum {USE_OPT = 0x8000};
#include "ap.h"
#include "d_diode.h"
/*--------------------------------------------------------------------------*/
const double NA(NOT_INPUT);
const double INF(BIGBIG);
/*--------------------------------------------------------------------------*/
int MODEL_DIODE::_count = 0;
/*--------------------------------------------------------------------------*/
SDP_DIODE::SDP_DIODE(const COMMON_COMPONENT* cc)
  :SDP_CARD(cc)
{
}
/*--------------------------------------------------------------------------*/
TDP_DIODE::TDP_DIODE(const DEV_DIODE*)
{
}
/*--------------------------------------------------------------------------*/
MODEL_DIODE::MODEL_DIODE()
  :MODEL_CARD(),
   js(1e-14),
   rs(0.0),
   n_factor(1.0),
   tt(0.0),
   cjo(NA),
   pb(NA),
   mj(0.5),
   eg(1.11),
   xti(3.0),
   kf(NA),
   af(NA),
   fc(0.5),
   bv(NA),
   ibv(1e-3),
   cjsw(0.0),
   pbsw(NA),
   mjsw(NA),
   gparallel(0.0),
   flags(USE_OPT),
   mos_level(0)
{
  ++_count;
  _tnom_c = OPT::tnom_c;
}
/*--------------------------------------------------------------------------*/
bool MODEL_DIODE::parse_front(CS& cmd)
{
  return ONE_OF
    || set(cmd, "D", &dummy, true)
    ;
}
/*--------------------------------------------------------------------------*/
bool MODEL_DIODE::parse_params(CS& cmd)
{
  return ONE_OF
    || get(cmd, "TNOM", &_tnom_c)
    || get(cmd, "IS", &js)
    || get(cmd, "RS", &rs)
    || get(cmd, "N", &n_factor)
    || get(cmd, "TT", &tt)
    || get(cmd, "CJo", &cjo)
    || get(cmd, "PB", &pb)
    || get(cmd, "VJ", &pb)
    || get(cmd, "Mj", &mj)
    || get(cmd, "EGap", &eg)
    || get(cmd, "XTI", &xti)
    || get(cmd, "KF", &kf)
    || get(cmd, "AF", &af)
    || get(cmd, "FC", &fc)
    || get(cmd, "BV", &bv)
    || get(cmd, "IBV", &ibv)
    || get(cmd, "CJSw", &cjsw)
    || get(cmd, "PBSw", &pbsw)
    || get(cmd, "MJSw", &mjsw)
    || get(cmd, "GParallel", &gparallel)
    || get(cmd, "FLAgs", &flags)
    || get(cmd, "MOS_LEVEL", &mos_level)
    ;
}
/*--------------------------------------------------------------------------*/
void MODEL_DIODE::elabo1()
{
  if (1 || !evaluated()) {
    const CARD_LIST* par_scope = scope();
    assert(par_scope);
    // final adjust: code_pre
    // final adjust: override
    // final adjust: raw
    this->js.e_val(1e-14, par_scope);
    this->rs.e_val(0.0, par_scope);
    this->n_factor.e_val(1.0, par_scope);
    this->tt.e_val(0.0, par_scope);
    this->cjo.e_val(0.0, par_scope);
    this->pb.e_val(1.0, par_scope);
    this->mj.e_val(0.5, par_scope);
    this->eg.e_val(1.11, par_scope);
    this->xti.e_val(3.0, par_scope);
    this->kf.e_val(NA, par_scope);
    this->af.e_val(NA, par_scope);
    this->fc.e_val(0.5, par_scope);
    this->bv.e_val(NA, par_scope);
    this->ibv.e_val(1e-3, par_scope);
    this->cjsw.e_val(0.0, par_scope);
    this->pbsw.e_val(pb, par_scope);
    this->mjsw.e_val(0.33, par_scope);
    this->gparallel.e_val(0.0, par_scope);
    this->flags.e_val(USE_OPT, par_scope);
    this->mos_level.e_val(0, par_scope);
    // final adjust: mid
    // final adjust: calculated
    // final adjust: post

      if (bv == 0.) {
	bv = NA;
      }
    // final adjust: done
  }else{
    untested();
  }
}
/*--------------------------------------------------------------------------*/
SDP_CARD* MODEL_DIODE::new_sdp(const COMMON_COMPONENT* c)const
{
  assert(c);
  {if (dynamic_cast<const COMMON_DIODE*>(c)) {
    return new SDP_DIODE(c);
  }else{
    return MODEL_CARD::new_sdp(c);
  }}
}
/*--------------------------------------------------------------------------*/
void MODEL_DIODE::print_front(OMSTREAM& o)const
{
  {if (dummy == true) {
    o << "  d";
  }else{
    unreachable();
  }}
}
/*--------------------------------------------------------------------------*/
void MODEL_DIODE::print_params(OMSTREAM& o)const
{
  o << "  tnom=" << _tnom_c;
  o << "  is=" << js;
  o << "  rs=" << rs;
  o << "  n=" << n_factor;
  o << "  tt=" << tt;
  o << "  cjo=" << cjo;
  o << "  pb=" << pb;
  o << "  mj=" << mj;
  o << "  egap=" << eg;
  o << "  xti=" << xti;
  if (kf != NA)
    o << "  kf=" << kf;
  if (af != NA)
    o << "  af=" << af;
  o << "  fc=" << fc;
  if (bv != NA)
    o << "  bv=" << bv;
  if (bv != NA)
    o << "  ibv=" << ibv;
  if (cjsw != 0.)
    o << "  cjsw=" << cjsw;
  if (cjsw != 0.)
    o << "  pbsw=" << pbsw;
  if (cjsw != 0.)
    o << "  mjsw=" << mjsw;
  if (gparallel != 0.)
    o << "  gparallel=" << gparallel;
  if (!(flags & USE_OPT))
    o << "  flags=" << flags;
  if (mos_level.has_value())
    o << "  mos_level=" << mos_level;
}
/*--------------------------------------------------------------------------*/
void MODEL_DIODE::print_calculated(OMSTREAM& o)const
{
  o << "";
}
/*--------------------------------------------------------------------------*/
bool MODEL_DIODE::is_valid(const COMMON_COMPONENT* cc)const
{
  return MODEL_CARD::is_valid(cc);
}
/*--------------------------------------------------------------------------*/
void MODEL_DIODE::tr_eval(COMPONENT*)const
{
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
int DEV_DIODE::_count = 0;
int COMMON_DIODE::_count = -1;
static COMMON_DIODE Default_DIODE(CC_STATIC);
/*--------------------------------------------------------------------------*/
COMMON_DIODE::COMMON_DIODE(int c)
  :COMMON_COMPONENT(c),
   area(1.0),
   perim(0.0),
   m(1.0),
   off(false),
   ic(NA),
   is_raw(NA),
   rs_raw(NA),
   cj_raw(NA),
   cjsw_raw(NA),
   gparallel_raw(NA),
   _sdp(0),
   is_adjusted(NA),
   rs_adjusted(NA),
   cj_adjusted(NA),
   cjsw_adjusted(NA),
   gparallel_adjusted(NA)
{
  ++_count;
}
/*--------------------------------------------------------------------------*/
COMMON_DIODE::COMMON_DIODE(const COMMON_DIODE& p)
  :COMMON_COMPONENT(p),
   area(p.area),
   perim(p.perim),
   m(p.m),
   off(p.off),
   ic(p.ic),
   is_raw(p.is_raw),
   rs_raw(p.rs_raw),
   cj_raw(p.cj_raw),
   cjsw_raw(p.cjsw_raw),
   gparallel_raw(p.gparallel_raw),
   _sdp(0),
   is_adjusted(p.is_adjusted),
   rs_adjusted(p.rs_adjusted),
   cj_adjusted(p.cj_adjusted),
   cjsw_adjusted(p.cjsw_adjusted),
   gparallel_adjusted(p.gparallel_adjusted)
{
  ++_count;
}
/*--------------------------------------------------------------------------*/
COMMON_DIODE::~COMMON_DIODE()
{
  --_count;
  delete _sdp;
}
/*--------------------------------------------------------------------------*/
bool COMMON_DIODE::operator==(const COMMON_COMPONENT& x)const
{
  const COMMON_DIODE* p = dynamic_cast<const COMMON_DIODE*>(&x);
  return (p
    && area == p->area
    && perim == p->perim
    && m == p->m
    && off == p->off
    && ic == p->ic
    && is_raw == p->is_raw
    && rs_raw == p->rs_raw
    && cj_raw == p->cj_raw
    && cjsw_raw == p->cjsw_raw
    && gparallel_raw == p->gparallel_raw
    && _sdp == p->_sdp
    && COMMON_COMPONENT::operator==(x));
}
/*--------------------------------------------------------------------------*/
void COMMON_DIODE::parse(CS& cmd)
{
  parse_modelname(cmd);
  if (cmd.is_float()) {
    cmd >> area;
  }
  int here = cmd.cursor();
  do{
    ONE_OF
    || get(cmd, "Area", &area)
    || get(cmd, "Perim", &perim)
    || get(cmd, "M", &m)
    || get(cmd, "OFF", &off)
    || get(cmd, "IC", &ic)
    || get(cmd, "IS", &is_raw)
    || get(cmd, "Rs", &rs_raw)
    || get(cmd, "Cjo", &cj_raw)
    || get(cmd, "CJSW", &cjsw_raw)
    || get(cmd, "GParallel", &gparallel_raw)
    ;
  }while (cmd.more() && !cmd.stuck(&here));
  cmd.check(bWARNING, "what's this?");
}
/*--------------------------------------------------------------------------*/
void COMMON_DIODE::print(OMSTREAM& o)const
{
  o << "  " << modelname();
  o.setfloatwidth(7);
  o << "  area=" << area;
  if (perim != 0.)
    o << "  perim=" << perim;
  if (m != 1.)
    o << "  m=" << m;
  if (off)
    o << "  off=" << off;
  if (ic != NA)
    o << "  ic=" << ic;
  if (is_raw != NA)
    o << "  is=" << is_raw;
  if (rs_raw != NA)
    o << "  rs=" << rs_raw;
  if (cj_raw != NA)
    o << "  cjo=" << cj_raw;
  if (cjsw_raw != NA)
    o << "  cjsw=" << cjsw_raw;
  if (gparallel_raw != NA)
    o << "  gparallel=" << gparallel_raw;
  o << '\n';
}
/*--------------------------------------------------------------------------*/
void COMMON_DIODE::elabo3(const COMPONENT* d)
{
  COMMON_DIODE* c = this;
  const MODEL_DIODE* m = dynamic_cast<const MODEL_DIODE*>(attach_model(d));
  if (!m) {
    error(bERROR, d->long_label() + ": model " + modelname()
          + " is not a diode\n");
  }

  assert(c);
  const CARD_LIST* par_scope = d->scope();
  assert(par_scope);
    // final adjust: code_pre
    // final adjust: override
    // final adjust: raw
    this->area.e_val(1.0, par_scope);
    this->perim.e_val(0.0, par_scope);
    this->m.e_val(1.0, par_scope);
    this->off.e_val(false, par_scope);
    this->ic.e_val(NA, par_scope);
    this->is_raw.e_val(NA, par_scope);
    this->rs_raw.e_val(NA, par_scope);
    this->cj_raw.e_val(NA, par_scope);
    this->cjsw_raw.e_val(NA, par_scope);
    this->gparallel_raw.e_val(NA, par_scope);
    // final adjust: mid
    // final adjust: calculated
    is_adjusted = ((c->is_raw == NA) ? m->js * c->area : c->is_raw);
    rs_adjusted = ((c->rs_raw == NA) ? m->rs / (c->area+1e-20) : c->rs_raw);
    cj_adjusted = ((c->cj_raw == NA) ? m->cjo * c->area : c->cj_raw);
    cjsw_adjusted = ((c->cjsw_raw == NA) ? m->cjsw * c->perim : c->cjsw_raw);
    gparallel_adjusted = ((c->gparallel_raw == NA)
		? m->gparallel*c->area : c->gparallel_raw);
    // final adjust: post
    // final adjust: done

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

  // subcircuit commons, recursive
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
static EVAL_DIODE_Cj Eval_Cj(CC_STATIC);
void EVAL_DIODE_Cj::tr_eval(ELEMENT* d)const
{
  assert(d);
  DEV_DIODE* p = prechecked_cast<DEV_DIODE*>(d->owner());
  assert(p);
  const COMMON_DIODE* c = prechecked_cast<const COMMON_DIODE*>(p->common());
  assert(c);
  const SDP_DIODE* s = prechecked_cast<const SDP_DIODE*>(c->sdp());
  assert(s);
  const MODEL_DIODE* m = prechecked_cast<const MODEL_DIODE*>(c->model());
  assert(m);

    double& volts = d->_y0.x;
    trace1(d->long_label().c_str(), volts);
    
    double cb;
    {if (c->cj_adjusted != 0.) {
      {if (volts < m->fc * m->pb) {
	cb = c->cj_adjusted / pow(1. - (volts / m->pb),  m->mj);
      }else{
	cb = (c->cj_adjusted / pow(1. - m->fc, 1. + m->mj))
	  * (1. - m->fc*(1.+m->mj) + (volts/m->pb)*m->mj);
      }}
    }else{
      cb = 0.;
    }}
    assert(cb >= 0.);
    
    double csw;
    {if (c->cjsw_adjusted != 0.) {
      {if (volts < m->fc * m->pbsw) {
	csw = c->cjsw_adjusted / pow(1. - (volts / m->pbsw),  m->mjsw);
      }else{
	csw = (c->cjsw_adjusted / pow(1. - m->fc, 1. + m->mjsw))
	  * (1. - m->fc*(1.+m->mjsw) + (volts/m->pbsw)*m->mjsw);
      }}
    }else{
      csw = 0.;
    }}
    assert(csw >= 0.);
    
    double ctt;
    {if (m->tt != 0.) {
      ctt = p->_gd * m->tt;
    }else{
      ctt = 0.;
    }}
    assert(ctt >= 0.);
    
    trace4("", cb, csw, ctt, cb+csw+ctt);
    d->_y0.f1 = cb + csw + ctt;
    {if (SIM::phase == SIM::pTRAN) {
      const DEV_CAPACITANCE* dd = prechecked_cast<const DEV_CAPACITANCE*>(d);
      double cap = (d->_y0.f1 + dd->_q[1].f1) / 2;
      d->_y0.f0 = (d->_y0.x - dd->_q[1].x) * cap + dd->_q[1].f0;
    }else{
      d->_y0.f0 = d->_y0.x * d->_y0.f1;
    }}
    d->_y0 *= c->m;
    trace3(d->long_label().c_str(), d->_y0.x, d->_y0.f0, d->_y0.f1);
}
/*--------------------------------------------------------------------------*/
static EVAL_DIODE_Yj Eval_Yj(CC_STATIC);
void EVAL_DIODE_Yj::tr_eval(ELEMENT* d)const
{
  assert(d);
  DEV_DIODE* p = prechecked_cast<DEV_DIODE*>(d->owner());
  assert(p);
  const COMMON_DIODE* c = prechecked_cast<const COMMON_DIODE*>(p->common());
  assert(c);
  const SDP_DIODE* s = prechecked_cast<const SDP_DIODE*>(c->sdp());
  assert(s);
  const MODEL_DIODE* m = prechecked_cast<const MODEL_DIODE*>(c->model());
  assert(m);

    FPOLY1& y = d->_y0;
    double volts = y.x;
    double amps  = y.f0;
    trace2(d->long_label().c_str(), volts, amps);
    
    int flags = (m->flags & USE_OPT) ? OPT::diodeflags : m->flags;
    double tempratio = (SIM::temp_c+P_CELSIUS0) / (m->_tnom_c+P_CELSIUS0);
    double vt = P_K_Q * (SIM::temp_c+P_CELSIUS0) * m->n_factor;
    region_t oldregion = p->_region;
    p->_isat = c->is_adjusted * pow(tempratio, m->xti)
      * exp((m->eg/vt) *(tempratio-1));
    trace4("", tempratio, vt, oldregion, p->_isat);
    
    if (m->mos_level > 0 || flags & 0040) { // Spice style limiting
      double vcrit = vt * log(vt / (M_SQRT2 * p->_isat));
      double vold = d->_y1.f0;
      {if((volts > vcrit) && (std::abs(volts - vold) > (vt + vt))) {
	{if(vold > 0) {
	  double arg = 1 + (volts - vold) / vt;
	  {if(arg > 0) {
	    volts = vold + vt * log(arg);
	  }else{
	    volts = vcrit;
	  }}
	}else{
	  volts = vt *log(volts/vt);
	}}
      }else{
	// leave volts as is
      }}
    }
    
    {if (m->mos_level > 0) {
      switch (m->mos_level) {
      case 1:
      case 2:
      case 3:
      case 6:
      case 4:
      case 5:
	{if (volts <= 0.) {
	  p->_region = REVERSE;
	  y.f1 = p->_isat / vt + OPT::gmin;
	  y.f0 = y.f1 * volts;
	}else{
	  p->_region = FORWARD;
	  double ev = exp(volts/vt);
	  y.f1 = p->_isat * ev / vt + OPT::gmin;
	  y.f0 = p->_isat * (ev - 1) + OPT::gmin * volts;
	}}
	break;
      case 7:
      case 8:
	{if (volts < .5) {
	  p->_region = REVERSE;
	  double ev = exp(volts/vt);
	  y.f1 = p->_isat * ev / vt + OPT::gmin;
	  y.f0 = p->_isat * (ev - 1) + OPT::gmin * volts;
	}else{
	  p->_region = FORWARD;
	  double ev = exp(.5/vt);
	  double t0 = p->_isat * ev / vt;
	  y.f1 = t0 + OPT::gmin;
	  y.f0 = p->_isat * (ev - 1) + t0 * (volts - .5) + OPT::gmin * volts;
	}}
	break;
      default:
	unreachable();
	y.f1 = OPT::gmin;
	y.f0 = volts * y.f1;
      }
    }else if (flags & 0040) { // exact Spice model
      {if (volts >= -3*vt) { // forward and weak reversed
	double evd = exp(volts/vt);
	y.f0 = p->_isat * (evd-1);
	y.f1 = p->_isat * evd/vt;
      }else if (m->bv == NA || volts >= m->bv) {
	double arg = 3 * vt / (volts * M_E); // strong reversed
	arg = arg * arg * arg;
	y.f0 = -p->_isat * (1+arg);
	y.f1 = p->_isat * 3 * arg / volts;
      }else{
	incomplete();
	double evrev = exp(-(m->bv+volts)/vt);
	y.f0 = -p->_isat * evrev;
	y.f1 = p->_isat * evrev / vt;
      }}
      y.f0 += OPT::gmin * volts;
      y.f1 += OPT::gmin;
    }else{
       {if (c->off  &&  d->initial_step(SIM::mode)) { /*initially guess off*/
	p->_region = INITOFF;
	y.f1 = 0.;
	y.f0 = 0.;
	if (flags & 0020) {
	  untested();
	  y.f1 = OPT::gmin;
	}
	trace2("initoff", y.f0, y.f1);
      }else if (volts <= 0. /* &&  amps < 0.*/) {    	  /* reverse biased */
	p->_region = REVERSE;	    		  /* x = volts, f(x) = amps */
	{if (flags & 0010) {
	  untested();
	  y.f1 = y.f0 = 0.;
	}else{
	  double expterm = p->_isat * exp(volts/vt);	
	  y.f0 = expterm - p->_isat;/* i = f(x) = _isat * (exp(volts/vt)-1) */
	  y.f1 = expterm / vt;	    /* f'(x) = (_isat/vt) * exp(volts/vt)   */
	}}
	
	if (flags & 0002) {	// g = gmin, maintain actual current
	  y.f1 += OPT::gmin;	// 3 is a resistor, R=1/gmin
	  y.f0 += OPT::gmin * volts;
	}
	if (flags & 0004) {	// 5 is a resistor, R=vt/_isat
	  double x = p->_isat / vt;
	  y.f1 += x;
	  y.f0 += x * volts;
	}
	if (flags & 0001) {
	  //y.f0 = y.f1 * volts;	// a resistor, R=1/f1
	}
	
	trace2("reverse", y.f0, y.f1);
      }else if (volts >= 0.  &&  amps >= 0.) {		  /* forward biased */
				    /* x = amps, f(x) = volts */
	/* derivation: */	    /* if f(x) = log(u): f'(x)=(1/u)(du/dx) */
	/* poly1 r; */
	/* r.f0 = vt * log(amps/p->_isat +1.); */
	/* r.f1 = vt / (_isat + amps); */
	/* y.f1 = 1. / r.f1; */
	/* y.f0 = amps - r.f0*y.f1 + volts*y.f1; */
	
	p->_region = FORWARD;
	y.f1 = (p->_isat + amps) / vt;
	y.f0 = amps - log(amps/p->_isat +1.)*(p->_isat + amps) + volts*y.f1;
	trace2("forward", y.f0, y.f1);
      }else{			    /* non-converged, inconsistent	    */
	p->_region = UNKNOWN;	    /* volts and amps have different signs  */
	y.f1 = p->_isat/vt;	    /* guess that the voltage should be 0   */
	y.f0 = 0.;		    /* (it usually is very close)	    */
	if (flags & 0001) {	    /* use the correct value there	    */
	  y.f0 = volts * y.f1;
	}
	trace2("unknown", y.f0, y.f1);
      }}
      y.f1 += c->gparallel_adjusted;
      y.f0 += c->gparallel_adjusted * volts;
      
      if (oldregion != p->_region  &&  OPT::dampstrategy & dsDEVLIMIT) {
	SIM::fulldamp = true;
	error(bTRACE, p->long_label() + ":device limit damp\n");
      }
      if (flags & 0100) {		// twist g to guarantee g >= gmin
	{if (y.f1 < OPT::gmin) {	// without changing i
	  y.f1 = OPT::gmin;
	  untested();
	}else{
	  untested();
	}}
      }
      if (flags & 0200) {		// add a gmin in parallel
	y.f1 += OPT::gmin;
	y.f0 += OPT::gmin * volts;
	untested();
      }
      if (flags & 0400) {		// linearize .. shift I to pass thru 0
	untested();
	y.f0 = y.f1 * volts;
      }
    }}
    y *= c->m;
    trace3(d->long_label().c_str(), y.x, y.f0, y.f1);
    p->_gd = y.f1;
}
/*--------------------------------------------------------------------------*/
DEV_DIODE::DEV_DIODE()
  :BASE_SUBCKT(),
   // input parameters,
   // calculated parameters,
   _region(UNKNOWN),
   _gd(NA),
   _isat(NA),
   // netlist,
   _Cj(0),
   _Yj(0),
   _Rs(0)
{
  _n = _nodes + int_nodes();
  attach_common(&Default_DIODE);
  ++_count;
  // overrides
}
/*--------------------------------------------------------------------------*/
DEV_DIODE::DEV_DIODE(const DEV_DIODE& p)
  :BASE_SUBCKT(p),
   // input parameters,
   // calculated parameters,
   _region(p._region),
   _gd(p._gd),
   _isat(p._isat),
   // netlist,
   _Cj(0),
   _Yj(0),
   _Rs(0)
{
  _n = _nodes + int_nodes();
  for (int ii = -int_nodes(); ii < max_nodes(); ++ii) {
    _n[ii] = p._n[ii];
  }
  ++_count;
  // overrides
}
/*--------------------------------------------------------------------------*/
void DEV_DIODE::elabo1()
{
  BASE_SUBCKT::elabo1();
  const COMMON_DIODE* c = prechecked_cast<const COMMON_DIODE*>(common());
  assert(c);
  const MODEL_DIODE* m = prechecked_cast<const MODEL_DIODE*>(c->model());
  assert(m);
  const SDP_DIODE* s = prechecked_cast<const SDP_DIODE*>(c->sdp());
  assert(s);
  if (!subckt()) {
    new_subckt();
  }

  // local nodes
  {if (!OPT::rstray || c->rs_adjusted==0.) {
    _n[n_ianode] = _n[n_anode];
  }else{
    _n[n_ianode].new_model_node();
  }}

  // clone subckt elements
  {if (c->cj_adjusted == 0. && c->cjsw_adjusted == 0. && m->tt == 0.) {
    if (_Cj) {
      subckt()->erase(_Cj);
      _Cj = NULL;
    }
  }else{
    if (!_Cj) {
      _Cj = new DEV_CAPACITANCE;
      subckt()->push_front(_Cj);
    }
    {{
      node_t nodes[] = {_n[n_ianode], _n[n_cathode]};
      _Cj->set_parameters("Cj", this, &Eval_Cj, 0., 0, 0, 2, nodes);
    }}
  }}
  {{
    if (!_Yj) {
      _Yj = new DEV_ADMITTANCE;
      subckt()->push_front(_Yj);
    }
    {{
      node_t nodes[] = {_n[n_ianode], _n[n_cathode]};
      _Yj->set_parameters("Yj", this, &Eval_Yj, 0., 0, 0, 2, nodes);
    }}
  }}
  {if (!OPT::rstray || c->rs_adjusted==0.) {
    if (_Rs) {
      subckt()->erase(_Rs);
      _Rs = NULL;
    }
  }else{
    if (!_Rs) {
      _Rs = new DEV_RESISTANCE;
      subckt()->push_front(_Rs);
    }
    {{
      node_t nodes[] = {_n[n_anode], _n[n_ianode]};
      _Rs->set_parameters("Rs", this, NULL, c->rs_adjusted/c->m, 0, 0, 2, nodes);
    }}
  }}
  subckt()->elabo2();
  assert(!is_constant());
}
/*--------------------------------------------------------------------------*/
double DEV_DIODE::tr_probe_num(CS& cmd)const
{
  const COMMON_DIODE* c = prechecked_cast<const COMMON_DIODE*>(common());
  assert(c);
  const MODEL_DIODE* m = prechecked_cast<const MODEL_DIODE*>(c->model());
  assert(m);
  const SDP_DIODE* s = prechecked_cast<const SDP_DIODE*>(c->sdp());
  assert(s);

  {if (cmd.pmatch("Vd")) {
    return  _n[n_anode].v0() - _n[n_cathode].v0();
  }else if (cmd.pmatch("Id")) {
    return  CARD::probe(_Yj,"I") + CARD::probe(_Cj,"I");
  }else if (cmd.pmatch("VJ")) {
    return  _n[n_ianode].v0() - _n[n_cathode].v0();
  }else if (cmd.pmatch("VSR")) {
    return  _n[n_anode].v0() - _n[n_ianode].v0();
  }else if (cmd.pmatch("VRS")) {
    return  _n[n_anode].v0() - _n[n_ianode].v0();
  }else if (cmd.pmatch("IJ")) {
    return  CARD::probe(_Yj,"I");
  }else if (cmd.pmatch("IC")) {
    return  CARD::probe(_Cj,"I");
  }else if (cmd.pmatch("CAPCUR")) {
    return  CARD::probe(_Cj,"I");
  }else if (cmd.pmatch("P")) {
    return  CARD::probe(_Yj,"P") + CARD::probe(_Cj,"P") + CARD::probe(_Rs,"P");
  }else if (cmd.pmatch("PD")) {
    return  CARD::probe(_Yj,"PD") + CARD::probe(_Cj,"PD") + CARD::probe(_Rs,"PD");
  }else if (cmd.pmatch("PS")) {
    return  CARD::probe(_Yj,"PS") + CARD::probe(_Cj,"PS") + CARD::probe(_Rs,"PS");
  }else if (cmd.pmatch("PJ")) {
    return  CARD::probe(_Yj,"P");
  }else if (cmd.pmatch("PC")) {
    return  CARD::probe(_Cj,"P");
  }else if (cmd.pmatch("Capacitance")) {
    return  CARD::probe(_Cj,"Capacitance");
  }else if (cmd.pmatch("CD")) {
    return  CARD::probe(_Cj,"Capacitance");
  }else if (cmd.pmatch("CHARGE")) {
    return  CARD::probe(_Cj,"Charge");
  }else if (cmd.pmatch("Req")) {
    return  CARD::probe(_Yj,"R") + CARD::probe(_Rs,"R");
  }else if (cmd.pmatch("Geq")) {
    return  (( CARD::probe(_Yj,"R") + CARD::probe(_Rs,"R") ) != 0) ? (1./( CARD::probe(_Yj,"R") + CARD::probe(_Rs,"R") )) : CARD::probe(_Yj,"Y");
  }else if (cmd.pmatch("GD")) {
    return  CARD::probe(_Yj,"Y");
  }else if (cmd.pmatch("Y")) {
    return  ( CARD::probe(_Rs,"R") != 0. && ( CARD::probe(_Yj,"Y") + CARD::probe(_Cj,"Y") ) != 0) ? 1./((1./( CARD::probe(_Yj,"Y") + CARD::probe(_Cj,"Y") )) + CARD::probe(_Rs,"R") ) : CARD::probe(_Yj,"Y") + CARD::probe(_Cj,"Y");
  }else if (cmd.pmatch("Z")) {
    return  port_impedance( _n[n_anode] , _n[n_cathode] ,lu,tr_probe_num_str("Y"));
  }else if (cmd.pmatch("ZRAW")) {
    return  port_impedance( _n[n_anode] , _n[n_cathode] , lu, 0.);
  }else if (cmd.pmatch("REgion")) {
    return  static_cast<double>(_region);
  }else if (cmd.pmatch("_REGION")) {
    return _region;
  }else if (cmd.pmatch("_GD")) {
    return _gd;
  }else if (cmd.pmatch("_ISAT")) {
    return _isat;
  }else {
    return BASE_SUBCKT::tr_probe_num(cmd);
  }}
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
