00001
00013 #include <stdlib.h>
00014 #include <stdio.h>
00015 #include <errno.h>
00016 #include <math.h>
00017
00018 #include "node.h"
00019 #include "fuse.h"
00020
00021
00022 CLASS* fuse::oclass = NULL;
00023 CLASS* fuse::pclass = NULL;
00024
00026
00028
00029 fuse::fuse(MODULE *mod) : link(mod)
00030 {
00031 if(oclass == NULL)
00032 {
00033 pclass = relay::oclass;
00034
00035 oclass = gl_register_class(mod,"fuse",sizeof(fuse),PC_PRETOPDOWN|PC_BOTTOMUP|PC_POSTTOPDOWN|PC_UNSAFE_OVERRIDE_OMIT);
00036 if(oclass == NULL)
00037 GL_THROW("unable to register object class implemented by %s",__FILE__);
00038
00039 if(gl_publish_variable(oclass,
00040 PT_INHERIT, "link",
00041 PT_double, "current_limit[A]",PADDR(current_limit),
00042 PT_double, "mean_replacement_time[H]",PADDR(mean_replacement_time),
00043 PT_enumeration, "phase_A_status", PADDR(phase_A_status),
00044 PT_KEYWORD, "GOOD", GOOD,
00045 PT_KEYWORD, "BLOWN", BLOWN,
00046 PT_enumeration, "phase_B_status", PADDR(phase_B_status),
00047 PT_KEYWORD, "GOOD", GOOD,
00048 PT_KEYWORD, "BLOWN", BLOWN,
00049 PT_enumeration, "phase_C_status", PADDR(phase_C_status),
00050 PT_KEYWORD, "GOOD", GOOD,
00051 PT_KEYWORD, "BLOWN", BLOWN,
00052 NULL) < 1) GL_THROW("unable to publish properties in %s",__FILE__);
00053 }
00054 }
00055
00056 int fuse::isa(char *classname)
00057 {
00058 return strcmp(classname,"fuse")==0 || link::isa(classname);
00059 }
00060
00061 int fuse::create()
00062 {
00063 int result = link::create();
00064
00065
00066 to = from = NULL;
00067 fix_time_A = TS_NEVER;
00068 fix_time_B = TS_NEVER;
00069 fix_time_C = TS_NEVER;
00070 Prev_Time = 0;
00071 current_limit = 0.0;
00072 mean_replacement_time = 0.0;
00073 phase_A_status = GOOD;
00074 phase_B_status = GOOD;
00075 phase_C_status = GOOD;
00076
00077 return result;
00078 }
00079
00086 int fuse::init(OBJECT *parent)
00087 {
00088 int jindex, kindex;
00089
00090 if ((phases & PHASE_S) == PHASE_S)
00091 GL_THROW("fuses cannot be placed on triplex circuits");
00092
00093
00094
00095
00096
00097
00098 SpecialLnk = SWITCH;
00099
00100 int result = link::init(parent);
00101
00102 if (current_limit<=0.0)
00103 GL_THROW("Fuse:%d has no or a negative current limit set.",OBJECTHDR(this)->id);
00104
00105
00106
00107
00108
00109 if (mean_replacement_time<0.0)
00110 GL_THROW("Fuse:%d (%s) has a mean replacement time interval set as a negative value set.",OBJECTHDR(this)->id,OBJECTHDR(this)->name);
00111
00112
00113
00114
00115 else if (mean_replacement_time==0.0)
00116 {
00117 gl_warning("Fuse:%d (%s) does not have a mean replacement time interval set, using default.",OBJECTHDR(this)->id,OBJECTHDR(this)->name);
00118 mean_replacement_time = 10000;
00119 }
00120 if (solver_method==SM_FBS)
00121 gl_warning("Fuses only work for the attached node in the FBS solver, not any deeper.");
00122
00123
00124
00125
00126
00127
00128
00129
00130 for (jindex=0;jindex<3;jindex++)
00131 {
00132 for (kindex=0;kindex<3;kindex++)
00133 {
00134 a_mat[jindex][kindex] = d_mat[jindex][kindex] = A_mat[jindex][kindex] = 0.0;
00135 c_mat[jindex][kindex] = 0.0;
00136 B_mat[jindex][kindex] = b_mat[jindex][kindex] = 0.0;
00137 }
00138 }
00139
00140 if (solver_method==SM_FBS)
00141 {
00142
00143
00144 if ((phases & PHASE_A) == PHASE_A)
00145 {
00146 a_mat[0][0] = d_mat[0][0] = A_mat[0][0] = 1.0;
00147 }
00148
00149
00150 if ((phases & PHASE_B) == PHASE_B)
00151 {
00152 a_mat[1][1] = d_mat[1][1] = A_mat[1][1] = 1.0;
00153 }
00154
00155
00156 if ((phases & PHASE_C) == PHASE_C)
00157 {
00158 a_mat[2][2] = d_mat[2][2] = A_mat[2][2] = 1.0;
00159 }
00160 }
00161 else if (solver_method==SM_NR)
00162 {
00163
00164
00165
00166
00167 if (((phases & PHASE_A) == PHASE_A) && (phase_A_status == GOOD))
00168 {
00169 From_Y[0][0] = complex(1e4,1e4);
00170 a_mat[0][0] = 1.0;
00171 }
00172
00173
00174 if (((phases & PHASE_B) == PHASE_B) && (phase_B_status == GOOD))
00175 {
00176 From_Y[1][1] = complex(1e4,1e4);
00177 a_mat[1][1] = 1.0;
00178 }
00179
00180
00181 if (((phases & PHASE_C) == PHASE_C) && (phase_C_status == GOOD))
00182 {
00183 From_Y[2][2] = complex(1e4,1e4);
00184 a_mat[2][2] = 1.0;
00185 }
00186 }
00187 else
00188 {
00189 GL_THROW("Fuses are not supported by this solver method");
00190
00191
00192
00193
00194
00195 }
00196
00197 return result;
00198 }
00199
00200
00201 TIMESTAMP fuse::postsync(TIMESTAMP t0)
00202 {
00203 OBJECT *hdr = OBJECTHDR(this);
00204 char jindex;
00205 unsigned char goodphases = 0x00;
00206 TIMESTAMP Ret_Val[3];
00207
00208
00209 if (Prev_Time != t0)
00210 Prev_Time = t0;
00211
00212
00213
00214 if ((phases & PHASE_A) == PHASE_A)
00215 {
00216 if (phase_A_status == GOOD)
00217 {
00218 Ret_Val[0] = TS_NEVER;
00219 goodphases |= 0x04;
00220 }
00221 else
00222 {
00223 if (t0 == fix_time_A)
00224 Ret_Val[0] = t0 + 1;
00225 else
00226 Ret_Val[0] = fix_time_A;
00227 }
00228 }
00229 else
00230 Ret_Val[0] = TS_NEVER;
00231
00232
00233 if ((phases & PHASE_B) == PHASE_B)
00234 {
00235 if (phase_B_status == GOOD)
00236 {
00237 Ret_Val[1] = TS_NEVER;
00238 goodphases |= 0x02;
00239 }
00240 else
00241 {
00242 if (t0 == fix_time_B)
00243 Ret_Val[1] = t0 + 1;
00244 else
00245 Ret_Val[1] = fix_time_B;
00246 }
00247 }
00248 else
00249 Ret_Val[1] = TS_NEVER;
00250
00251
00252
00253 if ((phases & PHASE_C) == PHASE_C)
00254 {
00255 if (phase_C_status == GOOD)
00256 {
00257 Ret_Val[2] = TS_NEVER;
00258 goodphases |= 0x01;
00259 }
00260 else
00261 {
00262 if (t0 == fix_time_C)
00263 Ret_Val[2] = t0 + 1;
00264 else
00265 Ret_Val[2] = fix_time_C;
00266 }
00267 }
00268 else
00269 Ret_Val[2] = TS_NEVER;
00270
00271 if (solver_method == SM_NR)
00272 {
00273
00274 goodphases |= 0xF8;
00275
00276
00277 NR_branchdata[NR_branch_reference].phases &= goodphases;
00278 }
00279
00280
00281 TIMESTAMP t1 = link::postsync(t0);
00282
00283
00284 for (jindex=0;jindex<3;jindex++)
00285 {
00286 if (Ret_Val[jindex] < t1)
00287 t1 = Ret_Val[jindex];
00288 }
00289 if (t1 != TS_NEVER)
00290 return -t1;
00291 else
00292 return TS_NEVER;
00293 }
00294
00301 int fuse::fuse_state(OBJECT *parent)
00302 {
00303 this->fuse_check(PHASE_A,current_in);
00304 this->fuse_check(PHASE_B,current_in);
00305 this->fuse_check(PHASE_C,current_in);
00306
00307 return 1;
00308 }
00318 void fuse::fuse_check(set phase_to_check, complex *fcurr)
00319 {
00320 char indexval;
00321 char phase_verbose;
00322 unsigned char work_phase;
00323 FUSESTATE *valstate;
00324 TIMESTAMP *fixtime;
00325 OBJECT *hdr = OBJECTHDR(this);
00326
00327 if (phase_to_check == PHASE_A)
00328 {
00329 indexval = 0;
00330 valstate = &phase_A_status;
00331 phase_verbose='A';
00332 fixtime = &fix_time_A;
00333 }
00334 else if (phase_to_check == PHASE_B)
00335 {
00336 indexval = 1;
00337 valstate = &phase_B_status;
00338 phase_verbose='B';
00339 fixtime = &fix_time_B;
00340 }
00341 else if (phase_to_check == PHASE_C)
00342 {
00343 indexval = 2;
00344 valstate = &phase_C_status;
00345 phase_verbose='C';
00346 fixtime = &fix_time_C;
00347 }
00348 else
00349 {
00350 GL_THROW("Unknown phase to check in fuse:%d",OBJECTHDR(this)->id);
00351
00352
00353
00354
00355
00356 }
00357
00358
00359 if ((phases & phase_to_check) == phase_to_check)
00360 {
00361 work_phase = 0x04 >> indexval;
00362
00363 if (*valstate == GOOD)
00364 {
00365
00366 if (fcurr[indexval].Mag() > current_limit)
00367 {
00368 *valstate = BLOWN;
00369
00370
00371 if (solver_method==SM_FBS)
00372 {
00373 A_mat[indexval][indexval] = d_mat[indexval][indexval] = 0.0;
00374 }
00375 else if (solver_method==SM_NR)
00376 {
00377 From_Y[indexval][indexval] = complex(0.0,0.0);
00378 a_mat[indexval][indexval] = 0.0;
00379 NR_admit_change = true;
00380
00381 work_phase = !work_phase;
00382 NR_branchdata[NR_branch_reference].phases &= work_phase;
00383 }
00384
00385
00386 *fixtime = Prev_Time + (int64)(3600*gl_random_exponential(1.0/mean_replacement_time));
00387
00388
00389 gl_verbose("Phase %c of fuse:%d (%s) just blew",phase_verbose,hdr->id,hdr->name);
00390 }
00391 else
00392 {
00393
00394 if (solver_method==SM_FBS)
00395 {
00396 A_mat[indexval][indexval] = d_mat[indexval][indexval] = 1.0;
00397 }
00398 else if (solver_method==SM_NR)
00399 {
00400 From_Y[indexval][indexval] = complex(1e4,1e4);
00401 a_mat[indexval][indexval] = 1.0;
00402 NR_branchdata[NR_branch_reference].phases |= work_phase;
00403 }
00404 }
00405 }
00406 else
00407 {
00408 if (*fixtime <= Prev_Time)
00409 {
00410
00411 if (solver_method==SM_FBS)
00412 {
00413 A_mat[indexval][indexval] = d_mat[indexval][indexval] = 1.0;
00414 }
00415 else if (solver_method==SM_NR)
00416 {
00417 From_Y[indexval][indexval] = complex(1e4,1e4);
00418 a_mat[indexval][indexval] = 1.0;
00419 NR_admit_change = true;
00420 NR_branchdata[NR_branch_reference].phases |= work_phase;
00421 }
00422
00423 *valstate = GOOD;
00424 *fixtime = TS_NEVER;
00425
00426
00427 gl_verbose("Phase %c of fuse:%d (%s) just returned to service",phase_verbose,hdr->id,hdr->name);
00428 }
00429 else
00430 {
00431
00432 if (solver_method==SM_FBS)
00433 {
00434 A_mat[indexval][indexval] = d_mat[indexval][indexval] = 0.0;
00435 }
00436 else if (solver_method==SM_NR)
00437 {
00438 From_Y[indexval][indexval] = complex(0.0,0.0);
00439 a_mat[indexval][indexval] = 0.0;
00440
00441 work_phase = !work_phase;
00442 NR_branchdata[NR_branch_reference].phases &= work_phase;
00443
00444 }
00445 }
00446 }
00447 }
00448 }
00449
00451
00453
00461 EXPORT int create_fuse(OBJECT **obj, OBJECT *parent)
00462 {
00463 try
00464 {
00465 *obj = gl_create_object(fuse::oclass);
00466 if (*obj!=NULL)
00467 {
00468 fuse *my = OBJECTDATA(*obj,fuse);
00469 gl_set_parent(*obj,parent);
00470 return my->create();
00471 }
00472 }
00473 catch (const char *msg)
00474 {
00475 gl_error("create_fuse: %s", msg);
00476 }
00477 return 0;
00478 }
00479
00480 EXPORT int init_fuse(OBJECT *obj)
00481 {
00482 fuse *my = OBJECTDATA(obj,fuse);
00483 try {
00484 return my->init(obj->parent);
00485 }
00486 catch (const char *msg)
00487 {
00488 GL_THROW("%s (fuse:%d): %s", my->get_name(), my->get_id(), msg);
00489 return 0;
00490 }
00491 }
00492
00493
00494
00495
00496
00497 EXPORT int commit_fuse(OBJECT *obj)
00498 {
00499 fuse *fsr = OBJECTDATA(obj,fuse);
00500 try {
00501 if (solver_method==SM_FBS || solver_method==SM_NR)
00502 {
00503 link *plink = OBJECTDATA(obj,link);
00504 plink->calculate_power();
00505 }
00506 return fsr->fuse_state(obj->parent);
00507 }
00508 catch (const char *msg)
00509 {
00510 GL_THROW("%s (fuse:%d): %s", fsr->get_name(), fsr->get_id(), msg);
00511 return 0;
00512 }
00513
00514 }
00515
00516
00517 EXPORT TIMESTAMP sync_fuse(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00518 {
00519 fuse *pObj = OBJECTDATA(obj,fuse);
00520 try {
00521 TIMESTAMP t1 = TS_NEVER;
00522 switch (pass) {
00523 case PC_PRETOPDOWN:
00524 return pObj->presync(t0);
00525 case PC_BOTTOMUP:
00526 return pObj->sync(t0);
00527 case PC_POSTTOPDOWN:
00528 t1 = pObj->postsync(t0);
00529 obj->clock = t0;
00530 return t1;
00531 default:
00532 throw "invalid pass request";
00533 }
00534 } catch (const char *error) {
00535 GL_THROW("%s (fuse:%d): %s", pObj->get_name(), pObj->get_id(), error);
00536 return 0;
00537 } catch (...) {
00538 GL_THROW("%s (fuse:%d): %s", pObj->get_name(), pObj->get_id(), "unknown exception");
00539 return 0;
00540 }
00541 }
00542
00551 EXPORT int isa_fuse(OBJECT *obj, char *classname)
00552 {
00553 return OBJECTDATA(obj,fuse)->isa(classname);
00554 }
00555