sharedspice.c: modified callback interface
enhanced function ngSpice_Init_Sync() three new callback functions for synchronization
This commit is contained in:
parent
a0757d3143
commit
d2dbe6145f
|
|
@ -168,44 +168,50 @@ typedef struct vecinfoall
|
|||
addresses received from caller with ngSpice_Init() function
|
||||
*/
|
||||
/* sending output from stdout, stderr to caller */
|
||||
typedef int (SendChar)(char*, void*);
|
||||
typedef int (SendChar)(char*, int, void*);
|
||||
/*
|
||||
char* string to be sent to caller output
|
||||
int identification number of calling ngspice shared lib
|
||||
void* return pointer received from caller, e.g. pointer to object having sent the request
|
||||
*/
|
||||
/* sending simulation status to caller */
|
||||
typedef int (SendStat)(char*, void*);
|
||||
typedef int (SendStat)(char*, int, void*);
|
||||
/*
|
||||
char* simulation status and value (in percent) to be sent to caller
|
||||
int identification number of calling ngspice shared lib
|
||||
void* return pointer received from caller
|
||||
*/
|
||||
/* asking for controlled exit */
|
||||
typedef int (ControlledExit)(int, bool, bool, void*);
|
||||
typedef int (ControlledExit)(int, bool, bool, int, void*);
|
||||
/*
|
||||
int exit status
|
||||
bool if true: immediate unloading dll, if false: just set flag, unload is done when function has returned
|
||||
bool if true: exit upon 'quit', if false: exit due to ngspice.dll error
|
||||
int identification number of calling ngspice shared lib
|
||||
void* return pointer received from caller
|
||||
*/
|
||||
/* send back actual vector data */
|
||||
typedef int (SendData)(pvecvaluesall, int, void*);
|
||||
typedef int (SendData)(pvecvaluesall, int, int, void*);
|
||||
/*
|
||||
vecvaluesall* pointer to array of structs containing actual values from all vectors
|
||||
int number of structs (one per vector)
|
||||
int identification number of calling ngspice shared lib
|
||||
void* return pointer received from caller
|
||||
*/
|
||||
|
||||
/* send back initailization vector data */
|
||||
typedef int (SendInitData)(pvecinfoall, void*);
|
||||
typedef int (SendInitData)(pvecinfoall, int, void*);
|
||||
/*
|
||||
vecinfoall* pointer to array of structs containing data from all vectors right after initialization
|
||||
int identification number of calling ngspice shared lib
|
||||
void* return pointer received from caller
|
||||
*/
|
||||
|
||||
/* indicate if background thread is running */
|
||||
typedef int (BGThreadRunning)(bool, void*);
|
||||
typedef int (BGThreadRunning)(bool, int, void*);
|
||||
/*
|
||||
bool true if background thread is running
|
||||
int identification number of calling ngspice shared lib
|
||||
void* return pointer received from caller
|
||||
*/
|
||||
|
||||
|
|
@ -214,11 +220,34 @@ typedef int (BGThreadRunning)(bool, void*);
|
|||
*/
|
||||
|
||||
/* ask for VSRC EXTERNAL value */
|
||||
typedef int (GetVSRCData)(double*, double, char*, void*);
|
||||
typedef int (GetVSRCData)(double*, double, char*, int, void*);
|
||||
/*
|
||||
double* return voltage value
|
||||
double actual time
|
||||
char* node name
|
||||
int identification number of calling ngspice shared lib
|
||||
void* return pointer received from caller
|
||||
*/
|
||||
|
||||
/* ask for ISRC EXTERNAL value */
|
||||
typedef int (GetISRCData)(double*, double, char*, int, void*);
|
||||
/*
|
||||
double* return current value
|
||||
double actual time
|
||||
char* node name
|
||||
int identification number of calling ngspice shared lib
|
||||
void* return pointer received from caller
|
||||
*/
|
||||
|
||||
/* ask for new delta time depending on synchronization requirements */
|
||||
typedef int (GetSyncData)(double, double*, double, int, int, int, void*);
|
||||
/*
|
||||
double actual time (ckt->CKTtime)
|
||||
double* delta time (ckt->CKTdelta)
|
||||
double old delta time (olddelta)
|
||||
int redostep (as set by ngspice)
|
||||
int identification number of calling ngspice shared lib
|
||||
int location of call for synchronization in dctran.c
|
||||
void* return pointer received from caller
|
||||
*/
|
||||
|
||||
|
|
@ -236,11 +265,17 @@ int ngSpice_Init(SendChar* printfcn, SendStat* statfcn, ControlledExit* ngexit,
|
|||
SendData* sdata, SendInitData* sinitdata, BGThreadRunning* bgtrun, void* userData);
|
||||
|
||||
/* initialization of synchronizing functions
|
||||
vsrcdat: pointer to callback function for retrieving a voltage source value
|
||||
vsrcdat: pointer to callback function for retrieving a voltage source value from caller
|
||||
isrcdat: pointer to callback function for retrieving a current source value from caller
|
||||
syncdat: pointer to callback function for synchronization
|
||||
ident: pointer to integer unique to this shared library (defaults to 0)
|
||||
userData: pointer to user-defined data, will not be modified, but
|
||||
handed over back to caller during Callback, e.g. address of calling object.
|
||||
If NULL is sent here, userdata info from ngSpice_Init() will be kept, otherwise
|
||||
userdata will be overridden by new value from here.
|
||||
*/
|
||||
IMPEXP
|
||||
int ngSpice_Init_Sync(GetVSRCData *vsrcdat, int *ident, void *userData);
|
||||
int ngSpice_Init_Sync(GetVSRCData *vsrcdat, GetISRCData *isrcdat, GetSyncData *syncdat, int *ident, void *userData);
|
||||
|
||||
/* Caller may send ngspice commands to ngspice.dll.
|
||||
Commands are executed immediately */
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@ void sighandler_sharedspice(int num);
|
|||
void wl_delete_first(wordlist **wlstart, wordlist **wlend);
|
||||
|
||||
int add_bkpt(void);
|
||||
int sharedsync(double*, double*, double, double, int, int*, int);
|
||||
|
||||
#if !defined(low_latency)
|
||||
static char* outstorage(char*, bool);
|
||||
|
|
@ -218,6 +219,8 @@ static SendData* datfcn;
|
|||
static SendInitData* datinitfcn;
|
||||
static BGThreadRunning* bgtr;
|
||||
static GetVSRCData* getvdat;
|
||||
static GetISRCData* getidat;
|
||||
static GetSyncData* getsync;
|
||||
static pvector_info myvec = NULL;
|
||||
char **allvecs = NULL;
|
||||
char **allplots = NULL;
|
||||
|
|
@ -227,6 +230,8 @@ static bool nodatawanted = FALSE;
|
|||
static bool nodatainitwanted = FALSE;
|
||||
static bool nobgtrwanted = FALSE;
|
||||
static bool wantvdat = FALSE;
|
||||
static bool wantidat = FALSE;
|
||||
static bool wantsync = FALSE;
|
||||
static bool immediate = FALSE;
|
||||
static bool coquit = FALSE;
|
||||
static jmp_buf errbufm, errbufc;
|
||||
|
|
@ -247,7 +252,7 @@ static bool is_initialized = FALSE;
|
|||
static char* no_init = "Error: ngspice is not initialized!\n Run ngSpice_Init first";
|
||||
|
||||
/* identifier for this ngspice invocation */
|
||||
static int ng_ident = 0;
|
||||
int ng_ident = 0;
|
||||
|
||||
|
||||
static struct plot *
|
||||
|
|
@ -296,7 +301,7 @@ _thread_run(void *string)
|
|||
fl_exited = FALSE;
|
||||
/* notify caller that thread is running */
|
||||
if (!nobgtrwanted)
|
||||
bgtr(fl_exited, userptr);
|
||||
bgtr(fl_exited, ng_ident, userptr);
|
||||
bgtid = thread_self();
|
||||
cp_evloop((char *)string);
|
||||
FREE(string);
|
||||
|
|
@ -309,7 +314,7 @@ _thread_run(void *string)
|
|||
fl_exited = TRUE;
|
||||
/* notify caller that thread has exited */
|
||||
if (!nobgtrwanted)
|
||||
bgtr(fl_exited, userptr);
|
||||
bgtr(fl_exited, ng_ident, userptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -485,23 +490,33 @@ ngSpice_running (void)
|
|||
#endif
|
||||
|
||||
|
||||
/* Initialise external voltage source */
|
||||
/* Initialise external voltage source and synchronization */
|
||||
IMPEXP
|
||||
int
|
||||
ngSpice_Init_Sync(GetVSRCData* vsrcdat, int *ident, void *userData)
|
||||
ngSpice_Init_Sync(GetVSRCData *vsrcdat, GetISRCData *isrcdat, GetSyncData *syncdat, int *ident, void *userData)
|
||||
{
|
||||
getvdat = vsrcdat;
|
||||
getidat = isrcdat;
|
||||
getsync = syncdat;
|
||||
/* set userdata, but don't overwrite with NULL */
|
||||
if (userData)
|
||||
userptr = userData;
|
||||
/* set ngspice shared lib identification number */
|
||||
ng_ident = *ident;
|
||||
if (ident)
|
||||
ng_ident = *ident;
|
||||
/* if caller sends NULL, don't try to retrieve voltage */
|
||||
if (getvdat) {
|
||||
wantvdat = TRUE;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
/* if caller sends NULL, don't try to retrieve current */
|
||||
if (getidat) {
|
||||
wantidat = TRUE;
|
||||
}
|
||||
/* if caller sends NULL, don't synchronize */
|
||||
if (getsync) {
|
||||
wantsync = TRUE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1097,7 +1112,7 @@ sh_fputsll(const char *input, FILE* outf)
|
|||
strcat(prstring, "stderr ");
|
||||
strcat(prstring, newstring);
|
||||
|
||||
result = pfcn(prstring, userptr);
|
||||
result = pfcn(prstring, ng_ident, userptr);
|
||||
tfree(newstring);
|
||||
tfree(prstring);
|
||||
}
|
||||
|
|
@ -1110,7 +1125,7 @@ sh_fputsll(const char *input, FILE* outf)
|
|||
return result;
|
||||
}
|
||||
else if (strchr(input, '\r')) {
|
||||
result = pfcn(outstringerr, userptr);
|
||||
result = pfcn(outstringerr, ng_ident, userptr);
|
||||
tfree(outstringerr);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1131,7 +1146,7 @@ sh_fputsll(const char *input, FILE* outf)
|
|||
prstring = TMALLOC(char, 7 + strlen(newstring) + 1);
|
||||
strcat(prstring, "stdout ");
|
||||
strcat(prstring, newstring);
|
||||
result = pfcn(prstring, userptr);
|
||||
result = pfcn(prstring, ng_ident, userptr);
|
||||
tfree(newstring);
|
||||
tfree(prstring);
|
||||
}
|
||||
|
|
@ -1144,7 +1159,7 @@ sh_fputsll(const char *input, FILE* outf)
|
|||
return result;
|
||||
}
|
||||
else if (strchr(input, '\r')) {
|
||||
result = pfcn(outstringout, userptr);
|
||||
result = pfcn(outstringout, ng_ident, userptr);
|
||||
tfree(outstringout);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1376,7 +1391,7 @@ void SetAnalyse(
|
|||
|
||||
if (DecaPercent >= 1000){
|
||||
sprintf( s, "--ready--");
|
||||
result = statfcn(s, userptr);
|
||||
result = statfcn(s, ng_ident, userptr);
|
||||
tfree(s);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1414,7 +1429,7 @@ void SetAnalyse(
|
|||
strncpy(OldAn, Analyse, 127);
|
||||
}
|
||||
|
||||
result = statfcn(s, userptr);
|
||||
result = statfcn(s, ng_ident, userptr);
|
||||
}
|
||||
tfree(s);
|
||||
#else
|
||||
|
|
@ -1423,7 +1438,7 @@ void SetAnalyse(
|
|||
static bool havesent = FALSE;
|
||||
if (!havesent) {
|
||||
s = copy("No usage info available");
|
||||
result = statfcn(s, userptr);
|
||||
result = statfcn(s, ng_ident, userptr);
|
||||
tfree(s);
|
||||
havesent = TRUE;
|
||||
}
|
||||
|
|
@ -1467,7 +1482,7 @@ void shared_exit(int status)
|
|||
if (outsend) {
|
||||
/* requires outsend to be copied by the caller,
|
||||
because it is freed immediately */
|
||||
pfcn(outsend, userptr);
|
||||
pfcn(outsend, ng_ident, userptr);
|
||||
tfree(outsend);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1475,9 +1490,9 @@ void shared_exit(int status)
|
|||
// detaching then has to be done explicitely by the caller
|
||||
if (fl_running && !fl_exited) {
|
||||
fl_exited = TRUE;
|
||||
bgtr(fl_exited, userptr);
|
||||
bgtr(fl_exited, ng_ident, userptr);
|
||||
// set a flag that ngspice wants to be detached
|
||||
ngexit(status, FALSE, coquit, userptr);
|
||||
ngexit(status, FALSE, coquit, ng_ident, userptr);
|
||||
// finish and exit the worker thread
|
||||
#ifdef HAVE_LIBPTHREAD
|
||||
pthread_exit(1);
|
||||
|
|
@ -1486,7 +1501,7 @@ void shared_exit(int status)
|
|||
#endif
|
||||
}
|
||||
// set a flag in caller to detach ngspice.dll
|
||||
ngexit(status, immediate, coquit, userptr);
|
||||
ngexit(status, immediate, coquit, ng_ident, userptr);
|
||||
|
||||
// jump back to finish the calling function
|
||||
if (!intermj)
|
||||
|
|
@ -1559,7 +1574,7 @@ int sh_ExecutePerLoop_old(void)
|
|||
}
|
||||
/* now call the callback function to return the data to the caller */
|
||||
if (!nodatawanted)
|
||||
// datfcn(curvecvals, len, userptr);
|
||||
// datfcn(curvecvals, len, ng_ident, userptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1594,7 +1609,7 @@ int sh_ExecutePerLoop(void)
|
|||
}
|
||||
}
|
||||
/* now call the callback function to return the data to the caller */
|
||||
datfcn(curvecvalsall, len, userptr);
|
||||
datfcn(curvecvalsall, len, ng_ident, userptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1653,7 +1668,7 @@ int sh_vecinit(runDesc *run)
|
|||
// the data
|
||||
pvca->vecs = pvc;
|
||||
/* now call the callback function to return the data to the caller */
|
||||
datinitfcn(pvca, userptr);
|
||||
datinitfcn(pvca, ng_ident, userptr);
|
||||
|
||||
/* generate the data tranfer structure,
|
||||
data will be sent from sh_ExecutePerLoop() via datfcn() */
|
||||
|
|
@ -1693,7 +1708,102 @@ getvsrcval(double time, char *vname)
|
|||
}
|
||||
else {
|
||||
/* callback fcn */
|
||||
getvdat(&vval, time, vname, userptr);
|
||||
getvdat(&vval, time, vname, ng_ident, userptr);
|
||||
return vval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* issue callback to request external current data for source iname*/
|
||||
double
|
||||
getisrcval(double time, char *iname)
|
||||
{
|
||||
double ival;
|
||||
if (!wantidat) {
|
||||
fprintf(stderr, "Error: No callback supplied for source %s\n", iname);
|
||||
shared_exit(EXIT_BAD);
|
||||
return(EXIT_BAD);
|
||||
}
|
||||
else {
|
||||
/* callback fcn */
|
||||
getidat(&ival, time, iname, ng_ident, userptr);
|
||||
return ival;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
return value 1: continue with new time step, ckt->CKTtime + ckt->CKTdelta will be
|
||||
done next automatically.
|
||||
For time synchronization we may choose our own ckt->CKTdelta, being
|
||||
smaller than the one suggested by ngspice.
|
||||
return value 0: will redo the most recent time step. We may subtract olddelta and
|
||||
continue with new ckt-CKTdelta.
|
||||
This is necessary if non-convergence has been detected (redostep = 1).
|
||||
The newly suggested ckt-CKTdelta has already been divided by 8.
|
||||
This is also enforced if the truncation error is too large.
|
||||
The newly suggested ckt-CKTdelta may be accompanied by an increase
|
||||
of integration order.
|
||||
For time synchronization, if the actual, converged ckt-CKTtime is
|
||||
beyond the optimum common time, we subtract olddelta and then choose
|
||||
our own ckt->CKTdelta, being smaller than olddelta.
|
||||
Whereas redostep is set by ngspice, the user may decide via the callback function,
|
||||
to redo the most recent step because of other reasons. This is accomplished by
|
||||
returning a 1 with the callback function.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
ckttime pointer to ckt->CKTtime, which already has been used trying to achieve
|
||||
convergence, after olddelta had been added in the previous step.
|
||||
cktdelta pointer to newly defined ckt->CKTdelta, e.g. by recognizing truncation errors
|
||||
olddelta old ckt->CKTdelta, has already been added in the previous step.
|
||||
finalt final time
|
||||
redostep if 0, converged,
|
||||
if 1, either no convergence, need to redo with new ckt->CKTdelta
|
||||
or ckt->CKTdelta has been reduced by tuncation errors too large.
|
||||
rejected pointer to ckt->CKTstat->STATrejected, counts rejected time points.
|
||||
loc location of function call in dctran.c: 0: after breakpoint handling, 1: at end of for loop
|
||||
*/
|
||||
|
||||
int
|
||||
sharedsync(double *pckttime, double *pcktdelta, double olddelta, double finalt, int redostep, int *rejected, int loc)
|
||||
{
|
||||
/* standard procedure, cktdelta has been provided by ngspice */
|
||||
if (!wantsync) {
|
||||
if (redostep) {
|
||||
*pckttime -= olddelta;
|
||||
(*rejected)++;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
/* synchronization required, to be done by changing cktdelta */
|
||||
} else {
|
||||
if (redostep) {
|
||||
*pckttime -= olddelta;
|
||||
(*rejected)++;
|
||||
/* use cktdelta as suggested by ngspice or acquire new cktdelta
|
||||
via pointer pcktdelta in user supplied callback */
|
||||
getsync(*pckttime, pcktdelta, olddelta, redostep, ng_ident, loc, userptr);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
/* Use cktdelta as suggested by ngspice or acquire new cktdelta
|
||||
via pointer pcktdelta in user supplied callback. Redo the previous
|
||||
step if return value from getsync is 1. */
|
||||
int retval = getsync(*pckttime, pcktdelta, olddelta, redostep, ng_ident, loc, userptr);
|
||||
/* never move beyond final time */
|
||||
if (*pckttime + *pcktdelta > finalt)
|
||||
*pcktdelta = finalt - *pckttime;
|
||||
|
||||
/* user has decided to redo the step, ignoring redostep being set to 0
|
||||
by ngspice. */
|
||||
if (retval) {
|
||||
*pckttime -= olddelta;
|
||||
(*rejected)++;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue