00001
00002
00003
00004 #include <stdlib.h>
00005 #include <stdio.h>
00006 #include <errno.h>
00007 #include <math.h>
00008
00009 #include "gridlabd.h"
00010
00011 #define _POWERFLOW_CPP
00012 #include "powerflow.h"
00013 #undef _POWERFLOW_CPP
00014
00015 #include "triplex_meter.h"
00016 #include "capacitor.h"
00017 #include "fuse.h"
00018 #include "line.h"
00019 #include "link.h"
00020 #include "load.h"
00021 #include "meter.h"
00022 #include "node.h"
00023 #include "regulator.h"
00024 #include "transformer.h"
00025 #include "switch_object.h"
00026 #include "substation.h"
00027 #include "pqload.h"
00028 #include "voltdump.h"
00029 #include "series_reactor.h"
00030 #include "restoration.h"
00031 #include "volt_var_control.h"
00032 #include "fault_check.h"
00033 #include "motor.h"
00034 #include "billdump.h"
00035 #include "power_metrics.h"
00036 #include "currdump.h"
00037 #include "recloser.h"
00038 #include "sectionalizer.h"
00039 #include "emissions.h"
00040 #include "load_tracker.h"
00041 #include "triplex_load.h"
00042 #include "impedance_dump.h"
00043 #include "vfd.h"
00044 #include "jsondump.h"
00045
00046 EXPORT CLASS *init(CALLBACKS *fntable, MODULE *module, int argc, char *argv[])
00047 {
00048 if (!set_callback(fntable)) {
00049 errno = EINVAL;
00050 return NULL;
00051 }
00052
00053
00054 gl_global_create("powerflow::show_matrix_values",PT_bool,&show_matrix_values,NULL);
00055 gl_global_create("powerflow::primary_voltage_ratio",PT_double,&primary_voltage_ratio,NULL);
00056 gl_global_create("powerflow::nominal_frequency",PT_double,&nominal_frequency,NULL);
00057 gl_global_create("powerflow::require_voltage_control", PT_bool,&require_voltage_control,NULL);
00058 gl_global_create("powerflow::geographic_degree",PT_double,&geographic_degree,NULL);
00059 gl_global_create("powerflow::fault_impedance",PT_complex,&fault_Z,NULL);
00060 gl_global_create("powerflow::ground_impedance",PT_complex,&ground_Z,NULL);
00061 gl_global_create("powerflow::warning_underfrequency",PT_double,&warning_underfrequency,NULL);
00062 gl_global_create("powerflow::warning_overfrequency",PT_double,&warning_overfrequency,NULL);
00063 gl_global_create("powerflow::warning_undervoltage",PT_double,&warning_undervoltage,NULL);
00064 gl_global_create("powerflow::warning_overvoltage",PT_double,&warning_overvoltage,NULL);
00065 gl_global_create("powerflow::warning_voltageangle",PT_double,&warning_voltageangle,NULL);
00066 gl_global_create("powerflow::maximum_voltage_error",PT_double,&default_maximum_voltage_error,NULL);
00067 gl_global_create("powerflow::solver_method",PT_enumeration,&solver_method,
00068 PT_KEYWORD,"FBS",SM_FBS,
00069 PT_KEYWORD,"GS",SM_GS,
00070 PT_KEYWORD,"NR",SM_NR,
00071 NULL);
00072 gl_global_create("powerflow::NR_matrix_file",PT_char256,&MDFileName,NULL);
00073 gl_global_create("powerflow::NR_matrix_output_interval",PT_enumeration,&NRMatDumpMethod,
00074 PT_KEYWORD,"NEVER",MD_NONE,
00075 PT_KEYWORD,"ONCE",MD_ONCE,
00076 PT_KEYWORD,"PER_CALL",MD_PERCALL,
00077 PT_KEYWORD,"ALL",MD_ALL,
00078 NULL);
00079 gl_global_create("powerflow::NR_matrix_output_references",PT_bool,&NRMatReferences,NULL);
00080 gl_global_create("powerflow::NR_island_failure_handled",PT_bool,&NR_island_fail_method,PT_DESCRIPTION,"Indicates if an island fails if it should be removed from service",NULL);
00081 gl_global_create("powerflow::line_capacitance",PT_bool,&use_line_cap,NULL);
00082 gl_global_create("powerflow::line_limits",PT_bool,&use_link_limits,NULL);
00083 gl_global_create("powerflow::lu_solver",PT_char256,&LUSolverName,NULL);
00084 gl_global_create("powerflow::NR_iteration_limit",PT_int64,&NR_iteration_limit,NULL);
00085 gl_global_create("powerflow::NR_deltamode_iteration_limit",PT_int64,&NR_delta_iteration_limit,NULL);
00086 gl_global_create("powerflow::NR_superLU_procs",PT_int32,&NR_superLU_procs,NULL);
00087 gl_global_create("powerflow::default_maximum_voltage_error",PT_double,&default_maximum_voltage_error,NULL);
00088 gl_global_create("powerflow::default_maximum_power_error",PT_double,&default_maximum_power_error,NULL);
00089 gl_global_create("powerflow::NR_admit_change",PT_bool,&NR_admit_change,NULL);
00090 gl_global_create("powerflow::enable_subsecond_models", PT_bool, &enable_subsecond_models,PT_DESCRIPTION,"Enable deltamode capabilities within the powerflow module",NULL);
00091 gl_global_create("powerflow::all_powerflow_delta", PT_bool, &all_powerflow_delta,PT_DESCRIPTION,"Forces all powerflow objects that are capable to participate in deltamode",NULL);
00092 gl_global_create("powerflow::deltamode_timestep", PT_double, &deltamode_timestep_publish,PT_UNITS,"ns",PT_DESCRIPTION,"Desired minimum timestep for deltamode-related simulations",NULL);
00093 gl_global_create("powerflow::current_frequency",PT_double,¤t_frequency,PT_UNITS,"Hz",PT_DESCRIPTION,"Current system-level frequency of the powerflow system",NULL);
00094 gl_global_create("powerflow::master_frequency_update",PT_bool,&master_frequency_update,PT_DESCRIPTION,"Tracking variable to see if an object has become the system frequency updater",NULL);
00095 gl_global_create("powerflow::enable_frequency_dependence",PT_bool,&enable_frequency_dependence,PT_DESCRIPTION,"Flag to enable frequency-based variations in impedance values of lines and loads",NULL);
00096 gl_global_create("powerflow::default_resistance",PT_double,&default_resistance,NULL);
00097 gl_global_create("powerflow::enable_inrush",PT_bool,&enable_inrush_calculations,PT_DESCRIPTION,"Flag to enable in-rush calculations for lines and transformers in deltamode",NULL);
00098 gl_global_create("powerflow::inrush_integration",PT_enumeration,&default_inrush_integration_method,PT_DESCRIPTION,"Determine the integration method utilized in in-rush calculations",
00099 PT_KEYWORD,"NONE",IRM_NONE,
00100 PT_KEYWORD,"TRAPEZOIDAL",IRM_TRAPEZOIDAL,
00101 PT_KEYWORD,"BACKWARD_EULER",IRM_BACKEULER,
00102 NULL);
00103 gl_global_create("powerflow::all_frequency_measure_default",PT_enumeration,&all_powerflow_freq_measure_method,
00104 PT_KEYWORD,"NONE", FMM_NONE,
00105 PT_KEYWORD,"SIMPLE", FMM_SIMPLE,
00106 PT_KEYWORD,"PLL", FMM_PLL,
00107 NULL);
00108 gl_global_create("powerflow::low_voltage_impedance_level",PT_double,&impedance_conversion_low_pu,PT_DESCRIPTION,"Lower limit of voltage (in per-unit) at which all load types are converted to impedance for in-rush calculations",NULL);
00109 gl_global_create("powerflow::enable_mesh_fault_current",PT_bool,&enable_mesh_fault_current,PT_DESCRIPTION,"Flag to enable mesh-based fault current calculations",NULL);
00110 gl_global_create("powerflow::market_price_name",PT_char1024,&market_price_name,PT_DESCRIPTION,"Market current price published variable name",NULL);
00111
00112
00113 new powerflow_object(module);
00114 new powerflow_library(module);
00115 new node(module);
00116 new link_object(module);
00117 new capacitor(module);
00118 new fuse(module);
00119 new meter(module);
00120 new line(module);
00121 new line_spacing(module);
00122 new overhead_line(module);
00123 new underground_line(module);
00124 new overhead_line_conductor(module);
00125 new underground_line_conductor(module);
00126 new line_configuration(module);
00127 new transformer_configuration(module);
00128 new transformer(module);
00129 new load(module);
00130 new regulator_configuration(module);
00131 new regulator(module);
00132 new triplex_node(module);
00133 new triplex_meter(module);
00134 new triplex_line(module);
00135 new triplex_line_configuration(module);
00136 new triplex_line_conductor(module);
00137 new switch_object(module);
00138 new substation(module);
00139 new pqload(module);
00140 new voltdump(module);
00141 new series_reactor(module);
00142 new restoration(module);
00143 new volt_var_control(module);
00144 new fault_check(module);
00145 new motor(module);
00146 new billdump(module);
00147 new power_metrics(module);
00148 new currdump(module);
00149 new recloser(module);
00150 new sectionalizer(module);
00151 new emissions(module);
00152 new load_tracker(module);
00153 new triplex_load(module);
00154 new impedance_dump(module);
00155 new vfd(module);
00156 new jsondump(module);
00157
00158
00159 return node::oclass;
00160 }
00161
00162
00163 void schedule_deltamode_start(TIMESTAMP tstart)
00164 {
00165 if (enable_subsecond_models == true)
00166 {
00167 if ( (tstart<deltamode_starttime) && ((tstart-gl_globalclock)<0x7fffffff ))
00168 deltamode_starttime = tstart;
00169 }
00170 else
00171 {
00172 GL_THROW("powerflow: a call was made to deltamode functions, but subsecond models are not enabled!");
00173
00174
00175
00176
00177
00178
00179 }
00180 }
00181
00182
00183
00184
00185
00186
00187
00188 EXPORT unsigned long deltamode_desired(int *flags)
00189 {
00190 unsigned long dt_val;
00191
00192 if (enable_subsecond_models == true)
00193 {
00194
00195 if ((deltamode_starttime>=gl_globalclock) && (deltamode_starttime<TS_NEVER))
00196 {
00197
00198 *flags |= DMF_SOFTEVENT;
00199
00200
00201 dt_val = (unsigned long)(deltamode_starttime - gl_globalclock);
00202
00203 gl_debug("powerflow: deltamode desired in %d", dt_val);
00204 return dt_val;
00205 }
00206 else
00207 {
00208
00209 return DT_INFINITY;
00210 }
00211 }
00212 else
00213 {
00214 return DT_INFINITY;
00215 }
00216 }
00217
00218
00219
00220
00221
00222 EXPORT unsigned long preupdate(MODULE *module, TIMESTAMP t0, unsigned int64 dt)
00223 {
00224 if (enable_subsecond_models == true)
00225 {
00226 if (deltamode_timestep_publish<=0.0)
00227 {
00228 gl_error("powerflow::deltamode_timestep must be a positive, non-zero number!");
00229
00230
00231
00232
00233
00234 return DT_INVALID;
00235 }
00236 else
00237 {
00238
00239 deltamode_timestep = (unsigned long)(deltamode_timestep_publish+0.5);
00240
00241
00242 return deltamode_timestep;
00243 }
00244 }
00245 else
00246 {
00247 return DT_INFINITY;
00248 }
00249 }
00250
00251
00252
00253
00254
00255 EXPORT SIMULATIONMODE interupdate(MODULE *module, TIMESTAMP t0, unsigned int64 delta_time, unsigned long dt, unsigned int iteration_count_val)
00256 {
00257 int curr_object_number;
00258 SIMULATIONMODE function_status = SM_EVENT;
00259 bool event_driven = true;
00260 bool delta_iter = false;
00261 bool bad_computation=false;
00262 NRSOLVERMODE powerflow_type;
00263 int64 pf_result;
00264 int64 simple_iter_test, limit_minus_one;
00265 bool error_state;
00266
00267
00268 simple_iter_test = 0;
00269 limit_minus_one = NR_delta_iteration_limit - 1;
00270 error_state = false;
00271
00272 if (enable_subsecond_models == true)
00273 {
00274
00275 if (deltatimestep_running < 0.0)
00276 {
00277
00278 deltatimestep_running = (double)((double)dt/(double)DT_SECOND);
00279 }
00280
00281
00282 while (simple_iter_test < NR_delta_iteration_limit)
00283 {
00284
00285
00286 for (curr_object_number=0; curr_object_number<pwr_object_count; curr_object_number++)
00287 {
00288
00289 if ((delta_objects[curr_object_number]->in_svc_double <= gl_globaldeltaclock) && (delta_objects[curr_object_number]->out_svc_double >= gl_globaldeltaclock))
00290 {
00291 if (delta_functions[curr_object_number] != NULL)
00292 {
00293
00294 try {
00295
00296 function_status = ((SIMULATIONMODE (*)(OBJECT *, unsigned int64, unsigned long, unsigned int, bool))(*delta_functions[curr_object_number]))(delta_objects[curr_object_number],delta_time,dt,iteration_count_val,false);
00297 }
00298 catch (const char *msg)
00299 {
00300 gl_error("powerflow:interupdate - pre-pass function call: %s", msg);
00301 error_state = true;
00302 function_status = SM_ERROR;
00303 }
00304 catch (...)
00305 {
00306 gl_error("powerflow:interupdate - pre-pass function call: unknown exception");
00307 error_state = true;
00308 function_status = SM_ERROR;
00309 }
00310 }
00311 else
00312 {
00313 function_status = SM_EVENT;
00314 }
00315 }
00316 else
00317 function_status = SM_DELTA;
00318
00319
00320 if (function_status == SM_ERROR)
00321 {
00322 gl_error("Powerflow object:%s - deltamode function returned an error!",delta_objects[curr_object_number]->name);
00323
00324
00325 error_state = true;
00326 break;
00327 }
00328
00329 }
00330
00331
00332 if ((error_state == true) || (function_status == SM_ERROR))
00333 {
00334
00335 break;
00336 }
00337
00338
00339 powerflow_type = PF_DYNCALC;
00340
00341
00342 try {
00343
00344 pf_result = solver_nr(NR_bus_count, NR_busdata, NR_branch_count, NR_branchdata, &NR_powerflow, powerflow_type, NULL, &bad_computation);
00345 }
00346 catch (const char *msg)
00347 {
00348 gl_error("powerflow:interupdate - solver_nr call: %s", msg);
00349 error_state = true;
00350 }
00351 catch (...)
00352 {
00353 gl_error("powerflow:interupdate - solver_nr call: unknown exception");
00354 error_state = true;
00355 }
00356
00357
00358 NR_admit_change = false;
00359
00360
00361 if (bad_computation==true)
00362 {
00363 gl_error("Newton-Raphson method is unable to converge the dynamic powerflow to a solution at this operation point");
00364
00365
00366
00367
00368
00369 error_state = true;
00370 break;
00371 }
00372 else if ((pf_result<0) && (simple_iter_test == limit_minus_one))
00373 {
00374 gl_error("Newton-Raphson failed to converge the dynamic powerflow, sticking at same iteration.");
00375
00376
00377
00378
00379
00380
00381 error_state = true;
00382 break;
00383 }
00384 else if (error_state == true)
00385 {
00386 break;
00387 }
00388
00389
00390 for (curr_object_number=0; curr_object_number<pwr_object_count; curr_object_number++)
00391 {
00392
00393 if ((delta_objects[curr_object_number]->in_svc_double <= gl_globaldeltaclock) && (delta_objects[curr_object_number]->out_svc_double >= gl_globaldeltaclock))
00394 {
00395 if (delta_functions[curr_object_number] != NULL)
00396 {
00397
00398 try {
00399
00400 function_status = ((SIMULATIONMODE (*)(OBJECT *, unsigned int64, unsigned long, unsigned int, bool))(*delta_functions[curr_object_number]))(delta_objects[curr_object_number],delta_time,dt,iteration_count_val,true);
00401 }
00402 catch (const char *msg)
00403 {
00404 gl_error("powerflow:interupdate - post-pass function call: %s", msg);
00405 error_state = true;
00406 function_status = SM_ERROR;
00407 }
00408 catch (...)
00409 {
00410 gl_error("powerflow:interupdate - post-pass function call: unknown exception");
00411 error_state = true;
00412 function_status = SM_ERROR;
00413 }
00414 }
00415 else
00416 {
00417 function_status = SM_EVENT;
00418 }
00419 }
00420 else
00421 function_status = SM_EVENT;
00422
00423
00424 if (function_status == SM_DELTA)
00425 {
00426 gl_verbose("Powerflow object:%d - %s - requested deltamode to continue",delta_objects[curr_object_number]->id,(delta_objects[curr_object_number]->name ? delta_objects[curr_object_number]->name : "Unnamed"));
00427
00428 event_driven = false;
00429 }
00430 else if (function_status == SM_DELTA_ITER)
00431 {
00432 gl_verbose("Powerflow object:%d - %s - requested a deltamode reiteration",delta_objects[curr_object_number]->id,(delta_objects[curr_object_number]->name ? delta_objects[curr_object_number]->name : "Unnamed"));
00433
00434 event_driven = false;
00435 delta_iter = true;
00436 }
00437 else if (function_status == SM_ERROR)
00438 {
00439 gl_error("Powerflow object:%d - %s - deltamode function returned an error!",delta_objects[curr_object_number]->id,(delta_objects[curr_object_number]->name ? delta_objects[curr_object_number]->name : "Unnamed"));
00440
00441
00442
00443
00444 error_state = true;
00445 break;
00446 }
00447
00448 }
00449
00450
00451 if ((error_state == true) || (function_status == SM_ERROR))
00452 {
00453
00454 break;
00455 }
00456 else if (pf_result < 0)
00457 {
00458
00459 simple_iter_test++;
00460 }
00461 else
00462 {
00463 break;
00464 }
00465 }
00466
00467
00468 if ((error_state == true) || (function_status == SM_ERROR))
00469 {
00470 return SM_ERROR;
00471 }
00472
00473
00474 if (event_driven == false)
00475 {
00476 if (delta_iter == true)
00477 return SM_DELTA_ITER;
00478 else
00479 return SM_DELTA;
00480 }
00481 else
00482 return SM_EVENT;
00483 }
00484 else
00485 {
00486 return SM_EVENT;
00487 }
00488 }
00489
00490
00491
00492
00493 EXPORT STATUS postupdate(MODULE *module, TIMESTAMP t0, unsigned int64 dt)
00494 {
00495 unsigned int64 seconds_advance, temp_time;
00496 int curr_object_number;
00497 STATUS function_status;
00498
00499 if (enable_subsecond_models == true)
00500 {
00501
00502 deltamode_starttime = TS_NEVER;
00503
00504
00505 deltatimestep_running = -1.0;
00506
00507
00508 seconds_advance = (unsigned int64)(dt/DT_SECOND);
00509
00510
00511 temp_time = dt - ((unsigned int64)(seconds_advance)*DT_SECOND);
00512
00513
00514
00515 deltamode_supersec_endtime = t0 + seconds_advance;
00516
00517
00518 if (temp_time != 0)
00519 seconds_advance++;
00520
00521
00522 deltamode_endtime = t0 + seconds_advance;
00523 deltamode_endtime_dbl = (double)(t0) + ((double)(dt)/double(DT_SECOND));
00524
00525
00526 for (curr_object_number=0; curr_object_number<pwr_object_count; curr_object_number++)
00527 {
00528
00529 if (post_delta_functions[curr_object_number] != NULL)
00530 {
00531
00532 if ((delta_objects[curr_object_number]->in_svc_double <= gl_globaldeltaclock) && (delta_objects[curr_object_number]->out_svc_double >= gl_globaldeltaclock))
00533 {
00534
00535 try {
00536
00537 function_status = ((STATUS (*)(OBJECT *))(*post_delta_functions[curr_object_number]))(delta_objects[curr_object_number]);
00538 }
00539 catch (const char *msg)
00540 {
00541 gl_error("powerflow:postupdate function call: %s", msg);
00542 function_status = FAILED;
00543 }
00544 catch (...)
00545 {
00546 gl_error("powerflow:postupdate function call: unknown exception");
00547 function_status = FAILED;
00548 }
00549 }
00550 else
00551 function_status = SUCCESS;
00552
00553
00554 if (function_status == FAILED)
00555 {
00556 gl_error("Powerflow object:%s - failed post-deltamode update",delta_objects[curr_object_number]->name);
00557
00558
00559
00560
00561 return FAILED;
00562 }
00563
00564 }
00565
00566 }
00567
00568
00569 return SUCCESS;
00570 }
00571 else
00572 {
00573 return SUCCESS;
00574 }
00575 }
00576
00577 CDECL int do_kill()
00578 {
00579
00580 return 0;
00581 }
00582
00583 typedef struct s_pflist {
00584 OBJECT *ptr;
00585 s_pflist *next;
00586 } PFLIST;
00587
00588 EXPORT int check()
00589 {
00590
00591 FINDLIST *list = gl_find_objects(FL_NEW,FT_MODULE,SAME,"powerflow",NULL);
00592 OBJECT *obj=NULL;
00593 int *nodemap,
00594 *linkmap,
00595 *tomap;
00596 int errcount = 0;
00597 int objct = 0;
00598 int queuef = 0, queueb = 0, queuect = 0;
00599 int islandct = 0;
00600
00601 GLOBALVAR *gvroot = NULL;
00602 PFLIST anchor, *tlist = NULL;
00603 link_object **linklist = NULL,
00604 **linkqueue = NULL;
00605
00606 objct = gl_get_object_count();
00607 anchor.ptr = NULL;
00608 anchor.next = NULL;
00609
00610 nodemap = (int *)malloc((size_t)(objct*sizeof(int)));
00611 linkmap = (int *)malloc((size_t)(objct*sizeof(int)));
00612 tomap = (int *)malloc((size_t)(objct*sizeof(int)));
00613 linkqueue = (link_object **)malloc((size_t)(objct*sizeof(link_object *)));
00614 linklist = (link_object **)malloc((size_t)(objct*sizeof(link_object *)));
00615 memset(nodemap, 0, objct*sizeof(int));
00616 memset(linkmap, 0, objct*sizeof(int));
00617 memset(tomap, 0, objct*sizeof(int));
00618 memset(linkqueue, 0, objct*sizeof(link_object *));
00619 memset(linklist, 0, objct*sizeof(link_object *));
00620
00621
00622
00623 while (obj=gl_find_next(list,obj))
00624 {
00625 if (gl_object_isa(obj,"node"))
00626 {
00627
00628 nodemap[obj->id]+=1;
00629
00630 if(obj->parent == NULL){
00631 tlist = (PFLIST *)malloc(sizeof(PFLIST));
00632 tlist->ptr = obj;
00633 tlist->next = anchor.next;
00634 anchor.next = tlist;
00635 tlist = NULL;
00636 }
00637 }
00638 else if (gl_object_isa(obj,"link"))
00639 {
00640 link_object *pLink = OBJECTDATA(obj,link_object);
00641 OBJECT *from = pLink->from;
00642 OBJECT *to = pLink->to;
00643 node *tNode = OBJECTDATA(to, node);
00644 node *fNode = OBJECTDATA(from, node);
00645
00646 tomap[to->id]++;
00647
00648 if (from==NULL){
00649 gl_error("link %s (%s:%d) from object is not specified", pLink->get_name(), pLink->oclass->name, pLink->get_id());
00650 ++errcount;
00651 }
00652 else if (!gl_object_isa(from,"node")){
00653 gl_error("link %s (%s:%d) from object is not a node", pLink->get_name(), pLink->oclass->name, pLink->get_id());
00654 ++errcount;
00655 } else {
00656 linkmap[from->id]++;
00657 }
00658 if (to==NULL){
00659 gl_error("link %s (%s:%d) to object is not specified", pLink->get_name(), pLink->oclass->name, pLink->get_id());
00660 ++errcount;
00661 }
00662 else if (!gl_object_isa(to,"node")){
00663 gl_error("link %s (%s:%d) to object is not a node", pLink->get_name(), pLink->oclass->name, pLink->get_id());
00664 ++errcount;
00665 } else {
00666 linkmap[to->id]++;
00667 }
00668
00669 if((from != NULL) && (to != NULL) && (linkmap[from->id] > 0) && (linkmap[to->id] > 0)){
00670 linklist[queuect] = pLink;
00671 queuect++;
00672 }
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695 }
00696 }
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771 gvroot = gl_global_find("powerflow::rootnode");
00772 if(gvroot != NULL){
00773 PFLIST *front=NULL, *back=NULL, *del=NULL;
00774 OBJECT *_node = gl_get_object((char *)gvroot->prop->addr);
00775 OBJECT *_link = NULL;
00776 int *rankmap = (int *)malloc((size_t)(objct*sizeof(int)));
00777 int bct = 0;
00778 if(_node == NULL){
00779 gl_error("powerflow check(): Unable to do directionality check, root node name not found.");
00780 } else {
00781 gl_testmsg("Powerflow Check ~ Backward Links:");
00782 }
00783 for(int i = 0; i < objct; ++i){
00784 rankmap[i] = objct;
00785 }
00786 rankmap[_node->id] = 0;
00787 front = (PFLIST *)malloc(sizeof(PFLIST));
00788 front->next = NULL;
00789 front->ptr = _node;
00790 back = front;
00791 while(front != NULL){
00792
00793 for(OBJECT *now=gl_find_next(list, NULL); now != NULL; now = gl_find_next(list, now)){
00794 link_object *l;
00795 if(!gl_object_isa(now, "link"))
00796 continue;
00797 l = OBJECTDATA(now, link_object);
00798 if((l->from != front->ptr) && (l->to != front->ptr)){
00799 continue;
00800 } else if(rankmap[l->from->id]<objct && rankmap[l->to->id]<objct){
00801 continue;
00802 } else if(rankmap[l->from->id] < rankmap[l->to->id]){
00803
00804 rankmap[l->to->id] = rankmap[l->from->id]+1;
00805 } else if(rankmap[l->from->id] > rankmap[l->to->id]){
00806
00807 OBJECT *t = l->from;
00808 gl_testmsg("reversed link: %s goes from %s to %s", now->name, l->from->name, l->to->name);
00809 l->from = l->to;
00810 l->to = t;
00811 rankmap[l->to->id] = rankmap[l->from->id]+1;;
00812 }
00813
00814 back->next = (PFLIST *)malloc(sizeof(PFLIST));
00815 back->next->next = NULL;
00816
00817 back = back->next;
00818 back->ptr = l->to;
00819 }
00820 del = front;
00821 front = front->next;
00822 free(del);
00823 }
00824 }
00825
00826 free(nodemap);
00827 free(linkmap);
00828 free(linklist);
00829 free(linkqueue);
00830
00831 return 1;
00832 }