/* tr_setup.c  94.07.29
 * Copyright 1983-1992   Albert Davis
 * set up transient and fourier analysis
 */
#include "ecah.h"
#include "argparse.h"
#include "error.h"
#include "io.h"
#include "mode.h"
#include "options.h"
#include "probh.h"
#include "tr.h"
#include "worst.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
	void	tr_setup(const char*,int*,transient_t*);
	void	fo_setup(const char*,int*,fourier_t*);
static	long	to_pow_of_2(double);
static	void	tr_options(const char*,int*,transient_t*);
/*--------------------------------------------------------------------------*/
extern const probe_t *plotlist[];
extern       struct ioctrl io;
extern const struct options opt;
extern const double last_time;	/* time to restart at (set by trkeep)	    */
extern int sim_mode;	/* simulation type (AC, DC, ...)		    */
extern int worstcase;	/* worst case, monte carlo mode	(enum type, worst.h)*/
extern double temp;	/* actual ambient temperature, kelvin		    */
/*--------------------------------------------------------------------------*/
/* tr_setup: transient analysis: parse command string and set options
 * 	(options set by call to tr_options)
 */
void tr_setup(const char *cmd, int *cnt, transient_t *tr)
{
 double oldrange;

 oldrange = tr->stop - tr->start;

 tr->cont = YES;
 if ( isdigit(cmd[*cnt]) || cmd[*cnt]=='.' ){
    double arg1,arg2,arg3;
    arg1 = fabs(ctof(cmd,cnt));
    arg2 = fabs(ctof(cmd,cnt));
    arg3 = fabs(ctof(cmd,cnt));
    if (arg3 != 0.){			    /* 3 args: all */
       if (arg1 == 0.  ||  arg1 > arg3){    /* eca (logical) order: */
	  tr->start = arg1;		    /* start stop step */
	  tr->stop  = arg2;
	  tr->step  = arg3;
       }else{ 				    /* spice (illogical) order */
	  tr->start = arg3;		    /* step stop start */
	  tr->stop  = arg2;
	  tr->step  = arg1;
       }
    }else if (arg2 != 0.){		    /* 2 args */
       if (arg1 == 0.){			    /* 2 args: start, stop */
	  tr->start = arg1;
	  tr->stop  = arg2;
	  /* tr->step unchanged */
       }else if (arg1 >= arg2){		    /* 2 args: stop, step */
	  tr->start = last_time;
	  tr->stop  = arg1;
	  tr->step  = arg2;
       }else{ /* arg1 < arg2 */		    /* 2 args: step, stop */
	  tr->start = arg3; /* 0 */	    /* spice order */
	  tr->stop  = arg2;
	  tr->step  = arg1;
       }
    }else if (arg1 > last_time){	    /* 1 arg: stop */
       tr->start = last_time;
       tr->stop  = arg1;
       /* tr->step unchanged */
    }else if (arg1 == 0.){		    /* 1 arg: start */
       tr->start = 0.;
       tr->stop  = oldrange;
       /* tr->step unchanged */
    }else{ /* arg1 < last_time, but not 0 */  /* 1 arg: step */
       tr->start = last_time;
       tr->stop  = last_time + oldrange;
       tr->step  = arg1;
    }
 }else{ /* no args */
    tr->start = last_time;
    tr->stop  = last_time + oldrange;
    /* tr->step unchanged */
 }
 if ( isdigit(cmd[*cnt]) || cmd[*cnt]=='.' ){
    tr->dtmax = fabs(ctof(cmd,cnt));
    tr->skip = (int)(tr->step / tr->dtmax + .5);
 }
 tr_options(cmd,cnt,tr);
 if  (tr->start < last_time  ||  last_time <= 0.){
    tr->cont = NO;
    tr->time1 = tr->time0 = 0.;
 }else{
    tr->cont = YES;
    tr->time1 = tr->time0 = last_time;
 }
 if (tr->step==0.)
    error(bERROR, "time step = 0\n");
}
/*--------------------------------------------------------------------------*/
/* fo_setup: fourier analysis: parse command string and set options
 * 	(options set by call to tr_options)
 */
void fo_setup(const char *cmd, int *cnt, fourier_t *fo)
{
 long points;

 fo->tr.cont = YES;
 if ( isdigit(cmd[*cnt]) || cmd[*cnt]=='.' ){
    double arg1,arg2,arg3;
    arg1 = fabs(ctof(cmd,cnt));
    arg2 = fabs(ctof(cmd,cnt));
    arg3 = fabs(ctof(cmd,cnt));
    if (arg3 != 0.){			    /* 3 args: all */
       fo->start = arg1;
       fo->stop  = arg2;
       fo->step  = arg3;
    }else if (arg2 != 0.){		    /* 2 args: start = 0 */
       if (arg1 >= arg2){		    /* 2 args: stop, step */
	  fo->start = 0.;		    /* 	(stop > step) */
	  fo->stop  = arg1;
	  fo->step  = arg2;
       }else{ /* arg1 < arg2 */		    /* 2 args: step, stop */
	  fo->start = 0.;
	  fo->stop  = arg2;
	  fo->step  = arg1;
       }
    }else if (arg1 == 0.){		    /* 1 arg: start */
	fo->start = 0.;
	/* fo->stop unchanged */
	/* fo->step unchanged */
    }else{				    /* 1 arg: step */
	fo->start = 0.;
	fo->stop  = opt.harmonics * arg1;
	fo->step  = arg1;
    }
 }
 /* else (no args) : no change */

 if (fo->step == 0.){
    error(bERROR, "frequency step = 0\n");
 }
 if (fo->stop == 0.){
    fo->stop = opt.harmonics * fo->step;
 }
 tr_options(cmd,cnt,&fo->tr);
 points = to_pow_of_2(fo->stop*2 / fo->step);
 if (fo->tr.cold){
    fo->tr.cont = NO;
    fo->tr.start = 0.;
 }else{
    fo->tr.cont = YES;
    fo->tr.start = last_time;
 }
 fo->tr.stop = fo->tr.start + 1. / fo->step;
 fo->tr.step = 1. / fo->step / points;
 fo->tr.time1 = fo->tr.time0 = fo->tr.start;
 foinit(points);
}
/*--------------------------------------------------------------------------*/
/* to_pow_of_2: round up to nearest power of 2
 * example: z=92 returns 128
 */
static long to_pow_of_2(double z)
{
 long x,y;
 x = (long)floor(z);
 for (y=1; x>0; x>>=1 )
    y<<=1;
 return y;
}   
/*--------------------------------------------------------------------------*/
/* tr_options: set options common to transient and fourier analysis
 */
static void tr_options(const char *cmd, int *cnt, transient_t *tr)
{
 io.where |= io.mstdout;
 temp = opt.tempamb;
 io.ploton = io.plotset && count_probes(plotlist[sim_mode]) > 0;
 tr->echo = tr->cold = tr->trace = worstcase = NO;
 tr->dtmin = opt.dtmin;
 tr->dtratio = opt.dtratio;
 for (;;){
    if (argparse(cmd,cnt,REPEAT,
    	"ACMAx",	aENUM,	    &worstcase,	wMAXAC,
	"ACMIn",	aENUM,	    &worstcase,	wMINAC,
	"ALl",		aENUM,	    &tr->trace,	tALLTIME,
	"Ambient",	aODOUBLE,   &temp,	opt.tempamb,
	"Cold",		aENUM,	    &tr->cold,	YES,
    	"DCMAx",	aENUM,	    &worstcase,	wMAXDC,
	"DCMIn",	aENUM,	    &worstcase,	wMINDC,
	"DTMIn",	aUDOUBLE,   &tr->dtmin,
	"DTRatio",	aUDOUBLE,   &tr->dtratio,
	"Echo",		aENUM,	    &tr->echo,	YES,
	"LAg",		aENUM,	    &worstcase, wLAG,
	"LEad",		aENUM,	    &worstcase, wLEAD,
	"NOPlot",	aENUM,	    &io.ploton, NO,
	"PLot",		aENUM,	    &io.ploton, YES,
	"RAndom",	aENUM,	    &worstcase, wRAND,
	"Reftemp",	aODOUBLE,   &temp,	opt.tnom,
	"SEnsitivity",	aENUM,	    &worstcase, wSENS,
	"SKip",		aUINT,	    &tr->skip,
	"Temperature",	aODOUBLE,   &temp,	-ABS_ZERO,
	"TRace",	aFINT,	    &tr->trace,
	"WAtch",	aENUM,	    &tr->trace,	tITERATION,
	""))
	;	
    else if (outset(cmd,cnt,"",""))
	;
    else{
       syntax_check(cmd,cnt,bWARNING);
       break;
    }
 }
 if (tr->skip < 1)
    tr->skip = 1;
 tr->dtmax = tr->step / (double)(tr->skip);
 tr->dtmin = MAX(tr->dtmin,tr->dtmax/tr->dtratio);
 
 initio(io.where,io.whence);
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
