559 lines
12 KiB
C
559 lines
12 KiB
C
#include <stdlib.h>
|
|
#include <float.h>
|
|
#include <strings.h>
|
|
#include <assert.h>
|
|
#include "myc_mem.h"
|
|
#include "myc_str.h"
|
|
#include "myc_err.h"
|
|
#include "myc_time.h"
|
|
#include "coc_logfile.h"
|
|
#include "tecs_data.h"
|
|
|
|
#define RUN_SIZE 1024
|
|
#define SET_LEN 1024
|
|
|
|
typedef struct {
|
|
int tmin, tmax, tlim;
|
|
float dmin, dmax;
|
|
int reset;
|
|
} Summary;
|
|
|
|
typedef struct _Run {
|
|
struct _Run *next;
|
|
int size, step;
|
|
int startTime, endTime;
|
|
float data[RUN_SIZE];
|
|
} Run;
|
|
|
|
typedef struct _Set {
|
|
DataSet set;
|
|
struct _Set *next;
|
|
int nRuns;
|
|
int step, lifetime;
|
|
int start, end;
|
|
float *var;
|
|
Run *runs;
|
|
Summary sum;
|
|
} Set;
|
|
|
|
typedef struct {
|
|
Set *head;
|
|
} Base;
|
|
|
|
typedef struct {
|
|
Base *base;
|
|
int tim, from, to;
|
|
int stdStep;
|
|
} ScanData;
|
|
|
|
static Base database;
|
|
|
|
void InsSum(Summary *sum, int t, float d) {
|
|
if (sum->tmin == 0) {
|
|
sum->tmin = t;
|
|
sum->tmax = t;
|
|
sum->dmin = d;
|
|
sum->dmax = d;
|
|
} else {
|
|
if (d <= sum->dmin) {
|
|
sum->dmin = d;
|
|
sum->tmin = t;
|
|
} else if (d >= sum->dmax) {
|
|
sum->dmax = d;
|
|
sum->tmax = t;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ResetSum(Summary *sum) {
|
|
sum->reset = 1;
|
|
sum->tmin = 0;
|
|
sum->dmin = DATA_UNDEF;
|
|
sum->dmax = DATA_UNDEF;
|
|
}
|
|
|
|
void PutSum(Summary *sum, float *data) {
|
|
if (sum->tmin == 0) {
|
|
data[1] = sum->dmin;
|
|
data[0] = sum->dmax;
|
|
} else if (sum->tmin > sum->tmax) {
|
|
data[1] = sum->dmin;
|
|
data[0] = sum->dmax;
|
|
sum->dmin = sum->dmax;
|
|
} else if (sum->tmin < sum->tmax) {
|
|
data[1] = sum->dmax;
|
|
data[0] = sum->dmin;
|
|
sum->dmax = sum->dmin;
|
|
} else {
|
|
data[1] = sum->dmin;
|
|
data[0] = sum->dmax;
|
|
}
|
|
sum->tmin = 0;
|
|
if (sum->reset) {
|
|
sum->dmin = DATA_UNDEF;
|
|
sum->dmax = DATA_UNDEF;
|
|
sum->reset = 0;
|
|
}
|
|
}
|
|
|
|
Set *FindSet(Base *base, char *name) {
|
|
Set *s;
|
|
int total;
|
|
|
|
total=0;
|
|
s = base->head;
|
|
while (s!=NULL && 0!=strcasecmp(name, s->set.name)) {
|
|
s = s->next;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
Set *CreateSet(Base *base, char *name, float *var, int step, int lifetime, int start) {
|
|
Set *s;
|
|
char *nam;
|
|
|
|
s = FindSet(base, name);
|
|
if (s != NULL) ERR_MSG("dataset exists");
|
|
NEW(s, Set);
|
|
s->next = base->head;
|
|
base->head = s;
|
|
NEW_STR(nam, name);
|
|
s->set.name = nam;
|
|
s->runs = NULL;
|
|
s->nRuns = 0;
|
|
s->lifetime = lifetime;
|
|
s->start = start;
|
|
s->step = step;
|
|
s->var = var;
|
|
ResetSum(&s->sum);
|
|
return s;
|
|
OnError:
|
|
return NULL;
|
|
}
|
|
|
|
DataSet *DataFindSet(DataBase *dBase, char *name) {
|
|
Base *base;
|
|
if (dBase==NULL) {
|
|
base=&database;
|
|
} else {
|
|
base=(Base *)dBase;
|
|
}
|
|
return (DataSet *) FindSet(base, name);
|
|
}
|
|
|
|
DataSet *DataCreateSet(DataBase *dBase, char *name, float *var, int step, int lifetime, int start) {
|
|
Base *base;
|
|
if (dBase==NULL) {
|
|
base=&database;
|
|
} else {
|
|
base=(Base *)dBase;
|
|
}
|
|
return (DataSet *) CreateSet(base, name, var, step, lifetime, start);
|
|
}
|
|
|
|
int DataSetStep(DataSet *set, int step) {
|
|
Set *s;
|
|
|
|
ERR_P(set);
|
|
ERR_I(step-1); /* step > 0 */
|
|
s = (Set *)set;
|
|
s->step = step;
|
|
return 0;
|
|
OnError: return -1;
|
|
}
|
|
|
|
int DataSetLifetime(DataSet *set, int lifetime) {
|
|
Set *s;
|
|
|
|
ERR_P(set);
|
|
s = (Set *)set;
|
|
s->lifetime = lifetime;
|
|
return 0;
|
|
OnError: return -1;
|
|
}
|
|
|
|
Run *InsertRun(Set *s, int time) {
|
|
Run *r, *next, *last;
|
|
|
|
NEW(r, Run);
|
|
r->next = s->runs;
|
|
s->runs = r;
|
|
r->step = s->step;
|
|
s->nRuns++;
|
|
if (s->nRuns * s->step > s->lifetime) {
|
|
next=r->next;
|
|
last=r;
|
|
while (next!=NULL && next->endTime > time - s->lifetime) {
|
|
last = next;
|
|
next = last->next;
|
|
}
|
|
while (next!=NULL) {
|
|
last->next = next->next;
|
|
FREE(next);
|
|
s->nRuns--;
|
|
next = last->next;
|
|
}
|
|
}
|
|
return r;
|
|
OnError:
|
|
return NULL;
|
|
}
|
|
|
|
int Put(Set *set, int time, float value) {
|
|
Run *r;
|
|
int t, try = 1;
|
|
int size;
|
|
float last;
|
|
|
|
ERR_P(set);
|
|
if (value == DATA_UNDEF) return 0;
|
|
r = set->runs;
|
|
if (r == NULL || r->step != set->step || r->size+3 > RUN_SIZE) {
|
|
ERR_P(r = InsertRun(set, time));
|
|
r->startTime = time;
|
|
r->endTime = time - r->step;
|
|
size = 0;
|
|
t = 1;
|
|
} else {
|
|
size = r->size;
|
|
t = (time - r->endTime) / r->step;
|
|
last = r->data[size-1];
|
|
}
|
|
if (t<0) {
|
|
if (t<-1) {
|
|
logfileOut(LOG_MAIN, "%s %d <? %d\n", set->set.name, time, r->endTime);
|
|
ERR_MSG("back in time not possible");
|
|
}
|
|
t=0;
|
|
}
|
|
if (t == 0) {
|
|
InsSum(&set->sum, time, value);
|
|
} else {
|
|
if (size % 2) {
|
|
PutSum(&set->sum, r->data+size-1); size++;
|
|
r->endTime += r->step;
|
|
t--;
|
|
}
|
|
if (t > 2) {
|
|
r->data[size]=t-1; size++;
|
|
r->data[size]=DATA_UNDEF; size++;
|
|
set->sum.reset = 1;
|
|
r->endTime += r->step * (t-1);
|
|
t=1;
|
|
}
|
|
InsSum(&set->sum, time, value);
|
|
if (t % 2) {
|
|
r->data[size]=value; size++; /* put a provisory value */
|
|
r->endTime += r->step;
|
|
} else if (t == 2) {
|
|
PutSum(&set->sum, r->data+size); size+=2;
|
|
r->endTime += r->step * 2;
|
|
}
|
|
}
|
|
r->size = size;
|
|
return 0;
|
|
OnError:
|
|
return -1;
|
|
}
|
|
|
|
int DataPut(DataSet *set, int time, float value) {
|
|
return Put((Set *)set, time, value);
|
|
}
|
|
|
|
int DataPutAll(DataBase *base, int time) {
|
|
Set *s;
|
|
|
|
if (base == NULL) {
|
|
s=database.head;
|
|
} else {
|
|
s=((Base *)base)->head;
|
|
}
|
|
while (s!=NULL) {
|
|
if (s->var!=NULL) {
|
|
ERR_I(Put(s, time, *s->var));
|
|
}
|
|
s=s->next;
|
|
}
|
|
return 0;
|
|
OnError:
|
|
return -1;
|
|
}
|
|
|
|
int Start(Set *s) {
|
|
Run *r;
|
|
int t1, t2;
|
|
|
|
r = s->runs;
|
|
t1 = s->start;
|
|
if (r != NULL) {
|
|
t2 = r->endTime - s->lifetime;
|
|
if (t1 < t2) {
|
|
while (r != NULL) {
|
|
t1 = r->startTime;
|
|
r = r->next;
|
|
}
|
|
if (t1 > t2) {
|
|
t1 = t2;
|
|
}
|
|
}
|
|
}
|
|
return t1;
|
|
}
|
|
|
|
void FreeBase(Base *base) {
|
|
Set *s, *sFree;
|
|
Run *r, *rFree;
|
|
|
|
s = base->head;
|
|
while (s != NULL) {
|
|
r = s->runs;
|
|
while (r != NULL) {
|
|
rFree = r;
|
|
r = r->next;
|
|
FREE(rFree);
|
|
}
|
|
sFree=s;
|
|
s = s->next;
|
|
FREE(sFree);
|
|
}
|
|
}
|
|
|
|
int GetSet(Set *s, int startTime, int endTime, int size, float *data) {
|
|
Run *r;
|
|
int t, tlim, tmin;
|
|
float d;
|
|
int i, idx;
|
|
Summary sum;
|
|
|
|
if (size<=0 || size%2 != 0) ERR_MSG("size must be even and positive");
|
|
ERR_P(s);
|
|
ERR_P(data);
|
|
|
|
r = s->runs;
|
|
|
|
ResetSum(&sum);
|
|
idx = size - 2;
|
|
tlim = (endTime - startTime) * idx / size + startTime;
|
|
|
|
while (r != NULL) {
|
|
if (startTime > r->endTime) break;
|
|
if (endTime >= r->startTime) {
|
|
t = r->endTime;
|
|
d = 0;
|
|
for (i = r->size - 1; i>=0; i--, t-=r->step) {
|
|
d = r->data[i];
|
|
if (d == DATA_UNDEF) {
|
|
i--;
|
|
t -= (int)(r->data[i] + 0.5) * r->step;
|
|
sum.reset = 1;
|
|
} else {
|
|
if (t < startTime) break;
|
|
if (t < endTime) {
|
|
while (t < tlim) {
|
|
PutSum(&sum, data+idx); idx-=2;
|
|
tlim = (endTime - startTime) * idx / size + startTime;
|
|
}
|
|
InsSum(&sum, t, d);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
r = r->next;
|
|
}
|
|
sum.reset = 1;
|
|
while (idx >= 0) {
|
|
PutSum(&sum, data+idx); idx-=2;
|
|
}
|
|
return 0;
|
|
OnError:
|
|
return -1;
|
|
}
|
|
|
|
void Scan(void *sData, char *line) {
|
|
Set *set;
|
|
Run *run;
|
|
Base *base;
|
|
char str[64], nam[64];
|
|
int l, iret, hh, mm, ss;
|
|
float num;
|
|
int tim, tshift, t0;
|
|
|
|
base=((ScanData *)sData)->base;
|
|
tim=((ScanData *)sData)->tim;
|
|
|
|
/* read time */
|
|
l=0; iret=sscanf(line, "%d:%d:%d%n", &hh, &mm, &ss, &l); line+=l;
|
|
if (iret!=3) return;
|
|
tim+=hh*3600+mm*60+ss;
|
|
if (tim < ((ScanData *)sData)->from || tim > ((ScanData *)sData)->to) return;
|
|
|
|
set=NULL;
|
|
l=0; iret=sscanf(line, "%64s%n", str, &l); line+=l;
|
|
while (iret==1) {
|
|
if (str[0] >= 'A') {
|
|
str_copy(nam, str);
|
|
l=0; iret=sscanf(line, "%64s%n", str, &l); line+=l;
|
|
if (iret==1) {
|
|
iret=sscanf(str, "%f", &num);
|
|
if (iret==1) {
|
|
tshift = 0;
|
|
if (0 != strcmp(nam, "_")) {
|
|
set=FindSet(base, nam);
|
|
if (set!=NULL) tshift = 1;
|
|
}
|
|
if (set!=NULL && tim < set->end) {
|
|
if (tshift) {
|
|
t0 = tim - ((ScanData *)sData)->stdStep*2;
|
|
run = set->runs;
|
|
if (run != NULL && run->endTime >= t0) {
|
|
t0 = run->endTime;
|
|
}
|
|
t0 += set->step;
|
|
if (t0 > tim) t0 = tim;
|
|
Put(set, t0, num);
|
|
} else {
|
|
Put(set, tim, num);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
l=0; iret=sscanf(line, "%64s%n", str, &l); line+=l;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Load(Base *base, int from, int to, int stdStep) {
|
|
Set *set;
|
|
ScanData scanData;
|
|
int t, date;
|
|
|
|
scanData.base = base;
|
|
scanData.stdStep = stdStep;
|
|
scanData.from = from;
|
|
scanData.to = to;
|
|
|
|
/* round down "from" and "to" to 00:00 local time */
|
|
from = from - (from % (24*3600));
|
|
to = to - (to % (24*3600));
|
|
|
|
for (t=from; t<=to; t+=24*3600) {
|
|
scanData.tim=t;
|
|
logfileScan(mycDate(t), Scan, &scanData);
|
|
}
|
|
}
|
|
|
|
int DataGetMult(char *names, int startTime, int endTime, int step, int stdStep, float *data, int data_len) {
|
|
Base base;
|
|
Set *set, *s;
|
|
int stp, minStep, period, s1;
|
|
char *nams, nam[32];
|
|
int p, l, n, i, j, siz1, siz2, halfsiz, start;
|
|
|
|
base.head = NULL;
|
|
period = endTime - startTime;
|
|
if (period<=0) period=1;
|
|
n=0; nams = names;
|
|
while (nams != NULL) { /* count names */
|
|
nams = str_split(nam, nams, ' ');
|
|
if (nam[0] != '\0') n++;
|
|
}
|
|
|
|
stp=step;
|
|
if (stp<stdStep) stp=stdStep;
|
|
nams=names;
|
|
while (nams!=NULL) { /* create sets for data not in memory */
|
|
nams=str_split(nam, nams, ' ');
|
|
if (nam[0]!='\0') {
|
|
set=FindSet(&database, nam);
|
|
if (set != NULL) {
|
|
start = Start(set);
|
|
} else {
|
|
start = endTime;
|
|
}
|
|
if (set == NULL || start > startTime) {
|
|
set=CreateSet(&base, nam, NULL, stp, period, startTime);
|
|
if (set != NULL) set->end = start;
|
|
}
|
|
}
|
|
}
|
|
if (base.head != NULL) { /* load if needed */
|
|
Load(&base, startTime, endTime, stdStep);
|
|
}
|
|
p=0;
|
|
nams=names;
|
|
while (nams!=NULL) {
|
|
nams=str_split(nam, nams, ' ');
|
|
if (nam[0]!='\0') {
|
|
s = FindSet(&database, nam);
|
|
set = FindSet(&base, nam);
|
|
s1 = startTime;
|
|
if (s == NULL) {
|
|
if (set == NULL) {
|
|
s1 = 0;
|
|
} else {
|
|
s = set;
|
|
}
|
|
} else {
|
|
minStep = s->step;
|
|
if (set != NULL) {
|
|
s1 = Start(s);
|
|
if (s1 >= endTime) {
|
|
s = set;
|
|
s1 = startTime;
|
|
} else if (s1 < startTime || s1 <= Start(set)) {
|
|
s1 = startTime;
|
|
}
|
|
}
|
|
}
|
|
if (s1 == 0) { /* empty array */
|
|
data[p++]=0;
|
|
} else {
|
|
minStep = s->step;
|
|
stp = step;
|
|
halfsiz = period / (2 * stp) + 1;
|
|
if (startTime + minStep * halfsiz * 2 > endTime) {
|
|
if (stp < minStep) stp = minStep;
|
|
halfsiz = period / (2 * stp) + 1;
|
|
if (halfsiz * 2 + n > data_len) { /* check if enough space */
|
|
halfsiz = ((data_len - p) / n - 1) / 2;
|
|
}
|
|
}
|
|
siz1 = (s1 - startTime) * halfsiz / period * 2;
|
|
siz2 = halfsiz * 2 - siz1;
|
|
s1 = startTime + (siz1 * period + halfsiz) / halfsiz / 2;
|
|
p++;
|
|
if (siz1 > 0) {
|
|
halfsiz = (s1 - startTime) / set->step / 2;
|
|
if (halfsiz * 2 < siz1 && halfsiz > 0) {
|
|
ERR_I(GetSet(set, startTime, s1, halfsiz*2, data+p));
|
|
j = siz1 - 1;
|
|
for (i = halfsiz * 2-1; i >= 0; i--) { /* expand data */
|
|
while (j > siz1 / 2 * i / halfsiz) {
|
|
data[p+j]=DATA_GAP; j--;
|
|
}
|
|
data[p+j]=data[p+i]; j--;
|
|
}
|
|
} else {
|
|
ERR_I(GetSet(set, startTime, s1, siz1, data+p));
|
|
}
|
|
l=siz1;
|
|
} else {
|
|
l=0;
|
|
}
|
|
if (siz2 > 0) {
|
|
ERR_I(GetSet(s, s1, endTime, siz2, data+p+siz1));
|
|
l+=siz2;
|
|
}
|
|
data[p-1]=l;
|
|
p+=l;
|
|
}
|
|
n--;
|
|
}
|
|
}
|
|
FreeBase(&base);
|
|
return p;
|
|
OnError:
|
|
return -1;
|
|
}
|