00001
00031 #include <ctype.h>
00032 #include <math.h>
00033 #include "platform.h"
00034 #include "aggregate.h"
00035 #include "output.h"
00036 #include "find.h"
00037
00041 AGGREGATION *aggregate_mkgroup(char *aggregator,
00042 char *group_expression)
00043 {
00044 AGGREGATOR op = AGGR_NOP;
00045 AGGREGATION *result=NULL;
00046 char aggrop[9], aggrval[257], *aggrpart;
00047 char aggrprop[33], aggrunit[9];
00048 unsigned char flags=0x00;
00049
00050
00051 OBJECT *obj;
00052 PROPERTY *pinfo=NULL;
00053 FINDPGM *pgm = NULL;
00054 FINDLIST *list=NULL;
00055
00056
00057 UNIT *from_unit = NULL, *to_unit = NULL;
00058 double scale = 1.0;
00059
00060 if (sscanf(aggregator,"%8[A-Za-z0-9_](%256[][A-Za-z0-9_.])",aggrop,aggrval)!=2 &&
00061 (flags|=AF_ABS,
00062 sscanf(aggregator,"%8[A-Za-z0-9_]|%256[][A-Za-z0-9_.]|",aggrop,aggrval)!=2
00063 ))
00064 {
00065 output_error("aggregate group '%s' is not valid", aggregator);
00066
00067
00068
00069
00070 errno = EINVAL;
00071 return NULL;
00072 }
00073
00074
00075 pgm = find_mkpgm(group_expression);
00076 if(pgm != NULL){
00077 list = find_runpgm(NULL,pgm);
00078 if(list != NULL){
00079 obj = find_first(list);
00080 if(obj != NULL){
00081 pinfo = class_find_property(obj->oclass,aggrval);
00082 if (pinfo==NULL)
00083 {
00084 aggrpart = strrchr(aggrval,'.');
00085
00086 if (aggrpart!=NULL)
00087 *aggrpart++ = '\0';
00088 else
00089 aggrpart="";
00090 }
00091 else
00092 {
00093 aggrpart="";
00094 }
00095 }
00096 }
00097 }
00098
00099
00100 if(sscanf(aggrval, "%32[A-Za-z0-9_][%[A-Za-z0-9_]]", aggrprop, aggrunit) == 2){
00101 to_unit = unit_find(aggrunit);
00102 if(to_unit == NULL){
00103 output_error("aggregate group '%s' has invalid units (%s)", aggrval, aggrunit);
00104
00105
00106
00107
00108 errno = EINVAL;
00109 return NULL;
00110 }
00111 strcpy(aggrval, aggrprop);
00112 }
00113
00114 if (stricmp(aggrop,"min")==0) op=AGGR_MIN;
00115 else if (stricmp(aggrop,"max")==0) op=AGGR_MAX;
00116 else if (stricmp(aggrop,"avg")==0) op=AGGR_AVG;
00117 else if (stricmp(aggrop,"std")==0) op=AGGR_STD;
00118 else if (stricmp(aggrop,"sum")==0) op=AGGR_SUM;
00119 else if (stricmp(aggrop,"prod")==0) op=AGGR_SUM;
00120 else if (stricmp(aggrop,"mbe")==0) op=AGGR_MBE;
00121 else if (stricmp(aggrop,"mean")==0) op=AGGR_MEAN;
00122 else if (stricmp(aggrop,"var")==0) op=AGGR_VAR;
00123 else if (stricmp(aggrop,"skew")==0) op=AGGR_SKEW;
00124 else if (stricmp(aggrop,"kur")==0) op=AGGR_KUR;
00125 else if (stricmp(aggrop,"count")==0) op=AGGR_COUNT;
00126 else if (stricmp(aggrop,"gamma")==0) op=AGGR_GAMMA;
00127 else
00128 {
00129 output_error("aggregate group '%s' does not use a known aggregator", aggregator);
00130
00131
00132
00133
00134 errno = EINVAL;
00135 return NULL;
00136 }
00137 if (op!=AGGR_NOP)
00138 {
00139 AGGRPART part=AP_NONE;
00140
00141 if (pgm==NULL)
00142 {
00143 output_error("aggregate group expression '%s' failed", group_expression);
00144
00145
00146
00147
00148 errno = EINVAL;
00149 return NULL;
00150 }
00151 else
00152 {
00153 PGMCONSTFLAGS flags = find_pgmconstants(pgm);
00154
00155
00156 if ((flags&CF_CLASS)!=CF_CLASS)
00157 {
00158 output_error("aggregate group expression '%s' does not result in a set with a fixed class", group_expression);
00159
00160
00161
00162
00163
00164 errno = EINVAL;
00165 free(pgm);
00166 return NULL;
00167 }
00168 else
00169 {
00170 if (list==NULL)
00171 {
00172 output_error("aggregate group expression '%s' does not result is a usable object list", group_expression);
00173
00174
00175
00176
00177 free(pgm);
00178 errno=EINVAL;
00179 return NULL;
00180 }
00181
00182 if (obj==NULL)
00183 {
00184 output_error("aggregate group expression '%s' results is an empty object list", group_expression);
00185
00186
00187
00188
00189 free(pgm);
00190 free(list);
00191 errno=EINVAL;
00192 return NULL;
00193 }
00194 pinfo = class_find_property(obj->oclass,aggrval);
00195 if (pinfo==NULL)
00196 {
00197 output_error("aggregate group property '%s' is not found in the objects satisfying search criteria '%s'", aggrval, group_expression);
00198
00199
00200
00201
00202 errno = EINVAL;
00203 free(pgm);
00204 free(list);
00205 return NULL;
00206 }
00207 else if (pinfo->ptype==PT_double)
00208 {
00209 if (strcmp(aggrpart,"")!=0)
00210 {
00211 output_error("aggregate group property '%s' cannot have part '%s'", aggrval, aggrpart);
00212
00213
00214
00215
00216 errno = EINVAL;
00217 free(pgm);
00218 free(list);
00219 return NULL;
00220 }
00221 part = AP_NONE;
00222 }
00223 else if (pinfo->ptype==PT_complex)
00224 {
00225 if (strcmp(aggrpart,"real")==0)
00226 part = AP_REAL;
00227 else if (strcmp(aggrpart,"imag")==0)
00228 part = AP_IMAG;
00229 else if (strcmp(aggrpart,"mag")==0)
00230 part = AP_MAG;
00231 else if (strcmp(aggrpart,"ang")==0)
00232 part = AP_ANG;
00233 else if (strcmp(aggrpart,"arg")==0)
00234 part = AP_ARG;
00235 else
00236 {
00237 output_error("aggregate group property '%s' cannot have part '%s'", aggrval, aggrpart);
00238
00239
00240
00241
00242 errno = EINVAL;
00243 free(pgm);
00244 free(list);
00245 return NULL;
00246 }
00247 }
00248 else
00249 {
00250 output_error("aggregate group property '%s' cannot be aggregated", aggrval);
00251
00252
00253
00254
00255 errno = EINVAL;
00256 free(pgm);
00257 free(list);
00258 return NULL;
00259 }
00260 from_unit = pinfo->unit;
00261 if(to_unit != NULL && from_unit == NULL){
00262 output_error("aggregate group property '%s' is unitless and cannot be converted", aggrval);
00263
00264
00265
00266
00267 errno = EINVAL;
00268 free(pgm);
00269 free(list);
00270 return NULL;
00271 }
00272 if (from_unit != NULL && to_unit != NULL && unit_convert_ex(from_unit, to_unit, &scale) == 0){
00273 output_error("aggregate group property '%s' cannot use units '%s'", aggrval, aggrunit);
00274
00275
00276
00277
00278
00279 errno = EINVAL;
00280 free(pgm);
00281 free(list);
00282 return NULL;
00283 }
00284 }
00285 }
00286
00287
00288 result = (AGGREGATION*)malloc(sizeof(AGGREGATION));
00289 if (result!=NULL)
00290 {
00291 result->op = op;
00292 result->group = pgm;
00293 result->pinfo = pinfo;
00294 result->part = part;
00295 result->last = list;
00296 result->next = NULL;
00297 result->flags = flags;
00298 result->punit = to_unit;
00299 result->scale = scale;
00300 }
00301 else
00302 {
00303 errno=ENOMEM;
00304 free(pgm);
00305 free(list);
00306 return NULL;
00307 }
00308 }
00309
00310 return result;
00311 }
00312
00313 double mag(complex *x)
00314 {
00315 return sqrt(x->r*x->r + x->i*x->i);
00316 }
00317
00318 double arg(complex *x)
00319 {
00320 return (x->r==0) ? (x->i>0 ? PI/2 : (x->i==0 ? 0 : -PI/2)) : ((x->i>0) ? (x->r>0 ? atan(x->i/x->r) : PI-atan(x->i/x->r)) : (x->r>0 ? -atan(x->i/x->r) : PI+atan(x->i/x->r)));
00321 }
00322
00325 double aggregate_value(AGGREGATION *aggr)
00326 {
00327 OBJECT *obj;
00328 double numerator=0, denominator=0, secondary=0, third=0, fourth=0;
00329 double scale = (aggr->punit ? aggr->scale : 1.0);
00330
00331
00332 if ((aggr->group->constflags & CF_CONSTANT) != CF_CONSTANT){
00333 aggr->last = find_runpgm(NULL,aggr->group);
00334 }
00335
00336 for(obj = find_first(aggr->last); obj != NULL; obj = find_next(aggr->last, obj)){
00337 double value=0;
00338 double *pdouble = NULL;
00339 complex *pcomplex = NULL;
00340
00341
00342 if(obj->in_svc >= global_clock || obj->out_svc <= global_clock)
00343 continue;
00344
00345 switch (aggr->pinfo->ptype) {
00346 case PT_complex:
00347 pcomplex = object_get_complex(obj,aggr->pinfo);
00348 if (pcomplex!=NULL)
00349 {
00350 switch (aggr->part) {
00351 case AP_REAL: value=pcomplex->r; break;
00352 case AP_IMAG: value=pcomplex->i; break;
00353 case AP_MAG: value=mag(pcomplex); break;
00354 case AP_ARG: value=arg(pcomplex); break;
00355 case AP_ANG: value=arg(pcomplex)*180/PI; break;
00356 default: pcomplex = NULL; break;
00357 }
00358 }
00359 break;
00360 case PT_double:
00361 pdouble = object_get_double(obj,aggr->pinfo);
00362 if (pdouble!=NULL)
00363 value = *pdouble;
00364 break;
00365 default:
00366 break;
00367 }
00368
00369 if (pdouble!=NULL || pcomplex!=NULL)
00370 {
00371 if ((aggr->flags&AF_ABS)==AF_ABS) value=fabs(value);
00372 switch (aggr->op) {
00373 case AGGR_MIN:
00374 if (value<numerator || denominator==0) numerator=value;
00375 denominator = 1;
00376 break;
00377 case AGGR_MAX:
00378 if (value>numerator || denominator==0) numerator=value;
00379 denominator = 1;
00380 break;
00381 case AGGR_COUNT:
00382 numerator++;
00383 denominator=1;
00384 break;
00385 case AGGR_MBE:
00386 denominator++;
00387 numerator += value;
00388 secondary += (value-secondary)/denominator;
00389 break;
00390 case AGGR_AVG:
00391 case AGGR_MEAN:
00392 numerator+=value;
00393 denominator++;
00394 break;
00395 case AGGR_SUM:
00396 numerator+=value;
00397 denominator = 1;
00398 break;
00399 case AGGR_PROD:
00400 numerator*=value;
00401 denominator = 1;
00402 break;
00403 case AGGR_GAMMA:
00404 denominator+=log(value);
00405 if (numerator==0 || secondary>value)
00406 secondary = value;
00407 numerator++;
00408 break;
00409 case AGGR_STD:
00410 case AGGR_VAR:
00411 denominator++;
00412
00413
00414 { double delta = value-secondary;
00415 secondary += delta/denominator;
00416 numerator += delta*(value-secondary);
00417 }
00418 break;
00419 case AGGR_SKEW:
00420 case AGGR_KUR:
00421 default:
00422 break;
00423 }
00424 }
00425 }
00426 switch (aggr->op) {
00427 double v = 0.0, t = 0.0, m = 0.0;
00428 case AGGR_GAMMA:
00429 return 1 + numerator/(denominator-numerator*log(secondary));
00430 case AGGR_STD:
00431 return sqrt(numerator/(denominator-1)) * scale;
00432 case AGGR_MBE:
00433 return numerator/denominator - secondary;
00434 case AGGR_SKEW:
00436 throw_exception("skewness aggregation is not implemented");
00437
00438
00439
00440
00441 case AGGR_KUR:
00443 throw_exception("kurtosis aggregation is not implemented");
00444
00445
00446
00447
00448 default:
00449 return numerator/denominator * scale;
00450 }
00451 }