blob: 23a0a548eb31a092d8f764b0ba1471a3580978f5 [file] [log] [blame]
/* For copyright information, see olden_v1.0/COPYRIGHT */
/* compute.c
*
* By: Martin C. Carlisle
* 6/15/94
*
* Implements computation phase of the Power Pricing problem
* based on code by: Steve Lumetta, Sherry Li, and Ismail Khalil
* University of California at Berkeley
*
*/
#include "power.h"
/*----------------------------------------------------------------------*/
/* Leaf optimization 'global' variables */
static double P=1.0;
static double Q=1.0;
/*----------------------------------------------------------------------*/
/* Leaf optimization procedures */
void optimize_node (double pi_R, double pi_I);
double find_g ();
double find_h ();
double find_gradient_f (double pi_R, double pi_I, double* gradient);
double find_gradient_g (double* gradient);
double find_gradient_h (double* gradient);
void find_dd_grad_f (double pi_R, double pi_I, double* dd_grad);
double make_orthogonal (double* v_mod, double* v_static);
void Compute_Tree(Root r) {
int i;
Lateral l;
Demand a;
Demand tmp;
double theta_R,theta_I;
tmp.P = 0.0;
tmp.Q = 0.0;
for (i=0; i<NUM_FEEDERS; i++) {
l = r->feeders[i];
theta_R = r->theta_R;
theta_I = r->theta_I;
a = Compute_Lateral(l,theta_R,theta_I,theta_R,theta_I);
tmp.P += a.P;
tmp.Q += a.Q;
}
r->D.P = tmp.P;
r->D.Q = tmp.Q;
}
Demand Compute_Lateral(Lateral l, double theta_R, double theta_I,
double pi_R, double pi_I) {
Demand a1;
Demand a2;
double new_pi_R, new_pi_I;
double a,b,c,root;
Lateral next;
Branch br;
new_pi_R = pi_R + l->alpha*(theta_R+(theta_I*l->X)/l->R);
new_pi_I = pi_I + l->beta*(theta_I+(theta_R*l->R)/l->X);
next = l->next_lateral;
if (next != NULL)
a1 = Compute_Lateral(next,theta_R,theta_I,new_pi_R,new_pi_I);
br = l->branch;
a2 = Compute_Branch(br,theta_R,theta_I,new_pi_R,new_pi_I);
if (next != NULL) {
l->D.P = a1.P + a2.P;
l->D.Q = a1.Q + a2.Q;
} else {
l->D.P = a2.P;
l->D.Q = a2.Q;
}
/* compute P,Q */
a = l->R*l->R + l->X*l->X;
b = 2*l->R*l->X*l->D.Q - 2*l->X*l->X*l->D.P - l->R;
c = l->R*l->D.Q - l->X*l->D.P;
c = c*c + l->R*l->D.P;
root = (-b-sqrt(b*b-4*a*c))/(2*a);
l->D.Q = l->D.Q + ((root-l->D.P)*l->X)/l->R;
l->D.P = root;
/* compute alpha, beta */
a = 2*l->R*l->D.P;
b = 2*l->X*l->D.Q;
l->alpha = a/(1-a-b);
l->beta = b/(1-a-b);
return l->D;
}
Demand Compute_Branch(Branch br, double theta_R, double theta_I,
double pi_R, double pi_I) {
Demand a2,tmp;
double new_pi_R, new_pi_I;
double a,b,c,root;
Leaf l;
Branch next;
int i;
Demand a1;
new_pi_R = pi_R + br->alpha*(theta_R+(theta_I*br->X)/br->R);
new_pi_I = pi_I + br->beta*(theta_I+(theta_R*br->R)/br->X);
next = br->next_branch;
if (next != NULL) {
a1 = Compute_Branch(next,theta_R,theta_I,new_pi_R,new_pi_I);
}
/* Initialize tmp */
tmp.P = 0.0; tmp.Q = 0.0;
for (i=0; i<LEAVES_PER_BRANCH; i++) {
l = br->leaves[i];
a2 = Compute_Leaf(l,new_pi_R,new_pi_I);
tmp.P += a2.P;
tmp.Q += a2.Q;
}
if (next != NULL) {
br->D.P = a1.P + tmp.P;
br->D.Q = a1.Q + tmp.Q;
} else {
br->D.P = tmp.P;
br->D.Q = tmp.Q;
}
/* compute P,Q */
a = br->R*br->R + br->X*br->X;
b = 2*br->R*br->X*br->D.Q - 2*br->X*br->X*br->D.P - br->R;
c = br->R*br->D.Q - br->X*br->D.P;
c = c*c + br->R*br->D.P;
root = (-b-sqrt(b*b-4*a*c))/(2*a);
br->D.Q = br->D.Q + ((root-br->D.P)*br->X)/br->R;
br->D.P = root;
/* compute alpha, beta */
a = 2*br->R*br->D.P;
b = 2*br->X*br->D.Q;
br->alpha = a/(1-a-b);
br->beta = b/(1-a-b);
return br->D;
}
Demand Compute_Leaf(Leaf l, double pi_R, double pi_I) {
P = l->D.P;
Q = l->D.Q;
optimize_node(pi_R,pi_I);
if (P<0.0) {
P = 0.0;
Q = 0.0;
}
l->D.P = P;
l->D.Q = Q;
return l->D;
}
/*----------------------------------------------------------------------*/
void optimize_node (double pi_R, double pi_I)
{
double g;
double h;
double grad_f[2];
double grad_g[2];
double grad_h[2];
double dd_grad_f[2];
double magnitude;
int i;
double total;
double max_dist;
do {
/* Move onto h=0 line */
h=find_h ();
if (fabs (h)>H_EPSILON) {
magnitude=find_gradient_h (grad_h);
total=h/magnitude;
P-=total*grad_h[0];
Q-=total*grad_h[1];
}
/* Check that g is still valid */
g=find_g ();
if (g>G_EPSILON) {
magnitude=find_gradient_g (grad_g);
find_gradient_h (grad_h);
magnitude*=make_orthogonal (grad_g,grad_h);
total=g/magnitude;
P-=total*grad_g[0];
Q-=total*grad_g[1];
}
/* Maximize benefit */
magnitude=find_gradient_f (pi_R,pi_I,grad_f);
find_dd_grad_f (pi_R,pi_I,dd_grad_f);
total=0.0;
for (i=0; i<2; i++)
total+=grad_f[i]*dd_grad_f[i];
magnitude/=fabs (total);
find_gradient_h (grad_h);
magnitude*=make_orthogonal (grad_f,grad_h);
find_gradient_g (grad_g);
total=0.0;
for (i=0; i<2; i++)
total+=grad_f[i]*grad_g[i];
if (total>0) {
max_dist=-find_g ()/total;
if (magnitude>max_dist)
magnitude=max_dist;
}
P+=magnitude*grad_f[0];
Q+=magnitude*grad_f[1];
h=find_h ();
g=find_g ();
find_gradient_f (pi_R,pi_I,grad_f);
find_gradient_h (grad_h);
} while (fabs (h)>H_EPSILON || g>G_EPSILON ||
(fabs (g)>G_EPSILON &&
fabs (grad_f[0]*grad_h[1]-grad_f[1]*grad_h[0])>F_EPSILON));
}
double find_g ()
{
return (P*P+Q*Q-0.8);
}
double find_h ()
{
return (P-5*Q);
}
double find_gradient_f (double pi_R, double pi_I, double* gradient)
{
int i;
double magnitude=0.0;
gradient[0]=1/(1+P)-pi_R;
gradient[1]=1/(1+Q)-pi_I;
for (i=0; i<2; i++)
magnitude+=gradient[i]*gradient[i];
magnitude=sqrt (magnitude);
for (i=0; i<2; i++)
gradient[i]/=magnitude;
return magnitude;
}
double find_gradient_g (double* gradient)
{
int i;
double magnitude=0.0;
gradient[0]=2*P;
gradient[1]=2*Q;
for (i=0; i<2; i++)
magnitude+=gradient[i]*gradient[i];
magnitude=sqrt (magnitude);
for (i=0; i<2; i++)
gradient[i]/=magnitude;
return magnitude;
}
double find_gradient_h (double* gradient)
{
int i;
double magnitude=0.0;
gradient[0]=1.0;
gradient[1]=-5.0;
for (i=0; i<2; i++)
magnitude+=gradient[i]*gradient[i];
magnitude=sqrt (magnitude);
for (i=0; i<2; i++)
gradient[i]/=magnitude;
return magnitude;
}
void find_dd_grad_f (double pi_R, double pi_I, double* dd_grad)
{
double P_plus_1_inv=1/(P+1);
double Q_plus_1_inv=1/(Q+1);
double P_grad_term=P_plus_1_inv-pi_R;
double Q_grad_term=Q_plus_1_inv-pi_I;
double grad_mag;
grad_mag=sqrt (P_grad_term*P_grad_term+Q_grad_term*Q_grad_term);
dd_grad[0]=-P_plus_1_inv*P_plus_1_inv*P_grad_term/grad_mag;
dd_grad[1]=-Q_plus_1_inv*Q_plus_1_inv*Q_grad_term/grad_mag;
}
double make_orthogonal (double* v_mod, double* v_static)
{
int i;
double total=0.0;
double length=0.0;
for (i=0; i<2; i++)
total+=v_mod[i]*v_static[i];
for (i=0; i<2; i++) {
v_mod[i]-=total*v_static[i];
length+=v_mod[i]*v_mod[i];
}
length=sqrt (length);
for (i=0; i<2; i++)
v_mod[i]/=length;
if (1-total*total<0) /* Roundoff error--vectors are parallel */
return 0;
return sqrt (1-total*total);
}
/*----------------------------------------------------------------------*/