/* $Id: d_diode.cc,v 20.12 2001/10/13 05:16:35 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., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, 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"
  static bool dummy=false;
  enum {USE_OPT = 0x8000};
#include "ap.h"
#include "d_diode.h"
/*--------------------------------------------------------------------------*/
const double NA(NOT_INPUT);
/*--------------------------------------------------------------------------*/
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 = OPT::tnom;
}
/*--------------------------------------------------------------------------*/
bool MODEL_DIODE::parse_front(CS& cmd)
{
  return set(cmd, "D", &dummy, true);
}
/*--------------------------------------------------------------------------*/
void MODEL_DIODE::parse_params(CS& cmd)
{
  get(cmd, "TNOM", &_tnom, mOFFSET, -ABS_ZERO);
  get(cmd, "IS", &js, mPOSITIVE);
  get(cmd, "RS", &rs, mPOSITIVE);
  get(cmd, "N", &n_factor, mPOSITIVE);
  get(cmd, "TT", &tt, mPOSITIVE);
  get(cmd, "CJo", &cjo, mPOSITIVE);
  get(cmd, "PB", &pb, mPOSITIVE);
  get(cmd, "VJ", &pb, mPOSITIVE);
  get(cmd, "Mj", &mj, mPOSITIVE);
  get(cmd, "EGap", &eg, mPOSITIVE);
  get(cmd, "XTI", &xti, mPOSITIVE);
  get(cmd, "KF", &kf, mPOSITIVE);
  get(cmd, "AF", &af, mPOSITIVE);
  get(cmd, "FC", &fc, mPOSITIVE);
  get(cmd, "BV", &bv, mPOSITIVE);
  get(cmd, "IBV", &ibv, mPOSITIVE);
  get(cmd, "CJSw", &cjsw, mPOSITIVE);
  get(cmd, "PBSw", &pbsw, mPOSITIVE);
  get(cmd, "MJSw", &mjsw, mPOSITIVE);
  get(cmd, "GParallel", &gparallel);
  get(cmd, "FLAgs", &flags, mOCTAL);
}
/*--------------------------------------------------------------------------*/
void MODEL_DIODE::parse_finish()
{

  _tnom = std::max(_tnom, 1.0);
  if (cjo == NA) {
    cjo = 0.0;
  }
  if (pb == NA) {
    pb = 1.0;
  }
  if (pbsw == NA) {
    pbsw = pb;
  }
  if (mjsw == NA) {
    mjsw = 0.33;
  }

      if (bv == 0.) {
	bv = NA;
      }
}
/*--------------------------------------------------------------------------*/
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-(-ABS_ZERO);
  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;
}
/*--------------------------------------------------------------------------*/
void MODEL_DIODE::print_calculated(OMSTREAM& o)const
{
  o << "";
}
/*--------------------------------------------------------------------------*/
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),
   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),
   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
    && 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
    && is_equal(x));
}
/*--------------------------------------------------------------------------*/
void COMMON_DIODE::parse(CS& cmd)
{
  assert(!has_model());
  parse_modelname(cmd);
  if (cmd.is_float()) {
    cmd >> area;
  }
  int here = cmd.cursor();
  do{
  get(cmd, "Area", &area, mPOSITIVE);
  get(cmd, "Perim", &perim, mPOSITIVE);
  get(cmd, "OFF", &off);
  get(cmd, "IC", &ic);
  get(cmd, "IS", &is_raw, mPOSITIVE);
  get(cmd, "Rs", &rs_raw, mPOSITIVE);
  get(cmd, "Cjo", &cj_raw, mPOSITIVE);
  get(cmd, "CJSW", &cjsw_raw, mPOSITIVE);
  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 (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::expand()
{
  const MODEL_DIODE* m = dynamic_cast<const MODEL_DIODE*>(attach_model());
  if (!m) {
    untested();
    error(bERROR, "model " + modelname() + " is not a diode");
  }
  delete _sdp;
  _sdp = m->new_sdp(this);
  assert(_sdp);
  const SDP_DIODE* b = dynamic_cast<const SDP_DIODE*>(_sdp);
  assert(b);

  is_adjusted = ((is_raw == NA) ? m->js * area : is_raw);
  rs_adjusted = ((rs_raw == NA) ? m->rs / (area+1e-20) : rs_raw);
  cj_adjusted = ((cj_raw == NA) ? m->cjo * area : cj_raw);
  cjsw_adjusted = ((cjsw_raw == NA) ? m->cjsw * perim : cjsw_raw);
  gparallel_adjusted = ((gparallel_raw == NA) ? m->gparallel*area : gparallel_raw);
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
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* b = prechecked_cast<const SDP_DIODE*>(c->sdp());
  assert(b);
  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;
    }}
    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* b = prechecked_cast<const SDP_DIODE*>(c->sdp());
  assert(b);
  const MODEL_DIODE* m = prechecked_cast<const MODEL_DIODE*>(c->model());
  assert(m);

    assert(m->_tnom > 0);
    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 / m->_tnom;
    double vt = KoQ * SIM::temp * 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/(kRT2*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 && m->mos_level < 8) {
      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:
	{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 * kE); // 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  &&  STATUS::iter[SIM::mode] <= 1) { /*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;
      }
    }}
    trace3(d->long_label().c_str(), y.x, y.f0, y.f1);
    p->_gd = y.f1;
}
/*--------------------------------------------------------------------------*/
DEV_DIODE::DEV_DIODE()
  :BASE_SUBCKT(),
   _region(UNKNOWN),
   _gd(NA),
   _isat(NA),
   _Cj(0),
   _Yj(0)
{
  set_inode_count(0);
  _n = _nodes + 0;
  attach_common(&Default_DIODE);
  ++_count;
}
/*--------------------------------------------------------------------------*/
DEV_DIODE::DEV_DIODE(const DEV_DIODE& p)
  :BASE_SUBCKT(p),
   _region(p._region),
   _gd(p._gd),
   _isat(p._isat),
   _Cj(0),
   _Yj(0)
{
  _n = _nodes + 0;
  for (int ii = -0; ii < 2; ++ii) {
    _n[ii] = p._n[ii];
  }
  ++_count;
}
/*--------------------------------------------------------------------------*/
void DEV_DIODE::parse(CS& cmd)
{
  assert(has_common());
  COMMON_DIODE* c = prechecked_cast<COMMON_DIODE*>(common()->clone());
  assert(c);

  parse_Label(cmd);
  parse_nodes(cmd,numnodes(),numnodes());
  c->parse(cmd);
  attach_common(c);
}
/*--------------------------------------------------------------------------*/
void DEV_DIODE::print(OMSTREAM& o, int)const
{
  const COMMON_DIODE* c = prechecked_cast<const COMMON_DIODE*>(common());
  assert(c);

  o << short_label();
  printnodes(o,numnodes());
  c->print(o);
}
/*--------------------------------------------------------------------------*/
void DEV_DIODE::expand()
{
  COMMON_DIODE* c = prechecked_cast<COMMON_DIODE*>(mutable_common());
  assert(c);
  c->expand();
  const MODEL_DIODE* m = prechecked_cast<const MODEL_DIODE*>(c->model());
  assert(m);
  const SDP_DIODE* b = prechecked_cast<const SDP_DIODE*>(c->sdp());
  assert(b);


  {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_anode], _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_anode], _n[n_cathode]};
      _Yj->set_parameters("Yj", this, &Eval_Yj, 0., 0, 0, 2, nodes);
    }}
  }}
  assert(subckt().exists());
  subckt().expand();
  assert(!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* b = prechecked_cast<const SDP_DIODE*>(c->sdp());
  assert(b);

  {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("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");
  }else if (cmd.pmatch("PD")) {
    return  CARD::probe(_Yj,"PD") + CARD::probe(_Cj,"PD");
  }else if (cmd.pmatch("PS")) {
    return  CARD::probe(_Yj,"PS") + CARD::probe(_Cj,"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");
  }else if (cmd.pmatch("Geq")) {
    return  CARD::probe(_Yj,"Y");
  }else if (cmd.pmatch("GD")) {
    return  CARD::probe(_Yj,"Y");
  }else if (cmd.pmatch("Y")) {
    return  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 {
    return BASE_SUBCKT::tr_probe_num(cmd);
  }}
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
