00001
00013 #include <stdlib.h>
00014 #include <stdio.h>
00015 #include <errno.h>
00016 #include <math.h>
00017
00018 #include "fuse.h"
00019
00020
00021 CLASS* fuse::oclass = NULL;
00022 CLASS* fuse::pclass = NULL;
00023
00025
00027
00028 fuse::fuse(MODULE *mod) : link_object(mod)
00029 {
00030 if(oclass == NULL)
00031 {
00032 pclass = link_object::oclass;
00033
00034 oclass = gl_register_class(mod,"fuse",sizeof(fuse),PC_PRETOPDOWN|PC_BOTTOMUP|PC_POSTTOPDOWN|PC_UNSAFE_OVERRIDE_OMIT|PC_AUTOLOCK);
00035 if (oclass==NULL)
00036 throw "unable to register class fuse";
00037 else
00038 oclass->trl = TRL_QUALIFIED;
00039
00040 if(gl_publish_variable(oclass,
00041 PT_INHERIT, "link",
00042 PT_enumeration, "phase_A_status", PADDR(phase_A_state),
00043 PT_KEYWORD, "BLOWN", (enumeration)BLOWN,
00044 PT_KEYWORD, "GOOD", (enumeration)GOOD,
00045 PT_enumeration, "phase_B_status", PADDR(phase_B_state),
00046 PT_KEYWORD, "BLOWN", (enumeration)BLOWN,
00047 PT_KEYWORD, "GOOD", (enumeration)GOOD,
00048 PT_enumeration, "phase_C_status", PADDR(phase_C_state),
00049 PT_KEYWORD, "BLOWN", (enumeration)BLOWN,
00050 PT_KEYWORD, "GOOD", (enumeration)GOOD,
00051 PT_enumeration, "repair_dist_type", PADDR(restore_dist_type),
00052 PT_KEYWORD, "NONE", (enumeration)NONE,
00053 PT_KEYWORD, "EXPONENTIAL", (enumeration)EXPONENTIAL,
00054 PT_double, "current_limit[A]", PADDR(current_limit),
00055 PT_double, "mean_replacement_time[s]",PADDR(mean_replacement_time),
00056 PT_double, "fuse_resistance[Ohm]",PADDR(fuse_resistance), PT_DESCRIPTION,"The resistance value of the fuse when it is not blown.",
00057 NULL) < 1) GL_THROW("unable to publish properties in %s",__FILE__);
00058
00059 if (gl_publish_function(oclass,"change_fuse_state",(FUNCTIONADDR)change_fuse_state)==NULL)
00060 GL_THROW("Unable to publish fuse state change function");
00061 if (gl_publish_function(oclass,"reliability_operation",(FUNCTIONADDR)fuse_reliability_operation)==NULL)
00062 GL_THROW("Unable to publish fuse reliability operation function");
00063 if (gl_publish_function(oclass, "create_fault", (FUNCTIONADDR)create_fault_fuse)==NULL)
00064 GL_THROW("Unable to publish fault creation function");
00065 if (gl_publish_function(oclass, "fix_fault", (FUNCTIONADDR)fix_fault_fuse)==NULL)
00066 GL_THROW("Unable to publish fault restoration function");
00067 if (gl_publish_function(oclass, "change_fuse_faults", (FUNCTIONADDR)fuse_fault_updates)==NULL)
00068 GL_THROW("Unable to publish fuse fault correction function");
00069
00070
00071 if (gl_publish_function(oclass, "interupdate_pwr_object", (FUNCTIONADDR)interupdate_link)==NULL)
00072 GL_THROW("Unable to publish fuse deltamode function");
00073
00074
00075 if (gl_publish_function(oclass, "update_power_pwr_object", (FUNCTIONADDR)updatepowercalc_link)==NULL)
00076 GL_THROW("Unable to publish fuse external power calculation function");
00077 if (gl_publish_function(oclass, "check_limits_pwr_object", (FUNCTIONADDR)calculate_overlimit_link)==NULL)
00078 GL_THROW("Unable to publish fuse external power limit calculation function");
00079 }
00080 }
00081
00082 int fuse::isa(char *classname)
00083 {
00084 return strcmp(classname,"fuse")==0 || link_object::isa(classname);
00085 }
00086
00087 int fuse::create()
00088 {
00089 int result = link_object::create();
00090
00091 prev_full_status = 0x00;
00092 phase_A_state = GOOD;
00093 phase_B_state = GOOD;
00094 phase_C_state = GOOD;
00095
00096 fix_time[0] = TS_NEVER;
00097 fix_time[1] = TS_NEVER;
00098 fix_time[2] = TS_NEVER;
00099
00100 phased_fuse_status = 0x00;
00101 faulted_fuse_phases = 0x00;
00102
00103 current_limit = 9999.0;
00104 mean_replacement_time = 0.0;
00105 restore_dist_type = NONE;
00106
00107 current_current_values[0] = current_current_values[1] = current_current_values[2] = 0.0;
00108
00109 prev_fuse_time = 0;
00110
00111 event_schedule = NULL;
00112 eventgen_obj = NULL;
00113 event_schedule_map_attempt = false;
00114
00115 fuse_resistance = -1.0;
00116
00117 return result;
00118 }
00119
00126 int fuse::init(OBJECT *parent)
00127 {
00128 char jindex, kindex;
00129 OBJECT *obj = OBJECTHDR(this);
00130
00131 if ((phases & PHASE_S) == PHASE_S)
00132 {
00133 GL_THROW("fuses cannot be placed on triplex circuits");
00134
00135
00136
00137
00138 }
00139
00140
00141 SpecialLnk = SWITCH;
00142
00143 int result = link_object::init(parent);
00144
00145
00146 if (current_limit < 0.0)
00147 {
00148 GL_THROW("fuse:%s has a negative current limit value!",obj->name);
00149
00150
00151
00152
00153 }
00154
00155 if (current_limit == 0.0)
00156 {
00157 current_limit = 9999.0;
00158
00159 gl_warning("fuse:%s has a zero current limit - set to 9999.9 Amps",obj->name);
00160
00161
00162
00163
00164 }
00165
00166 if (mean_replacement_time<=0.0)
00167 {
00168 gl_warning("Fuse:%s has a negative or 0 mean replacement time - defaulting to 1 hour",obj->name);
00169
00170
00171
00172
00173 mean_replacement_time = 3600.0;
00174 }
00175
00176
00177 mean_repair_time = mean_replacement_time;
00178
00179 if (solver_method==SM_FBS)
00180 {
00181 gl_warning("Fuses only work for the attached node in the FBS solver, not any deeper.");
00182
00183
00184
00185
00186
00187
00188 }
00189
00190 if (solver_method == SM_NR){
00191 if(fuse_resistance == 0.0){
00192 gl_warning("Fuse:%s fuse_resistance has been set to zero. This will result singular matrix. Setting to the global default.",obj->name);
00193
00194
00195
00196
00197 }
00198 if(fuse_resistance < 0.0){
00199 fuse_resistance = default_resistance;
00200 }
00201 }
00202
00203
00204 for (jindex=0;jindex<3;jindex++)
00205 {
00206 for (kindex=0;kindex<3;kindex++)
00207 {
00208 a_mat[jindex][kindex] = d_mat[jindex][kindex] = A_mat[jindex][kindex] = 0.0;
00209 c_mat[jindex][kindex] = 0.0;
00210 B_mat[jindex][kindex] = b_mat[jindex][kindex] = 0.0;
00211 }
00212 }
00213
00214 a_mat[0][0] = d_mat[0][0] = A_mat[0][0] = (is_closed() && has_phase(PHASE_A) ? 1.0 : 0.0);
00215 a_mat[1][1] = d_mat[1][1] = A_mat[1][1] = (is_closed() && has_phase(PHASE_B) ? 1.0 : 0.0);
00216 a_mat[2][2] = d_mat[2][2] = A_mat[2][2] = (is_closed() && has_phase(PHASE_C) ? 1.0 : 0.0);
00217
00218 if (solver_method==SM_FBS)
00219 {
00220 b_mat[0][0] = c_mat[0][0] = B_mat[0][0] = 0.0;
00221 b_mat[1][1] = c_mat[1][1] = B_mat[1][1] = 0.0;
00222 b_mat[2][2] = c_mat[2][2] = B_mat[2][2] = 0.0;
00223 }
00224 else if (solver_method==SM_NR)
00225 {
00226
00227
00228
00229 From_Y[0][1] = From_Y[0][2] = From_Y[1][0] = 0.0;
00230 From_Y[1][2] = From_Y[2][0] = From_Y[2][1] = 0.0;
00231
00232 b_mat[0][1] = b_mat[0][2] = b_mat[1][0] = 0.0;
00233 b_mat[1][2] = b_mat[2][0] = b_mat[2][1] = 0.0;
00234
00235 if (status==LS_OPEN)
00236 {
00237 From_Y[0][0] = complex(0.0,0.0);
00238 From_Y[1][1] = complex(0.0,0.0);
00239 From_Y[2][2] = complex(0.0,0.0);
00240
00241 b_mat[0][0] = complex(0.0,0.0);
00242 b_mat[1][1] = complex(0.0,0.0);
00243 b_mat[2][2] = complex(0.0,0.0);
00244
00245 phase_A_state = phase_B_state = phase_C_state = BLOWN;
00246 phased_fuse_status = 0x00;
00247 }
00248 else
00249 {
00250 if (has_phase(PHASE_A))
00251 {
00252 if (phase_A_state == GOOD)
00253 {
00254 From_Y[0][0] = complex(1.0/fuse_resistance,1.0/fuse_resistance);
00255 b_mat[0][0] = complex(fuse_resistance,fuse_resistance);
00256 phased_fuse_status |= 0x04;
00257 }
00258 else
00259 {
00260 From_Y[0][0] = complex(0.0,0.0);
00261 b_mat[0][0] = complex(0.0,0.0);
00262 phased_fuse_status &=0xFB;
00263 }
00264 }
00265
00266 if (has_phase(PHASE_B))
00267 {
00268 if (phase_B_state == GOOD)
00269 {
00270 From_Y[1][1] = complex(1.0/fuse_resistance,1.0/fuse_resistance);
00271 b_mat[1][1] = complex(fuse_resistance,fuse_resistance);
00272 phased_fuse_status |= 0x02;
00273 }
00274 else
00275 {
00276 From_Y[1][1] = complex(0.0,0.0);
00277 b_mat[1][1] = complex(0.0,0.0);
00278 phased_fuse_status &=0xFD;
00279 }
00280 }
00281
00282 if (has_phase(PHASE_C))
00283 {
00284 if (phase_C_state == GOOD)
00285 {
00286 From_Y[2][2] = complex(1.0/fuse_resistance,1.0/fuse_resistance);
00287 b_mat[2][2] = complex(fuse_resistance,fuse_resistance);
00288 phased_fuse_status |= 0x01;
00289 }
00290 else
00291 {
00292 From_Y[2][2] = complex(0.0,0.0);
00293 b_mat[2][2] = complex(0.0,0.0);
00294 phased_fuse_status &=0xFE;
00295 }
00296 }
00297 }
00298 }
00299 else
00300 {
00301 GL_THROW("Fuses are not supported by this solver method");
00302
00303
00304
00305
00306
00307 }
00308
00309 return result;
00310 }
00311
00312 TIMESTAMP fuse::sync(TIMESTAMP t0)
00313 {
00314 OBJECT *obj = OBJECTHDR(this);
00315 unsigned char work_phases;
00316 bool fuse_blew;
00317 TIMESTAMP replacement_time;
00318 TIMESTAMP replacement_duration;
00319 TIMESTAMP t2;
00320 char fault_val[9];
00321 int result_val;
00322
00323
00324 if (event_schedule_map_attempt == false)
00325 {
00326
00327 if (fault_check_object != NULL)
00328 {
00329
00330 eventgen_obj = get_object(fault_check_object, "eventgen_object");
00331
00332
00333 if (*eventgen_obj != NULL)
00334 {
00335
00336 event_schedule = (FUNCTIONADDR)(gl_get_function(*eventgen_obj,"add_event"));
00337
00338
00339 if (event_schedule == NULL)
00340 {
00341 gl_warning("Unable to map add_event function in eventgen:%s",*(*eventgen_obj)->name);
00342
00343
00344
00345
00346
00347 }
00348 }
00349
00350 }
00351
00352
00353
00354 event_schedule_map_attempt = true;
00355 }
00356
00357
00358 if (prev_fuse_time != t0)
00359 prev_fuse_time = t0;
00360
00361
00362
00363 if (solver_method == SM_NR)
00364 {
00365
00366 if (((fix_time[0] <= t0) || (fix_time[1] <= t0) || (fix_time[2] <= t0)) && (event_schedule == NULL))
00367 {
00368
00369 if ((fix_time[0] <= t0) && ((NR_branchdata[NR_branch_reference].origphases & 0x04) == 0x04))
00370 {
00371
00372 phase_A_state = GOOD;
00373
00374
00375 fix_time[0] = TS_NEVER;
00376 }
00377
00378 if ((fix_time[1] <= t0) && ((NR_branchdata[NR_branch_reference].origphases & 0x02) == 0x02))
00379 {
00380
00381 phase_B_state = GOOD;
00382
00383
00384 fix_time[1] = TS_NEVER;
00385 }
00386
00387 if ((fix_time[2] <= t0) && ((NR_branchdata[NR_branch_reference].origphases & 0x01) == 0x01))
00388 {
00389
00390 phase_C_state = GOOD;
00391
00392
00393 fix_time[2] = TS_NEVER;
00394 }
00395 }
00396
00397
00398 fuse_sync_function();
00399
00400
00401 t2=link_object::sync(t0);
00402
00403
00404
00405 fuse_blew = false;
00406 work_phases = 0x00;
00407 replacement_time = 0;
00408
00409
00410 if ((NR_branchdata[NR_branch_reference].phases & 0x04) == 0x04)
00411 {
00412
00413 current_current_values[0] = current_in[0].Mag();
00414
00415 if ((current_current_values[0] > current_limit) && (phase_A_state == GOOD))
00416 {
00417 phase_A_state = BLOWN;
00418 gl_warning("Phase A of fuse:%s just blew!",obj->name);
00419
00420
00421
00422
00423
00424 fuse_blew = true;
00425 work_phases |= 0x04;
00426
00427
00428 if (replacement_time == 0)
00429 {
00430
00431 if (restore_dist_type == EXPONENTIAL)
00432 {
00433
00434 mean_repair_time = gl_random_exponential(RNGSTATE,1.0/mean_replacement_time);
00435 replacement_duration = (TIMESTAMP)(mean_repair_time);
00436 }
00437 else
00438 {
00439
00440 mean_repair_time = mean_replacement_time;
00441 replacement_duration = (TIMESTAMP)(mean_repair_time);
00442 }
00443
00444
00445 replacement_time = prev_fuse_time + replacement_duration;
00446 }
00447 }
00448
00449 }
00450
00451 if ((NR_branchdata[NR_branch_reference].phases & 0x02) == 0x02)
00452 {
00453
00454 current_current_values[1] = current_in[1].Mag();
00455
00456 if ((current_current_values[1] > current_limit) && (phase_B_state == GOOD))
00457 {
00458 phase_B_state = BLOWN;
00459
00460 gl_warning("Phase B of fuse:%s just blew!",obj->name);
00461
00462
00463
00464
00465
00466 fuse_blew = true;
00467 work_phases |= 0x02;
00468
00469
00470 if (replacement_time == 0)
00471 {
00472
00473 if (restore_dist_type == EXPONENTIAL)
00474 {
00475
00476 mean_repair_time = gl_random_exponential(RNGSTATE,1.0/mean_replacement_time);
00477 replacement_duration = (TIMESTAMP)(mean_repair_time);
00478 }
00479 else
00480 {
00481
00482 mean_repair_time = mean_replacement_time;
00483 replacement_duration = (TIMESTAMP)(mean_repair_time);
00484 }
00485
00486
00487 replacement_time = prev_fuse_time + replacement_duration;
00488 }
00489 }
00490
00491 }
00492
00493 if ((NR_branchdata[NR_branch_reference].phases & 0x01) == 0x01)
00494 {
00495
00496 current_current_values[2] = current_in[2].Mag();
00497
00498 if ((current_current_values[2] > current_limit) && (phase_C_state == GOOD))
00499 {
00500 phase_C_state = BLOWN;
00501
00502 gl_warning("Phase C of fuse:%s just blew!",obj->name);
00503
00504
00505
00506
00507
00508 fuse_blew = true;
00509 work_phases |= 0x01;
00510
00511
00512 if (replacement_time == 0)
00513 {
00514
00515 if (restore_dist_type == EXPONENTIAL)
00516 {
00517
00518 mean_repair_time = gl_random_exponential(RNGSTATE,1.0/mean_replacement_time);
00519 replacement_duration = (TIMESTAMP)(mean_repair_time);
00520 }
00521 else
00522 {
00523
00524 mean_repair_time = mean_replacement_time;
00525 replacement_duration = (TIMESTAMP)(mean_repair_time);
00526 }
00527
00528
00529 replacement_time = prev_fuse_time + replacement_duration;
00530 }
00531 }
00532
00533 }
00534
00535 if (fuse_blew == true)
00536 {
00537
00538 fault_val[0] = 'F';
00539 fault_val[1] = 'U';
00540 fault_val[2] = 'S';
00541 fault_val[3] = '-';
00542
00543
00544 switch (work_phases)
00545 {
00546 case 0x00:
00547 GL_THROW("fuse:%s supposedly blew, but doesn't register the right phases",obj->name);
00548
00549
00550
00551
00552
00553 break;
00554 case 0x01:
00555 fix_time[2] = replacement_time;
00556 fault_val[4] = 'C';
00557 fault_val[5] = '\0';
00558 break;
00559 case 0x02:
00560 fix_time[1] = replacement_time;
00561 fault_val[4] = 'B';
00562 fault_val[5] = '\0';
00563 break;
00564 case 0x03:
00565 fix_time[1] = replacement_time;
00566 fix_time[2] = replacement_time;
00567 fault_val[4] = 'B';
00568 fault_val[5] = 'C';
00569 fault_val[6] = '\0';
00570 break;
00571 case 0x04:
00572 fix_time[0] = replacement_time;
00573 fault_val[4] = 'A';
00574 fault_val[5] = '\0';
00575 break;
00576 case 0x05:
00577 fix_time[0] = replacement_time;
00578 fix_time[2] = replacement_time;
00579 fault_val[4] = 'A';
00580 fault_val[5] = 'C';
00581 fault_val[6] = '\0';
00582 break;
00583 case 0x06:
00584 fix_time[0] = replacement_time;
00585 fix_time[1] = replacement_time;
00586 fault_val[4] = 'A';
00587 fault_val[5] = 'B';
00588 fault_val[6] = '\0';
00589 break;
00590 case 0x07:
00591 fix_time[0] = replacement_time;
00592 fix_time[1] = replacement_time;
00593 fix_time[2] = replacement_time;
00594 fault_val[4] = 'A';
00595 fault_val[5] = 'B';
00596 fault_val[6] = 'C';
00597 fault_val[7] = '\0';
00598 break;
00599 default:
00600 GL_THROW("fuse:%s supposedly blew, but doesn't register the right phases",obj->name);
00601
00602 }
00603
00604 if (event_schedule != NULL)
00605 {
00606
00607 result_val = ((int (*)(OBJECT *, OBJECT *, char *, TIMESTAMP, TIMESTAMP, int, bool))(*event_schedule))(*eventgen_obj,obj,fault_val,t0,0,-1,false);
00608
00609
00610 if (result_val != 1)
00611 {
00612 GL_THROW("Attempt to blow fuse:%s failed in a reliability manner",obj->name);
00613
00614
00615
00616
00617 }
00618
00619
00620 t2 = t0;
00621
00622 }
00623 else
00624 {
00625 gl_warning("No fault_check object present - Newton-Raphson solver may fail!");
00626
00627
00628
00629
00630
00631
00632 }
00633 }
00634 }
00635 else
00636 t2 = link_object::sync(t0);
00637
00638 if (t2==TS_NEVER)
00639 return(t2);
00640 else
00641 return(-t2);
00642 }
00643
00644 TIMESTAMP fuse::postsync(TIMESTAMP t0)
00645 {
00646 OBJECT *hdr = OBJECTHDR(this);
00647 char jindex;
00648 unsigned char goodphases = 0x00;
00649 TIMESTAMP Ret_Val[3], t1;
00650
00651
00652 if (solver_method == SM_FBS)
00653 {
00654
00655
00656 if ((phases & PHASE_A) == PHASE_A)
00657 {
00658 if (phase_A_state == GOOD)
00659 {
00660 Ret_Val[0] = TS_NEVER;
00661 goodphases |= 0x04;
00662 }
00663 else
00664 {
00665 if (t0 == fix_time[0])
00666 Ret_Val[0] = t0 + 1;
00667 else
00668 Ret_Val[0] = fix_time[0];
00669 }
00670 }
00671 else
00672 Ret_Val[0] = TS_NEVER;
00673
00674
00675 if ((phases & PHASE_B) == PHASE_B)
00676 {
00677 if (phase_B_state == GOOD)
00678 {
00679 Ret_Val[1] = TS_NEVER;
00680 goodphases |= 0x02;
00681 }
00682 else
00683 {
00684 if (t0 == fix_time[1])
00685 Ret_Val[1] = t0 + 1;
00686 else
00687 Ret_Val[1] = fix_time[1];
00688 }
00689 }
00690 else
00691 Ret_Val[1] = TS_NEVER;
00692
00693
00694
00695 if ((phases & PHASE_C) == PHASE_C)
00696 {
00697 if (phase_C_state == GOOD)
00698 {
00699 Ret_Val[2] = TS_NEVER;
00700 goodphases |= 0x01;
00701 }
00702 else
00703 {
00704 if (t0 == fix_time[2])
00705 Ret_Val[2] = t0 + 1;
00706 else
00707 Ret_Val[2] = fix_time[2];
00708 }
00709 }
00710 else
00711 Ret_Val[2] = TS_NEVER;
00712
00713
00714 t1 = link_object::postsync(t0);
00715
00716
00717 for (jindex=0;jindex<3;jindex++)
00718 {
00719 if (Ret_Val[jindex] < t1)
00720 t1 = Ret_Val[jindex];
00721 }
00722 }
00723 else
00724 {
00725 t1 = link_object::postsync(t0);
00726 }
00727
00728 if (t1 != TS_NEVER)
00729 return -t1;
00730 else
00731 return TS_NEVER;
00732 }
00733
00734
00735
00736
00737 void fuse::fuse_change_status_function(void)
00738 {
00739 unsigned char pres_status;
00740
00741 if (solver_method==SM_NR)
00742 {
00743 if (status == LS_OPEN)
00744 {
00745 From_Y[0][0] = complex(0.0,0.0);
00746 From_Y[1][1] = complex(0.0,0.0);
00747 From_Y[2][2] = complex(0.0,0.0);
00748
00749 b_mat[0][0] = complex(0.0,0.0);
00750 b_mat[1][1] = complex(0.0,0.0);
00751 b_mat[2][2] = complex(0.0,0.0);
00752
00753 a_mat[0][0] = d_mat[0][0] = A_mat[0][0] = 0.0;
00754 a_mat[1][1] = d_mat[1][1] = A_mat[1][1] = 0.0;
00755 a_mat[2][2] = d_mat[2][2] = A_mat[2][2] = 0.0;
00756
00757 phase_A_state = phase_B_state = phase_C_state = BLOWN;
00758
00759 NR_branchdata[NR_branch_reference].phases &= 0xF0;
00760 if (meshed_fault_checking_enabled==true)
00761 {
00762 NR_branchdata[NR_branch_reference].faultphases = NR_branchdata[NR_branch_reference].origphases & 0x07;
00763 }
00764
00765 }
00766 else
00767 {
00768 if (has_phase(PHASE_A))
00769 {
00770 if (phase_A_state == GOOD)
00771 {
00772 From_Y[0][0] = complex(1.0/fuse_resistance,1.0/fuse_resistance);
00773 b_mat[0][0] = complex(fuse_resistance,fuse_resistance);
00774 a_mat[0][0] = d_mat[0][0] = A_mat[0][0] = 1.0;
00775 pres_status |= 0x04;
00776 NR_branchdata[NR_branch_reference].phases |= 0x04;
00777 if (meshed_fault_checking_enabled==true)
00778 {
00779 NR_branchdata[NR_branch_reference].faultphases &= 0xFB;
00780 }
00781 }
00782 else
00783 {
00784 From_Y[0][0] = complex(0.0,0.0);
00785 b_mat[0][0] = complex(0.0,0.0);
00786 a_mat[0][0] = d_mat[0][0] = A_mat[0][0] = 0.0;
00787 NR_branchdata[NR_branch_reference].phases &= 0xFB;
00788 if (meshed_fault_checking_enabled==true)
00789 {
00790 NR_branchdata[NR_branch_reference].faultphases |= 0x04;
00791 }
00792 }
00793 }
00794
00795 if (has_phase(PHASE_B))
00796 {
00797 if (phase_B_state == GOOD)
00798 {
00799 From_Y[1][1] = complex(1.0/fuse_resistance,1.0/fuse_resistance);
00800 b_mat[1][1] = complex(fuse_resistance,fuse_resistance);
00801 a_mat[1][1] = d_mat[1][1] = A_mat[1][1] = 1.0;
00802 pres_status |= 0x02;
00803 NR_branchdata[NR_branch_reference].phases |= 0x02;
00804 if (meshed_fault_checking_enabled==true)
00805 {
00806 NR_branchdata[NR_branch_reference].faultphases &= 0xFD;
00807 }
00808 }
00809 else
00810 {
00811 From_Y[1][1] = complex(0.0,0.0);
00812 b_mat[1][1] = complex(0.0,0.0);
00813 a_mat[1][1] = d_mat[1][1] = A_mat[1][1] = 0.0;
00814 NR_branchdata[NR_branch_reference].phases &= 0xFD;
00815 if (meshed_fault_checking_enabled==true)
00816 {
00817 NR_branchdata[NR_branch_reference].faultphases |= 0x02;
00818 }
00819 }
00820 }
00821
00822 if (has_phase(PHASE_C))
00823 {
00824 if (phase_C_state == GOOD)
00825 {
00826 From_Y[2][2] = complex(1.0/fuse_resistance,1.0/fuse_resistance);
00827 b_mat[2][2] = complex(fuse_resistance,fuse_resistance);
00828 a_mat[2][2] = d_mat[2][2] = A_mat[2][2] = 1.0;
00829 pres_status |= 0x01;
00830 NR_branchdata[NR_branch_reference].phases |= 0x01;
00831 if (meshed_fault_checking_enabled==true)
00832 {
00833 NR_branchdata[NR_branch_reference].faultphases &= 0xFE;
00834 }
00835 }
00836 else
00837 {
00838 From_Y[2][2] = complex(0.0,0.0);
00839 b_mat[2][2] = complex(0.0,0.0);
00840 a_mat[2][2] = d_mat[2][2] = A_mat[2][2] = 0.0;
00841 NR_branchdata[NR_branch_reference].phases &= 0xFE;
00842 if (meshed_fault_checking_enabled==true)
00843 {
00844 NR_branchdata[NR_branch_reference].faultphases |= 0x01;
00845 }
00846 }
00847 }
00848 }
00849
00850 LOCK_OBJECT(NR_swing_bus);
00851 NR_admit_change = true;
00852 UNLOCK_OBJECT(NR_swing_bus);
00853
00854 prev_status = status;
00855
00856 }
00857 else
00858 {
00859 gl_warning("Fuse status updated, but no other changes made.");
00860
00861
00862
00863
00864
00865 }
00866 }
00867
00868
00869
00870 void fuse::fuse_sync_function(void)
00871 {
00872 unsigned char pres_status;
00873
00874 if (solver_method==SM_NR)
00875 {
00876 pres_status = 0x00;
00877
00878 if (status == LS_OPEN)
00879 {
00880 From_Y[0][0] = complex(0.0,0.0);
00881 From_Y[1][1] = complex(0.0,0.0);
00882 From_Y[2][2] = complex(0.0,0.0);
00883
00884 b_mat[0][0] = complex(0.0,0.0);
00885 b_mat[1][1] = complex(0.0,0.0);
00886 b_mat[2][2] = complex(0.0,0.0);
00887
00888 phase_A_state = phase_B_state = phase_C_state = BLOWN;
00889 NR_branchdata[NR_branch_reference].phases &= 0xF0;
00890 }
00891 else
00892 {
00893 if (has_phase(PHASE_A))
00894 {
00895 if (phase_A_state == GOOD)
00896 {
00897 From_Y[0][0] = complex(1.0/fuse_resistance,1.0/fuse_resistance);
00898 b_mat[0][0] = complex(fuse_resistance,fuse_resistance);
00899 pres_status |= 0x04;
00900
00901
00902 if ((prev_full_status & 0x04) != 0x04)
00903 {
00904 NR_branchdata[NR_branch_reference].phases |= 0x04;
00905 }
00906 }
00907 else
00908 {
00909 From_Y[0][0] = complex(0.0,0.0);
00910 b_mat[0][0] = complex(0.0,0.0);
00911
00912
00913 if ((prev_full_status & 0x04) != 0x00)
00914 {
00915 NR_branchdata[NR_branch_reference].phases &= 0xFB;
00916 }
00917 }
00918 }
00919
00920 if (has_phase(PHASE_B))
00921 {
00922 if (phase_B_state == GOOD)
00923 {
00924 From_Y[1][1] = complex(1.0/fuse_resistance,1.0/fuse_resistance);
00925 b_mat[1][1] = complex(fuse_resistance,fuse_resistance);
00926 pres_status |= 0x02;
00927
00928
00929 if ((prev_full_status & 0x02) != 0x02)
00930 {
00931 NR_branchdata[NR_branch_reference].phases |= 0x02;
00932 }
00933 }
00934 else
00935 {
00936 From_Y[1][1] = complex(0.0,0.0);
00937 b_mat[1][1] = complex(0.0,0.0);
00938
00939
00940 if ((prev_full_status & 0x02) != 0x00)
00941 {
00942 NR_branchdata[NR_branch_reference].phases &= 0xFD;
00943 }
00944 }
00945 }
00946
00947 if (has_phase(PHASE_C))
00948 {
00949 if (phase_C_state == GOOD)
00950 {
00951 From_Y[2][2] = complex(1.0/fuse_resistance,1.0/fuse_resistance);
00952 b_mat[2][2] = complex(fuse_resistance,fuse_resistance);
00953 pres_status |= 0x01;
00954
00955
00956 if ((prev_full_status & 0x01) != 0x01)
00957 {
00958 NR_branchdata[NR_branch_reference].phases |= 0x01;
00959 }
00960 }
00961 else
00962 {
00963 From_Y[2][2] = complex(0.0,0.0);
00964 b_mat[2][2] = complex(0.0,0.0);
00965
00966
00967 if ((prev_full_status & 0x01) != 0x00)
00968 {
00969 NR_branchdata[NR_branch_reference].phases &= 0xFE;
00970 }
00971 }
00972 }
00973 }
00974
00975
00976 if ((status != prev_status) || (pres_status != prev_full_status))
00977 {
00978 LOCK_OBJECT(NR_swing_bus);
00979 NR_admit_change = true;
00980 UNLOCK_OBJECT(NR_swing_bus);
00981 }
00982
00983 prev_full_status = pres_status;
00984 }
00985 }
00986
00987
00988
00989
00990 void fuse::set_fuse_full(char desired_status_A, char desired_status_B, char desired_status_C)
00991 {
00992 if (desired_status_A == 0)
00993 phase_A_state = BLOWN;
00994 else if (desired_status_A == 1)
00995 phase_A_state = GOOD;
00996
00997
00998 if (desired_status_B == 0)
00999 phase_B_state = BLOWN;
01000 else if (desired_status_B == 1)
01001 phase_B_state = GOOD;
01002
01003
01004 if (desired_status_C == 0)
01005 phase_C_state = BLOWN;
01006 else if (desired_status_C == 1)
01007 phase_C_state = GOOD;
01008
01009
01010
01011 fuse_sync_function();
01012
01013 }
01014
01015
01016
01017
01018 void fuse::set_fuse_full_reliability(unsigned char desired_status)
01019 {
01020 unsigned char desA, desB, desC, phase_change;
01021
01022
01023 phase_change = desired_status ^ (~faulted_fuse_phases);
01024
01025
01026 if ((phase_change & 0x04) == 0x04)
01027 {
01028
01029 if ((desired_status & 0x04) == 0x04)
01030 {
01031
01032 if ((phased_fuse_status & 0x04) == 0x04)
01033 {
01034 desA=1;
01035 }
01036 else
01037 {
01038 desA=0;
01039 }
01040
01041 faulted_fuse_phases &= 0xFB;
01042 }
01043 else
01044 {
01045 if (phase_A_state == GOOD)
01046 {
01047 phased_fuse_status |= 0x04;
01048 }
01049 else
01050 {
01051 phased_fuse_status &= 0xFB;
01052 }
01053
01054 desA=0;
01055 faulted_fuse_phases |= 0x04;
01056 }
01057 }
01058 else
01059 desA=2;
01060
01061 if ((phase_change & 0x02) == 0x02)
01062 {
01063
01064 if ((desired_status & 0x02) == 0x02)
01065 {
01066
01067 if ((phased_fuse_status & 0x02) == 0x02)
01068 {
01069 desB=1;
01070 }
01071 else
01072 {
01073 desB=0;
01074 }
01075
01076 faulted_fuse_phases &= 0xFD;
01077 }
01078 else
01079 {
01080 if (phase_B_state == GOOD)
01081 {
01082 phased_fuse_status |= 0x02;
01083 }
01084 else
01085 {
01086 phased_fuse_status &= 0xFD;
01087 }
01088
01089 desB=0;
01090 faulted_fuse_phases |= 0x02;
01091 }
01092 }
01093 else
01094 desB=2;
01095
01096 if ((phase_change & 0x01) == 0x01)
01097 {
01098
01099 if ((desired_status & 0x01) == 0x01)
01100 {
01101
01102 if ((phased_fuse_status & 0x01) == 0x01)
01103 {
01104 desC=1;
01105 }
01106 else
01107 {
01108 desC=0;
01109 }
01110
01111 faulted_fuse_phases &= 0xFE;
01112 }
01113 else
01114 {
01115 if (phase_C_state == GOOD)
01116 {
01117 phased_fuse_status |= 0x01;
01118 }
01119 else
01120 {
01121 phased_fuse_status &= 0xFE;
01122 }
01123
01124 desC=0;
01125 faulted_fuse_phases |= 0x01;
01126 }
01127 }
01128 else
01129 desC=2;
01130
01131
01132 set_fuse_full(desA,desB,desC);
01133
01134 }
01135
01136
01137 OBJECT **fuse::get_object(OBJECT *obj, char *name)
01138 {
01139 PROPERTY *p = gl_get_property(obj,name);
01140 if (p==NULL || p->ptype!=PT_object)
01141 return NULL;
01142 return (OBJECT**)GETADDR(obj,p);
01143 }
01144
01145
01146 void fuse::set_fuse_faulted_phases(unsigned char desired_status)
01147 {
01148
01149 phased_fuse_status |= desired_status;
01150 }
01151
01161 void fuse::fuse_check(set phase_to_check, complex *fcurr)
01162 {
01163 char indexval;
01164 char phase_verbose;
01165 unsigned char work_phase;
01166 FUSESTATE *valstate;
01167 TIMESTAMP *fixtime;
01168 OBJECT *hdr = OBJECTHDR(this);
01169
01170 if (phase_to_check == PHASE_A)
01171 {
01172 indexval = 0;
01173 valstate = (FUSESTATE*)&phase_A_state;
01174 phase_verbose='A';
01175 fixtime = &fix_time[0];
01176 }
01177 else if (phase_to_check == PHASE_B)
01178 {
01179 indexval = 1;
01180 valstate = (FUSESTATE*)&phase_B_state;
01181 phase_verbose='B';
01182 fixtime = &fix_time[1];
01183 }
01184 else if (phase_to_check == PHASE_C)
01185 {
01186 indexval = 2;
01187 valstate = (FUSESTATE*)&phase_C_state;
01188 phase_verbose='C';
01189 fixtime = &fix_time[2];
01190 }
01191 else
01192 {
01193 GL_THROW("Unknown phase to check in fuse:%d",OBJECTHDR(this)->id);
01194
01195
01196
01197
01198
01199 }
01200
01201
01202 if ((phases & phase_to_check) == phase_to_check)
01203 {
01204 work_phase = 0x04 >> indexval;
01205
01206 if (*valstate == GOOD)
01207 {
01208
01209 if (fcurr[indexval].Mag() > current_limit)
01210 {
01211 *valstate = BLOWN;
01212
01213
01214 A_mat[indexval][indexval] = d_mat[indexval][indexval] = 0.0;
01215
01216
01217 *fixtime = prev_fuse_time + (int64)(3600*gl_random_exponential(RNGSTATE,1.0/mean_replacement_time));
01218
01219
01220 gl_warning("Phase %c of fuse:%d (%s) just blew",phase_verbose,hdr->id,hdr->name);
01221 }
01222 else
01223 {
01224
01225 A_mat[indexval][indexval] = d_mat[indexval][indexval] = 1.0;
01226 }
01227 }
01228 else
01229 {
01230 if (*fixtime <= prev_fuse_time)
01231 {
01232
01233 A_mat[indexval][indexval] = d_mat[indexval][indexval] = 1.0;
01234
01235 *valstate = GOOD;
01236 *fixtime = TS_NEVER;
01237
01238
01239 gl_warning("Phase %c of fuse:%d (%s) just returned to service",phase_verbose,hdr->id,hdr->name);
01240 }
01241 else
01242 {
01243
01244 A_mat[indexval][indexval] = d_mat[indexval][indexval] = 0.0;
01245 }
01246 }
01247 }
01248 }
01249
01257 int fuse::fuse_state(OBJECT *parent)
01258 {
01259 this->fuse_check(PHASE_A,current_in);
01260 this->fuse_check(PHASE_B,current_in);
01261 this->fuse_check(PHASE_C,current_in);
01262
01263 return 1;
01264 }
01265
01267
01269
01277 EXPORT int create_fuse(OBJECT **obj, OBJECT *parent)
01278 {
01279 try
01280 {
01281 *obj = gl_create_object(fuse::oclass);
01282 if (*obj!=NULL)
01283 {
01284 fuse *my = OBJECTDATA(*obj,fuse);
01285 gl_set_parent(*obj,parent);
01286 return my->create();
01287 }
01288 else
01289 return 0;
01290 }
01291 CREATE_CATCHALL(fuse);
01292 }
01293
01294 EXPORT int init_fuse(OBJECT *obj)
01295 {
01296 try {
01297 fuse *my = OBJECTDATA(obj,fuse);
01298 return my->init(obj->parent);
01299 }
01300 INIT_CATCHALL(fuse);
01301 }
01302
01303
01304 EXPORT TIMESTAMP commit_fuse(OBJECT *obj, TIMESTAMP t1, TIMESTAMP t2)
01305 {
01306 fuse *fsr = OBJECTDATA(obj,fuse);
01307 try
01308 {
01309 if (solver_method==SM_FBS)
01310 {
01311 link_object *plink = OBJECTDATA(obj,link_object);
01312 plink->calculate_power();
01313
01314 return (fsr->fuse_state(obj->parent) ? TS_NEVER : 0);
01315 }
01316 else
01317 return TS_NEVER;
01318 }
01319 catch (const char *msg)
01320 {
01321 gl_error("%s (fuse:%d): %s", fsr->get_name(), fsr->get_id(), msg);
01322 return 0;
01323 }
01324 }
01325
01326 EXPORT TIMESTAMP sync_fuse(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
01327 {
01328 try {
01329 fuse *pObj = OBJECTDATA(obj,fuse);
01330 TIMESTAMP t1 = TS_NEVER;
01331 switch (pass) {
01332 case PC_PRETOPDOWN:
01333 return pObj->presync(t0);
01334 case PC_BOTTOMUP:
01335 return pObj->sync(t0);
01336 case PC_POSTTOPDOWN:
01337 t1 = pObj->postsync(t0);
01338 obj->clock = t0;
01339 return t1;
01340 default:
01341 throw "invalid pass request";
01342 }
01343 }
01344 SYNC_CATCHALL(fuse);
01345 }
01346
01355 EXPORT int isa_fuse(OBJECT *obj, char *classname)
01356 {
01357 return OBJECTDATA(obj,fuse)->isa(classname);
01358 }
01359
01360
01361 EXPORT int change_fuse_state(OBJECT *thisobj, unsigned char phase_change, bool state)
01362 {
01363 char desA, desB, desC;
01364
01365
01366 fuse *fuseobj = OBJECTDATA(thisobj,fuse);
01367
01368
01369 if ((phase_change & 0x04) == 0x04)
01370 {
01371 if (state==true)
01372 desA=1;
01373 else
01374 desA=0;
01375 }
01376 else
01377 desA=2;
01378
01379
01380 if ((phase_change & 0x02) == 0x02)
01381 {
01382 if (state==true)
01383 desB=1;
01384 else
01385 desB=0;
01386 }
01387 else
01388 desB=2;
01389
01390
01391 if ((phase_change & 0x01) == 0x01)
01392 {
01393 if (state==true)
01394 desC=1;
01395 else
01396 desC=0;
01397 }
01398 else
01399 desC=2;
01400
01401
01402 fuseobj->set_fuse_full(desA,desB,desC);
01403
01404 return 1;
01405 }
01406
01407
01408 EXPORT int fuse_reliability_operation(OBJECT *thisobj, unsigned char desired_phases)
01409 {
01410
01411 fuse *fuseobj = OBJECTDATA(thisobj,fuse);
01412
01413 fuseobj->set_fuse_full_reliability(desired_phases);
01414
01415 return 1;
01416 }
01417
01418 EXPORT int create_fault_fuse(OBJECT *thisobj, OBJECT **protect_obj, char *fault_type, int *implemented_fault, TIMESTAMP *repair_time)
01419 {
01420 int retval;
01421
01422
01423 fuse *thisfuse = OBJECTDATA(thisobj,fuse);
01424
01425
01426 retval = thisfuse->link_fault_on(protect_obj, fault_type, implemented_fault,repair_time);
01427
01428 return retval;
01429 }
01430 EXPORT int fix_fault_fuse(OBJECT *thisobj, int *implemented_fault, char *imp_fault_name)
01431 {
01432 int retval;
01433
01434
01435 fuse *thisfuse = OBJECTDATA(thisobj,fuse);
01436
01437
01438 retval = thisfuse->link_fault_off(implemented_fault, imp_fault_name);
01439
01440
01441 *implemented_fault = -1;
01442
01443 return retval;
01444 }
01445
01446 EXPORT int fuse_fault_updates(OBJECT *thisobj, unsigned char restoration_phases)
01447 {
01448
01449 fuse *thisfuse = OBJECTDATA(thisobj,fuse);
01450
01451
01452 thisfuse->set_fuse_faulted_phases(restoration_phases);
01453
01454 return 1;
01455 }
01456