sharedspice.c: modified callback interface

enhanced function ngSpice_Init_Sync()
three new callback functions for synchronization
This commit is contained in:
h_vogt 2013-08-10 15:13:03 +02:00 committed by rlar
parent a0757d3143
commit d2dbe6145f
2 changed files with 177 additions and 32 deletions

View File

@ -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 */

View File

@ -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;
}
}
}