00001
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032 #include <errno.h>
00033 #include <ctype.h>
00034 #include "gridlabd.h"
00035 #include "object.h"
00036 #include "aggregate.h"
00037
00038 #include "tape.h"
00039 #include "file.h"
00040 #include "odbc.h"
00041
00042 #ifndef WIN32
00043 #define strtok_s strtok_r
00044 #endif
00045
00046 CLASS *multi_recorder_class = NULL;
00047 static OBJECT *last_recorder = NULL;
00048
00049 EXPORT int create_multi_recorder(OBJECT **obj, OBJECT *parent)
00050 {
00051 *obj = gl_create_object(multi_recorder_class);
00052 if (*obj!=NULL)
00053 {
00054 struct recorder *my = OBJECTDATA(*obj,struct recorder);
00055 last_recorder = *obj;
00056 gl_set_parent(*obj,parent);
00057 strcpy(my->file,"");
00058 strcpy(my->multifile,"");
00059 strcpy(my->filetype,"txt");
00060 strcpy(my->delim,",");
00061 strcpy(my->property,"(undefined)");
00062 my->interval = -1;
00063 my->dInterval = -1.0;
00064 my->last.ts = -1;
00065 strcpy(my->last.value,"");
00066 my->limit = 0;
00067 my->samples = 0;
00068 my->status = TS_INIT;
00069 my->trigger[0]='\0';
00070 my->format = 0;
00071 strcpy(my->plotcommands,"");
00072 my->target = gl_get_property(*obj,my->property);
00073 return 1;
00074 }
00075 return 0;
00076 }
00077
00078 static int multi_recorder_open(OBJECT *obj)
00079 {
00080 char32 type="file";
00081 char1024 fname="";
00082 char32 flags="w";
00083 struct recorder *my = OBJECTDATA(obj,struct recorder);
00084
00085 my->interval = (int64)(my->dInterval/TS_SECOND);
00086
00087 if (sscanf(my->file,"%32[^:]:%1024[^:]:%[^:]",type,fname,flags)==1)
00088 {
00089
00090 strcpy(fname,my->file);
00091 strcpy(type,"file");
00092 }
00093
00094
00095 if (strcmp(fname,"")==0)
00096
00097
00098 sprintf(fname,"%s-%d.%s",obj->parent->oclass->name,obj->parent->id, my->filetype);
00099
00100
00101 if(my->type == FT_FILE && my->multifile[0] != 0){
00102 if(my->interval < 1){
00103 gl_error("multirecorder: transient recorders cannot use multi-run output files");
00104 return 0;
00105 }
00106 sprintf(my->multitempfile, "temp_%s", my->file);
00107 my->multifp = fopen(my->multitempfile, "w");
00108 if(my->multifp == NULL){
00109 gl_error("multirecorder: unable to open \'%s\' for multi-run output", my->multitempfile);
00110 } else {
00111 time_t now=time(NULL);
00112
00113 my->inputfp = fopen(my->multifile, "r");
00114
00115
00116 fprintf(my->multifp,"# file...... %s\n", my->file);
00117 fprintf(my->multifp,"# date...... %s", asctime(localtime(&now)));
00118 #ifdef WIN32
00119 fprintf(my->multifp,"# user...... %s\n", getenv("USERNAME"));
00120 fprintf(my->multifp,"# host...... %s\n", getenv("MACHINENAME"));
00121 #else
00122 fprintf(my->multifp,"# user...... %s\n", getenv("USER"));
00123 fprintf(my->multifp,"# host...... %s\n", getenv("HOST"));
00124 #endif
00125 if(obj->parent){
00126 fprintf(my->multifp,"# target.... %s %d\n", obj->parent->oclass->name, obj->parent->id);
00127 } else {
00128 fprintf(my->multifp,"# target.... (none)\n");
00129 }
00130 fprintf(my->multifp,"# trigger... %s\n", my->trigger[0]=='\0'?"(none)":my->trigger);
00131 fprintf(my->multifp,"# interval.. %d\n", my->interval);
00132 fprintf(my->multifp,"# limit..... %d\n", my->limit);
00133 fprintf(my->multifp,"# property.. %s\n", my->property);
00134
00135 }
00136 if(my->inputfp != NULL){
00137 char1024 inbuffer;
00138 char *data;
00139 int get_col = 0;
00140 do{
00141 if(0 != fgets(inbuffer, 1024, my->inputfp)){
00142 char *end = strchr(inbuffer, '\n');
00143 data = inbuffer+strlen("# file...... ");
00144 if(end != 0){
00145 *end = 0;
00146 }
00147
00148 if(strncmp(inbuffer, "# file", strlen("# file")) == 0){
00149 ;
00150 } else if(strncmp(inbuffer, "# date", strlen("# date")) == 0){
00151 ;
00152 } else if(strncmp(inbuffer, "# user", strlen("# user")) == 0){
00153 ;
00154 } else if(strncmp(inbuffer, "# host", strlen("# host")) == 0){
00155 ;
00156 } else if(strncmp(inbuffer, "# target", strlen("# target")) == 0){
00157
00158 char256 target;
00159 if(obj->parent != 0){
00160 sprintf(target, "%s %d", obj->parent->oclass->name, obj->parent->id);
00161 if(0 != strncmp(target, data, strlen(data))){
00162 gl_error("multirecorder:%i: re-recording target mismatch: was %s, now %s", obj->id, data, target);
00163 }
00164 } else {
00165 if(strncmp("(none)", target, 6)){
00166 gl_error("multirecorder:%i: re-recording target mismatch: was %s, now blank", obj->id, data);
00167 }
00168 }
00169 } else if(strncmp(inbuffer, "# trigger", strlen("# trigger")) == 0){
00170
00171 ;
00172 } else if(strncmp(inbuffer, "# interval", strlen("# interval")) == 0){
00173
00174 int interval = atoi(data);
00175 if(interval != my->interval){
00176 gl_error("multirecorder:%i: re-recording interval mismatch: was %i, now %i", obj->id, interval, my->interval);
00177 }
00178 } else if(strncmp(inbuffer, "# limit", strlen("# limit")) == 0){
00179
00180 int limit = atoi(data);
00181 if(limit != my->limit){
00182 gl_error("multirecorder:%i: re-recording limit mismatch: was %i, now %i", obj->id, limit, my->limit);
00183 }
00184 } else if(strncmp(inbuffer, "# property", strlen("# property")) == 0){
00185
00186 if(0 != strncmp(my->property, data, strlen(my->property))){
00187 gl_error("multirecorder:%i: re-recording property mismatch: was %s, now %s", obj->id, data, my->property);
00188 }
00189
00190 get_col = 1;
00191 }
00192 } else {
00193 gl_error("multirecorder: error reading multi-read input file \'%s\'", my->multifile);
00194 break;
00195 }
00196 } while(inbuffer[0] == '#' && get_col == 0);
00197
00198 if(0 != fgets(inbuffer, 1024, my->inputfp)){
00199 int rep=0;
00200 int replen = (int)strlen("# repetition");
00201 int len, lenmax = 1024, i = 0;
00202 char1024 propstr, shortstr;
00203 PROPERTY *tprop = my->target;
00204 gl_verbose("read last buffer");
00205 if(strncmp(inbuffer, "# repetition", replen) == 0){
00206 char *trim;
00207 rep = atoi(inbuffer + replen + 1);
00208 ++rep;
00209 fprintf(my->multifp, "# repetition %i\n", rep);
00210 fgets(inbuffer, 1024, my->inputfp);
00211 trim = strchr(inbuffer, '\n');
00212 if(trim) *trim = 0;
00213 } else {
00214 rep = 0;
00215 fprintf(my->multifp, "# repetition %i\n", rep);
00216 }
00217
00218 while(tprop != NULL){
00219 sprintf(shortstr, ",%s(%i)", tprop->name, rep);
00220 len = (int)strlen(shortstr);
00221 if(len > lenmax){
00222 gl_error("multirecorder: multi-run recorder output full property list is larger than the buffer, please start a new file!");
00223 break;
00224 }
00225 strncpy(propstr+i, shortstr, len+1);
00226 i += len;
00227 tprop = tprop->next;
00228 }
00229 fprintf(my->multifp, "%s%s\n", inbuffer, propstr);
00230 }
00231 } else {
00232 char1024 propstr, shortstr;
00233
00234
00235
00236 int len, lenmax = 1024, i = 0;
00237 PROPERTY *tprop = my->target;
00238 fprintf(my->multifp, "# repetition 0\n");
00239
00240 sprintf(propstr, "# timestamp");
00241 len = (int)strlen(propstr);
00242 lenmax-=len;
00243 i = len;
00244
00245 while(tprop != NULL){
00246 sprintf(shortstr, ",%s(0)", tprop->name);
00247 len = (int)strlen(shortstr);
00248 if(len > lenmax){
00249 gl_error("multirecorder: multi-run recorder output full property list is larger than the buffer, please start a new file!");
00250 break;
00251 }
00252 strncpy(propstr+i, shortstr, len+1);
00253 i += len;
00254 tprop = tprop->next;
00255 }
00256 fprintf(my->multifp, "%s\n", propstr);
00257
00258
00259
00260 }
00261 }
00262
00263
00264 my->ops = get_ftable(type)->recorder;
00265 if(my->ops == NULL)
00266 return 0;
00267 return my->ops->open(my, fname, flags);
00268 }
00269
00270 static int write_multi_recorder(struct recorder *my, char *ts, char *value)
00271 {
00272 return my->ops->write(my, ts, value);
00273 }
00274
00275 static void close_multi_recorder(struct recorder *my)
00276 {
00277 if (my->ops){
00278 my->ops->close(my);
00279 }
00280 if(my->multifp){
00281 if(0 != fclose(my->multifp)){
00282 gl_error("multirecorder: unable to close multi-run temp file \'%s\'", my->multitempfile);
00283 perror("fclose(): ");
00284 }
00285
00286 my->multifp = 0;
00287
00288 if(my->inputfp != NULL){
00289 fclose(my->inputfp);
00290 if(0 != remove(my->multifile)){
00291 gl_error("multirecorder: unable to remove out-of-data multi-run file \'%s\'", my->multifile);
00292 perror("remove(): ");
00293 }
00294 }
00295 if(0 != rename(my->multitempfile, my->multifile)){
00296 gl_error("multirecorder: unable to rename multi-run file \'%s\' to \'%s\'", my->multitempfile, my->multifile);
00297 perror("rename(): ");
00298 }
00299
00300 }
00301 }
00302
00303 static TIMESTAMP multi_recorder_write(OBJECT *obj)
00304 {
00305 struct recorder *my = OBJECTDATA(obj,struct recorder);
00306 char ts[64]="0";
00307 if (my->format==0)
00308 {
00309 if (my->last.ts>TS_ZERO)
00310 {
00311 DATETIME dt;
00312 gl_localtime(my->last.ts,&dt);
00313 gl_strtime(&dt,ts,sizeof(ts));
00314 }
00315
00316 }
00317 else
00318 sprintf(ts,"%" FMT_INT64 "d", my->last.ts);
00319 if ((my->limit>0 && my->samples > my->limit)
00320 || write_multi_recorder(my, ts, my->last.value)==0)
00321 {
00322 close_multi_recorder(my);
00323 my->status = TS_DONE;
00324 }
00325 else
00326 my->samples++;
00327
00328
00329
00330
00331 if(my->multifp != NULL){
00332 char1024 inbuffer;
00333 char1024 outbuffer;
00334 char *lasts = 0;
00335 char *in_ts = 0;
00336 char *in_tok = 0;
00337
00338 memset(inbuffer, 0, sizeof(inbuffer));
00339
00340 if(my->inputfp != NULL){
00341
00342 do{
00343 if(0 == fgets(inbuffer, 1024, my->inputfp)){
00344 if(feof(my->inputfp)){
00345
00346
00347
00348 return TS_NEVER;
00349 } else {
00350 gl_error("multirecorder: error reading past recordings file");
00351 my->status = TS_ERROR;
00352 return TS_NEVER;
00353 }
00354 }
00355
00356 } while(inbuffer[0] == '#');
00357
00358
00359
00360 in_ts = strtok_s(inbuffer, ",\n", &lasts);
00361 in_tok = strtok_s(NULL, "\n", &lasts);
00362
00363 if(in_ts == NULL){
00364 gl_error("multirecorder: unable to indentify a timestamp within the line read from ");
00365 }
00366
00367
00368
00369 if(strcmp(in_ts, ts) != 0){
00370 gl_warning("multirecorder: timestamp mismatch between current input line and simulation time");
00371 }
00372 sprintf(outbuffer, "%s,%s", in_tok, my->last.value);
00373 } else {
00374 strcpy(outbuffer, my->last.value);
00375 }
00376
00377 fprintf(my->multifp, "%s,%s\n", ts, outbuffer);
00378 }
00379 return TS_NEVER;
00380 }
00381
00382 RECORDER_MAP *link_multi_properties(OBJECT *obj, char *property_list)
00383 {
00384 char *itemptr, *item;
00385 char objstr[128];
00386 char itemstr[128];
00387 RECORDER_MAP *first=NULL, *last=NULL, *rmap;
00388 OBJECT *target_obj = NULL;
00389 UNIT *unit = NULL;
00390 char1024 list;
00391 complex oblig;
00392 int partres = 0;
00393 char name[128];
00394
00395 strcpy(list,property_list);
00396 for (itemptr = strtok(list,","); itemptr != NULL; itemptr = strtok(NULL,","))
00397 {
00398 char256 pstr, ustr;
00399 char *cpart = 0;
00400 int64 cid = -1;
00401 PROPERTY *prop = NULL;
00402 PROPERTY *target = NULL;
00403 double scale = 1.0;
00404
00405 if(2 == sscanf(itemptr, "%[^:]:%[^\n\r\0]", objstr, itemstr)){
00406 item = itemstr;
00407 target_obj = gl_get_object(objstr);
00408 if(target_obj == 0){
00409 gl_error("multirecorder: unable to find object '%s'", objstr);
00410 return 0;
00411 }
00412 } else {
00413 if(obj == 0){
00414 gl_error("multirecorder: no parent object and no specified target object in '%s'", itemstr);
00415 return 0;
00416 }
00417 target_obj = obj;
00418 item = objstr;
00419 }
00420
00421
00422 while (isspace(*item)) item++;
00423 if(2 == sscanf(item,"%[A-Za-z0-9_.][%[^]\n,\0]", pstr, ustr)){
00424 unit = gl_find_unit(ustr);
00425 if(unit == NULL){
00426 gl_error("multirecorder: unable to find unit '%s' for property '%s' in object '%s %i'", ustr,pstr,target_obj->oclass->name, target_obj->id);
00427 return NULL;
00428 }
00429 item = pstr;
00430 }
00431 rmap = (RECORDER_MAP *)malloc(sizeof(RECORDER_MAP));
00432 memset(rmap, 0, sizeof(RECORDER_MAP));
00433
00434
00435
00436 cpart = strchr(item, '.');
00437 if(cpart != NULL){
00438 if(strcmp("imag", cpart+1) == 0){
00439 cid = (int)((int64)&(oblig.i) - (int64)&oblig);
00440 *cpart = 0;
00441 } else if(strcmp("real", cpart+1) == 0){
00442 cid = (int)((int64)&(oblig.r) - (int64)&oblig);
00443 *cpart = 0;
00444 } else {
00445 ;
00446 }
00447 }
00448
00449 target = gl_get_property(target_obj,item);
00450
00451 if (rmap != NULL && target != NULL)
00452 {
00453 if(unit != NULL && target->unit == NULL){
00454 gl_error("recorder:%d: property '%s' is unitless, ignoring unit conversion", obj->id, item);
00455 }
00456 else if(unit != NULL && 0 == gl_convert_ex(target->unit, unit, &scale))
00457 {
00458 gl_error("recorder:%d: unable to convert property '%s' units to '%s'", obj->id, item, ustr);
00459 return NULL;
00460 }
00461 if(first == NULL){
00462 first = rmap;
00463 } else {
00464 last->next=rmap;
00465 }
00466 last = rmap;
00467 rmap->obj = target_obj;
00468 memcpy(&(rmap->prop), target, sizeof(PROPERTY));
00469 if(unit){
00470 rmap->prop.unit = unit;
00471 }
00472 rmap->next = NULL;
00473 }
00474 else
00475 {
00476 gl_name_object(target_obj, name, 128);
00477 gl_error("multirecorder: property '%s' not found in object '%s'", item, name);
00478 return NULL;
00479 }
00480 if(cid >= 0){
00481 rmap->prop.ptype = PT_double;
00482 (rmap->prop.addr) = (int64)(rmap->prop.addr) + cid;
00483 }
00484 }
00485 return first;
00486 }
00487
00488 int read_multi_properties(OBJECT *obj, RECORDER_MAP *rmap, char *buffer, int size)
00489 {
00490 RECORDER_MAP *r;
00491 int offset=0;
00492 int count=0;
00493 for(r = rmap; r != NULL && offset < size - 33; r = r->next){
00494 if(offset > 0){
00495 strcpy(buffer+offset++,",");
00496 }
00497 offset += gl_get_value(r->obj, GETADDR(r->obj, &(r->prop)), buffer + offset, size - offset - 1, &(r->prop));
00498 buffer[offset] = '\0';
00499 count++;
00500 }
00501 return count;
00502 }
00503
00504 EXPORT TIMESTAMP sync_multi_recorder(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00505 {
00506 struct recorder *my = OBJECTDATA(obj,struct recorder);
00507 typedef enum {NONE='\0', LT='<', EQ='=', GT='>'} COMPAREOP;
00508 COMPAREOP comparison;
00509 char1024 buffer = "";
00510
00511 if (my->status==TS_DONE)
00512 {
00513 close_multi_recorder(my);
00514 return TS_NEVER;
00515 }
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527 if(my->last.ts < 1 && my->interval != -1)
00528 my->last.ts = t0;
00529
00530
00531 if (my->rmap==NULL){
00532 my->rmap = link_multi_properties(obj->parent,my->property);
00533 }
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543 if (my->rmap==NULL)
00544 {
00545 sprintf(buffer,"'%s' contains a property reference that was not found", my->property);
00546 close_multi_recorder(my);
00547 my->status = TS_ERROR;
00548 goto Error;
00549 }
00550
00551
00552 if ((my->status==TS_OPEN) && (t0 > obj->clock))
00553 {
00554 obj->clock = t0;
00555
00556 if((my->interval > 0) && (my->last.ts < t0) && (my->last.value[0] != 0)){
00557 multi_recorder_write(obj);
00558 my->last.value[0] = 0;
00559 }
00560 }
00561
00562
00563 if ((my->rmap != NULL) && (my->interval == 0 || my->interval == -1)){
00564 if(read_multi_properties(obj->parent,my->rmap,buffer,sizeof(buffer))==0)
00565 {
00566
00567 sprintf(buffer,"unable to read a property");
00568 close_multi_recorder(my);
00569 my->status = TS_ERROR;
00570 }
00571 }
00572 if ((my->rmap != NULL) && (my->interval > 0)){
00573 if((t0 >=my->last.ts + my->interval) || (t0 == my->last.ts)){
00574 if(read_multi_properties(obj->parent,my->rmap,buffer,sizeof(buffer))==0)
00575 {
00576
00577 sprintf(buffer,"unable to read a property");
00578 close_multi_recorder(my);
00579 my->status = TS_ERROR;
00580 }
00581 my->last.ts = t0;
00582 }
00583 }
00584
00585
00586 comparison = (COMPAREOP)my->trigger[0];
00587 if (comparison!=NONE)
00588 {
00589 int desired = comparison==LT ? -1 : (comparison==EQ ? 0 : (comparison==GT ? 1 : -2));
00590
00591
00592 int actual = strcmp(buffer,my->trigger+1);
00593 if (actual!=desired || (my->status==TS_INIT && !multi_recorder_open(obj)))
00594 {
00595
00596 return (my->interval==0 || my->interval==-1) ? TS_NEVER : t0+my->interval;
00597 }
00598 }
00599 else if (my->status==TS_INIT && !multi_recorder_open(obj))
00600 {
00601 close_multi_recorder(my);
00602 return TS_NEVER;
00603 }
00604
00605 if(my->last.ts < 1 && my->interval != -1)
00606 my->last.ts = t0;
00607
00608
00609 if (my->status==TS_OPEN)
00610 {
00611 if (my->interval==0
00612 || ((my->interval==-1) && my->last.ts!=t0 && strcmp(buffer,my->last.value)!=0)
00613 )
00614
00615 {
00616 strncpy(my->last.value,buffer,sizeof(my->last.value));
00617 my->last.ts = t0;
00618 multi_recorder_write(obj);
00619 } else if (my->interval > 0 && my->last.ts == t0){
00620 strncpy(my->last.value,buffer,sizeof(my->last.value));
00621 }
00622 }
00623 Error:
00624 if (my->status==TS_ERROR)
00625 {
00626 gl_error("recorder %d %s\n",obj->id, buffer);
00627 close_multi_recorder(my);
00628 my->status=TS_DONE;
00629 return TS_NEVER;
00630 }
00631
00632 if (my->interval==0 || my->interval==-1)
00633 {
00634 return TS_NEVER;
00635 }
00636 else
00637 {
00638 return my->last.ts+my->interval;
00639 }
00640 }
00641