tape/shaper.c

Go to the documentation of this file.
00001 
00035 #include <stdlib.h>
00036 #include <stdio.h>
00037 #include <errno.h>
00038 #include <ctype.h>
00039 #include "gridlabd.h"
00040 #include "object.h"
00041 #include "aggregate.h"
00042 
00043 #include "tape.h"
00044 #include "file.h"
00045 #include "odbc.h"
00046 
00047 
00048 CLASS *shaper_class = NULL;
00049 static OBJECT *last_shaper = NULL;
00050 
00051 EXPORT int create_shaper(OBJECT **obj, OBJECT *parent)
00052 {
00053     *obj = gl_create_object(shaper_class,sizeof(struct shaper));
00054     if (*obj!=NULL)
00055     {
00056         struct shaper *my = OBJECTDATA(*obj,struct shaper);
00057         last_shaper = *obj;
00058         gl_set_parent(*obj,parent);
00059         strcpy(my->file,"");
00060         strcpy(my->filetype,"txt");
00061         strcpy(my->property,"");
00062         strcpy(my->group,"");
00063         my->loopnum = 0;
00064         my->status = TS_INIT;
00065         my->targets = NULL;
00066         memset(my->shape,0,sizeof(my->shape));
00067         my->scale = 0.0;    /* scale of shape values */
00068         my->magnitude = 1.0;    /* magnitude of 1 event (only used when QUEUE is enabled) */
00069         my->step = 3600;    /* one hour shape steps */
00070         my->interval = 24; /* one day unit integral of shape */
00071         my->events = 0;     /* no events by default (disables QUEUE) */
00072         return 1;
00073     }
00074     return 0;
00075 }
00076 
00077 static int shaper_open(OBJECT *obj)
00078 {
00079     char32 type="file";
00080     char1024 fname="";
00081     char32 flags="r";
00082     struct shaper *my = OBJECTDATA(obj,struct shaper);
00083     
00084     /* if prefix is omitted (no colons found) */
00085     if (sscanf(my->file,"%32[^:]:%1024[^:]:%[^:]",type,fname,flags)==1)
00086     {
00087         /* filename is file by default */
00088         strcpy(fname,my->file);
00089         strcpy(type,"file");
00090     }
00091 
00092     /* if no filename given */
00093     if (strcmp(fname,"")==0)
00094 
00095         /* use object name-id as default file name */
00096         sprintf(fname,"%s-%d.%s",obj->parent->oclass->name,obj->parent->id, my->filetype);
00097 
00098     /* if type is file or file is stdin */
00099     my->ops = get_ftable(type)->shaper;
00100     if(my->ops == NULL)
00101         return 0;
00102     return my->ops->open(my, fname, flags);
00103 }
00104 
00105 static void rewind_shaper(struct shaper *my)
00106 {
00107     my->ops->rewind(my);
00108 }
00109 
00110 static void close_shaper(struct shaper *my)
00111 {
00112     my->ops->close(my);
00113 }
00114 
00115 static TIMESTAMP shaper_read(OBJECT *obj, TIMESTAMP t0, unsigned int n)
00116 {
00117     struct shaper *my = OBJECTDATA(obj,struct shaper);
00118     TIMESTAMP t1 = TS_NEVER;
00119 
00120     /* determine shape time */
00121     time_t t = (time_t)(t0/TS_SECOND);
00122     struct tm *tval = localtime(&t); /* TODO: this should use machine local time, but sim local time */
00123 
00124     /* set the value at that time */
00125     if (my->events<=0) /* direct shape */
00126     {
00127         /* value is directly injected */
00128         my->targets[n].value = my->magnitude * my->shape[tval->tm_mon][tval->tm_mday][tval->tm_wday][tval->tm_hour] * my->scale;
00129 
00130         /* determine time of next change in shape */
00131         t1 = my->targets[n].ts = ((t0 / my->step) + 1)*my->step;
00132     }
00133     else /* shape queue */
00134     {
00135         /* value is added to queue */ 
00136         my->targets[n].value += my->shape[tval->tm_mon][tval->tm_mday][tval->tm_wday][tval->tm_hour] * my->scale * my->events;
00137 
00138         /* compute time to the start of the event */
00140         my->targets[n].ts = t0 + (TIMESTAMP)gl_random_uniform(0,my->step);
00141     }
00142 
00143     return my->targets[n].ts;
00144 }
00145 
00146 static TIMESTAMP shaper_update(OBJECT *obj, TIMESTAMP t0, unsigned int n)
00147 {
00148     struct shaper *my = OBJECTDATA(obj,struct shaper);
00149     TIMESTAMP t1 = TS_NEVER;
00150     if (my->events<=0) /* direct shaper */
00151     {
00152         /* value is directly injected */
00153         *(my->targets[n].addr) = my->targets[n].value;
00154     }
00155     else if (*(my->targets[n].addr)==0 && gl_random_bernoulli(my->targets[n].value)==1) /* shape queue event starts */
00156     {   
00157         double event_size = gl_random_uniform(0,1);
00158 
00159         /* magnitude is fixed */
00160         *(my->targets[n].addr) = my->magnitude;
00161 
00162         /* integral determines time to end of 1 event */
00163         t1 = my->targets[n].ts = t0 + (TIMESTAMP)(event_size*my->step*my->interval/my->magnitude);
00164         my->targets[n].value-=event_size; /* remove event from queue */
00165     }
00166     else if (*(my->targets[n].addr)!=0 && t0==my->targets[n].ts) /* shape queue event ends */ 
00167     {   /* event ends */
00168         /* read next shape event */
00169         t1 = shaper_read(obj,t0,n);
00170 
00171         /* clear target value */
00172         *(my->targets[n].addr) = 0;
00173     }
00174     return t1;
00175 }
00176 
00177 EXPORT TIMESTAMP sync_shaper(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00178 {
00179     struct shaper *my = OBJECTDATA(obj,struct shaper);
00180     TIMESTAMP t1 = TS_NEVER;
00181     if (my->status==TS_INIT)
00182         shaper_open(obj);
00183     if (my->status==TS_OPEN)
00184     {   
00185         /* build target list */
00186         if (my->targets==NULL && my->group[0]!='\0')
00187         {
00188             FINDLIST *object_list = gl_find_objects(FL_GROUP,my->group);
00189             OBJECT *item=NULL;
00190             int n=0;
00191             if (object_list==NULL || object_list->hit_count<=0)
00192             {
00193                 gl_warning("shaper group '%s' is empty", my->group);
00194                 my->status=TS_DONE;
00195                 return TS_NEVER;
00196             }
00197             my->n_targets = object_list->hit_count;
00198             my->targets = (SHAPERTARGET*)gl_malloc(sizeof(SHAPERTARGET*)*my->n_targets);
00199             memset(my->targets,0,sizeof(SHAPERTARGET*)*my->n_targets);
00200             if (my->targets==NULL)
00201             {
00202                 gl_error("shaper memory allocation failed!");
00203                 my->status=TS_DONE;
00204                 return TS_NEVER;
00205             }
00206             for ( ;(item=gl_find_next(object_list,item))!=NULL; n++)
00207             {
00208                 PROPERTY *prop=gl_get_property(item,my->property);
00209                 if (prop!=NULL)
00210                 {
00211                     if (prop->ptype==PT_double)
00212                     {
00213                         TIMESTAMP tn;
00214 
00215                         /* get the address of the property */
00216                         my->targets[n].addr = (double*)(GETADDR(item,prop)); /* pointer => int64 */
00217 
00218                         /* get the next event */
00219                         tn = shaper_read(obj,t0,n);
00220                         if (tn<t1) t1=tn;
00221                     }
00222                     else
00223                         gl_warning("object %s:%d property %s is not a double", item->oclass->name,item->id, prop->name);
00224                 }
00225             }
00226         }
00227 
00228         /* write to targets */
00229         if (my->targets!=NULL)
00230         {
00231             unsigned int n;
00232             for (n=0; n<my->n_targets; n++)
00233             {
00234                 TIMESTAMP tn = TS_NEVER;
00235 
00236                 /* get shape event/data */
00237                 if (my->targets[n].ts==t0) 
00238                 {
00239                     /* post the new value */
00240                     tn = shaper_update(obj,t0,n);
00241 
00242                     /* read the next value */
00243                     if (tn==TS_NEVER)
00244                         tn = shaper_read(obj,t0,n);
00245                 }
00246 
00247                 /* make sure caller knows next event time */
00248                 else if (my->targets[n].ts<t1)
00249                     tn = my->targets[n].ts;
00250 
00251                 /* keep track of "nextest" event */
00252                 if (tn<t1) t1=tn;
00253             }
00254         }
00255     }
00256     obj->clock = t0;
00257     return t1!=TS_NEVER?-t1:TS_NEVER; /* negative indicates a "soft" event which is only considered for stepping, not for stopping */
00258 }
00259 

GridLAB-DTM Version 1.0
An open-source project initiated by the US Department of Energy