network/generator.cpp

Go to the documentation of this file.
00001 
00009 #include <stdlib.h>
00010 #include <stdio.h>
00011 #include <errno.h>
00012 #include <math.h>
00013 #include "network.h"
00014 
00015 int generator_state_from_string(void *addr, char *value)
00016 {
00017     if (strcmp(value,"STOPPED")==0)
00018         *(enumeration*)addr = generator::STOPPED;
00019     else if (strcmp(value,"STANDBY")==0)
00020         *(enumeration*)addr = generator::STANDBY;
00021     else if (strcmp(value,"ONLINE")==0)
00022         *(enumeration*)addr = generator::ONLINE;
00023     else if (strcmp(value,"TRIPPED")==0)
00024         *(enumeration*)addr = generator::TRIPPED;
00025     else
00026         return 0;
00027     return 1;
00028 }
00029 
00030 int generator_state_to_string(void *addr, char *value, int size)
00031 {
00032     enumeration state = *(enumeration*)addr;
00033     switch (state) {
00034     case generator::STOPPED: if (size>7) strcpy(value,"STOPPED"); else return 0;
00035         return 1;
00036     case generator::STANDBY: if (size>7) strcpy(value,"STANDBY"); else return 0;
00037         return 1;
00038     case generator::ONLINE: if (size>6) strcpy(value,"ONLINE"); else return 0;
00039         return 1;
00040     case generator::TRIPPED: if (size>7) strcpy(value,"TRIPPED"); else return 0;
00041         return 1;
00042     default:
00043         return 0;
00044     }
00045 }
00046 
00048 // generator CLASS FUNCTIONS
00050 
00051 CLASS* generator::oclass = NULL;
00052 CLASS* generator::pclass = NULL;
00053 generator *generator::defaults = NULL;
00054 
00055 generator::generator(MODULE *mod)
00056 {
00057     // first time init
00058     if (oclass==NULL)
00059     {
00060         // register the class definition
00061         generator_class = oclass = gl_register_class(mod,"generator",PC_BOTTOMUP);
00062         if (oclass==NULL)
00063             GL_THROW("unable to register object class implemented by %s",__FILE__);
00064 
00065         DELEGATEDTYPE *generator_state = gl_register_type(generator_class,"state",generator_state_from_string,generator_state_to_string);
00066     
00067         // publish the class properties
00068         if (gl_publish_variable(oclass,
00069             PT_double, "Pdesired_MW", PADDR(Pdesired_MW),
00070             PT_double, "Qdesired_MVAR", PADDR(Qdesired_MVAR),
00071             PT_int32, "Qcontrolled", PADDR(Qcontrolled),
00072             PT_double, "Pmax_MW", PADDR(Pmax_MW),
00073             PT_double, "Qmin_MVAR", PADDR(Qmin_MVAR),
00074             PT_double, "Qmax_MVAR", PADDR(Qmax_MVAR),
00075             PT_double, "QVa", PADDR(QVa),
00076             PT_double, "QVb", PADDR(QVb),
00077             PT_double, "QVc", PADDR(QVc),
00078             //TODO: Resolve what is correct for this macro
00079             //Old: PUBLISH_DELEGATED(generator,generator_state,state);
00080             //PT_delegated, "state", generator_state, 
00081             PT_enumeration,"state",PADDR(state),
00082                 PT_KEYWORD,"STOPPED",STOPPED,
00083                 PT_KEYWORD,"STANDBY",STANDBY,
00084                 PT_KEYWORD,"ONLINE",ONLINE,
00085                 PT_KEYWORD,"TRIPPED",TRIPPED,
00086             //PT_delegated, "state", state,
00087             NULL)<1) GL_THROW("unable to publish properties in %s",__FILE__);
00088 
00089         // setup the default values
00090         defaults = this;
00091         Pdesired_MW = 0;        // desired real power output
00092         Qdesired_MVAR = 0;      // desired reactive power output (if controlled)
00093         Qcontrolled = 0;        // flag true if reactive power is controlled
00094         Pmax_MW = 0;            // maximum real power
00095         Qmin_MVAR = 0;          // maximum reactive power possible
00096         Qmax_MVAR = 0;          // minimum reactive power possible
00097         QVa = QVb = QVc = 0;    // voltage response parameters (Q = a*V^2 + b*V + c)
00098         state = STOPPED;    
00099     }
00100 }
00101 
00102 int generator::create() 
00103 {
00104     memcpy(this,defaults,sizeof(*this));
00105     return 1;
00106 }
00107 
00108 int generator::init(node *parent)
00109 {
00110     // check sanity of initial state
00111     if (parent->type==PQ && !Qcontrolled)
00112     {
00113         OBJECT *obj = OBJECTHDR(this);
00114         gl_error("generator:%d is Qcontrolled but is not connected to a PQ bus", obj->id);
00115         return 0;
00116     }
00117     else if (parent->type!=PQ && Qcontrolled)
00118     {
00119         OBJECT *obj = OBJECTHDR(this);
00120         gl_error("generator:%d is not Qcontrolled but is connected to a PQ bus", obj->id);
00121         return 0;
00122     }
00123     else if (Qcontrolled && Qdesired_MVAR<Qmin_MVAR && Qdesired_MVAR>Qmax_MVAR)
00124     {
00125         OBJECT *obj = OBJECTHDR(this);
00126         gl_error("generator:%d Qdesired is out of Qmin/Qmax limits", obj->id);
00127         return 0;
00128     }
00129     else if (parent->type!=SWING && Pdesired_MW>Pmax_MW)
00130     {
00131         OBJECT *obj = OBJECTHDR(this);
00132         gl_error("generator:%d Pdesired exceeds Pmax", obj->id);
00133         return 0;
00134     }
00135     return 1;
00136 }
00137 
00138 TIMESTAMP generator::sync(TIMESTAMP t0) 
00139 {
00140     TIMESTAMP t1 = TS_NEVER;
00141     OBJECT *obj = OBJECTHDR(this);
00142     node *pBus = OBJECTDATA(obj->parent,node);
00143     switch (pBus->type) {
00144         case SWING:
00145             // check for overlimit
00146             if (pBus->S.Re()>Pmax_MW || pBus->S.Im()<Qmin_MVAR || pBus->S.Im()>Qmax_MVAR)
00147             {
00148                 // this happens because we don't support redispatching yet (after redispatch we could do tripping).
00149                 gl_error("generator:%d exceeded limits when connected to swing bus; clock stopped", obj->id);
00150                 return TS_ZERO;
00151             }
00152             break;
00153         case PV:
00154             // post real power and reactive limits
00155             pBus->S.Re() = Pdesired_MW;
00156             pBus->Qmax_MVAR = Qmax_MVAR;
00157             pBus->Qmin_MVAR = Qmin_MVAR;
00158             break;
00159         case PQ:
00160             // post both real and reactive power
00161             pBus->S = complex(Pdesired_MW,Qdesired_MVAR);
00162             break;
00163         default:
00164             break;
00165     }
00166     return t1;
00167 }
00168 
00170 // IMPLEMENTATION OF CORE LINKAGE: generator
00172 
00173 EXPORT int create_generator(OBJECT **obj)
00174 {
00175     *obj = gl_create_object(generator_class,sizeof(generator));
00176     if (*obj!=NULL)
00177     {
00178         last_generator = *obj;
00179         generator *my = OBJECTDATA(*obj,generator);
00180         my->create();
00181         return 1;
00182     }
00183     return 0;
00184 }
00185 
00186 EXPORT int init_generator(OBJECT *obj)
00187 {
00188     if (obj->parent && gl_object_isa(obj->parent,"node"))
00189         return OBJECTDATA(obj,generator)->init(OBJECTDATA(obj->parent,node));
00190     else
00191     {
00192         gl_error("generator:%d is not connected to a network node", obj->id);
00193         return 0;
00194     }
00195 }
00196 
00197 EXPORT TIMESTAMP sync_generator(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00198 {
00199     TIMESTAMP t1 = TS_NEVER;
00200     if (pass==PC_BOTTOMUP)
00201         t1 = OBJECTDATA(obj,generator)->sync(t0);
00202     obj->clock = t0;
00203     return t1;
00204 }
00205 

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