00001
00012 #include <stdlib.h>
00013 #include <stdio.h>
00014 #include <errno.h>
00015 #include <math.h>
00016
00017 #include "relay.h"
00018 #include "node.h"
00019
00021
00023 CLASS* relay::oclass = NULL;
00024 CLASS* relay::pclass = NULL;
00025
00026 relay::relay(MODULE *mod) : link(mod)
00027 {
00028 if(oclass == NULL)
00029 {
00030 pclass = link::oclass;
00031
00032 oclass = gl_register_class(mod,"relay",sizeof(relay),PC_PRETOPDOWN|PC_BOTTOMUP|PC_POSTTOPDOWN|PC_UNSAFE_OVERRIDE_OMIT);
00033 if(oclass == NULL)
00034 GL_THROW("unable to register object class implemented by %s",__FILE__);
00035
00036 if(gl_publish_variable(oclass,
00037 PT_INHERIT, "link",
00038 PT_double, "time_to_change[s]", PADDR(time_to_change),
00039 PT_double, "recloser_delay[s]", PADDR(recloser_delay),
00040 PT_int16, "recloser_tries", PADDR(recloser_tries),
00041 PT_int16, "recloser_limit", PADDR(recloser_limit),
00042 PT_bool, "recloser_event", PADDR(recloser_event),
00043 NULL) < 1) GL_THROW("unable to publish properties in %s",__FILE__);
00044 }
00045 }
00046
00047 int relay::isa(char *classname)
00048 {
00049 return strcmp(classname,"relay")==0 || link::isa(classname);
00050 }
00051
00052 int relay::create()
00053 {
00054 int result = link::create();
00055 recloser_delay = 0;
00056 recloser_tries = 0;
00057 recloser_limit = 0;
00058 current_recloser_tries=0;
00059
00060 recloser_event=false;
00061 recloser_delay_time=0;
00062 recloser_reset_time=0;
00063
00064 return result;
00065 }
00066
00067 int relay::init(OBJECT *parent)
00068 {
00069 int result = link::init(parent);
00070
00071 if (recloser_limit == 0)
00072 {
00073 recloser_limit = 5;
00074 gl_warning("Recloser:%d tries limit was not specified, defaulted to 5 tries",OBJECTHDR(this)->id);
00075
00076
00077
00078 }
00079
00080 if (recloser_delay == 0)
00081 {
00082 recloser_delay = 3;
00083 gl_warning("Recloser:%d reclose delay was not specified, defaulted to 3 seconds",OBJECTHDR(this)->id);
00084
00085
00086
00087 }
00088
00089 if (recloser_delay<1.0)
00090 {
00091 GL_THROW("recloser delay must be at least 1 second");
00092
00093
00094
00095
00096 }
00097
00098 a_mat[0][0] = d_mat[0][0] = A_mat[0][0] = (link::is_closed() && has_phase(PHASE_A) ? 1.0 : 0.0);
00099 a_mat[1][1] = d_mat[1][1] = A_mat[1][1] = (link::is_closed() && has_phase(PHASE_B) ? 1.0 : 0.0);
00100 a_mat[2][2] = d_mat[2][2] = A_mat[2][2] = (link::is_closed() && has_phase(PHASE_C) ? 1.0 : 0.0);
00101
00102 b_mat[0][0] = c_mat[0][0] = B_mat[0][0] = 0.0;
00103 b_mat[1][1] = c_mat[1][1] = B_mat[1][1] = 0.0;
00104 b_mat[2][2] = c_mat[2][2] = B_mat[2][2] = 0.0;
00105
00106 return result;
00107 }
00108
00109 TIMESTAMP relay::sync(TIMESTAMP t0)
00110 {
00111 TIMESTAMP t1 = TS_NEVER;
00112 node *f;
00113 node *t;
00114 set reverse = get_flow(&f,&t);
00115
00116 #ifdef SUPPORT_OUTAGES
00117
00118 if (recloser_event)
00119 {
00120
00121 if ((recloser_reset_time != 0) && (recloser_reset_time<=t0))
00122 {
00123
00124 recloser_reset_time = 0;
00125 recloser_delay_time = 0;
00126 current_recloser_tries = 0;
00127 status = LS_CLOSED;
00128 t1 = TS_NEVER;
00129 gl_verbose("Recloser:%d just unlocked and rejoined service",OBJECTHDR(this)->id);
00130 }
00131 else if ((recloser_reset_time != 0 ) && (recloser_reset_time>t0))
00132 {
00133 status=LS_OPEN;
00134 t1 = recloser_reset_time;
00135 }
00136 else
00137 {
00138 if (status==LS_OPEN)
00139 {
00140 if (recloser_delay_time<=t0)
00141 {
00142 recloser_tries++;
00143 current_recloser_tries++;
00144 if (current_recloser_tries>recloser_limit)
00145 {
00146 recloser_delay_time = 0;
00147 recloser_reset_time = t0+(TIMESTAMP)(gl_random_exponential(3600)*TS_SECOND);
00148 gl_verbose("Recloser:%d just reached its limit and locked out for a while",OBJECTHDR(this)->id);
00149 t1 = recloser_reset_time;
00150 }
00151 else
00152 {
00153 recloser_delay_time = t0+(TIMESTAMP)(recloser_delay*TS_SECOND);
00154 gl_verbose("Recloser:%d just tried to reclose and failed",OBJECTHDR(this)->id);
00155 t1 = recloser_delay_time;
00156 }
00157 }
00158 else
00159 {
00160 t1 = recloser_delay_time;
00161 }
00162 }
00163 else
00164 {
00165 status=LS_OPEN;
00166 current_recloser_tries = 0;
00167 recloser_reset_time = 0;
00168
00169 recloser_delay_time = t0+(TIMESTAMP)(recloser_delay*TS_SECOND);
00170 gl_verbose("Recloser:%d detected a fault and opened",OBJECTHDR(this)->id);
00171 t1 = recloser_delay_time;
00172 }
00173 }
00174 }
00175 else
00176 {
00177 set trip = (f->is_contact_any() || t->is_contact_any());
00178
00179
00180 if ((recloser_reset_time != 0 ) && (recloser_reset_time>=t0))
00181 {
00182
00183 recloser_reset_time = 0;
00184 recloser_delay_time = 0;
00185 recloser_tries = 0;
00186 status = LS_CLOSED;
00187 t1 = TS_NEVER;
00188 gl_verbose("Recloser:%d just unlocked and rejoined service",OBJECTHDR(this)->id);
00189 }
00190 else if ((recloser_reset_time != 0 ) && (recloser_reset_time>t0))
00191 {
00192 t1 = recloser_reset_time;
00193 }
00194 else
00195 {
00196
00197 if (status==LS_CLOSED && trip)
00198 {
00199 status = LS_OPEN;
00200
00201
00202 recloser_delay_time=t0+(TIMESTAMP)(recloser_delay*TS_SECOND);
00203 gl_verbose("Recloser:%d detected a fault and opened",OBJECTHDR(this)->id);
00204 t1 = recloser_delay_time;
00205 }
00206
00207 else if (status==LS_OPEN && t0>=recloser_delay_time)
00208 {
00209
00210 if (trip)
00211 {
00212
00213 if (recloser_limit>recloser_tries)
00214 {
00215 recloser_tries++;
00216 gl_verbose("Recloser:%d just tried to reclose and failed",OBJECTHDR(this)->id);
00217 recloser_delay_time = t0+(TIMESTAMP)(recloser_delay*TS_SECOND);
00218
00219 t1 = recloser_delay_time;
00220 }
00221
00222
00223 else
00224 {
00225 gl_verbose("Recloser:%d just reached its limit and locked out for a while",OBJECTHDR(this)->id);
00226 recloser_reset_time = t0+(TIMESTAMP)(gl_random_exponential(3600)*TS_SECOND);
00227 t1 = recloser_reset_time;
00228 }
00229 }
00230 else
00231 status = LS_CLOSED;
00232 }
00233 else if ((recloser_delay_time != 0) && (recloser_delay_time>t0))
00234 {
00235 t1 = recloser_delay_time;
00236 }
00237 else
00238 {
00239 if (status==LS_OPEN)
00240 {
00241 gl_verbose("Recloser:%d recovered from a fault",OBJECTHDR(this)->id);
00242 }
00243
00244 current_recloser_tries = 0;
00245 recloser_tries = 0;
00246 status=LS_CLOSED;
00247 }
00248 }
00249 }
00250 #endif
00251
00252 TIMESTAMP t2=link::sync(t0);
00253
00254 return t1<t2?t1:t2;
00255 }
00256
00257 TIMESTAMP relay::postsync(TIMESTAMP t0)
00258 {
00259 return link::postsync(t0);
00260 }
00261
00263
00265
00273 EXPORT int create_relay(OBJECT **obj, OBJECT *parent)
00274 {
00275 try
00276 {
00277 *obj = gl_create_object(relay::oclass);
00278 if (*obj!=NULL)
00279 {
00280 relay *my = OBJECTDATA(*obj,relay);
00281 gl_set_parent(*obj,parent);
00282 return my->create();
00283 }
00284 }
00285 catch (const char *msg)
00286 {
00287 gl_error("create_relay: %s", msg);
00288 }
00289 return 0;
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00312 EXPORT int init_relay(OBJECT *obj)
00313 {
00314 relay *my = OBJECTDATA(obj,relay);
00315 try {
00316 return my->init(obj->parent);
00317 }
00318 catch (const char *msg)
00319 {
00320 GL_THROW("%s (relay:%d): %s", my->get_name(), my->get_id(), msg);
00321 return 0;
00322 }
00323 }
00324
00333 EXPORT TIMESTAMP sync_relay(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00334 {
00335 relay *pObj = OBJECTDATA(obj,relay);
00336 try {
00337 TIMESTAMP t1 = TS_NEVER;
00338 switch (pass) {
00339 case PC_PRETOPDOWN:
00340 return pObj->presync(t0);
00341 case PC_BOTTOMUP:
00342 return pObj->sync(t0);
00343 case PC_POSTTOPDOWN:
00344 t1 = pObj->postsync(t0);
00345 obj->clock = t0;
00346 return t1;
00347 default:
00348 throw "invalid pass request";
00349 }
00350 } catch (const char *error) {
00351 GL_THROW("%s (relay:%d): %s", pObj->get_name(), pObj->get_id(), error);
00352 return 0;
00353 } catch (...) {
00354 GL_THROW("%s (relay:%d): %s", pObj->get_name(), pObj->get_id(), "unknown exception");
00355 return 0;
00356 }
00357 }
00358
00359 EXPORT int isa_relay(OBJECT *obj, char *classname)
00360 {
00361 return OBJECTDATA(obj,relay)->isa(classname);
00362 }
00363