/* d_vcvs.c  94.12.10
 * Copyright 1983-1992   Albert Davis
 * functions for vcvs
 * temporary kluge: it has resistance
 */
#include "ecah.h"
#include "branch.h"
#include "d_subckt.h"
#include "mode.h"
#include "options.h"
#include "types.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
static	void	expand_vcvs(branch_t*);
static	double	probe_vcvs(const branch_t*, const char*);
static 	int	tr_vcvs(branch_t*);
static	void	ac_vcvs(branch_t*);
/*--------------------------------------------------------------------------*/
extern const struct options opt;
/*--------------------------------------------------------------------------*/
functions_t dev_vcvs = {
   (generic_t*)NULL,	/* x */
   sizeof(functions_t),	/* ssize */
   sizeof(branch_t),	/* elementsize */
   (functions_t*)NULL,	/* super */
   4, 			/* numnodes */
   rnTWOPORT,		/* refnode */
   rnTWOPORT,		/* isdevice */
   create_std,		/* create */
   copy_std,		/* copy */
   parse_std,		/* parse */
   print_std,		/* print */
   expand_vcvs,		/* expand */
   probe_vcvs,		/* probe */
   NULL,		/* tr_probe */
   NULL,		/* ac_probe */
   NULL,		/* xprobe */
   tr_subckt,		/* dotr */
   un_subckt,		/* untr */
   ac_subckt,		/* doac */
   trfix1,		/* trfun1 */
   trfix0,		/* trfun0 */
   acfix,		/* acfun */
   NULL,		/* tr_guess */
   NULL,		/* tr_advance */
   NULL			/* tr_review */
};
/*--------------------------------------------------------------------------*/
static void expand_vcvs(branch_t *brh)
{
 static functions_t *dev_vcvs_internal;
 branch_t *sub;
 
 brh->subckt = NULL;	/* BUG: memory leak */

 if (!dev_vcvs_internal){
    dev_vcvs_internal = (functions_t*)calloc(1, sizeof(functions_t));
    *dev_vcvs_internal = dev_vcvs;
    dev_vcvs_internal->super = &dev_vcvs;
    dev_vcvs_internal->expand = NULL;
    dev_vcvs_internal->probe = probe_std;
    dev_vcvs_internal->dotr = tr_vcvs;
    dev_vcvs_internal->untr = unloadactive;
    dev_vcvs_internal->doac = ac_vcvs;
    dev_vcvs_internal->tr_review  = NULL;
 }
 
 sub = copy_branch(brh);
 sub->parent = brh;
 strcpy(sub->label,"Geq");
 sub->f = dev_vcvs_internal;
 sub->next = brh->subckt;
 sub->prev = (branch_t*)NULL;
 brh->subckt = insertbranch(sub);
 
 sub = create_branch(&dev_admittance);
 sub->parent = brh;
 strcpy(sub->label,"Yeq");
 sub->n[OUT1] = brh->n[OUT1];
 sub->n[OUT2] = brh->n[OUT2];
 sub->val = 1./opt.shortckt;
 sub->next = brh->subckt;
 sub->prev = (branch_t*)NULL;
 brh->subckt = insertbranch(sub); 

 brh->tracesubckt = YES;
}
/*--------------------------------------------------------------------------*/
static double probe_vcvs(const branch_t *brh, const char *what)
{
 return probe_std(brh->subckt->next, what);
 /* BUG: just probes the transfer element like the old version */
}
/*--------------------------------------------------------------------------*/
static int tr_vcvs(branch_t *brh)
{
 brh->m0.x = tr_volts_limited(&(brh->n[IN1]),&(brh->n[IN2]));
 brh->y0.x = brh->m0.x;
 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.f1 = brh->y0.f1;
 brh->m0.c0 /= -opt.shortckt;
 brh->m0.f1 /= -opt.shortckt;
 trloadactive(brh);
 return brh->converged = conv_check(brh);
}
/*--------------------------------------------------------------------------*/
static void ac_vcvs(branch_t *brh)
{
 if (brh->f->acfun){
    brh->acbias = dc_volts(&(brh->n[IN1]),&(brh->n[IN2]));
    brh->ev = (*brh->f->acfun)(brh);
    brh->acg.x = brh->ev.x / -opt.shortckt;
    brh->acg.y = brh->ev.y / -opt.shortckt;
 }else{
    brh->ev.x  = brh->y0.f1;
    brh->ev.y  = 0.;
    brh->acg.x = brh->ev.x / -opt.shortckt;
    brh->acg.y = 0.;
 }
 acloadactive(brh);
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
