00001
00005 #include <stdlib.h>
00006 #include <stdio.h>
00007 #include <errno.h>
00008 #include <math.h>
00009
00010 #include "fault_check.h"
00011
00013
00015 CLASS* fault_check::oclass = NULL;
00016 CLASS* fault_check::pclass = NULL;
00017
00018 fault_check::fault_check(MODULE *mod) : powerflow_object(mod)
00019 {
00020 if(oclass == NULL)
00021 {
00022 pclass = powerflow_object::oclass;
00023 oclass = gl_register_class(mod,"fault_check",sizeof(fault_check),PC_BOTTOMUP|PC_AUTOLOCK);
00024 if (oclass==NULL)
00025 throw "unable to register class fault_check";
00026 else
00027 oclass->trl = TRL_DEMONSTRATED;
00028
00029 if(gl_publish_variable(oclass,
00030 PT_enumeration, "check_mode", PADDR(fcheck_state),PT_DESCRIPTION,"Frequency of fault checks",
00031 PT_KEYWORD, "SINGLE", (enumeration)SINGLE,
00032 PT_KEYWORD, "ONCHANGE", (enumeration)ONCHANGE,
00033 PT_KEYWORD, "ALL", (enumeration)ALLT,
00034 PT_KEYWORD, "SINGLE_DEBUG", (enumeration)SINGLE_DEBUG,
00035 PT_char1024,"output_filename",PADDR(output_filename),PT_DESCRIPTION,"Output filename for list of unsupported nodes",
00036 PT_bool,"reliability_mode",PADDR(reliability_mode),PT_DESCRIPTION,"General flag indicating if fault_check is operating under faulting or restoration mode -- reliability set this",
00037 PT_bool,"strictly_radial",PADDR(reliability_search_mode),PT_DESCRIPTION,"Flag to indicate if a system is known to be strictly radial -- uses radial assumptions for reliability alterations",
00038 PT_bool,"full_output_file",PADDR(full_print_output),PT_DESCRIPTION,"Flag to indicate if the output_filename report contains both supported and unsupported nodes -- if false, just does unsupported",
00039 PT_bool,"grid_association",PADDR(grid_association_mode),PT_DESCRIPTION,"Flag to indicate if multiple, distinct grids are allowed in a GLM, or if anything not attached to the master swing is removed",
00040 PT_object,"eventgen_object",PADDR(rel_eventgen),PT_DESCRIPTION,"Link to generic eventgen object to handle unexpected faults",
00041 NULL) < 1) GL_THROW("unable to publish properties in %s",__FILE__);
00042 if (gl_publish_function(oclass,"reliability_alterations",(FUNCTIONADDR)powerflow_alterations)==NULL)
00043 GL_THROW("Unable to publish remove from service function");
00044 if (gl_publish_function(oclass,"handle_sectionalizer",(FUNCTIONADDR)handle_sectionalizer)==NULL)
00045 GL_THROW("Unable to publish sectionalizer special function");
00046 if (gl_publish_function(oclass,"island_removal_function",(FUNCTIONADDR)powerflow_disable_island)==NULL)
00047 GL_THROW("Unable to publish island deletion function");
00048 if (gl_publish_function(oclass,"rescan_topology",(FUNCTIONADDR)powerflow_rescan_topo)==NULL)
00049 GL_THROW("Unable to publish the topology rescan function");
00050 }
00051 }
00052
00053 int fault_check::isa(char *classname)
00054 {
00055 return strcmp(classname,"fault_check")==0;
00056 }
00057
00058 int fault_check::create(void)
00059 {
00060 int result = powerflow_object::create();
00061 prev_time = 0;
00062 phases = PHASE_A;
00063
00064 fcheck_state = SINGLE;
00065 output_filename[0] = '\0';
00066
00067 full_print_output = false;
00068
00069 reliability_mode = false;
00070
00071 reliability_search_mode = true;
00072
00073 rel_eventgen = NULL;
00074
00075 restoration_fxn = NULL;
00076
00077 grid_association_mode = false;
00078
00079 force_reassociation = false;
00080
00081 return result;
00082 }
00083
00084 int fault_check::init(OBJECT *parent)
00085 {
00086 OBJECT *obj = OBJECTHDR(this);
00087 FILE *FPoint;
00088
00089 if (solver_method == SM_NR)
00090 {
00091
00092 gl_set_rank(obj,5);
00093 }
00094 else
00095 {
00096 GL_THROW("Fault checking object is only valid for the Newton-Raphson solver at this time.");
00097
00098
00099
00100
00101 }
00102
00103
00104 if (fault_check_object == NULL)
00105 {
00106 fault_check_object = obj;
00107 }
00108 else
00109 {
00110 GL_THROW("Only one fault_check object is supported at this time");
00111
00112
00113
00114
00115 }
00116
00117
00118
00119 if(rel_eventgen != NULL){
00120 if(!gl_object_isa(rel_eventgen,"eventgen")){
00121 gl_error("fault_check:%s %s is not an eventgen object. Please specify the name of an eventgen object.",obj->name,rel_eventgen);
00122 return 0;
00123
00124
00125
00126
00127 }
00128
00129
00130 reliability_mode = true;
00131 }
00132
00133
00134 if (output_filename[0] != '\0')
00135 {
00136 FPoint = fopen(output_filename,"wt");
00137 fclose(FPoint);
00138 }
00139
00140
00141 if (grid_association_mode == true)
00142 {
00143 if (reliability_search_mode == true)
00144 {
00145 gl_warning("fault_check:%s was forced into meshed search mode due to multiple grids being desired",obj->name ? obj->name : "Unnamed");
00146
00147
00148
00149
00150
00151 reliability_search_mode = false;
00152 }
00153 }
00154
00155
00156 if (reliability_search_mode == false)
00157 {
00158 meshed_fault_checking_enabled = true;
00159 }
00160
00161
00162 if (fcheck_state == SINGLE_DEBUG)
00163 {
00164
00165 fault_check_override_mode = true;
00166 }
00167
00168 return powerflow_object::init(parent);
00169 }
00170
00171 TIMESTAMP fault_check::sync(TIMESTAMP t0)
00172 {
00173 OBJECT *obj = OBJECTHDR(this);
00174 TIMESTAMP tret = powerflow_object::sync(t0);
00175 unsigned int index;
00176 int return_val;
00177 bool perform_check, override_output;
00178
00179 if (prev_time == 0)
00180 {
00181 allocate_alterations_values(reliability_mode);
00182 }
00183
00184 if (fault_check_override_mode == true)
00185 {
00186 perform_check = true;
00187 }
00188 else if ((fcheck_state == SINGLE) && (prev_time == 0))
00189 {
00190 perform_check = true;
00191 }
00192 else if ((fcheck_state == ONCHANGE) && (NR_admit_change == true))
00193 {
00194 perform_check = true;
00195 }
00196 else if (fcheck_state == ALLT)
00197 {
00198 perform_check = true;
00199 }
00200 else if (force_reassociation == true)
00201 {
00202 perform_check = true;
00203 }
00204 else
00205 {
00206 perform_check = false;
00207 }
00208
00209 if (perform_check)
00210 {
00211
00212 if ((restoration_object != NULL) && (fault_check_override_mode == false))
00213 {
00214
00215 if (restoration_fxn == NULL)
00216 {
00217
00218 restoration_fxn = (FUNCTIONADDR)(gl_get_function(restoration_object,"perform_restoration"));
00219
00220
00221 if (restoration_fxn == NULL)
00222 {
00223 GL_THROW("Unable to map restoration function");
00224
00225
00226
00227
00228 }
00229 }
00230
00231
00232 if (reliability_search_mode == true)
00233 {
00234 gl_warning("fault_check interaction with restoration requires meshed checking mode - enabling this now");
00235
00236
00237
00238
00239
00240
00241 reliability_search_mode = false;
00242 }
00243
00244
00245 return_val = ((int (*)(OBJECT *,int))(*restoration_fxn))(restoration_object,-99);
00246
00247
00248 if (return_val != 1)
00249 {
00250 GL_THROW("Restoration failed to execute properly");
00251
00252
00253
00254
00255 }
00256
00257
00258 }
00259
00260
00261 if (reliability_search_mode == true)
00262 {
00263
00264 support_check(0);
00265
00266
00267 for (index=0; index<NR_bus_count; index++)
00268 {
00269 if ((Supported_Nodes[index][0] == 0) || (Supported_Nodes[index][1] == 0) || (Supported_Nodes[index][2] == 0))
00270 {
00271 if (output_filename[0] != '\0')
00272 {
00273 write_output_file(t0,0);
00274 }
00275
00276
00277 if ((reliability_mode == false) && (fault_check_override_mode == false))
00278 {
00279 GL_THROW("Unsupported phase on node %s",NR_busdata[index].name);
00280
00281
00282
00283
00284 }
00285 else
00286 {
00287 gl_warning("Unsupported phase on node %s",NR_busdata[index].name);
00288
00289
00290
00291
00292 }
00293 break;
00294 }
00295 }
00296 }
00297 else
00298 {
00299
00300
00301 if (grid_association_mode == true)
00302 {
00303 associate_grids();
00304 }
00305
00306
00307
00308 if (NR_curr_bus != NR_bus_count)
00309 {
00310 GL_THROW("fault_check: Incomplete initialization detected - this will cause issues");
00311
00312
00313
00314
00315
00316 }
00317 else
00318 {
00319
00320 support_check_mesh();
00321 }
00322
00323
00324 if (prev_time == 0)
00325 {
00326
00327 support_search_links_mesh(-77,false);
00328 }
00329
00330
00331 if (grid_association_mode == true)
00332 {
00333 associate_grids();
00334 }
00335
00336 override_output = output_check_supported_mesh();
00337
00338
00339 if (override_output == true)
00340 {
00341 if (output_filename[0] != '\0')
00342 {
00343 write_output_file(t0,0);
00344 }
00345
00346
00347 if ((reliability_mode == false) && (fault_check_override_mode == false))
00348 {
00349 GL_THROW("Unsupported phase on a possibly meshed node");
00350
00351
00352
00353
00354 }
00355 else
00356 {
00357 gl_warning("Unsupported phase on a possibly meshed node");
00358
00359
00360
00361
00362 }
00363 }
00364 }
00365 }
00366
00367
00368 prev_time = t0;
00369
00370
00371 if (fault_check_override_mode == true)
00372 {
00373 gl_error("fault_check:%d %s -- Special debug mode utilized, simulation terminating",obj->id,(obj->name ? obj->name : "Unnamed"));
00374
00375
00376
00377
00378
00379 return TS_INVALID;
00380 }
00381 else
00382 {
00383 return tret;
00384 }
00385 }
00386
00387
00388 void fault_check::search_links(int node_int)
00389 {
00390 unsigned int index, indexb;
00391 bool both_handled, from_val, first_resto, proceed_in;
00392 int branch_val;
00393 BRANCHDATA temp_branch;
00394 unsigned char work_phases;
00395
00396
00397 for (index=0; index<NR_busdata[node_int].Link_Table_Size; index++)
00398 {
00399 temp_branch = NR_branchdata[NR_busdata[node_int].Link_Table[index]];
00400
00401 first_resto = false;
00402 proceed_in = false;
00403
00404
00405 if ((temp_branch.phases & 0x07) != 0x00)
00406 {
00407 for (indexb=0; indexb<3; indexb++)
00408 {
00409 work_phases = 0x04 >> indexb;
00410
00411 if ((temp_branch.phases & work_phases) == work_phases)
00412 {
00413 both_handled = false;
00414
00415
00416 if (temp_branch.from == node_int)
00417 {
00418 from_val = true;
00419 }
00420 else
00421 {
00422 from_val = false;
00423 }
00424
00425
00426 if ((Supported_Nodes[temp_branch.to][indexb]==1) && (Supported_Nodes[temp_branch.from][indexb]==1))
00427 both_handled=true;
00428
00429
00430 if (both_handled==false)
00431 {
00432
00433 if (from_val)
00434 {
00435 branch_val = temp_branch.to;
00436
00437
00438 if (Supported_Nodes[temp_branch.from][indexb] == 1)
00439 {
00440 proceed_in = true;
00441 }
00442 else
00443 {
00444 continue;
00445 }
00446 }
00447 else
00448 {
00449 branch_val = temp_branch.from;
00450
00451
00452 if (Supported_Nodes[temp_branch.to][indexb] == 1)
00453 {
00454 proceed_in = true;
00455 }
00456 else
00457 {
00458 continue;
00459 }
00460 }
00461
00462
00463 Supported_Nodes[branch_val][indexb] = 1;
00464
00465 }
00466 }
00467 }
00468
00469 if (proceed_in)
00470 {
00471
00472 search_links(branch_val);
00473 }
00474 }
00475 }
00476 }
00477
00478
00479 void fault_check::search_links_mesh(int node_int)
00480 {
00481 unsigned int index, device_value, node_value;
00482 unsigned char temp_phases, temp_compare_phases, result_phases;
00483
00484
00485 if (grid_association_mode == false)
00486 {
00487
00488 for (index=0; index<NR_busdata[node_int].Link_Table_Size; index++)
00489 {
00490
00491 device_value = NR_busdata[node_int].Link_Table[index];
00492
00493
00494 if (node_int == NR_branchdata[device_value].from)
00495 {
00496
00497 node_value = NR_branchdata[device_value].to;
00498 }
00499 else
00500 {
00501
00502 node_value = NR_branchdata[device_value].from;
00503 }
00504
00505
00506 temp_phases = NR_branchdata[device_value].phases;
00507
00508
00509 if ((valid_phases[node_int] != 0x00) || (valid_phases[node_value] != 0x00))
00510 {
00511
00512 if ((NR_branchdata[device_value].lnk_type == 2) || (NR_branchdata[device_value].lnk_type == 5) || (NR_branchdata[device_value].lnk_type == 6))
00513 {
00514 if (*NR_branchdata[device_value].status == 1)
00515 {
00516 temp_phases |= NR_branchdata[device_value].origphases & 0x07;
00517 }
00518 }
00519 else if (NR_branchdata[device_value].lnk_type == 3)
00520 {
00521
00522 if (*NR_branchdata[device_value].status == 1)
00523 {
00524
00525 result_phases = (((~NR_branchdata[device_value].faultphases) & 0x07) | 0xF8);
00526
00527
00528 temp_phases |= NR_branchdata[device_value].origphases & result_phases;
00529 }
00530 else
00531 {
00532 temp_phases = 0x00;
00533 }
00534 }
00535 else
00536 {
00537 temp_phases |= NR_branchdata[device_value].origphases & 0x07;
00538 }
00539 }
00540
00541
00542 valid_phases[node_value] |= (valid_phases[node_int] & temp_phases);
00543 }
00544 }
00545 else
00546 {
00547
00548 for (index=0; index<NR_busdata[node_int].Link_Table_Size; index++)
00549 {
00550
00551 device_value = NR_busdata[node_int].Link_Table[index];
00552
00553
00554 if (node_int == NR_branchdata[device_value].from)
00555 {
00556
00557 node_value = NR_branchdata[device_value].to;
00558 }
00559 else
00560 {
00561
00562 node_value = NR_branchdata[device_value].from;
00563 }
00564
00565
00566 temp_phases = NR_branchdata[device_value].phases;
00567
00568
00569 if ((valid_phases[node_int] != 0x00) || (valid_phases[node_value] != 0x00))
00570 {
00571
00572 if ((NR_branchdata[device_value].lnk_type == 2) || (NR_branchdata[device_value].lnk_type == 5) || (NR_branchdata[device_value].lnk_type == 6))
00573 {
00574 if (*NR_branchdata[device_value].status == 1)
00575 {
00576 temp_phases |= NR_branchdata[device_value].origphases & 0x07;
00577 }
00578 }
00579 else if (NR_branchdata[device_value].lnk_type == 3)
00580 {
00581
00582 if (*NR_branchdata[device_value].status == 1)
00583 {
00584
00585 result_phases = (((~NR_branchdata[device_value].faultphases) & 0x07) | 0xF8);
00586
00587
00588 temp_phases |= NR_branchdata[device_value].origphases & result_phases;
00589 }
00590 else
00591 {
00592 temp_phases = 0x00;
00593 }
00594 }
00595 else
00596 {
00597 temp_phases |= NR_branchdata[device_value].origphases & 0x07;
00598 }
00599 }
00600
00601
00602 temp_compare_phases = (valid_phases[node_value] | (valid_phases[node_int] & temp_phases));
00603
00604
00605 if (valid_phases[node_value] != temp_compare_phases)
00606 {
00607
00608 valid_phases[node_value] = temp_compare_phases;
00609
00610
00611 search_links_mesh(node_value);
00612 }
00613
00614 }
00615 }
00616 }
00617
00618 void fault_check::support_check(int swing_node_int)
00619 {
00620 unsigned int index;
00621 unsigned char phase_vals;
00622
00623
00624 reset_support_check();
00625
00626
00627 for (index=0; index<3; index++)
00628 {
00629 phase_vals = 0x04 >> index;
00630
00631 if ((NR_busdata[swing_node_int].phases & phase_vals) == phase_vals)
00632 Supported_Nodes[swing_node_int][index] = 1;
00633 }
00634
00635
00636 search_links(swing_node_int);
00637 }
00638
00639
00640 void fault_check::support_check_mesh(void)
00641 {
00642 unsigned int indexa, indexb;
00643
00644
00645 reset_support_check();
00646
00647 if (grid_association_mode == false)
00648 {
00649
00650 valid_phases[0] = NR_busdata[0].phases & 0x07;
00651
00652
00653
00654 for (indexa=0; indexa<NR_bus_count; indexa++)
00655 {
00656 for (indexb=0; indexb<NR_bus_count; indexb++)
00657 {
00658
00659 search_links_mesh(indexb);
00660 }
00661 }
00662 }
00663 else
00664 {
00665
00666 for (indexa=0; indexa<NR_bus_count; indexa++)
00667 {
00668
00669 if ((NR_busdata[indexa].type == 2) || ((NR_busdata[indexa].type == 3) && (NR_busdata[indexa].swing_functions_enabled == true)) || ((*NR_busdata[indexa].busflag & NF_ISSOURCE) == NF_ISSOURCE))
00670 {
00671
00672 if ((NR_busdata[indexa].phases & 0x07) != valid_phases[indexa])
00673 {
00674
00675 valid_phases[indexa] |= (NR_busdata[indexa].phases & 0x07);
00676
00677
00678 search_links_mesh(indexa);
00679 }
00680
00681 }
00682
00683 }
00684 }
00685 }
00686
00687 void fault_check::reset_support_check(void)
00688 {
00689 unsigned int index;
00690
00691
00692 for (index=0; index<NR_bus_count; index++)
00693 {
00694 if (reliability_search_mode == true)
00695 {
00696 if ((NR_busdata[index].origphases & 0x04) == 0x04)
00697 {
00698 Supported_Nodes[index][0] = 0;
00699 }
00700 else
00701 {
00702 Supported_Nodes[index][0] = 2;
00703 }
00704
00705 if ((NR_busdata[index].origphases & 0x02) == 0x02)
00706 {
00707 Supported_Nodes[index][1] = 0;
00708 }
00709 else
00710 {
00711 Supported_Nodes[index][1] = 2;
00712 }
00713
00714 if ((NR_busdata[index].origphases & 0x01) == 0x01)
00715 {
00716 Supported_Nodes[index][2] = 0;
00717 }
00718 else
00719 {
00720 Supported_Nodes[index][2] = 2;
00721 }
00722 }
00723 else
00724 {
00725
00726 valid_phases[index] = 0x00;
00727 }
00728 }
00729 }
00730
00731 void fault_check::write_output_file(TIMESTAMP tval, double tval_delta)
00732 {
00733 unsigned int index, ret_value;
00734 DATETIME temp_time;
00735 bool headerwritten = false;
00736 bool supportheaderwritten = false;
00737 bool deltamodeflag;
00738 char phase_outs;
00739 char deltaprint_buffer[64];
00740 FILE *FPOutput;
00741
00742
00743 if (tval == 0)
00744 {
00745 deltamodeflag=true;
00746 }
00747 else
00748 {
00749 deltamodeflag=false;
00750 }
00751
00752
00753 FPOutput = fopen(output_filename,"at");
00754
00755 for (index=0; index<NR_bus_count; index++)
00756 {
00757 if (reliability_search_mode == true)
00758 {
00759
00760 phase_outs = 0x00;
00761
00762 if (Supported_Nodes[index][0] == 0)
00763 phase_outs |= 0x04;
00764
00765 if (Supported_Nodes[index][1] == 0)
00766 phase_outs |= 0x02;
00767
00768 if (Supported_Nodes[index][2] == 0)
00769 phase_outs |= 0x01;
00770 }
00771 else
00772 {
00773 phase_outs = ((~(valid_phases[index] & NR_busdata[index].origphases)) & (0x07 & NR_busdata[index].origphases));
00774 }
00775
00776 if (phase_outs != 0x00)
00777 {
00778
00779 if (headerwritten == false)
00780 {
00781 if (fault_check_override_mode == false)
00782 {
00783 if (deltamodeflag == true)
00784 {
00785
00786 ret_value = gl_printtimedelta(tval_delta,deltaprint_buffer,64);
00787
00788
00789 fprintf(FPOutput,"Unsupported at timestamp %0.9f - %s =\n\n",tval_delta,deltaprint_buffer);
00790 }
00791 else
00792 {
00793
00794 gl_localtime(tval,&temp_time);
00795
00796 fprintf(FPOutput,"Unsupported at timestamp %lld - %04d-%02d-%02d %02d:%02d:%02d =\n\n",tval,temp_time.year,temp_time.month,temp_time.day,temp_time.hour,temp_time.minute,temp_time.second);
00797 }
00798 }
00799 else
00800 {
00801
00802 fprintf(FPOutput,"Special debug topology check -- phase checks bypassed -- Unsupported nodes list\n\n");
00803 }
00804
00805 headerwritten = true;
00806 }
00807
00808
00809 switch (phase_outs) {
00810 case 0x01:
00811 {
00812 fprintf(FPOutput,"Phase C on node %s\n",NR_busdata[index].name);
00813 break;
00814 }
00815 case 0x02:
00816 {
00817 fprintf(FPOutput,"Phase B on node %s\n",NR_busdata[index].name);
00818 break;
00819 }
00820 case 0x03:
00821 {
00822 fprintf(FPOutput,"Phases B and C on node %s\n",NR_busdata[index].name);
00823 break;
00824 }
00825 case 0x04:
00826 {
00827 fprintf(FPOutput,"Phase A on node %s\n",NR_busdata[index].name);
00828 break;
00829 }
00830 case 0x05:
00831 {
00832 fprintf(FPOutput,"Phases A and C on node %s\n",NR_busdata[index].name);
00833 break;
00834 }
00835 case 0x06:
00836 {
00837 fprintf(FPOutput,"Phases A and B on node %s\n",NR_busdata[index].name);
00838 break;
00839 }
00840 case 0x07:
00841 {
00842 fprintf(FPOutput,"Phases A, B, and C on node %s\n",NR_busdata[index].name);
00843 break;
00844 }
00845 default:
00846 {
00847 GL_THROW("Error parsing unsupported phases on node %s",NR_busdata[index].name);
00848
00849
00850
00851
00852
00853 }
00854 }
00855 }
00856 }
00857
00858
00859 if ((headerwritten == false) && (fault_check_override_mode == true))
00860 {
00861 fprintf(FPOutput,"Special debug topology check -- phase checks bypassed -- No unsupported nodes found\n\n");
00862 }
00863
00864
00865 if (full_print_output == true)
00866 {
00867 for (index=0; index<NR_bus_count; index++)
00868 {
00869 phase_outs = (NR_busdata[index].phases & 0x07);
00870
00871 if (phase_outs != 0x00)
00872 {
00873
00874 if (fault_check_override_mode == false)
00875 {
00876
00877 if (headerwritten == false)
00878 {
00879 if (deltamodeflag == true)
00880 {
00881
00882 ret_value = gl_printtimedelta(tval_delta,deltaprint_buffer,64);
00883
00884
00885 fprintf(FPOutput,"Supported at timestamp %0.9f - %s =\n",tval_delta,deltaprint_buffer);
00886
00887
00888 if (grid_association_mode == false)
00889 {
00890 fprintf(FPOutput,"\n");
00891 }
00892 else
00893 {
00894
00895 fprintf(FPOutput,"Number detected islands = %d\n\n",NR_islands_detected);
00896 }
00897 }
00898 else
00899 {
00900
00901 gl_localtime(tval,&temp_time);
00902
00903 fprintf(FPOutput,"Supported at timestamp %lld - %04d-%02d-%02d %02d:%02d:%02d =\n",tval,temp_time.year,temp_time.month,temp_time.day,temp_time.hour,temp_time.minute,temp_time.second);
00904
00905 if (grid_association_mode == false)
00906 {
00907 fprintf(FPOutput,"\n");
00908 }
00909 else
00910 {
00911
00912 fprintf(FPOutput,"Number detected islands = %d\n\n",NR_islands_detected);
00913 }
00914 }
00915
00916 headerwritten = true;
00917 supportheaderwritten = true;
00918 }
00919 else if (supportheaderwritten == false)
00920 {
00921 if (grid_association_mode == false)
00922 {
00923 fprintf(FPOutput,"\nSupported Nodes\n");
00924 }
00925 else
00926 {
00927 fprintf(FPOutput,"\nSupported Nodes -- %d Islands detected\n",NR_islands_detected);
00928 }
00929
00930 supportheaderwritten = true;
00931 }
00932 }
00933 else
00934 {
00935
00936 if (headerwritten == false)
00937 {
00938 if (grid_association_mode == false)
00939 {
00940
00941 fprintf(FPOutput,"Special debug topology check -- phase checks bypassed -- Supported nodes list\n\n");
00942 }
00943 else
00944 {
00945
00946 fprintf(FPOutput,"Special debug topology check -- phase checks bypassed -- Supported nodes list -- %d Islands detected\n\n",NR_islands_detected);
00947 }
00948
00949
00950 headerwritten = true;
00951 supportheaderwritten = true;
00952 }
00953 else if (supportheaderwritten == false)
00954 {
00955 if (grid_association_mode == false)
00956 {
00957 fprintf(FPOutput,"\nSupported Nodes\n");
00958 }
00959 else
00960 {
00961 fprintf(FPOutput,"\nSupported Nodes -- %d Islands detected\n",NR_islands_detected);
00962 }
00963
00964 supportheaderwritten = true;
00965 }
00966
00967 }
00968
00969
00970 switch (phase_outs) {
00971 case 0x01:
00972 {
00973 fprintf(FPOutput,"Phase C on node %s",NR_busdata[index].name);
00974
00975
00976 if (grid_association_mode == true)
00977 {
00978 fprintf(FPOutput," - Island %d\n",(NR_busdata[index].island_number+1));
00979 }
00980 else
00981 {
00982 fprintf(FPOutput,"\n");
00983 }
00984 break;
00985 }
00986 case 0x02:
00987 {
00988 fprintf(FPOutput,"Phase B on node %s",NR_busdata[index].name);
00989
00990
00991 if (grid_association_mode == true)
00992 {
00993 fprintf(FPOutput," - Island %d\n",(NR_busdata[index].island_number+1));
00994 }
00995 else
00996 {
00997 fprintf(FPOutput,"\n");
00998 }
00999 break;
01000 }
01001 case 0x03:
01002 {
01003 fprintf(FPOutput,"Phases B and C on node %s",NR_busdata[index].name);
01004
01005
01006 if (grid_association_mode == true)
01007 {
01008 fprintf(FPOutput," - Island %d\n",(NR_busdata[index].island_number+1));
01009 }
01010 else
01011 {
01012 fprintf(FPOutput,"\n");
01013 }
01014 break;
01015 }
01016 case 0x04:
01017 {
01018 fprintf(FPOutput,"Phase A on node %s",NR_busdata[index].name);
01019
01020
01021 if (grid_association_mode == true)
01022 {
01023 fprintf(FPOutput," - Island %d\n",(NR_busdata[index].island_number+1));
01024 }
01025 else
01026 {
01027 fprintf(FPOutput,"\n");
01028 }
01029 break;
01030 }
01031 case 0x05:
01032 {
01033 fprintf(FPOutput,"Phases A and C on node %s",NR_busdata[index].name);
01034
01035
01036 if (grid_association_mode == true)
01037 {
01038 fprintf(FPOutput," - Island %d\n",(NR_busdata[index].island_number+1));
01039 }
01040 else
01041 {
01042 fprintf(FPOutput,"\n");
01043 }
01044 break;
01045 }
01046 case 0x06:
01047 {
01048 fprintf(FPOutput,"Phases A and B on node %s",NR_busdata[index].name);
01049
01050
01051 if (grid_association_mode == true)
01052 {
01053 fprintf(FPOutput," - Island %d\n",(NR_busdata[index].island_number+1));
01054 }
01055 else
01056 {
01057 fprintf(FPOutput,"\n");
01058 }
01059 break;
01060 }
01061 case 0x07:
01062 {
01063 fprintf(FPOutput,"Phases A, B, and C on node %s",NR_busdata[index].name);
01064
01065
01066 if (grid_association_mode == true)
01067 {
01068 fprintf(FPOutput," - Island %d\n",(NR_busdata[index].island_number+1));
01069 }
01070 else
01071 {
01072 fprintf(FPOutput,"\n");
01073 }
01074 break;
01075 }
01076 default:
01077 {
01078 GL_THROW("Error parsing supported phases on node %s",NR_busdata[index].name);
01079
01080
01081
01082
01083
01084 }
01085 }
01086 }
01087 }
01088 }
01089
01090 fprintf(FPOutput,"\n");
01091
01092
01093 fclose(FPOutput);
01094 }
01095
01096
01097 void fault_check::support_check_alterations(int baselink_int, bool rest_mode)
01098 {
01099 int base_bus_val, return_val;
01100 double delta_ts_value;
01101 TIMESTAMP event_ts_value;
01102
01103 if (prev_time == 0)
01104 {
01105 allocate_alterations_values(true);
01106 }
01107
01108
01109 if (reliability_search_mode == true)
01110 {
01111
01112 if ((baselink_int == -99) || (baselink_int == -77))
01113 base_bus_val = 0;
01114 else
01115 {
01116
01117 base_bus_val = NR_branchdata[baselink_int].to;
01118
01119
01120 if (rest_mode == true)
01121 NR_busdata[base_bus_val].phases |= (NR_branchdata[baselink_int].phases & 0x07);
01122 else
01123 NR_busdata[base_bus_val].phases &= (NR_branchdata[baselink_int].phases & 0x07);
01124 }
01125
01126
01127 reset_alterations_check();
01128
01129
01130 Alteration_Nodes[base_bus_val] = 1;
01131
01132
01133 if (rest_mode == true)
01134 {
01135 gl_verbose("Alterations support check called restoration on bus %s",NR_busdata[base_bus_val].name);
01136
01137 if ((NR_busdata[base_bus_val].phases & 0x07) != 0x00)
01138 {
01139
01140 support_search_links(base_bus_val, base_bus_val, rest_mode);
01141 }
01142 else
01143 return;
01144 }
01145 else
01146 {
01147 gl_verbose("Alterations support check called removal on bus %s",NR_busdata[base_bus_val].name);
01148
01149
01150 support_search_links(base_bus_val, base_bus_val, rest_mode);
01151 }
01152 }
01153 else
01154 {
01155
01156 if (restoration_checks_active == false)
01157 {
01158
01159 if ((restoration_object != NULL) && (restoration_fxn != NULL))
01160 {
01161
01162 return_val = ((int (*)(OBJECT *,int))(*restoration_fxn))(restoration_object,baselink_int);
01163
01164
01165 if (return_val != 1)
01166 {
01167 GL_THROW("Restoration failed to execute properly");
01168
01169
01170
01171
01172 }
01173 }
01174
01175 }
01176
01177
01178
01179 reset_alterations_check();
01180
01181
01182
01183 if (grid_association_mode == true)
01184 {
01185 associate_grids();
01186 }
01187
01188
01189
01190 support_check_mesh();
01191
01192
01193 support_search_links_mesh(baselink_int,rest_mode);
01194
01195
01196 if (grid_association_mode == true)
01197 {
01198 associate_grids();
01199 }
01200 }
01201
01202
01203 if ((restoration_checks_active == false) && (output_filename[0] != '\0'))
01204 {
01205
01206 if (deltatimestep_running > 0.0)
01207 {
01208
01209 delta_ts_value = gl_globaldeltaclock;
01210
01211
01212 event_ts_value = 0;
01213 }
01214 else
01215 {
01216
01217 event_ts_value = gl_globalclock;
01218
01219
01220 delta_ts_value = 0.0;
01221 }
01222
01223
01224 write_output_file(event_ts_value,delta_ts_value);
01225 }
01226
01227 }
01228
01229
01230
01231
01232 void fault_check::support_search_links_mesh(int baselink_int, bool impact_mode)
01233 {
01234 unsigned int indexval, index;
01235 int device_index;
01236 unsigned char temp_phases, work_phases, remove_phases, add_phases;
01237
01238
01239 if (impact_mode == false)
01240 {
01241 if ((baselink_int != -99) && (baselink_int != -77))
01242 {
01243
01244 temp_phases = ((valid_phases[NR_branchdata[baselink_int].from] ^ valid_phases[NR_branchdata[baselink_int].to]) & 0x07);
01245
01246
01247 remove_phases = temp_phases & NR_branchdata[baselink_int].origphases;
01248
01249
01250 Alteration_Links[baselink_int] = 1;
01251 }
01252 else
01253 {
01254
01255 remove_phases = ((NR_busdata[0].origphases ^ NR_busdata[0].phases) & 0x07);
01256
01257
01258 Alteration_Nodes[0] = 1;
01259 }
01260
01261 }
01262 else
01263 {
01264 if ((baselink_int != -99) && (baselink_int != -77))
01265 {
01266
01267 Alteration_Links[baselink_int] = 1;
01268 }
01269 else
01270 {
01271
01272 Alteration_Nodes[0] = 1;
01273 }
01274 }
01275
01276
01277 for (indexval=0; indexval<NR_bus_count; indexval++)
01278 {
01279
01280 if (impact_mode == true)
01281 {
01282
01283 work_phases = NR_busdata[indexval].phases & 0x07;
01284
01285
01286 if (work_phases != valid_phases[indexval])
01287 {
01288
01289 work_phases = NR_busdata[indexval].origphases & valid_phases[indexval];
01290
01291
01292 add_phases = ((NR_busdata[indexval].phases ^ work_phases) & 0x07);
01293
01294
01295 if ((NR_busdata[indexval].origphases & 0x80) == 0x80)
01296 {
01297 add_phases |= (NR_busdata[indexval].origphases & 0xE0);
01298 }
01299 else if (work_phases == 0x07)
01300 {
01301 add_phases |= (NR_busdata[indexval].origphases & 0x18);
01302 }
01303
01304
01305 NR_busdata[indexval].phases |= add_phases;
01306
01307
01308 for (index=0; index<NR_busdata[indexval].Link_Table_Size; index++)
01309 {
01310
01311 device_index = NR_busdata[indexval].Link_Table[index];
01312
01313
01314 if (Alteration_Links[device_index] == 0)
01315 {
01316
01317 temp_phases = (valid_phases[NR_branchdata[device_index].from] & valid_phases[NR_branchdata[device_index].to]);
01318
01319
01320 add_phases = NR_branchdata[device_index].origphases & temp_phases;
01321
01322
01323 if (add_phases != 0x00)
01324 {
01325
01326 if ((NR_branchdata[device_index].origphases & 0x80) == 0x80)
01327 {
01328 add_phases |= (NR_branchdata[device_index].origphases & 0xE0);
01329 }
01330
01331
01332 if ((NR_branchdata[device_index].lnk_type == 2) || (NR_branchdata[device_index].lnk_type == 5) || (NR_branchdata[device_index].lnk_type == 6))
01333 {
01334 if (*NR_branchdata[device_index].status == 1)
01335 {
01336
01337 NR_branchdata[device_index].phases |= add_phases;
01338 }
01339 }
01340 else
01341 {
01342
01343 NR_branchdata[device_index].phases |= add_phases;
01344 }
01345 }
01346
01347
01348
01349 Alteration_Links[device_index] = 1;
01350
01351
01352 special_object_alteration_handle(device_index);
01353 }
01354
01355 }
01356 }
01357
01358
01359
01360 Alteration_Nodes[indexval] = 1;
01361 }
01362 else
01363 {
01364
01365 work_phases = NR_busdata[indexval].phases & 0x07;
01366
01367
01368 if (work_phases != valid_phases[indexval])
01369 {
01370
01371 work_phases = work_phases & valid_phases[indexval];
01372
01373
01374 remove_phases = ((NR_busdata[indexval].phases ^ work_phases) & 0x07);
01375
01376
01377 for (index=0; index<NR_busdata[indexval].Link_Table_Size; index++)
01378 {
01379
01380 device_index = NR_busdata[indexval].Link_Table[index];
01381
01382
01383 if (Alteration_Links[device_index] == 0)
01384 {
01385
01386 if ((NR_branchdata[device_index].phases & 0x80) == 0x80)
01387 {
01388
01389 NR_branchdata[device_index].phases = 0x00;
01390 }
01391 else
01392 {
01393
01394 NR_branchdata[device_index].phases &= work_phases;
01395 }
01396
01397
01398 Alteration_Links[device_index] = 1;
01399
01400
01401 special_object_alteration_handle(device_index);
01402 }
01403 else
01404 {
01405 continue;
01406 }
01407 }
01408
01409
01410 if (((NR_busdata[indexval].phases & 0x80) == 0x80) && (work_phases != 0x00))
01411 {
01412 work_phases |= 0xE0;
01413 }
01414 else if (work_phases == 0x07)
01415 {
01416 work_phases |= 0x18;
01417 }
01418
01419
01420 NR_busdata[indexval].phases &= work_phases;
01421
01422
01423 Alteration_Nodes[indexval] = 1;
01424 }
01425
01426 }
01427 }
01428
01429
01430 }
01431
01432
01433 void fault_check::special_object_alteration_handle(int branch_idx)
01434 {
01435 int return_val;
01436 unsigned char temp_phases;
01437 OBJECT *temp_obj;
01438 FUNCTIONADDR funadd = NULL;
01439
01440
01441 if (meshed_fault_checking_enabled == false)
01442 {
01443
01444 if (NR_branchdata[branch_idx].lnk_type == 2)
01445 {
01446
01447 temp_obj = NR_branchdata[branch_idx].obj;
01448
01449
01450 if (temp_obj == NULL)
01451 {
01452 GL_THROW("Failed to find switch object:%s for reliability manipulation",NR_branchdata[branch_idx].name);
01453
01454
01455
01456
01457 }
01458
01459
01460 funadd = (FUNCTIONADDR)(gl_get_function(temp_obj,"reliability_operation"));
01461
01462
01463 if (funadd==NULL)
01464 {
01465 GL_THROW("Failed to find reliability manipulation method on object %s",NR_branchdata[branch_idx].name);
01466
01467
01468
01469
01470
01471 }
01472
01473
01474 temp_phases = (NR_branchdata[branch_idx].phases & 0x07);
01475 return_val = ((int (*)(OBJECT *, unsigned char))(*funadd))(temp_obj,temp_phases);
01476
01477 if (return_val == 0)
01478 {
01479 GL_THROW("Failed to handle reliability manipulation on %s",NR_branchdata[branch_idx].name);
01480
01481
01482
01483
01484 }
01485 }
01486 else if (NR_branchdata[branch_idx].lnk_type == 3)
01487 {
01488
01489 temp_obj = NR_branchdata[branch_idx].obj;
01490
01491
01492 if (temp_obj == NULL)
01493 {
01494 GL_THROW("Failed to find fuse object:%s for reliability manipulation",NR_branchdata[branch_idx].name);
01495
01496
01497
01498
01499 }
01500
01501
01502 funadd = (FUNCTIONADDR)(gl_get_function(temp_obj,"reliability_operation"));
01503
01504
01505 if (funadd==NULL)
01506 {
01507 GL_THROW("Failed to find reliability manipulation method on object %s",NR_branchdata[branch_idx].name);
01508
01509
01510
01511
01512
01513 }
01514
01515
01516 temp_phases = (NR_branchdata[branch_idx].phases & 0x07);
01517 return_val = ((int (*)(OBJECT *, unsigned char))(*funadd))(temp_obj,temp_phases);
01518
01519 if (return_val == 0)
01520 {
01521 GL_THROW("Failed to handle reliability manipulation on %s",NR_branchdata[branch_idx].name);
01522
01523
01524
01525
01526 }
01527 }
01528 else if (NR_branchdata[branch_idx].lnk_type == 6)
01529 {
01530
01531 temp_obj = NR_branchdata[branch_idx].obj;
01532
01533
01534 if (temp_obj == NULL)
01535 {
01536 GL_THROW("Failed to find recloser object:%s for reliability manipulation",NR_branchdata[branch_idx].name);
01537
01538
01539
01540
01541 }
01542
01543
01544 funadd = (FUNCTIONADDR)(gl_get_function(temp_obj,"recloser_reliability_operation"));
01545
01546
01547 if (funadd==NULL)
01548 {
01549 GL_THROW("Failed to find reliability manipulation method on object %s",NR_branchdata[branch_idx].name);
01550
01551 }
01552
01553
01554 temp_phases = (NR_branchdata[branch_idx].phases & 0x07);
01555 return_val = ((int (*)(OBJECT *, unsigned char))(*funadd))(temp_obj,temp_phases);
01556
01557 if (return_val == 0)
01558 {
01559 GL_THROW("Failed to handle reliability manipulation on %s",NR_branchdata[branch_idx].name);
01560
01561 }
01562 }
01563 else if (NR_branchdata[branch_idx].lnk_type == 5)
01564 {
01565
01566 temp_obj = NR_branchdata[branch_idx].obj;
01567
01568
01569 if (temp_obj == NULL)
01570 {
01571 GL_THROW("Failed to find sectionalizer object:%s for reliability manipulation",NR_branchdata[branch_idx].name);
01572
01573
01574
01575
01576 }
01577
01578
01579 funadd = (FUNCTIONADDR)(gl_get_function(temp_obj,"sectionalizer_reliability_operation"));
01580
01581
01582 if (funadd==NULL)
01583 {
01584 GL_THROW("Failed to find reliability manipulation method on object %s",NR_branchdata[branch_idx].name);
01585
01586 }
01587
01588
01589 temp_phases = (NR_branchdata[branch_idx].phases & 0x07);
01590 return_val = ((int (*)(OBJECT *, unsigned char))(*funadd))(temp_obj,temp_phases);
01591
01592 if (return_val == 0)
01593 {
01594 GL_THROW("Failed to handle reliability manipulation on %s",NR_branchdata[branch_idx].name);
01595
01596 }
01597 }
01598 }
01599 }
01600
01601
01602
01603 void fault_check::support_search_links(int node_int, int node_start, bool impact_mode)
01604 {
01605 unsigned int index;
01606 bool both_handled, from_val;
01607 int branch_val;
01608 BRANCHDATA temp_branch;
01609 unsigned char work_phases, phase_restrictions;
01610
01611
01612 for (index=0; index<NR_busdata[node_int].Link_Table_Size; index++)
01613 {
01614 temp_branch = NR_branchdata[NR_busdata[node_int].Link_Table[index]];
01615
01616 both_handled = false;
01617
01618
01619 if (temp_branch.from == node_int)
01620 {
01621 from_val = true;
01622 }
01623 else
01624 {
01625 from_val = false;
01626 }
01627
01628 if ((node_int == node_start) && (from_val == false))
01629 {
01630 Alteration_Nodes[temp_branch.from] = 1;
01631 continue;
01632 }
01633 else
01634 {
01635
01636 if ((Alteration_Nodes[temp_branch.to]==1) && (Alteration_Nodes[temp_branch.from]==1))
01637 both_handled=true;
01638 }
01639
01640
01641 if (both_handled==false)
01642 {
01643
01644 if (from_val)
01645 {
01646 branch_val = temp_branch.to;
01647
01648 if (impact_mode == false)
01649 {
01650
01651 if (Alteration_Nodes[temp_branch.from] == 1)
01652 {
01653
01654 work_phases = NR_busdata[temp_branch.from].phases & 0x07;
01655
01656
01657 if ((NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases & 0x80) == 0x80)
01658 {
01659
01660 if ((NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases & work_phases) == 0x00)
01661 {
01662
01663 NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases = 0x00;
01664 }
01665
01666 }
01667 else
01668 {
01669
01670 NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases &= work_phases;
01671 }
01672
01673
01674 work_phases = NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases & 0x07;
01675
01676
01677 if ((NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases & 0x80) == 0x80)
01678 {
01679 work_phases |= 0xE0;
01680 }
01681 else if (work_phases == 0x07)
01682 {
01683 work_phases |= 0x18;
01684 }
01685
01686
01687 NR_busdata[temp_branch.to].phases &= work_phases;
01688 }
01689 else
01690 {
01691 continue;
01692 }
01693 }
01694 else
01695 {
01696
01697 if (Alteration_Nodes[temp_branch.from] == 1)
01698 {
01699
01700 phase_restrictions = ~(NR_branchdata[NR_busdata[node_int].Link_Table[index]].faultphases & 0x07);
01701
01702 phase_restrictions &= (NR_branchdata[NR_busdata[node_int].Link_Table[index]].origphases & 0x07);
01703
01704 if (phase_restrictions == 0x00)
01705 {
01706 continue;
01707 }
01708 else
01709 {
01710
01711 work_phases = NR_busdata[temp_branch.from].phases & phase_restrictions;
01712
01713 if ((temp_branch.origphases & 0x80) == 0x80)
01714 {
01715 if (work_phases != 0x00)
01716 work_phases |= (NR_branchdata[NR_busdata[node_int].Link_Table[index]].origphases & 0xE0);
01717 }
01718
01719
01720 NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases |= work_phases;
01721
01722
01723 work_phases = NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases & 0x07;
01724
01725
01726 if ((NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases & 0x80) == 0x80)
01727 {
01728 work_phases |= (NR_busdata[temp_branch.to].origphases & 0xE0);
01729 }
01730 else if (work_phases == 0x07)
01731 {
01732 work_phases |= (NR_busdata[temp_branch.to].origphases & 0x18);
01733 }
01734
01735
01736 NR_busdata[temp_branch.to].phases |= work_phases;
01737 }
01738 }
01739 else
01740 {
01741 continue;
01742 }
01743 }
01744 }
01745 else
01746 {
01747 branch_val = temp_branch.from;
01748
01749 if (impact_mode == false)
01750 {
01751
01752 if (Alteration_Nodes[temp_branch.to] == 1)
01753 {
01754
01755 work_phases = NR_busdata[temp_branch.to].phases & 0x07;
01756
01757 if ((temp_branch.phases & 0x80) == 0x80)
01758 {
01759 if (work_phases != 0x00)
01760 work_phases |= 0xA0;
01761 }
01762
01763
01764 NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases &= work_phases;
01765
01766
01767 work_phases = NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases & 0x07;
01768
01769
01770 if ((NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases & 0x80) == 0x80)
01771 {
01772 work_phases |= 0xE0;
01773 }
01774 else if (work_phases == 0x07)
01775 {
01776 work_phases |= 0x18;
01777 }
01778
01779
01780 NR_busdata[temp_branch.from].phases &= work_phases;
01781 }
01782 else
01783 {
01784 continue;
01785 }
01786 }
01787 else
01788 {
01789
01790 if (Alteration_Nodes[temp_branch.to] == 1)
01791 {
01792
01793 phase_restrictions = ~(NR_branchdata[NR_busdata[node_int].Link_Table[index]].faultphases & 0x07);
01794
01795 phase_restrictions &= (NR_branchdata[NR_busdata[node_int].Link_Table[index]].origphases & 0x07);
01796
01797 if (phase_restrictions == 0x00)
01798 {
01799 continue;
01800 }
01801 else
01802 {
01803
01804 work_phases = NR_busdata[temp_branch.to].phases & phase_restrictions;
01805
01806 if ((temp_branch.origphases & 0x80) == 0x80)
01807 {
01808 if (work_phases != 0x00)
01809 work_phases |= 0x80;
01810 }
01811
01812
01813 NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases |= work_phases;
01814
01815
01816 work_phases = NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases & 0x07;
01817
01818
01819 if ((NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases & 0x80) == 0x80)
01820 {
01821 work_phases |= (NR_busdata[temp_branch.from].origphases & 0xE0);
01822 }
01823 else if (work_phases == 0x07)
01824 {
01825 work_phases |= (NR_busdata[temp_branch.from].origphases & 0x18);
01826 }
01827
01828
01829 NR_busdata[temp_branch.from].phases |= work_phases;
01830 }
01831 }
01832 else
01833 {
01834 continue;
01835 }
01836 }
01837 }
01838
01839
01840 special_object_alteration_handle(NR_busdata[node_int].Link_Table[index]);
01841
01842
01843 Alteration_Nodes[branch_val] = 1;
01844
01845
01846 support_search_links(branch_val,node_start,impact_mode);
01847 }
01848 }
01849 }
01850
01851
01852 void fault_check::reset_alterations_check(void)
01853 {
01854 unsigned int index;
01855
01856
01857 if (Alteration_Nodes == NULL)
01858 {
01859 allocate_alterations_values(true);
01860 }
01861
01862
01863 for (index=0; index<NR_bus_count; index++)
01864 {
01865 Alteration_Nodes[index] = 0;
01866 }
01867
01868
01869 if (reliability_search_mode == false)
01870 {
01871 for (index=0; index<NR_branch_count; index++)
01872 {
01873 Alteration_Links[index] = 0;
01874 }
01875 }
01876 }
01877
01878
01879
01880 void fault_check::allocate_alterations_values(bool reliability_mode_bool)
01881 {
01882 unsigned int index;
01883
01884
01885 if (Supported_Nodes == NULL)
01886 {
01887 if (restoration_object==NULL)
01888 {
01889 gl_warning("Restoration object not detected!");
01890
01891
01892
01893
01894 }
01895
01896
01897 Supported_Nodes = (unsigned int**)gl_malloc(NR_bus_count*sizeof(unsigned int*));
01898
01899 if (Supported_Nodes == NULL)
01900 {
01901 GL_THROW("fault_check: node status vector allocation failure");
01902
01903
01904
01905
01906 }
01907
01908
01909 for (index=0; index<NR_bus_count; index++)
01910 {
01911 Supported_Nodes[index] = (unsigned int*)gl_malloc(3*sizeof(unsigned int));
01912
01913 if (Supported_Nodes[index] == NULL)
01914 {
01915 GL_THROW("fault_check: node status vector allocation failure");
01916
01917 }
01918 }
01919
01920
01921 if ((reliability_mode_bool == true) || (reliability_search_mode == false))
01922 {
01923
01924 Alteration_Nodes = (char*)gl_malloc(NR_bus_count*sizeof(char));
01925 if (Alteration_Nodes == NULL)
01926 {
01927 GL_THROW("fault_check: node alteration status vector allocation failure");
01928
01929
01930
01931
01932 }
01933
01934
01935 if (reliability_search_mode == false)
01936 {
01937 Alteration_Links = (char*)gl_malloc(NR_branch_count*sizeof(char));
01938
01939
01940 if (Alteration_Links == NULL)
01941 {
01942 GL_THROW("fault_check: link alteration status vector allocation failure");
01943
01944
01945
01946
01947 }
01948 }
01949
01950
01951 valid_phases = (unsigned char*)gl_malloc(NR_bus_count*sizeof(unsigned char));
01952
01953
01954 if (valid_phases == NULL)
01955 {
01956 GL_THROW("fault_check: node alteration status vector allocation failure");
01957
01958 }
01959
01960
01961 reset_alterations_check();
01962 }
01963 }
01964 }
01965
01966
01967 void fault_check::momentary_activation(int node_int)
01968 {
01969 unsigned int index;
01970 OBJECT *tmp_obj;
01971 bool *momentary_flag;
01972 PROPERTY *pval;
01973
01974
01975 tmp_obj = NR_busdata[node_int].obj;
01976
01977
01978 if (tmp_obj == NULL)
01979 {
01980 GL_THROW("Failed to map node:%s during momentary interruption!",NR_busdata[node_int].name);
01981
01982
01983
01984
01985
01986 }
01987
01988
01989 if ((gl_object_isa(tmp_obj,"triplex_meter","powerflow")) || (gl_object_isa(tmp_obj,"meter","powerflow")))
01990 {
01991
01992 pval = gl_get_property(tmp_obj,"customer_interrupted_secondary");
01993
01994
01995 if (pval == NULL)
01996 {
01997 GL_THROW("Failed to map momentary outage flag on node:%s",tmp_obj->name);
01998
01999
02000
02001
02002
02003 }
02004
02005
02006 momentary_flag = (bool*)GETADDR(tmp_obj,pval);
02007
02008
02009 *momentary_flag = true;
02010 }
02011
02012
02013 for (index=0; index<NR_busdata[node_int].Link_Table_Size; index++)
02014 {
02015
02016 if (NR_branchdata[NR_busdata[node_int].Link_Table[index]].from == node_int)
02017 {
02018
02019 momentary_activation(NR_branchdata[NR_busdata[node_int].Link_Table[index]].to);
02020 }
02021
02022 }
02023 }
02024
02025
02026 bool fault_check::output_check_supported_mesh(void)
02027 {
02028 unsigned int index;
02029
02030 for (index=0; index<NR_bus_count; index++)
02031 {
02032 if ((NR_busdata[index].phases ^ NR_busdata[index].origphases) != 0x00)
02033 {
02034
02035 return true;
02036 }
02037 }
02038
02039
02040 return false;
02041 }
02042
02043
02044 void fault_check::reset_associated_grid(void)
02045 {
02046 unsigned int indexval;
02047
02048
02049 for (indexval=0; indexval<NR_bus_count; indexval++)
02050 {
02051 NR_busdata[indexval].island_number = -1;
02052 }
02053
02054
02055 for (indexval=0; indexval<NR_branch_count; indexval++)
02056 {
02057 NR_branchdata[indexval].island_number = -1;
02058 }
02059 }
02060
02061
02062 void fault_check::associate_grids(void)
02063 {
02064 unsigned int indexval;
02065 int grid_counter;
02066 STATUS stat_return_val;
02067
02068
02069 reset_associated_grid();
02070
02071
02072 grid_counter = 0;
02073
02074
02075
02076 for (indexval=0; indexval<NR_bus_count; indexval++)
02077 {
02078
02079 if (NR_busdata[indexval].type == 2)
02080 {
02081
02082 if (NR_busdata[indexval].island_number == -1)
02083 {
02084
02085 if ((NR_busdata[indexval].phases & 0x07) != 0x00)
02086 {
02087
02088 search_associated_grids(indexval,grid_counter);
02089
02090
02091 grid_counter++;
02092 }
02093
02094 }
02095
02096 }
02097
02098 }
02099
02100
02101
02102 for (indexval=0; indexval<NR_bus_count; indexval++)
02103 {
02104
02105 if (NR_busdata[indexval].type == 3)
02106 {
02107
02108 if (NR_busdata[indexval].island_number == -1)
02109 {
02110
02111 if ((NR_busdata[indexval].phases & 0x07) != 0x00)
02112 {
02113
02114 NR_busdata[indexval].swing_functions_enabled = true;
02115
02116
02117 search_associated_grids(indexval,grid_counter);
02118
02119
02120 grid_counter++;
02121 }
02122
02123 }
02124 else
02125 {
02126 NR_busdata[indexval].swing_functions_enabled = false;
02127 }
02128
02129 }
02130
02131 }
02132
02133
02134 for (indexval=0; indexval<NR_bus_count; indexval++)
02135 {
02136
02137 if ((*NR_busdata[indexval].busflag & NF_ISSOURCE) == NF_ISSOURCE)
02138 {
02139
02140 if (NR_busdata[indexval].island_number == -1)
02141 {
02142
02143 if ((NR_busdata[indexval].phases & 0x07) != 0x00)
02144 {
02145
02146 search_associated_grids(indexval,grid_counter);
02147
02148
02149 grid_counter++;
02150 }
02151
02152 }
02153
02154 }
02155
02156 }
02157
02158
02159 if (NR_islands_detected != grid_counter)
02160 {
02161
02162 if ((NR_powerflow.island_matrix_values != NULL) && (NR_islands_detected != 0))
02163 {
02164 stat_return_val = NR_array_structure_free(&NR_powerflow,NR_islands_detected);
02165
02166
02167 if (stat_return_val == FAILED)
02168 {
02169 GL_THROW("fault_check: Failed to free up a multi-island NR solver array properly");
02170
02171
02172
02173
02174
02175 }
02176 }
02177
02178
02179 stat_return_val = NR_array_structure_allocate(&NR_powerflow,grid_counter);
02180
02181
02182 if (stat_return_val == FAILED)
02183 {
02184 GL_THROW("fault_check: Failed to allocate a multi-island NR solver array properly");
02185
02186
02187
02188
02189
02190 }
02191
02192
02193 NR_islands_detected = grid_counter;
02194
02195
02196 NR_admit_change = true;
02197 }
02198
02199
02200
02201 force_reassociation = false;
02202 }
02203
02204
02205
02206 void fault_check::search_associated_grids(unsigned int node_int, int grid_counter)
02207 {
02208 unsigned int index;
02209 int node_ref;
02210
02211
02212 for (index=0; index<NR_busdata[node_int].Link_Table_Size; index++)
02213 {
02214
02215 if (NR_branchdata[NR_busdata[node_int].Link_Table[index]].from == node_int)
02216 {
02217
02218 node_ref = NR_branchdata[NR_busdata[node_int].Link_Table[index]].to;
02219 }
02220 else
02221 {
02222
02223 node_ref = NR_branchdata[NR_busdata[node_int].Link_Table[index]].from;
02224 }
02225
02226
02227
02228 if (((NR_busdata[node_int].phases & 0x07) & (NR_branchdata[NR_busdata[node_int].Link_Table[index]].phases & 0x07)) != 0x00)
02229 {
02230
02231 if (NR_busdata[node_ref].island_number == -1)
02232 {
02233
02234 NR_busdata[node_ref].island_number = grid_counter;
02235
02236
02237 NR_branchdata[NR_busdata[node_int].Link_Table[index]].island_number = grid_counter;
02238
02239
02240 search_associated_grids(node_ref,grid_counter);
02241 }
02242 else if (NR_busdata[node_ref].island_number != grid_counter)
02243 {
02244 GL_THROW("fault_check: duplicate grid assignment on node %s!",NR_busdata[node_ref].name);
02245
02246
02247
02248
02249
02250 }
02251
02252 }
02253
02254 }
02255 }
02256
02257
02258 STATUS fault_check::disable_island(int island_number)
02259 {
02260 int index_value;
02261 TIMESTAMP curr_time_val_TS;
02262 double curr_time_val_DBL;
02263
02264
02265 for (index_value=0; index_value < NR_bus_count; index_value++)
02266 {
02267
02268 if (NR_busdata[index_value].island_number == island_number)
02269 {
02270
02271 NR_busdata[index_value].phases &= 0xF8;
02272
02273
02274 NR_busdata[index_value].island_number = -1;
02275
02276
02277 valid_phases[index_value] = 0x00;
02278 }
02279
02280 }
02281
02282
02283 for (index_value=0; index_value < NR_branch_count; index_value++)
02284 {
02285
02286 if (NR_branchdata[index_value].island_number == island_number)
02287 {
02288
02289 NR_branchdata[index_value].phases &= 0xF8;
02290
02291
02292 NR_branchdata[index_value].island_number = -1;
02293 }
02294
02295 }
02296
02297
02298 if (output_filename[0] != '\0')
02299 {
02300
02301 if (deltatimestep_running > 0.0)
02302 {
02303 curr_time_val_TS = 0;
02304 curr_time_val_DBL = gl_globaldeltaclock;
02305 }
02306 else
02307 {
02308 curr_time_val_TS = gl_globalclock;
02309 curr_time_val_DBL = 0.0;
02310 }
02311
02312 write_output_file(curr_time_val_TS,curr_time_val_DBL);
02313 }
02314
02315
02316 force_reassociation = true;
02317
02318
02319 gl_verbose("fault_check: Removed island %d from the powerflow",(island_number+1));
02320
02321
02322 return SUCCESS;
02323 }
02324
02325
02326 STATUS fault_check::rescan_topology(int bus_that_called_reset)
02327 {
02328
02329 if (NR_solver_working == true)
02330 {
02331
02332 return FAILED;
02333 }
02334
02335
02336 support_check_alterations(bus_that_called_reset,true);
02337
02338
02339 return SUCCESS;
02340 }
02341
02342
02344
02346
02354 EXPORT int create_fault_check(OBJECT **obj, OBJECT *parent)
02355 {
02356 try
02357 {
02358 *obj = gl_create_object(fault_check::oclass);
02359 if (*obj!=NULL)
02360 {
02361 fault_check *my = OBJECTDATA(*obj,fault_check);
02362 gl_set_parent(*obj,parent);
02363 return my->create();
02364 }
02365 else
02366 return 0;
02367 }
02368 CREATE_CATCHALL(fault_check);
02369 }
02370
02371 EXPORT int init_fault_check(OBJECT *obj, OBJECT *parent)
02372 {
02373 try {
02374 fault_check *my = OBJECTDATA(obj,fault_check);
02375 return my->init(parent);
02376 }
02377 INIT_CATCHALL(fault_check);
02378 }
02379
02388 EXPORT TIMESTAMP sync_fault_check(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
02389 {
02390 try {
02391 fault_check *pObj = OBJECTDATA(obj,fault_check);
02392 TIMESTAMP t1 = TS_NEVER;
02393 switch (pass) {
02394 case PC_PRETOPDOWN:
02395 return pObj->presync(t0);
02396 case PC_BOTTOMUP:
02397 return pObj->sync(t0);
02398 case PC_POSTTOPDOWN:
02399 t1 = pObj->postsync(t0);
02400 obj->clock = t0;
02401 return t1;
02402 default:
02403 throw "invalid pass request";
02404 }
02405 }
02406 SYNC_CATCHALL(fault_check);
02407 }
02408
02409 EXPORT int isa_fault_check(OBJECT *obj, char *classname)
02410 {
02411 return OBJECTDATA(obj,fault_check)->isa(classname);
02412 }
02413
02414
02415 EXPORT int powerflow_alterations(OBJECT *thisobj, int baselink, bool rest_mode)
02416 {
02417 fault_check *thsfltchk = OBJECTDATA(thisobj,fault_check);
02418
02419
02420 thsfltchk->support_check_alterations(baselink,rest_mode);
02421
02422 return 1;
02423 }
02424
02425
02426 EXPORT double handle_sectionalizer(OBJECT *thisobj, int sectionalizer_number)
02427 {
02428 double result_val;
02429 unsigned int index;
02430 int branch_val, node_val;
02431 bool loop_complete, proper_exit;
02432 double *rec_tries;
02433 PROPERTY *Pval;
02434 OBJECT *tmp_obj;
02435 fault_check *fltyobj;
02436
02437
02438 node_val = NR_branchdata[sectionalizer_number].from;
02439
02440
02441 loop_complete = false;
02442
02443
02444 while (loop_complete == false)
02445 {
02446
02447 proper_exit = false;
02448
02449
02450 for (index=0; index<NR_busdata[node_val].Link_Table_Size; index++)
02451 {
02452
02453 branch_val = NR_busdata[node_val].Link_Table[index];
02454
02455
02456 if (NR_branchdata[branch_val].to == node_val)
02457 {
02458
02459 if (NR_branchdata[branch_val].lnk_type == 6)
02460 {
02461
02462 tmp_obj = NR_branchdata[branch_val].obj;
02463
02464
02465 if (tmp_obj == NULL)
02466 {
02467 GL_THROW("Failure to map recloser object %s during sectionalizer handling",NR_branchdata[branch_val].name);
02468
02469
02470
02471
02472
02473 }
02474
02475
02476 Pval = gl_get_property(tmp_obj,"number_of_tries");
02477
02478
02479 if (Pval == NULL)
02480 {
02481 GL_THROW("Failed to map recloser:%s retry count!",NR_branchdata[branch_val].name);
02482
02483
02484
02485
02486 }
02487
02488
02489 rec_tries = (double*)GETADDR(tmp_obj,Pval);
02490
02491
02492 *rec_tries += 1;
02493
02494
02495 result_val = *rec_tries;
02496
02497
02498
02499 fltyobj = OBJECTDATA(fault_check_object,fault_check);
02500
02501
02502 fltyobj->momentary_activation(NR_branchdata[branch_val].to);
02503
02504
02505 proper_exit = true;
02506
02507
02508 loop_complete = true;
02509
02510
02511 break;
02512
02513 }
02514 else
02515 {
02516
02517 node_val = NR_branchdata[branch_val].from;
02518
02519
02520 if ((NR_busdata[node_val].type == 2) || ((NR_busdata[node_val].type == 3) && (NR_busdata[node_val].swing_functions_enabled == true)))
02521 {
02522 result_val = -1.0;
02523 loop_complete = true;
02524 proper_exit = true;
02525 break;
02526 }
02527 else
02528 {
02529 proper_exit = true;
02530 break;
02531 }
02532 }
02533 }
02534 else
02535 {
02536 continue;
02537 }
02538 }
02539
02540
02541 if ((index>NR_busdata[node_val].Link_Table_Size) && (proper_exit==false))
02542 {
02543 result_val = 0.0;
02544 loop_complete = true;
02545 }
02546 }
02547
02548 return result_val;
02549 }
02550
02551
02552 EXPORT STATUS powerflow_disable_island(OBJECT *thisobj, int island_number)
02553 {
02554
02555 fault_check *fltyobj = OBJECTDATA(fault_check_object,fault_check);
02556
02557
02558 return fltyobj->disable_island(island_number);
02559 }
02560
02561
02562 EXPORT STATUS powerflow_rescan_topo(OBJECT *thisobj,int bus_that_called_reset)
02563 {
02564
02565 fault_check *fltyobj = OBJECTDATA(fault_check_object,fault_check);
02566
02567
02568 return fltyobj->rescan_topology(bus_that_called_reset);
02569 }