00001
00010 #include <stdlib.h>
00011 #include <stdio.h>
00012 #include <errno.h>
00013 #include <math.h>
00014 #include <float.h>
00015
00016 #include "histogram.h"
00017
00018
00019 CLASS* histogram::oclass = NULL;
00020 CLASS* histogram::pclass = NULL;
00021 histogram *histogram::defaults = NULL;
00022
00024
00026
00027 void new_histogram(MODULE *mod){
00028 new histogram(mod);
00029 }
00030
00031 histogram::histogram(MODULE *mod)
00032 {
00033 if(oclass == NULL)
00034 {
00035 #ifdef _DEBUG
00036 gl_debug("construction histogram class");
00037 #endif
00038 oclass = gl_register_class(mod,"histogram",sizeof(histogram), PC_PRETOPDOWN);
00039 if (oclass==NULL)
00040 throw "unable to register class histogram";
00041 else
00042 oclass->trl = TRL_PROTOTYPE;
00043
00044 if(gl_publish_variable(oclass,
00045 PT_char1024, "filename", PADDR(filename),PT_DESCRIPTION,"the name of the file to write",
00046 PT_char8, "filetype", PADDR(ftype),PT_DESCRIPTION,"the format to output a histogram in",
00047 PT_char32, "mode", PADDR(mode),PT_DESCRIPTION,"the mode of file output",
00048 PT_char1024, "group", PADDR(group),PT_DESCRIPTION,"the GridLAB-D group expression to use for this histogram",
00049 PT_char1024, "bins", PADDR(bins),PT_DESCRIPTION,"the specific bin values to use",
00050 PT_char256, "property", PADDR(property),PT_DESCRIPTION,"the property to sample",
00051 PT_double, "min", PADDR(min),PT_DESCRIPTION,"the minimum value of the auto-sized bins to use",
00052 PT_double, "max", PADDR(max),PT_DESCRIPTION,"the maximum value of the auto-sized bins to use",
00053 PT_double, "samplerate[s]", PADDR(sampling_interval),PT_DESCRIPTION,"the rate at which samples are read",
00054 PT_double, "countrate[s]", PADDR(counting_interval),PT_DESCRIPTION,"the reate at which bins are counted and written",
00055 PT_int32, "bin_count", PADDR(bin_count),PT_DESCRIPTION,"the number of auto-sized bins to use",
00056 PT_int32, "limit", PADDR(limit),PT_DESCRIPTION,"the number of samples to write",
00057 NULL) < 1) GL_THROW("unable to publish properties in %s",__FILE__);
00058 defaults = this;
00059 memset(filename, 0, 1025);
00060 memset(group, 0, 1025);
00061 memset(bins, 0, 1025);
00062 memset(property, 0, 33);
00063 min = 0;
00064 max = -1;
00065 bin_count = -1;
00066 sampling_interval = -1.0;
00067 counting_interval = -1.0;
00068 limit = 0;
00069 bin_list = NULL;
00070 group_list = NULL;
00071 binctr = NULL;
00072 prop_ptr = NULL;
00073 next_count = t_count = next_sample = t_sample = TS_ZERO;
00074 strcpy(mode, "file");
00075 flags[0]='w';
00076 }
00077 }
00078
00079 int histogram::create()
00080 {
00081 memcpy(this, defaults, sizeof(histogram));
00082 return 1;
00083 }
00084
00085
00086
00087 void eat_white(char **pos){
00088 while(**pos == ' ' || **pos == '\t')
00089 ++(*pos);
00090 }
00091
00096 int parse_bin_val(char *tok, BIN *bin){
00097 char *pos = tok;
00098 int low_set = 0, high_set = 0;
00099
00100 eat_white(&pos);
00101
00102
00103 if(pos[0] == '['){
00104 ++pos;
00105 bin->low_inc = 1;
00106 } else if (pos[0] == '('){
00107 ++pos;
00108 bin->low_inc = 0;
00109 } else {
00110 bin->low_inc = 1;
00111 }
00112
00113
00114 eat_white(&pos);
00115
00116
00117 if(isdigit(*pos)){
00118 bin->low_val = strtod(pos, &pos);
00119 low_set = 1;
00120 } else if(*pos == '.' && pos[1] == '.'){
00121 bin->low_val = -DBL_MAX;
00122 bin->low_inc = 0;
00123 } else if(*pos == '-') {
00124 bin->low_val = -DBL_MAX;
00125 bin->low_inc = 0;
00126
00127 }
00128
00129 eat_white(&pos);
00130
00131 if(*pos == '.' && pos[1] == '.'){
00132 pos+=2;
00133 } else if (*pos == '-'){
00134 ++pos;
00135 } else {
00136 gl_error("parse_bin failure");
00137 return 0;
00138 }
00139
00140 eat_white(&pos);
00141
00142 if(isdigit(*pos)){
00143 bin->high_val = strtod(pos, &pos);
00144 high_set = 1;
00145 if(low_set == 0)
00146 bin->high_inc = 1;
00147 } else {
00148 bin->high_val = DBL_MAX;
00149 }
00150
00151 if(*pos == 0 || *pos == '\n' || *pos == ','){
00152 return 1;
00153 } else if (*pos == ')'){
00154 bin->high_inc = 0;
00155 return 1;
00156 } else if (*pos == ']'){
00157 bin->high_inc = 1;
00158 return 1;
00159 }
00160 return 0;
00161 }
00162
00163 int parse_bin_enum(char *cptr, BIN *bin, PROPERTY *prop){
00164
00165 char *pos = cptr;
00166 KEYWORD *kw = NULL;
00167
00168 if(prop->keywords == NULL){
00169 gl_error("parse_bin_enum error: property has no keywords");
00170 return 0;
00171 }
00172
00173 eat_white(&pos);
00174
00175 for(kw = prop->keywords; kw != NULL; kw = kw->next){
00176 if(strcmp(kw->name, pos) == 0){
00177 bin->low_inc = bin->high_inc = 1;
00178 bin->low_val = bin->high_val = (double)(kw->value);
00179 return 1;
00180 }
00181 }
00182
00183 gl_error("parse_bin_enum error: unable to find property \'%s\'", pos);
00184 return 0;
00185 }
00186
00193 void histogram::test_for_complex(char *tprop, char *tpart){
00194
00195 if(sscanf(property.get_string(), "%[^.\n\t ].%s", tprop, tpart) == 2){
00196 if(0 == memcmp(tpart, "real", 4)){comp_part = REAL;}
00197 else if(0 == memcmp(tpart, "imag", 3)){comp_part = IMAG;}
00198 else if(0 == memcmp(tpart, "mag", 3)){comp_part = MAG;}
00199 else if(0 == memcmp(tpart, "ang", 3)){comp_part = ANG;}
00200 else {
00201 comp_part = NONE;
00202 throw("Unable to resolve complex part for \'%s\'", property.get_string());
00203 return;
00204 }
00205 strtok(property, ".");
00206 }
00207 }
00208
00215 int histogram::init(OBJECT *parent)
00216 {
00217 PROPERTY *prop = NULL;
00218 OBJECT *obj = OBJECTHDR(this);
00219 char tprop[64], tpart[8];
00220 int e = 0;
00221 TAPEFUNCS *tf = 0;
00222 tprop[0]=0;
00223 tpart[0] = 0;
00224
00225 if(parent == NULL)
00226 {
00227 OBJECT *group_obj = NULL;
00228 CLASS *oclass = NULL;
00229 if(group[0] == NULL){
00230 gl_error("Histogram has no parent and no group");
00231 return 0;
00232 }
00233 group_list = gl_find_objects(FL_GROUP,group.get_string());
00234 if(group_list == NULL){
00235 gl_error("Histogram group could not be parsed");
00236 return 0;
00237 }
00238 if(group_list->hit_count < 1){
00239 gl_error("Histogram group is an empty set");
00240 return 0;
00241 }
00242
00243
00244
00245 test_for_complex(tprop, tpart);
00246
00247 while(group_obj = gl_find_next(group_list, group_obj)){
00248 prop = gl_find_property(group_obj->oclass, property.get_string());
00249 if(prop == NULL){
00250 gl_error("Histogram group is unable to find prop '%s' in class '%s' for group '%s'", property.get_string(), group_obj->oclass->name, group.get_string());
00251 return 0;
00252 }
00253
00254 if (oclass == NULL){
00255 oclass = group_obj->oclass;
00256 prop_ptr = prop;
00257 }
00258 if(oclass != group_obj->oclass){
00259 prop_ptr = NULL;
00260 }
00261
00262 }
00263 } else {
00264
00265 test_for_complex(tprop, tpart);
00266
00267 prop = gl_find_property(parent->oclass, property.get_string());
00268
00269 if(prop == NULL){
00270 gl_error("Histogram parent '%s' of class '%s' does not contain property '%s'", parent->name ? parent->name : "(anon)", parent->oclass->name, property.get_string());
00271 return 0;
00272 } else {
00273 prop_ptr = prop;
00274 }
00275 }
00276
00277
00278 if(counting_interval > 0.0)
00279 next_count = gl_globalclock + counting_interval;
00280 if(sampling_interval > 0.0)
00281 next_sample = gl_globalclock + sampling_interval;
00282
00283
00284
00285 if((bin_count > 0) && (min < max))
00286 {
00287 int i=0;
00288 double range = max - min;
00289 double step = range/bin_count;
00290
00291 bin_list = (BIN *)gl_malloc(sizeof(BIN) * bin_count);
00292 if(bin_list == NULL){
00293 gl_error("Histogram malloc error: unable to alloc %i * %i bytes for %s", bin_count, sizeof(BIN), obj->name ? obj->name : "(anon. histogram)");
00294 return 0;
00295 }
00296 memset(bin_list, 0, sizeof(BIN) * bin_count);
00297 for(i = 0; i < bin_count; i++){
00298 bin_list[i].low_val = min + i * step;
00299 bin_list[i].high_val = bin_list[i].low_val + step;
00300 bin_list[i].low_inc = 1;
00301 bin_list[i].high_inc = 0;
00302 }
00303 bin_list[i-1].high_inc = 1;
00304 binctr = (int *)gl_malloc(sizeof(int) * bin_count);
00305 memset(binctr, 0, sizeof(int) * bin_count);
00306 }
00307 else if (bins[0] != 0)
00308
00309
00310
00311
00312 {
00313 char *cptr = bins;
00314 char bincpy[1025];
00315 int i = 0;
00316 bin_count = 1;
00317
00318
00319 for(cptr = bins; *cptr != 0; ++cptr){
00320 if(*cptr == ',' && cptr[1] != 0){
00321 ++bin_count;
00322 }
00323
00324 }
00325 bin_list = (BIN *)gl_malloc(sizeof(BIN) * bin_count);
00326 if(bin_list == NULL){
00327 gl_error("Histogram malloc error: unable to alloc %i * %i bytes for %s", bin_count, sizeof(BIN), obj->name ? obj->name : "(anon. histogram)");
00328 return 0;
00329 }
00330 memset(bin_list, 0, sizeof(BIN) * bin_count);
00331 memcpy(bincpy, bins, 1024);
00332 cptr = strtok(bincpy, ",\t\r\n\0");
00333 if(prop->ptype == PT_complex || prop->ptype == PT_double || prop->ptype == PT_int16 || prop->ptype == PT_int32 || prop->ptype == PT_int64 || prop->ptype == PT_float || prop->ptype == PT_real){
00334 for(i = 0; i < bin_count && cptr != NULL; ++i){
00335 if(parse_bin_val(cptr, bin_list+i) == 0){
00336 gl_error("Histogram unable to parse \'%s\' in %s", cptr, obj->name ? obj->name : "(unnamed histogram)");
00337 return 0;
00338 }
00339 cptr = strtok(NULL, ",\t\r\n\0");
00340 }
00341 } else if (prop->ptype == PT_enumeration || prop->ptype == PT_set){
00342 for(i = 0; i < bin_count && cptr != NULL; ++i){
00343 if(parse_bin_enum(cptr, bin_list+i, prop) == 0){
00344 gl_error("Histogram unable to parse \'%s\' in %s", cptr, obj->name ? obj->name : "(unnamed histogram)");
00345 return 0;
00346 }
00347 cptr = strtok(NULL, ",\t\r\n\0");
00348 }
00349 }
00350
00351 if(i < bin_count){
00352 gl_error("Histrogram encountered a problem parsing bins for %s", obj->name ? obj->name : "(unnamed histogram)");
00353 return 0;
00354 }
00355 binctr = (int *)malloc(sizeof(int) * bin_count);
00356 memset(binctr, 0, sizeof(int) * bin_count);
00357 } else {
00358 gl_error("Histogram has neither bins or a bin range to work with");
00359 return 0;
00360 }
00361
00362
00363
00364
00365
00366
00367 strcpy(fname,filename);
00368
00369
00370
00371 if (strcmp(fname,"")==0)
00372
00373
00374 sprintf(fname,"%s-%d.%s",obj->parent->oclass->name,obj->parent->id, ftype.get_string());
00375
00376
00377 tf = get_ftable(mode);
00378 if(tf == NULL)
00379 return 0;
00380 ops = tf->histogram;
00381 if(ops == NULL)
00382 return 0;
00383 return ops->open(this, fname, flags);
00384 }
00385
00386 int histogram::feed_bins(OBJECT *obj){
00387 double value = 0.0;
00388 complex cval = 0.0;
00389 int64 ival = 0;
00390 int i = 0;
00391
00392 switch(prop_ptr->ptype){
00393 case PT_complex:
00394 cval = (prop_ptr ? *gl_get_complex(obj, prop_ptr) : *gl_get_complex_by_name(obj, property) );
00395 switch(this->comp_part){
00396 case REAL:
00397 value = cval.Re();
00398 break;
00399 case IMAG:
00400 value = cval.Im();
00401 break;
00402 case MAG:
00403 value = cval.Mag();
00404 break;
00405 case ANG:
00406 value = cval.Arg();
00407 break;
00408 default:
00409 gl_error("Complex property with no part defined in %s", (obj->name ? obj->name : "(unnamed)"));
00410 }
00411 ival = 1;
00412
00413 case PT_double:
00414 if(ival == 0)
00415 value = (prop_ptr ? *gl_get_double(obj, prop_ptr) : *gl_get_double_by_name(obj, property.get_string()) );
00416 for(i = 0; i < bin_count; ++i){
00417 if(value > bin_list[i].low_val && value < bin_list[i].high_val){
00418 ++binctr[i];
00419 } else if(bin_list[i].low_inc && bin_list[i].low_val == value){
00420 ++binctr[i];
00421 } else if(bin_list[i].high_inc && bin_list[i].high_val == value){
00422 ++binctr[i];
00423 }
00424 }
00425 break;
00426 case PT_int16:
00427 ival = (prop_ptr ? *gl_get_int16(obj, prop_ptr) : *gl_get_int16_by_name(obj, property.get_string()) );
00428 value = 1.0;
00429 case PT_int32:
00430 if(value == 0.0){
00431 ival = (prop_ptr ? *gl_get_int32(obj, prop_ptr) : *gl_get_int32_by_name(obj, property.get_string()) );
00432 value = 1.0;
00433 }
00434 case PT_int64:
00435 if(value == 0.0){
00436 ival = (prop_ptr ? *gl_get_int64(obj, prop_ptr) : *gl_get_int64_by_name(obj, property.get_string()) );
00437 value = 1.0;
00438 }
00439 case PT_enumeration:
00440 if(value == 0.0){
00441 ival = (prop_ptr ? *gl_get_enum(obj, prop_ptr) : *gl_get_enum_by_name(obj, property.get_string()) );
00442 value = 1.0;
00443 }
00444 case PT_set:
00445 if(value == 0.0){
00446 ival = (prop_ptr ? *gl_get_set(obj, prop_ptr) : *gl_get_set_by_name(obj, property.get_string()) );
00447 value = 1.0;
00448 }
00449
00450
00451 for(i = 0; i < bin_count; ++i){
00452 if(ival > bin_list[i].low_val && ival < bin_list[i].high_val){
00453 ++binctr[i];
00454 } else if(bin_list[i].low_inc && bin_list[i].low_val == ival){
00455 ++binctr[i];
00456 } else if(bin_list[i].high_inc && bin_list[i].high_val == ival){
00457 ++binctr[i];
00458 }
00459 }
00460 break;
00461 }
00462
00463 return 0;
00464 }
00465
00466 TIMESTAMP histogram::sync(TIMESTAMP t0, TIMESTAMP t1)
00467 {
00468 int i = 0;
00469 double value = 0.0;
00470 OBJECT *obj = OBJECTHDR(this);
00471
00472 if((sampling_interval == -1.0 && t_count > t1) ||
00473 sampling_interval == 0.0 ||
00474 (sampling_interval > 0.0 && t1 >= next_sample))
00475 {
00476 if(group_list == NULL){
00477 feed_bins(obj->parent);
00478 } else {
00479 OBJECT *obj = gl_find_next(group_list, NULL);
00480 for(; obj != NULL; obj = gl_find_next(group_list, obj)){
00481 feed_bins(obj);
00482 }
00483 }
00484 t_sample = t1;
00485 if(sampling_interval > 0.0001){
00486 next_sample = t1 + (int64)(sampling_interval/TS_SECOND);
00487 } else {
00488 next_sample = TS_NEVER;
00489 }
00490 }
00491
00492 if((counting_interval == -1.0 && t_count < t1) ||
00493 counting_interval == 0.0 ||
00494 (counting_interval > 0.0 && t1 >= next_count))
00495 {
00496 char line[1025];
00497 char ts[64];
00498 int off=0, i=0;
00499 DATETIME dt;
00500
00501
00502 gl_localtime(t1,&dt);
00503 gl_strtime(&dt,ts,64);
00504
00505
00506 for(i = 0; i < bin_count; ++i){
00507 off += sprintf(line+off, "%i", binctr[i]);
00508 if(i != bin_count){
00509 off += sprintf(line+off, ",");
00510 }
00511 }
00512
00513
00514 ops->write(this, ts, line);
00515
00516
00517 for(i = 0; i < bin_count; ++i){
00518 binctr[i] = 0;
00519 }
00520 t_count = t1;
00521 if(counting_interval > 0){
00522 next_count = t_count + (int64)(counting_interval/TS_SECOND);
00523 } else {
00524 next_count = TS_NEVER;
00525 }
00526
00527
00528 if(--limit < 1){
00529 ops->close(this);
00530 next_count = TS_NEVER;
00531 next_sample = TS_NEVER;
00532 }
00533 }
00534 return ( next_count < next_sample && counting_interval > 0.0 ? next_count : next_sample );
00535 }
00536
00537 int histogram::isa(char *classname)
00538 {
00539 return strcmp(classname,"histogram")==0;
00540 }
00541
00542
00544
00546
00554 EXPORT int create_histogram(OBJECT **obj, OBJECT *parent)
00555 {
00556 try
00557 {
00558 *obj = gl_create_object(histogram::oclass);
00559 if (*obj!=NULL)
00560 {
00561 histogram *my = OBJECTDATA(*obj,histogram);
00562 gl_set_parent(*obj,parent);
00563 return my->create();
00564 }
00565 }
00566 catch (char *msg)
00567 {
00568 gl_error("create_histogram: %s", msg);
00569 }
00570 return 0;
00571 }
00572
00573 EXPORT int init_histogram(OBJECT *obj)
00574 {
00575 histogram *my = OBJECTDATA(obj,histogram);
00576 try {
00577 return my->init(obj->parent);
00578 }
00579 catch (char *msg)
00580 {
00581 GL_THROW("%s (histogram:%d): %s", (obj->name ? obj->name : "(unnamed)"), obj->id, msg);
00582 return 0;
00583 }
00584 }
00585
00586 EXPORT TIMESTAMP sync_histogram(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00587 {
00588 histogram *pObj = OBJECTDATA(obj,histogram);
00589 try {
00590 if (pass == PC_PRETOPDOWN)
00591 return pObj->sync(obj->clock, t0);
00592 } catch (const char *error) {
00593 GL_THROW("%s (histogram:%d): %s", (obj->name ? obj->name : "(unnamed)"), obj->id, error);
00594 return 0;
00595 } catch (...) {
00596 GL_THROW("%s (histogram:%d): %s", (obj->name ? obj->name : "(unnamed)"), obj->id, "unknown exception");
00597 return 0;
00598 }
00599 return TS_NEVER;
00600 }
00601
00610 EXPORT int isa_histogram(OBJECT *obj, char *classname)
00611 {
00612 return OBJECTDATA(obj,histogram)->isa(classname);
00613 }
00614