00001
00010 #include <stdlib.h>
00011 #include <stdio.h>
00012 #include <errno.h>
00013 #include <math.h>
00014 #include <iostream>
00015 using namespace std;
00016
00017 #include "line.h"
00018
00019 CLASS* triplex_line::oclass = NULL;
00020 CLASS* triplex_line::pclass = NULL;
00021
00022 triplex_line::triplex_line(MODULE *mod) : line(mod)
00023 {
00024 if(oclass == NULL)
00025 {
00026 pclass = line::oclass;
00027
00028 oclass = gl_register_class(mod,"triplex_line",sizeof(triplex_line),PC_PRETOPDOWN|PC_BOTTOMUP|PC_POSTTOPDOWN|PC_UNSAFE_OVERRIDE_OMIT|PC_AUTOLOCK);
00029 if (oclass==NULL)
00030 throw "unable to register class triplex_line";
00031 else
00032 oclass->trl = TRL_PROVEN;
00033
00034 if(gl_publish_variable(oclass,
00035 PT_INHERIT, "line",
00036 NULL) < 1) GL_THROW("unable to publish properties in %s",__FILE__);
00037
00038
00039 if (gl_publish_function(oclass, "interupdate_pwr_object", (FUNCTIONADDR)interupdate_link)==NULL)
00040 GL_THROW("Unable to publish triplex line deltamode function");
00041 if (gl_publish_function(oclass, "recalc_distribution_line", (FUNCTIONADDR)recalc_triplex_line)==NULL)
00042 GL_THROW("Unable to publish triplex line recalc function");
00043
00044
00045 if (gl_publish_function(oclass, "update_power_pwr_object", (FUNCTIONADDR)updatepowercalc_link)==NULL)
00046 GL_THROW("Unable to publish triplex line external power calculation function");
00047 if (gl_publish_function(oclass, "check_limits_pwr_object", (FUNCTIONADDR)calculate_overlimit_link)==NULL)
00048 GL_THROW("Unable to publish triplex line external power limit calculation function");
00049 }
00050 }
00051
00052 int triplex_line::create(void)
00053 {
00054 int result = line::create();
00055 return result;
00056 }
00057
00058 int triplex_line::isa(char *classname)
00059 {
00060 return strcmp(classname,"triplex_line")==0 || line::isa(classname);
00061 }
00062
00063 int triplex_line::init(OBJECT *parent)
00064 {
00065 double *temp_rating_value = NULL;
00066 double temp_rating_continuous = 10000.0;
00067 double temp_rating_emergency = 20000.0;
00068 char index;
00069 OBJECT *temp_obj;
00070 OBJECT *obj = OBJECTHDR(this);
00071 triplex_line_configuration *temp_config = NULL;
00072
00073 int result = line::init(parent);
00074
00075 if (!has_phase(PHASE_S))
00076 gl_warning("%s (%s:%d) is triplex but doesn't have phases S set", obj->name, obj->oclass->name, obj->id);
00077
00078
00079
00080
00081
00082
00083 phase_conductor_checks();
00084
00085 recalc();
00086
00087
00088 temp_config = OBJECTDATA(configuration,triplex_line_configuration);
00089
00090
00091 if (temp_config->phaseA_conductor != NULL || temp_config->phaseB_conductor != NULL) {
00092 for (index=0; index<2; index++)
00093 {
00094 if (index==0)
00095 {
00096 temp_obj = temp_config->phaseA_conductor;
00097 }
00098 else
00099 {
00100 temp_obj = temp_config->phaseB_conductor;
00101 }
00102
00103
00104 if (temp_obj != NULL)
00105 {
00106
00107 temp_rating_value = get_double(temp_obj,"rating.summer.continuous");
00108
00109
00110 if (temp_rating_value != NULL)
00111 {
00112
00113 if (temp_rating_continuous > *temp_rating_value)
00114 {
00115 temp_rating_continuous = *temp_rating_value;
00116 }
00117 }
00118
00119
00120 temp_rating_value = get_double(temp_obj,"rating.winter.continuous");
00121
00122
00123 if (temp_rating_value != NULL)
00124 {
00125
00126 if (temp_rating_continuous > *temp_rating_value)
00127 {
00128 temp_rating_continuous = *temp_rating_value;
00129 }
00130 }
00131
00132
00133 temp_rating_value = get_double(temp_obj,"rating.summer.emergency");
00134
00135
00136 if (temp_rating_value != NULL)
00137 {
00138
00139 if (temp_rating_emergency > *temp_rating_value)
00140 {
00141 temp_rating_emergency = *temp_rating_value;
00142 }
00143 }
00144
00145
00146 temp_rating_value = get_double(temp_obj,"rating.winter.emergency");
00147
00148
00149 if (temp_rating_value != NULL)
00150 {
00151
00152 if (temp_rating_emergency > *temp_rating_value)
00153 {
00154 temp_rating_emergency = *temp_rating_value;
00155 }
00156 }
00157
00158
00159 link_rating[0][index] = temp_rating_continuous;
00160 link_rating[1][index] = temp_rating_emergency;
00161 }
00162 }
00163 }
00164 else {
00165 temp_obj = configuration;
00166
00167 if (temp_obj != NULL)
00168 {
00169
00170 temp_rating_value = get_double(temp_obj,"rating.summer.continuous");
00171
00172
00173 if (temp_rating_value != NULL)
00174 {
00175
00176 if (temp_rating_continuous > *temp_rating_value)
00177 {
00178 temp_rating_continuous = *temp_rating_value;
00179 }
00180 }
00181
00182
00183 temp_rating_value = get_double(temp_obj,"rating.winter.continuous");
00184
00185
00186 if (temp_rating_value != NULL)
00187 {
00188
00189 if (temp_rating_continuous > *temp_rating_value)
00190 {
00191 temp_rating_continuous = *temp_rating_value;
00192 }
00193 }
00194
00195
00196 temp_rating_value = get_double(temp_obj,"rating.summer.emergency");
00197
00198
00199 if (temp_rating_value != NULL)
00200 {
00201
00202 if (temp_rating_emergency > *temp_rating_value)
00203 {
00204 temp_rating_emergency = *temp_rating_value;
00205 }
00206 }
00207
00208
00209 temp_rating_value = get_double(temp_obj,"rating.winter.emergency");
00210
00211
00212 if (temp_rating_value != NULL)
00213 {
00214
00215 if (temp_rating_emergency > *temp_rating_value)
00216 {
00217 temp_rating_emergency = *temp_rating_value;
00218 }
00219 }
00220
00221
00222 link_rating[0][0] = link_rating[0][1] = link_rating[0][2] = temp_rating_continuous;
00223 link_rating[1][0] = link_rating[1][1] = link_rating[1][2] = temp_rating_emergency;
00224 }
00225 }
00226 return result;
00227 }
00228
00229
00230 void triplex_line::phase_conductor_checks(void)
00231 {
00232
00233 OBJECT *obj = OBJECTHDR(this);
00234 triplex_line_configuration *line_config = OBJECTDATA(configuration,triplex_line_configuration);
00235
00236
00237 if ((line_config->impedance11 == 0.0) && (line_config->impedance22 == 0.0))
00238 {
00239
00240 if (line_config->phaseA_conductor != NULL)
00241 {
00242
00243 if (gl_object_isa(line_config->phaseA_conductor,"triplex_line_conductor","powerflow") != true)
00244 {
00245 GL_THROW("triplex_line:%d - %s - configuration does not use a triplex_line_conductor for at least one phase!",obj->id,(obj->name ? obj->name : "Unnamed"));
00246
00247
00248
00249
00250 }
00251
00252 }
00253 else
00254 {
00255 GL_THROW("triplex_line:%d - %s - configuration doesn't have a valid phase conductor!",obj->id,(obj->name ? obj->name : "Unnamed"));
00256
00257
00258
00259 }
00260
00261 if (line_config->phaseB_conductor != NULL)
00262 {
00263
00264 if (gl_object_isa(line_config->phaseB_conductor,"triplex_line_conductor","powerflow") != true)
00265 {
00266 GL_THROW("triplex_line:%d - %s - configuration does not use a triplex_line_conductor for at least one phase!",obj->id,(obj->name ? obj->name : "Unnamed"));
00267
00268 }
00269
00270 }
00271 else
00272 {
00273 GL_THROW("triplex_line:%d - %s - configuration doesn't have a valid phase conductor!",obj->id,(obj->name ? obj->name : "Unnamed"));
00274
00275 }
00276
00277 if (line_config->phaseC_conductor != NULL)
00278 {
00279
00280 if (gl_object_isa(line_config->phaseC_conductor,"triplex_line_conductor","powerflow") != true)
00281 {
00282 GL_THROW("triplex_line:%d - %s - configuration does not use a triplex_line_conductor for at least one phase!",obj->id,(obj->name ? obj->name : "Unnamed"));
00283
00284 }
00285
00286 }
00287 else
00288 {
00289 GL_THROW("triplex_line:%d - %s - configuration doesn't have a valid phase conductor!",obj->id,(obj->name ? obj->name : "Unnamed"));
00290
00291 }
00292 }
00293
00294 }
00295
00296 void triplex_line::recalc(void)
00297 {
00298 triplex_line_configuration *line_config = OBJECTDATA(configuration,triplex_line_configuration);
00299
00300 OBJECT *obj = OBJECTHDR(this);
00301
00302 if (line_config->impedance11 != 0.0 || line_config->impedance22 != 0.0)
00303 {
00304 gl_warning("Using a 2x2 z-matrix, instead of geometric values, is an under-determined system. Ground and/or neutral currents will be incorrect.");
00305
00306 complex miles = complex(length/5280,0);
00307 if ((solver_method == SM_FBS) || (solver_method == SM_NR))
00308 {
00309 b_mat[0][0] = B_mat[0][0] = line_config->impedance11 * miles;
00310 b_mat[0][1] = B_mat[0][1] = line_config->impedance12 * miles;
00311 b_mat[1][0] = B_mat[1][0] = line_config->impedance21 * miles;
00312 b_mat[1][1] = B_mat[1][1] = line_config->impedance22 * miles;
00313 b_mat[2][0] = B_mat[2][0] = complex(0,0);
00314 b_mat[2][1] = B_mat[2][1] = complex(0,0);
00315 b_mat[2][2] = B_mat[2][2] = complex(0,0);
00316 b_mat[0][2] = B_mat[0][2] = complex(0,0);
00317 b_mat[1][2] = B_mat[1][2] = complex(0,0);
00318
00319 tn[0] = 0;
00320 tn[1] = 0;
00321 tn[2] = 0;
00322 }
00323 else
00324 GL_THROW("Only NR and FBS support z-matrix components.");
00325
00326 }
00327 else
00328 {
00329
00330 double dcond,ins_thick,D12,D13,D23;
00331 double r1,r2,rn,gmr1,gmr2,gmrn;
00332 complex zp11,zp22,zp33,zp12,zp13,zp23;
00333 complex zs[3][3];
00334 double freq_coeff_real, freq_coeff_imag, freq_additive_term;
00335
00336
00337
00338 if (enable_frequency_dependence == true)
00339 {
00340 freq_coeff_real = 0.00158836*current_frequency;
00341 freq_coeff_imag = 0.00202237*current_frequency;
00342 freq_additive_term = log(EARTH_RESISTIVITY/current_frequency)/2.0 + 7.6786;
00343 }
00344 else
00345 {
00346 freq_coeff_real = 0.00158836*nominal_frequency;
00347 freq_coeff_imag = 0.00202237*nominal_frequency;
00348 freq_additive_term = log(EARTH_RESISTIVITY/nominal_frequency)/2.0 + 7.6786;
00349 }
00350
00351
00352 dcond = line_config->diameter;
00353 ins_thick = line_config->ins_thickness;
00354
00355 triplex_line_conductor *l1 = OBJECTDATA(line_config->phaseA_conductor,triplex_line_conductor);
00356 triplex_line_conductor *l2 = OBJECTDATA(line_config->phaseB_conductor,triplex_line_conductor);
00357 triplex_line_conductor *lN = OBJECTDATA(line_config->phaseC_conductor,triplex_line_conductor);
00358
00359 if (l1 == NULL || l2 == NULL || lN == NULL)
00360 {
00361 GL_THROW("triplex_line_configuration:%d (%s) is missing a conductor specification.",line_config->get_id(),line_config->get_name());
00362
00363
00364
00365
00366
00367 }
00368
00369 r1 = l1->resistance;
00370 r2 = l2->resistance;
00371 rn = lN->resistance;
00372 gmr1 = l1->geometric_mean_radius;
00373 gmr2 = l2->geometric_mean_radius;
00374 gmrn = lN->geometric_mean_radius;
00375
00376
00377 D12 = (dcond + 2 * ins_thick)/12;
00378 D13 = (dcond + ins_thick)/12;
00379 D23 = D13;
00380
00381 if (D12 <= 0.0 || D13 <= 0.0)
00382 {
00383 GL_THROW("triplex_line_configuration diameter and/or insulation_thickness are incorrectly set. Please set both of these values to a positive value.");
00384
00385
00386
00387
00388
00389
00390 }
00391
00392 zp11 = complex(r1,0) + freq_coeff_real + complex(0.0,freq_coeff_imag) * (log(1/gmr1) + freq_additive_term);
00393 zp22 = complex(r2,0) + freq_coeff_real + complex(0.0,freq_coeff_imag) * (log(1/gmr2) + freq_additive_term);
00394 zp33 = complex(rn,0) + freq_coeff_real + complex(0.0,freq_coeff_imag) * (log(1/gmrn) + freq_additive_term);
00395 zp12 = complex(freq_coeff_real,0.0) + complex(0.0,freq_coeff_imag) * (log(1/D12) + freq_additive_term);
00396 zp13 = complex(freq_coeff_real,0.0) + complex(0.0,freq_coeff_imag) * (log(1/D13) + freq_additive_term);
00397 zp23 = complex(freq_coeff_real,0.0) + complex(0.0,freq_coeff_imag) * (log(1/D23) + freq_additive_term);
00398
00399 if ((solver_method==SM_FBS) || (solver_method==SM_NR))
00400 {
00401 zs[0][0] = zp11-((zp13*zp13)/zp33);
00402 zs[0][1] = zp12-((zp13*zp23)/zp33);
00403 zs[1][0] = -(zp12-((zp13*zp23)/zp33));
00404 zs[1][1] = -(zp22-((zp23*zp23)/zp33));
00405 zs[0][2] = complex(0,0);
00406 zs[1][2] = complex(0,0);
00407 zs[2][2] = complex(0,0);
00408 zs[2][1] = complex(0,0);
00409 zs[2][0] = complex(0,0);
00410 }
00411 else
00412 {
00413 GL_THROW("triplex_line:unsupported solver method");
00414
00415
00416
00417
00418
00419 }
00420
00421
00422
00423 tn[0] = -zp13/zp33;
00424 tn[1] = -zp23/zp33;
00425 tn[2] = 0;
00426
00427 multiply(length/5280.0,zs,b_mat);
00428 multiply(length/5280.0,zs,B_mat);
00429 }
00430
00431
00432 bool neg_res = false;
00433 for (int n = 0; n < 2; n++){
00434 if(b_mat[0][n].Re() < 0.0){
00435 neg_res = true;
00436 }
00437 }
00438
00439 if(neg_res == true){
00440 gl_warning("INIT: triplex_line:%s has a negative resistance in it's impedance matrix. This will result in unusual behavior. Please check the line's geometry and cable parameters.", obj->name);
00441
00442
00443
00444
00445
00446 }
00447
00448
00449 a_mat[0][0] = complex(1,0);
00450 a_mat[0][1] = complex(0,0);
00451 a_mat[0][2] = complex(0,0);
00452 a_mat[1][0] = complex(0,0);
00453 a_mat[1][1] = complex(1,0);
00454 a_mat[1][2] = complex(0,0);
00455 a_mat[2][0] = complex(0,0);
00456 a_mat[2][1] = complex(0,0);
00457 a_mat[2][2] = complex(1,0);
00458
00459 c_mat[0][0] = complex(0,0);
00460 c_mat[0][1] = complex(0,0);
00461 c_mat[0][2] = complex(0,0);
00462 c_mat[1][0] = complex(0,0);
00463 c_mat[1][1] = complex(0,0);
00464 c_mat[1][2] = complex(0,0);
00465 c_mat[2][0] = complex(0,0);
00466 c_mat[2][1] = complex(0,0);
00467 c_mat[2][2] = complex(0,0);
00468
00469 d_mat[0][0] = complex(1,0);
00470 d_mat[0][1] = complex(0,0);
00471 d_mat[0][2] = complex(0,0);
00472 d_mat[1][0] = complex(0,0);
00473 d_mat[1][1] = complex(1,0);
00474 d_mat[1][2] = complex(0,0);
00475 d_mat[2][0] = complex(0,0);
00476 d_mat[2][1] = complex(0,0);
00477 d_mat[2][2] = complex(1,0);
00478
00479 A_mat[0][0] = complex(1,0);
00480 A_mat[0][1] = complex(0,0);
00481 A_mat[0][2] = complex(0,0);
00482 A_mat[1][0] = complex(0,0);
00483 A_mat[1][1] = complex(1,0);
00484 A_mat[1][2] = complex(0,0);
00485 A_mat[2][0] = complex(0,0);
00486 A_mat[2][1] = complex(0,0);
00487 A_mat[2][2] = complex(1,0);
00488
00489
00490 #ifdef _TESTING
00491 if (show_matrix_values)
00492 {
00493 gl_testmsg("triplex_line: a matrix");
00494 print_matrix(a_mat);
00495
00496 gl_testmsg("triplex_line: A matrix");
00497 print_matrix(A_mat);
00498
00499 gl_testmsg("triplex_line: b matrix");
00500 print_matrix(b_mat);
00501
00502 gl_testmsg("triplex_line: B matrix");
00503 print_matrix(B_mat);
00504
00505 gl_testmsg("triplex_line: c matrix");
00506 print_matrix(c_mat);
00507
00508 gl_testmsg("triplex_line: d matrix");
00509 print_matrix(d_mat);
00510 }
00511 #endif
00512 }
00513
00515
00517
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539 EXPORT int create_triplex_line(OBJECT **obj, OBJECT *parent)
00540 {
00541 try
00542 {
00543 *obj = gl_create_object(triplex_line::oclass);
00544 if (*obj!=NULL)
00545 {
00546 triplex_line *my = OBJECTDATA(*obj,triplex_line);
00547 gl_set_parent(*obj,parent);
00548 return my->create();
00549 }
00550 else
00551 return 0;
00552 }
00553 CREATE_CATCHALL(triplex_line);
00554 }
00555
00556 EXPORT TIMESTAMP sync_triplex_line(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00557 {
00558 try {
00559 triplex_line *pObj = OBJECTDATA(obj,triplex_line);
00560 TIMESTAMP t1 = TS_NEVER;
00561 switch (pass) {
00562 case PC_PRETOPDOWN:
00563 return pObj->presync(t0);
00564 case PC_BOTTOMUP:
00565 return pObj->sync(t0);
00566 case PC_POSTTOPDOWN:
00567 t1 = pObj->postsync(t0);
00568 obj->clock = t0;
00569 return t1;
00570 default:
00571 throw "invalid pass request";
00572 }
00573 }
00574 SYNC_CATCHALL(triplex_line);
00575 }
00576
00577 EXPORT int init_triplex_line(OBJECT *obj)
00578 {
00579 try {
00580 triplex_line *my = OBJECTDATA(obj,triplex_line);
00581 return my->init(obj->parent);
00582 }
00583 INIT_CATCHALL(triplex_line);
00584 }
00585
00586 EXPORT int isa_triplex_line(OBJECT *obj, char *classname)
00587 {
00588 return OBJECTDATA(obj,triplex_line)->isa(classname);
00589 }
00590
00591 EXPORT int recalc_triplex_line(OBJECT *obj)
00592 {
00593 OBJECTDATA(obj,triplex_line)->recalc();
00594 return 1;
00595 }
00596