00001
00005 #include <stdlib.h>
00006 #include <stdio.h>
00007 #include <errno.h>
00008 #include <math.h>
00009 #include <iostream>
00010
00011 using namespace std;
00012
00013 #include "fault_check.h"
00014 #include "restoration.h"
00015 #include "solver_nr.h"
00016
00018
00020 CLASS* fault_check::oclass = NULL;
00021 CLASS* fault_check::pclass = NULL;
00022
00023 fault_check::fault_check(MODULE *mod) : powerflow_object(mod)
00024 {
00025 if(oclass == NULL)
00026 {
00027 pclass = powerflow_object::oclass;
00028 oclass = gl_register_class(mod,"fault_check",sizeof(fault_check),PC_BOTTOMUP);
00029 if(oclass == NULL)
00030 GL_THROW("unable to register object class implemented by %s",__FILE__);
00031
00032 if(gl_publish_variable(oclass,
00033 PT_enumeration, "check_mode", PADDR(fcheck_state),PT_DESCRIPTION,"Frequency of fault checks",
00034 PT_KEYWORD, "SINGLE", SINGLE,
00035 PT_KEYWORD, "ONCHANGE", ONCHANGE,
00036 PT_KEYWORD, "ALL", ALLT,
00037 PT_char1024,"output_filename",PADDR(output_filename),
00038 NULL) < 1) GL_THROW("unable to publish properties in %s",__FILE__);
00039 }
00040 }
00041
00042 int fault_check::isa(char *classname)
00043 {
00044 return strcmp(classname,"fault_check")==0;
00045 }
00046
00047 int fault_check::create(void)
00048 {
00049 int result = powerflow_object::create();
00050 prev_time = 0;
00051 phases = PHASE_A;
00052
00053 fcheck_state = SINGLE;
00054 output_filename[0] = '\0';
00055
00056 return result;
00057 }
00058
00059 int fault_check::init(OBJECT *parent)
00060 {
00061 OBJECT *obj = OBJECTHDR(this);
00062 FILE *FPoint;
00063
00064 if (solver_method == SM_NR)
00065 {
00066
00067 gl_set_rank(obj,5);
00068 }
00069 else
00070 {
00071 GL_THROW("Fault checking object is only valid for the Newton-Raphson solver at this time.");
00072
00073
00074
00075
00076 }
00077
00078
00079 if (output_filename[0] != '\0')
00080 {
00081 FPoint = fopen(output_filename,"wt");
00082 fclose(FPoint);
00083 }
00084
00085 return powerflow_object::init(parent);
00086 }
00087
00088 TIMESTAMP fault_check::sync(TIMESTAMP t0)
00089 {
00090 OBJECT *obj = OBJECTHDR(this);
00091 TIMESTAMP tret = powerflow_object::sync(t0);
00092 restoration *rest_obj;
00093 unsigned int index;
00094 bool perform_check;
00095
00096 if (prev_time == 0)
00097 {
00098 if (restoration_object==NULL)
00099 {
00100 gl_warning("Restoration object not detected!");
00101
00102
00103
00104
00105 }
00106
00107
00108 Supported_Nodes = (int**)gl_malloc(NR_bus_count*sizeof(int));
00109 if (Supported_Nodes == NULL)
00110 {
00111 GL_THROW("fault_check: node status vector allocation failure");
00112
00113
00114
00115
00116 }
00117
00118
00119 for (index=0; index<NR_bus_count; index++)
00120 {
00121 Supported_Nodes[index] = (int*)gl_malloc(3*sizeof(int));
00122
00123 if (Supported_Nodes[index] == NULL)
00124 {
00125 GL_THROW("fault_check: node status vector allocation failure");
00126
00127 }
00128 }
00129 }
00130
00131 if (NR_cycle==false)
00132 {
00133 if ((fcheck_state == SINGLE) && (prev_time == 0))
00134 {
00135 perform_check = true;
00136 }
00137 else if ((fcheck_state == ONCHANGE) && (NR_admit_change == true))
00138 {
00139 perform_check = true;
00140 }
00141 else if (fcheck_state == ALLT)
00142 {
00143 perform_check = true;
00144 }
00145 else
00146 {
00147 perform_check = false;
00148 }
00149
00150 if (perform_check)
00151 {
00152
00153 if (restoration_object != NULL)
00154 {
00155
00156 rest_obj = OBJECTDATA(restoration_object,restoration);
00157
00158
00159 support_check(0,rest_obj->populate_tree);
00160
00161
00162 for (index=0; index<NR_bus_count; index++)
00163 {
00164 if ((Supported_Nodes[index][0] == 0) || (Supported_Nodes[index][1] == 0) || (Supported_Nodes[index][2] == 0))
00165 {
00166 if (output_filename[0] != '\0')
00167 {
00168 write_output_file(t0);
00169 }
00170
00171 gl_warning("Unsupported phase on node %s",NR_busdata[index].name);
00172
00173 rest_obj->Perform_Reconfiguration(OBJECTHDR(this),t0);
00174
00175 break;
00176 }
00177 }
00178 }
00179 else
00180 {
00181
00182 support_check(0,false);
00183
00184
00185 for (index=0; index<NR_bus_count; index++)
00186 {
00187 if ((Supported_Nodes[index][0] == 0) || (Supported_Nodes[index][1] == 0) || (Supported_Nodes[index][2] == 0))
00188 {
00189 if (output_filename[0] != '\0')
00190 {
00191 write_output_file(t0);
00192 }
00193
00194 GL_THROW("Unsupported phase on node %s",NR_busdata[index].name);
00195
00196
00197
00198
00199 }
00200 }
00201 }
00202 }
00203 }
00204
00205
00206 prev_time = t0;
00207
00208 return tret;
00209 }
00210
00211
00212 void fault_check::search_links(unsigned int node_int)
00213 {
00214 unsigned int index, temp_child_idx, indexb;
00215 bool both_handled, from_val, first_resto, proceed_in;
00216 int branch_val;
00217 BRANCHDATA temp_branch;
00218 restoration *rest_object;
00219 unsigned char work_phases;
00220
00221
00222 for (index=0; index<NR_busdata[node_int].Link_Table_Size; index++)
00223 {
00224 temp_branch = NR_branchdata[NR_busdata[node_int].Link_Table[index]];
00225
00226 first_resto = false;
00227 proceed_in = false;
00228
00229
00230 if ((temp_branch.phases & 0x07) != 0x00)
00231 {
00232 for (indexb=0; indexb<3; indexb++)
00233 {
00234 work_phases = 0x04 >> indexb;
00235
00236 if ((temp_branch.phases & work_phases) == work_phases)
00237 {
00238 both_handled = false;
00239
00240
00241 if (temp_branch.from == node_int)
00242 {
00243 from_val = true;
00244 }
00245 else
00246 {
00247 from_val = false;
00248 }
00249
00250
00251 if ((Supported_Nodes[temp_branch.to][indexb]==1) && (Supported_Nodes[temp_branch.from][indexb]==1))
00252 both_handled=true;
00253
00254
00255 if (both_handled==false)
00256 {
00257
00258 if (from_val)
00259 {
00260 branch_val = temp_branch.to;
00261
00262
00263 if (Supported_Nodes[temp_branch.from][indexb] == 1)
00264 {
00265 proceed_in = true;
00266 }
00267 else
00268 {
00269 continue;
00270 }
00271 }
00272 else
00273 {
00274 branch_val = temp_branch.from;
00275
00276
00277 if (Supported_Nodes[temp_branch.to][indexb] == 1)
00278 {
00279 proceed_in = true;
00280 }
00281 else
00282 {
00283 continue;
00284 }
00285 }
00286
00287
00288 if (restoration_object != NULL)
00289 {
00290
00291 rest_object = OBJECTDATA(restoration_object,restoration);
00292
00293
00294 if ((rest_object->populate_tree == true) && (first_resto == false))
00295 {
00296 first_resto = true;
00297
00298 if (from_val)
00299 {
00300
00301 NR_busdata[temp_branch.to].Parent_Node = temp_branch.from;
00302
00303
00304 temp_child_idx = NR_busdata[temp_branch.from].Link_Table_Size;
00305 if (NR_busdata[temp_branch.from].Child_Node_idx < temp_child_idx)
00306 {
00307 if (rest_object ->Connectivity_Matrix[temp_branch.from][ temp_branch.to] != 3)
00308 {
00309 NR_busdata[temp_branch.from].Child_Nodes[NR_busdata[temp_branch.from].Child_Node_idx] = temp_branch.to;
00310 NR_busdata[temp_branch.from].Child_Node_idx++;
00311 }
00312 else if ((rest_object ->Connectivity_Matrix[temp_branch.from][ temp_branch.to] == 3) && (*temp_branch.status == true))
00313 {
00314 NR_busdata[temp_branch.from].Child_Nodes[NR_busdata[temp_branch.from].Child_Node_idx] = temp_branch.to;
00315 NR_busdata[temp_branch.from].Child_Node_idx++;
00316 }
00317 else
00318 {
00319 temp_child_idx -= 1;
00320 }
00321 }
00322 else
00323 {
00324 GL_THROW("NR: Too many children were attempted to be populated!");
00325
00326
00327
00328
00329
00330 }
00331 }
00332
00333 }
00334 }
00335
00336
00337 Supported_Nodes[branch_val][indexb] = 1;
00338
00339 }
00340 }
00341 }
00342
00343 if (proceed_in)
00344 {
00345
00346 search_links(branch_val);
00347 }
00348 }
00349 }
00350 }
00351
00352 void fault_check::support_check(unsigned int swing_node_int,bool rest_pop_tree)
00353 {
00354 unsigned int index;
00355
00356
00357 reset_support_check();
00358
00359
00360 if (rest_pop_tree == true)
00361 {
00362 for (index=0; index<NR_bus_count; index++)
00363 NR_busdata[index].Child_Node_idx = 0;
00364 }
00365
00366
00367 Supported_Nodes[swing_node_int][0] = Supported_Nodes[swing_node_int][1] = Supported_Nodes[swing_node_int][2] = 1;
00368
00369
00370 search_links(swing_node_int);
00371 }
00372
00373 void fault_check::reset_support_check(void)
00374 {
00375 unsigned int index;
00376
00377
00378 for (index=0; index<NR_bus_count; index++)
00379 {
00380 if ((NR_busdata[index].origphases & 0x04) == 0x04)
00381 {
00382 Supported_Nodes[index][0] = 0;
00383 }
00384 else
00385 {
00386 Supported_Nodes[index][0] = 2;
00387 }
00388
00389 if ((NR_busdata[index].origphases & 0x02) == 0x02)
00390 {
00391 Supported_Nodes[index][1] = 0;
00392 }
00393 else
00394 {
00395 Supported_Nodes[index][1] = 2;
00396 }
00397
00398 if ((NR_busdata[index].origphases & 0x01) == 0x01)
00399 {
00400 Supported_Nodes[index][2] = 0;
00401 }
00402 else
00403 {
00404 Supported_Nodes[index][2] = 2;
00405 }
00406 }
00407 }
00408
00409 void fault_check::write_output_file(TIMESTAMP tval)
00410 {
00411 unsigned int index;
00412 bool headerwritten = false;
00413 char phase_outs;
00414
00415
00416 FILE *FPOutput = fopen(output_filename,"at");
00417
00418 for (index=0; index<NR_bus_count; index++)
00419 {
00420
00421 phase_outs = 0x00;
00422
00423 if (Supported_Nodes[index][0] == 0)
00424 phase_outs |= 0x04;
00425
00426 if (Supported_Nodes[index][1] == 0)
00427 phase_outs |= 0x02;
00428
00429 if (Supported_Nodes[index][2] == 0)
00430 phase_outs |= 0x01;
00431
00432 if (phase_outs != 0x00)
00433 {
00434
00435 if (headerwritten == false)
00436 {
00437 fprintf(FPOutput,"Unsupported at timestamp %lld:\n\n",tval);
00438 headerwritten = true;
00439 }
00440
00441
00442 switch (phase_outs) {
00443 case 0x01:
00444 {
00445 fprintf(FPOutput,"Phase C on node %s\n",NR_busdata[index].name);
00446 break;
00447 }
00448 case 0x02:
00449 {
00450 fprintf(FPOutput,"Phase B on node %s\n",NR_busdata[index].name);
00451 break;
00452 }
00453 case 0x03:
00454 {
00455 fprintf(FPOutput,"Phases B and C on node %s\n",NR_busdata[index].name);
00456 break;
00457 }
00458 case 0x04:
00459 {
00460 fprintf(FPOutput,"Phase A on node %s\n",NR_busdata[index].name);
00461 break;
00462 }
00463 case 0x05:
00464 {
00465 fprintf(FPOutput,"Phases A and C on node %s\n",NR_busdata[index].name);
00466 break;
00467 }
00468 case 0x06:
00469 {
00470 fprintf(FPOutput,"Phases A and B on node %s\n",NR_busdata[index].name);
00471 break;
00472 }
00473 case 0x07:
00474 {
00475 fprintf(FPOutput,"Phases A, B, and C on node %s\n",NR_busdata[index].name);
00476 break;
00477 }
00478 default:
00479 {
00480 GL_THROW("Error parsing unsupported phases on node %s",NR_busdata[index].name);
00481
00482
00483
00484
00485
00486 }
00487 }
00488 }
00489 }
00490
00491 fprintf(FPOutput,"\n\n\n");
00492
00493
00494 fclose(FPOutput);
00495 }
00497
00499
00507 EXPORT int create_fault_check(OBJECT **obj, OBJECT *parent)
00508 {
00509 try
00510 {
00511 *obj = gl_create_object(fault_check::oclass);
00512 if (*obj!=NULL)
00513 {
00514 fault_check *my = OBJECTDATA(*obj,fault_check);
00515 gl_set_parent(*obj,parent);
00516 return my->create();
00517 }
00518 }
00519 catch (const char *msg)
00520 {
00521 gl_error("%s %s (id=%d): %s", (*obj)->name?(*obj)->name:"unnamed", (*obj)->oclass->name, (*obj)->id, msg);
00522 return 0;
00523 }
00524 return 1;
00525 }
00526
00527 EXPORT int init_fault_check(OBJECT *obj, OBJECT *parent)
00528 {
00529 try {
00530 return OBJECTDATA(obj,fault_check)->init(parent);
00531 }
00532 catch (const char *msg)
00533 {
00534 gl_error("%s %s (id=%d): %s", obj->name?obj->name:"unnamed", obj->oclass->name, obj->id, msg);
00535 return 0;
00536 }
00537 return 1;
00538 }
00539
00548 EXPORT TIMESTAMP sync_fault_check(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00549 {
00550 fault_check *pObj = OBJECTDATA(obj,fault_check);
00551 try {
00552 TIMESTAMP t1 = TS_NEVER;
00553 switch (pass) {
00554 case PC_PRETOPDOWN:
00555 return pObj->presync(t0);
00556 case PC_BOTTOMUP:
00557 return pObj->sync(t0);
00558 case PC_POSTTOPDOWN:
00559 t1 = pObj->postsync(t0);
00560 obj->clock = t0;
00561 return t1;
00562 default:
00563 throw "invalid pass request";
00564 }
00565 }
00566 catch (const char *msg)
00567 {
00568 gl_error("fault_check %s (%s:%d): %s", obj->name, obj->oclass->name, obj->id, msg);
00569 }
00570 catch (...)
00571 {
00572 gl_error("fault_check %s (%s:%d): unknown exception", obj->name, obj->oclass->name, obj->id);
00573 }
00574 return TS_INVALID;
00575 }
00576
00577 EXPORT int isa_fault_check(OBJECT *obj, char *classname)
00578 {
00579 return OBJECTDATA(obj,fault_check)->isa(classname);
00580 }
00581