src/grid/events.h
typedef struct _Event Event;
typedef int (* Expr) (int *, double *, Event *);
struct _Event {
int last, nexpr;
int (* action) (const int, const double, Event *);
[3];
Expr exprint * arrayi;
double * arrayt;
char * file;
int line;
char * name;
double t;
int i, a;
void * data;
Event * next;
};
static Event * Events = NULL; // all events
int iter = 0, inext = 0; // current step and step of next event
double t = 0, tnext = 0; // current time and time of next event
void init_events (void);
void event_register (Event event);
static void _init_solver (void);
#define INIT ev->expr[0]
#define COND ev->expr[1]
#define INC ev->expr[2]
static int END_EVENT = 1234567890;
static double TEND_EVENT = 1234567890;
static double TEPS = 1e-9;
static void event_error (Event * ev, const char * s)
{
fprintf (stderr, "%s:%d: error: %s\n", ev->file, ev->line, s);
exit (1);
}
static void init_event (Event * ev)
{
if (ev->arrayi || ev->arrayt) {
->i = -1; ev->t = - TEND_EVENT;
evif (ev->arrayi)
->i = ev->arrayi[0];
evelse
->t = ev->arrayt[0];
ev->a = 1;
ev->expr[1] = NULL;
ev}
else {
if (ev->nexpr > 0) {
= NULL, cond = NULL, inc = NULL;
Expr init for (int j = 0; j < ev->nexpr; j++) {
int i = -123456; double t = - TEND_EVENT;
(* ev->expr[j]) (&i, &t, ev);
if (i == -123456 && t == - TEND_EVENT) {
/* nothing done to i and t: this must be the condition */
if (cond)
event_error (ev, "events can only use a single condition");
= ev->expr[j];
cond }
else {
/* this is either an initialisation or an increment */
int i1 = i; double t1 = t;
(* ev->expr[j]) (&i1, &t1, ev);
if (i1 == i && t1 == t) {
/* applying twice does not change anything: this is an
initialisation */
if (init)
event_error (ev, "events can only use a single initialisation");
= ev->expr[j];
init }
else {
/* this is the increment */
if (inc)
event_error (ev, "events can only use a single increment");
= ev->expr[j];
inc }
}
}
= init;
INIT = cond;
COND = inc;
INC ->nexpr = 0;
ev}
->i = -1; ev->t = - TEND_EVENT;
evif (INIT) {
(* INIT) (&ev->i, &ev->t, ev);
if (ev->i == END_EVENT || ev->t == TEND_EVENT) {
->i = END_EVENT; ev->t = - TEND_EVENT;
ev}
}
else if (INC) {
(* INC) (&ev->i, &ev->t, ev);
if (ev->i != -1)
->i = 0;
evif (ev->t != - TEND_EVENT)
->t = 0;
ev}
}
}
enum { event_done, event_alive, event_stop };
static int event_finished (Event * ev)
{
->i = -1; ev->t = - TEND_EVENT;
evreturn event_done;
}
void event_register (Event event) {
assert (Events);
assert (!event.last);
int n = 0, parent = -1;
for (Event * ev = Events; !ev->last; ev++) {
if (!strcmp (event.name, ev->name)) {
assert (parent < 0);
= n;
parent }
++;
n}
if (parent < 0) {
(Events, n + 2, Event);
qrealloc [n] = event;
Events[n].next = NULL;
Events[n + 1].last = true;
Eventsinit_event (&Events[n]);
}
else {
Event * ev = qcalloc (1, Event);
*ev = Events[parent];
[parent] = event;
Events[parent].next = ev;
Eventsinit_event (&Events[parent]);
}
}
static int event_cond (Event * ev, int i, double t)
{
if (!COND)
return true;
return (* COND) (&i, &t, ev);
}
#if DEBUG_EVENTS
static void event_print (Event * ev, FILE * fp)
{
char * root = strstr (ev->file, BASILISK);
fprintf (fp, " %-25s %s%s:%d\n", ev->name,
? "src" : "",
root ? &ev->file[strlen(BASILISK)] : ev->file,
root ->line);
ev}
#endif
The interpreter overloads the function below to control (i.e. shorten) the events loop.
static bool overload_event() { return true; }
static int event_do (Event * ev, bool action)
{
if ((iter > ev->i && t > ev->t) || !event_cond (ev, iter, t))
return event_finished (ev);
if (!overload_event() || iter == ev->i || fabs (t - ev->t) <= TEPS*t) {
if (action) {
bool finished = false;
for (Event * e = ev; e; e = e->next) {
#if DEBUG_EVENTS
event_print (e, stderr);
#endif
if ((* e->action) (iter, t, e))
= true;
finished }
if (finished) {
event_finished (ev);
return event_stop;
}
}
if (ev->arrayi) { /* i = {...} */
->i = ev->arrayi[ev->a++];
evif (ev->i < 0)
return event_finished (ev);
}
if (ev->arrayt) { /* t = {...} */
->t = ev->arrayt[ev->a++];
evif (ev->t < 0)
return event_finished (ev);
}
else if (INC) {
int i0 = ev->i;
(* INC) (&ev->i, &ev->t, ev);
if (i0 == -1 && ev->i != i0)
->i += iter + 1;
evif (!event_cond (ev, iter + 1, ev->t))
return event_finished (ev);
}
else if (INIT && !COND)
return event_finished (ev);
}
return event_alive;
}
static void end_event_do (bool action)
{
#if DEBUG_EVENTS
if (action)
fprintf (stderr, "\nend events (i = %d, t = %g)\n", iter, t);
#endif
for (Event * ev = Events; !ev->last; ev++)
if (ev->i == END_EVENT && action)
for (Event * e = ev; e; e = e->next) {
#if DEBUG_EVENTS
event_print (e, stderr);
#endif
->action (iter, t, e);
e}
}
int events (bool action)
{
#if DEBUG_EVENTS
if (action)
fprintf (stderr, "\nevents (i = %d, t = %g)\n", iter, t);
#endif
if (iter == 0)
for (Event * ev = Events; !ev->last; ev++)
init_event (ev);
int cond = 0, cond1 = 0;
= END_EVENT; tnext = HUGE;
inext for (Event * ev = Events; !ev->last && !cond; ev++)
if (ev->i != END_EVENT &&
(COND || (INIT && !COND && !INC) || ev->arrayi || ev->arrayt))
= 1;
cond for (Event * ev = Events; !ev->last; ev++) {
int status = event_do (ev, action);
if (status == event_stop) {
end_event_do (action);
return 0;
}
if (status == event_alive && ev->i != END_EVENT &&
(COND || (INIT && !COND && !INC) || ev->arrayi || ev->arrayt))
= 1;
cond1 if (ev->t > t && ev->t < tnext)
= ev->t;
tnext if (ev->i > iter && ev->i < inext)
= ev->i;
inext }
if (overload_event() && (!cond || cond1) && (tnext != HUGE || inext != END_EVENT)) {
= iter + 1;
inext return 1;
}
end_event_do (action);
return 0;
}
void event (const char * name)
{
for (Event * ev = Events; !ev->last; ev++)
if (!strcmp (ev->name, name))
for (Event * e = ev; e; e = e->next) {
#if DEBUG_EVENTS
event_print (e, stderr);
#endif
(* e->action) (0, 0, e);
}
}
double dtnext (double dt)
{
if (tnext != HUGE && tnext > t) {
assert (dt > 0.);
unsigned int n = (tnext - t)/dt;
assert (n < INT_MAX); // check that dt is not too small
if (n == 0)
= tnext - t;
dt else {
double dt1 = (tnext - t)/n;
if (dt1 > dt*(1. + TEPS))
= (tnext - t)/(n + 1);
dt else if (dt1 < dt)
= dt1;
dt = t + dt;
tnext }
}
else= t + dt;
tnext return dt;
}
void init_solver()
{
= malloc (sizeof (Event));
Events [0].last = 1;
Events= calloc (datasize/sizeof(real), sizeof (_Attributes));
_attribute int n = datasize/sizeof(real);
= (scalar *) malloc (sizeof (scalar)*(n + 1));
all = (scalar *) malloc (sizeof (scalar)*(n + 1));
baseblock for (int i = 0; i < n; i++)
[i].i = all[i].i = i;
baseblock[n].i = all[n].i = -1;
baseblock#if _CADNA
(-1);
cadna_init #endif
#if _MPI
();
mpi_init#elif MTRACE == 1
char * etrace = getenv ("MTRACE");
.fp = fopen (etrace ? etrace : "mtrace", "w");
pmtrace.fname = systrdup (etrace ? etrace : "mtrace");
pmtrace#endif
}