/* d_admit.c  94.12.09
 * Copyright 1983-1992   Albert Davis
 * functions for admittance (type 'Y')
 * does not exist in spice
 * x = volts, y.f0 = amps, ev = y.f1 = mhos.
 */
#include "ecah.h"
#include "branch.h"
#include "mode.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
static	void	expand_admittance(branch_t*);
static	int	tr_admittance_lin(branch_t*);
static	int	tr_admittance_nl(branch_t*);
static	void	ac_admittance_lin(branch_t*);
static	void	ac_admittance_nl(branch_t*);
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
functions_t dev_admittance = {
   (generic_t*)NULL,	/* x */
   sizeof(functions_t),	/* ssize */
   sizeof(branch_t),	/* elementsize */
   (functions_t*)NULL,	/* super */
   2, 			/* numnodes */
   rnONEPORT,		/* refnode */
   rnONEPORT,		/* isdevice */
   create_std,		/* create */
   copy_std,		/* copy */
   parse_std,		/* parse */
   print_std,		/* print */
   expand_admittance,	/* expand */
   probe_std,		/* probe */
   tr_probe_std,	/* tr_probe */
   ac_probe_std,	/* ac_probe */
   xprobe_std,		/* xprobe */
   tr_admittance_nl,	/* dotr */
   unloadpassive,	/* untr */
   ac_admittance_nl,	/* doac */
   trfix1,		/* trfun1 */
   trfix0,		/* trfun0 */
   acfix,		/* acfun */
   NULL,		/* tr_guess */
   NULL,		/* tr_advance */
   NULL			/* tr_review */
};
/*--------------------------------------------------------------------------*/
static void expand_admittance(branch_t *brh)
{
 if (!brh->x){
    static functions_t *ff;
    if (!ff){
       ff = (functions_t*)calloc(1, sizeof(functions_t));
       *ff = dev_admittance;
       ff->super = &dev_admittance;
       ff->refnode = rnLINEAR;
       ff->dotr = tr_admittance_lin;
       ff->doac = ac_admittance_lin;
       ff->trfun1 = NULL;
       ff->trfun0 = NULL;
       ff->acfun  = NULL;
    }
    brh->f = ff;
    brh->y0.f1 = brh->val;
    brh->y0.f0 = LINEAR;
    brh->m0.c0 = 0.;
    brh->m0.f1 = brh->y0.f1;
    brh->ev.x  = brh->val;
    brh->ev.y  = 0.;
    brh->acg.x = brh->m0.f1;
    brh->acg.y = 0.;
 }
}
/*--------------------------------------------------------------------------*/
static int tr_admittance_lin(branch_t *brh)
{
 trloadpassive(brh);
 return brh->converged = YES;
}
/*--------------------------------------------------------------------------*/
static int tr_admittance_nl(branch_t *brh)
{
 brh->m0.x = tr_volts_limited(&(brh->n[OUT1]),&(brh->n[OUT2]));
 brh->y0.x = brh->m0.x;
 brh->y0.f0 = brh->m0.f1 * brh->m0.x + brh->m0.c0;
 if (brh->f->trfun1){
    (*brh->f->trfun1)(brh);
    brh->m0.c0 = brh->y0.f0 - brh->y0.x * brh->y0.f1;
 }else{
    brh->y0.f1 = brh->val;
    brh->y0.f0 = brh->y0.x * brh->y0.f1;
    brh->m0.c0 = 0.;
 }
 brh->m0.x  = brh->y0.x;
 brh->m0.f1 = brh->y0.f1;
 trloadpassive(brh);
 return brh->converged = conv_check(brh);
}
/*--------------------------------------------------------------------------*/
static void ac_admittance_lin(branch_t *brh)
{
 acloadpassivereal(brh);
}
/*--------------------------------------------------------------------------*/
static void ac_admittance_nl(branch_t *brh)
{
 if (brh->f->acfun){
    brh->acbias = dc_volts(&(brh->n[OUT1]),&(brh->n[OUT2]));
    brh->acg = brh->ev = (*brh->f->acfun)(brh);
    acloadpassive(brh);
 }else{
    brh->ev.x  = brh->y0.f1;
    brh->ev.y  = 0.;
    brh->acg = brh->ev;
    acloadpassivereal(brh);
 }
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
