Example #1
0
// wake modeling - Park model used to calculate the change in wind speed due to wake effects of upwind turbine
double wind_power_calculator::delta_V_Park( double Uo, double Ui, double dDistCrossWind, double dDistDownWind, double dRadiusUpstream, double dRadiusDownstream, double dThrustCoeff)
{	// returns the wind speed due to wake effects from upwind turbine
	
	// bound the coeff of thrust
	double Ct = max_of(min_of(0.999,dThrustCoeff),m_dMinThrustCoeff);

	double k=0;
	if (IMITATE_OPENWIND)
		k = 0.5/log(m_dHubHeight/0.03);
	else
		k = m_dWakeDecayCoefficient;


	double dRadiusOfWake = dRadiusUpstream + (k * dDistDownWind); // radius of circle formed by wake from upwind rotor
	double dAreaOverlap = circle_overlap(dDistCrossWind, dRadiusDownstream, dRadiusOfWake);

	// if there is no overlap, no impact on wind speed
	if (dAreaOverlap <= 0.0) return Uo;

	double dDef = (1 - sqrt(1-Ct)) * pow(dRadiusUpstream/dRadiusOfWake,2) * (dAreaOverlap/(physics::PI*dRadiusDownstream*dRadiusDownstream));

	if (IMITATE_OPENWIND)
		return Uo * (1.0 - (Uo/Ui)*dDef);
	else
		return Ui * (1.0 - dDef);

//	double Uw = Ui*(1.0-        ((1.0-sqrt(1.0-Ct))*sqr(diamUp/(diamUp+2.0*k*(ptDown.x-ptUp.x)))) *f);  // classic park
//	double Uw = Uo*(1.0-((Uo/Ui)*(1.0-sqrt(1.0-Ct))*sqr(diamUp/(diamUp+2.0*k*(ptDown.x-ptUp.x)))) *f); // my park - same near wake but tends back to free stream
//	double Uw = Uo*(1.0-        ((1.0-sqrt(1.0-Ct))*sqr(diamUp/(diamUp+2.0*k*(ptDown.x-ptUp.x)))) *f); 
}
Example #2
0
void wind_power_calculator::wake_calculations_Park(/*INPUTS */ double air_density, double aDistanceDownwind[], double aDistanceCrosswind[],
												   /*OUTPUTS*/ double Power[], double Thrust[], double Eff[], double adWindSpeed[] )
{
	double dTurbineRadius = m_dRotorDiameter/2;

	for (size_t i=1; i<m_iNumberOfTurbinesInFarm; i++) // downwind turbines, i=0 has already been done
	{
		double dNewSpeed = adWindSpeed[0];
		for (size_t j=0; j<i; j++) // upwind turbines
		{
			// distance downwind = distance from turbine i to turbine j along axis of wind direction
			double fDistanceDownwindMeters = dTurbineRadius*fabs(aDistanceDownwind[i] - aDistanceDownwind[j]); 

			// separation crosswind between turbine i and turbine j
			double fDistanceCrosswindMeters = dTurbineRadius*fabs(aDistanceCrosswind[i] - aDistanceCrosswind[j]);
				
			// Calculate the wind speed reduction at turbine i, due turbine [j]
			// keep this new speed if it's less than any other calculated speed
			dNewSpeed = min_of(dNewSpeed, delta_V_Park(adWindSpeed[0], adWindSpeed[j], fDistanceCrosswindMeters, fDistanceDownwindMeters, dTurbineRadius, dTurbineRadius, Thrust[j]) );

		}
		// The Park model uses the minimum speed found from all the upwind turbine impacts
		// It ignores all other deficits
		adWindSpeed[i] = dNewSpeed;
		turbine_power(adWindSpeed[i], air_density,  &Power[i], &Thrust[i]);

		if (Power[0] < 0.0)
			Eff[i] = 0.0;
		else
			Eff[i] = 100.0*(Power[i]+0.0001)/(Power[0]+0.0001);
	} 
}
float fuzzy_system(float inputs[], fuzzy_system_rec fz) {
	int i, j;
	short variable_index, fuzzy_set;
	float sum1 = 0.0, sum2 = 0.0, weight;
	float m_values[MAX_NO_OF_INPUTS];

	for (i = 0; i < fz.no_of_rules; i++) {
		for (j = 0; j < fz.no_of_inputs; j++) {
			variable_index = fz.rules[i].inp_index[j];
			fuzzy_set = fz.rules[i].inp_fuzzy_set[j];
			m_values[j] = trapz(inputs[variable_index],
				fz.inp_mem_fns[variable_index][fuzzy_set]);
		} /* end j  */
		weight = min_of(m_values, fz.no_of_inputs);
		sum1 += weight * fz.output_values[fz.rules[i].out_fuzzy_set];
		sum2 += weight;
	} /* end i  */

	if (fabs(sum2) < TOO_SMALL) {
		cout << "\r\nFLPRCS Error: Sum2 in fuzzy_system is 0.  Press key: " << endl;
		//~ getch();
		exit(1);
		return 0.0;
	}

	return (sum1 / sum2);
}  /* end fuzzy_system  */
Example #4
0
void wind_power_calculator::calc_EV_vm_for_turbine(double U, double Ii, double Ct, double , VMLN& vmln)
{
	// Ii is incident TI in percent at upstream turbine
	Ct = max_of(min_of(0.999,Ct), m_dMinThrustCoeff);
	
	// these formulae can be found in Wind Energy Handbook by Bossanyi, pages 36 and 37
	// although there are errors in that book so it has been supplemented from the original work  
	// by Vermeulen, P.E.J.  TNO - report
	double dr_dx;
	
	double m = 1.0/sqrt(1.0-Ct);
	
	double r0 = 0.5*m_dRotorDiameter*sqrt((m+1.0)/2.0);
	
	double t1 = sqrt(0.214+0.144*m);
	double t2 = sqrt(0.134+0.124*m);
	
	double n = (t1*(1.0-t2))/((1.0-t1)*t2);
	
	double dr_dx_A = Ii < 2.0 ? 0.05*Ii : 0.025*Ii + 0.05; // from original TNO report
	
	double dr_dx_M = ((1.0-m)*sqrt(1.49+m))/((1.0+m)*9.76);

	double dr_dx_L = 0.012*(double)m_iNumberOfBlades * tip_speed_ratio(U);
		
	dr_dx = sqrt(dr_dx_A*dr_dx_A + dr_dx_M*dr_dx_M + dr_dx_L*dr_dx_L);
	
	/////////////////////////////////////////////////////////
	
	vmln.m = m;
	
	vmln.diam = m_dRotorDiameter;
	
	vmln.Xh = r0/(dr_dx); // end of region 1
	
	vmln.Xn = n*vmln.Xh; // end of region 2
	
	return;	////////////////////////////////////////////////////////////// end here for now - save processing

	//	this part not fully used just now but its coded and it could be used in future enhancements
	//
	//vmln.Xf = 5.0*vmln.Xn; // end of region 3
	//
	//vmln.Ro = r0;
	//
	//double c1 = 0.416 + 0.134*m;
	//double c2 = 0.021*(1.0+0.8*m-0.45*m*m);
	//
	//vmln.Rh = r0*((-c1+sqrt(c1*c1+4.0*c2))/(2.0*c2)); // A
	//
	//vmln.Rn = r0 + n*(vmln.Rh-r0);
	//
	//vmln.dUc_Uinf_Xn = ((m-1.0)/m)*((-0.258*m + sqrt(0.066564*m*m + 0.536*(1.0-m)*(vmln.Ro/vmln.Rn)*(vmln.Ro/vmln.Rn)))/(0.268*(1.0-m))); // A-16
	//
	//vmln.Rf = m_dRotorDiameter*(sqrt(m*m-1.0)/0.882*m) * (1.0/sqrt(0.353*vmln.dUc_Uinf_Xn - 0.0245*vmln.dUc_Uinf_Xn*vmln.dUc_Uinf_Xn));
}
Example #5
0
double wind_power_calculator::simple_intersect(double dist_center_to_center, double dRadiusTurbine, double dRadiusWake)
{	// returns the fraction of overlap, NOT an area
	if (dist_center_to_center<0 || dRadiusTurbine<0 || dRadiusWake<0)
		return 0;

	if (dist_center_to_center > dRadiusTurbine+dRadiusWake)
		return 0;

	if (dRadiusWake >= dist_center_to_center + dRadiusTurbine)
		return 1; // turbine completely inside wake

	return min_of(1.0,max_of(0.0,(dRadiusTurbine+dRadiusWake-dist_center_to_center)/(2*dRadiusTurbine)));
}
Example #6
0
// Tests the bit algorithms
void test_bit_algo()
{
      // Test sign of
      assert(sign_of_int(-10) == -1 && sign_of_int(10) == 0);
      assert(sign_of_int_ec(-10) == -1 && sign_of_int_ec(10) == 0);
      // Test opposite_sign
      assert(opposite_sign(1,-1) == 1 && opposite_sign(-1,-1) == 0 &&
            opposite_sign(1,1) == 0);
      // Test absolute number
      assert(abs_of_int(-10) == abs_of_int(10));
      // Test min of
      assert(min_of(1,2) == 1 && min_of(2,1) == 1);
      // Test min of 3
      assert(min_of3(1,2,3) == 1 && min_of3(3,2,1) == 1);
      // Test is power of 2
      assert(is_power_of2(1024) && !is_power_of2(1023));
      // Test next power of two
      assert(next_power_of2(2000) == 2048 && next_power_of2(2049) == 4096);
      // Test swap bits
      assert(swap_bits(42) == 21 && swap_bits(21) == 10);
      // Test count bits
}
hsv_color rgb_to_hsv(rgb_color pRgbColor)
{
	int delta;
	int min;
	hsv_color hsvColor;
	
	hsvColor.A = pRgbColor.A;
	
	min = min_of(pRgbColor.R, min_of(pRgbColor.G, pRgbColor.B));
	hsvColor.V = max_of(pRgbColor.R, max_of(pRgbColor.G, pRgbColor.B));
	delta = hsvColor.V - min;
	
	if (hsvColor.V == 0)
		hsvColor.S = 0;
	else hsvColor.S = (delta * 255) / hsvColor.V;
	
	if (hsvColor.S == 0)
		hsvColor.H = 0;
	else
	{
		if (pRgbColor.R == hsvColor.V)
		{
			hsvColor.H = ((pRgbColor.G - pRgbColor.B) * 60) / delta;
		}
		else if (pRgbColor.G == hsvColor.V)
		{
			hsvColor.H = 120 + ((pRgbColor.B - pRgbColor.R) * 60) / delta;
		}
		else if (pRgbColor.B == hsvColor.V)
		{
			hsvColor.H = 240 + ((pRgbColor.R - pRgbColor.G) * 60) / delta;
		}
	}
	if (hsvColor.H < 0)
		hsvColor.H = hsvColor.H + 360;
	
	return hsvColor;
}
Example #8
0
 void EdgeDetector::normalize(xpatch &xp, lockable & ) throw()
 {
     assert(Gmax>0);
     pixmap<float> &G   = *this;
     const float    fac = 1.0f/Gmax;
     for(unit_t y=xp.upper.y;y>=xp.lower.y;--y)
     {
         pixmap<float>::row &Gy = G[y];
         for(unit_t x=xp.upper.x;x>=xp.lower.x;--x)
         {
             Gy[x] = min_of(1.0f,fac*Gy[x]);
         }
     }
 }
Example #9
0
Records:: Records(const Real          scale,
                  const Matrix<Real> &neurodata,
                  const size_t        num_neurons) :
Object(scale),
RecordsBase( __get_num_trials(neurodata.rows,num_neurons), num_neurons ),
trials(rows),
neurones(cols),
maxCount(0),
tauMin(0),
tauMax(0)
{
    build_with<Train*>(NULL);
    RecordsBase &self = *this;
    size_t iTrain = 0;
    size_t count  = 0;
    Unit   tMin   = 0;
    Unit   tMax   = 0;
    bool   init   = true;
    for(size_t iN = 0; iN < neurones; ++iN )
    {
        for(size_t iT = 0; iT < trials; ++iT )
        {
            Train *tr = new Train(scale,neurodata,iTrain);
            self[iT][iN].reset(tr);
            const size_t trSize = tr->size();
            if(init)
            {
                if(trSize>0)
                {
                    tMin = (*tr)[0];
                    tMax = (*tr)[trSize-1];
                    init = false;
                }
            }
            else
            {
                if(trSize>0)
                {
                    tMin = min_of(tMin,(*tr)[0]);
                    tMax = max_of(tMax,(*tr)[trSize-1]);
                }
            }
            ++iTrain;
            if(trSize>count) count = trSize;
        }
    }
    (size_t&)maxCount = count;
    (size_t&)tauMin   = tMin;
    (size_t&)tauMax   = tMax;
}
/*
 * ******************************************* 
 *  Function: 
 *     send_connect_ack 
 *
 *  Description: 
 *     Sends connection acknoledgment packet 
 *
 *  Parameters: 
 *      dest_id  - destination 
 *
 *      req_mtu - requested mtu   
 *
 *      cid     - conncection id 
 *
 *
 *      sid     - service id 
 *
 *
 *
 * ******************************************* 
 */
void send_connect_ack( int dest_id  , int req_mtu , int cid , int sid  )
{
    char buffer[DUMMY_SIZE]; 
    int my_mtu; 
    int ctrl_cmd  = CONTROL_CONNECT_ACK; 
    void *buff  = (void *)buffer; 
    my_mtu = min_of (  cfg_items[__current_node-1].mtu_size - 3 * TRASPORT_LAYER_SIZE , req_mtu ) ; 
    buff = expand_packet(&buff,DUMMY_SIZE , TRASPORT_LAYER_SIZE ); 
    pack_into_packet(buff , CONTROL_INFO_OFFSET ,&ctrl_cmd, CONTROL_INFO_SIZE);
    pack_into_packet(buff , WIND_OFFSET ,&my_mtu , WIND_SIZE);    
    set_packet_cid(buff,cid);   
    pack_into_packet(buff , SENDER_ID_OFFSET , &sid , SENDER_ID_SIZE); 
    handle_packet_transport(buff , DUMMY_SIZE + TRASPORT_LAYER_SIZE ,dest_id); 
    



}
Example #11
0
double wind_power_calculator::vel_delta_PQ( double fRadiiCrosswind, double fAxialDistInRadii, double fThrustCoeff, double *fNewTurbulenceIntensity)
{
	// Velocity deficit calculation for Pat Quinlan wake model.
	// This function calculates the velcity deficit (% reduction in wind speed) and the turbulence intensity (TI) due to an upwind turbine.

	// Note that the calculation of fNewTurbulenceIntensity does NOT include fRadiiCrosswind - so it's only influenced by how far upwind the other turbine is,
	// EVEN IF IT'S 19 ROTOR RADII TO THE SIDE!!!

	if (fRadiiCrosswind > 20.0 || *fNewTurbulenceIntensity <= 0.0 || fAxialDistInRadii <= 0.0 || fThrustCoeff <= 0.0)
		return 0.0;

	double fAddedTurbulence = (fThrustCoeff/7.0)*(1.0-(2.0/5.0)*log(2.0*fAxialDistInRadii)); // NOTE that this equation does not account for how far over the turbine is!!
	*fNewTurbulenceIntensity = sqrt( pow(fAddedTurbulence,2.0) + pow(*fNewTurbulenceIntensity,2.0) );

	double AA = pow(*fNewTurbulenceIntensity,2.0) * pow(fAxialDistInRadii,2.0);
	double fExp = max_of( -99.0, (-pow(fRadiiCrosswind,2.0)/(2.0*AA)) );
	double dVelocityDeficit = (fThrustCoeff/(4.0*AA))*exp(fExp);
	return max_of(min_of(dVelocityDeficit, 1.0), 0.0); // limit result from zero to one
}
Example #12
0
bool wind_power_calculator::fill_turbine_wake_arrays_for_EV(int iTurbineNumber, double dAmbientVelocity, double dVelocityAtTurbine, double dPower, double dThrustCoeff, double dTurbulenceIntensity, double dMetersToFurthestDownwindTurbine)
{
	if(dPower <= 0.0)
		return true; // no wake effect - wind speed is below cut-in, or above cut-out

	if (dThrustCoeff<=0.0)
		return true; // i.e. there is no wake (both arrays were initialized with zeros, so they just stay that way)

	dThrustCoeff = max_of(min_of(0.999,dThrustCoeff), m_dMinThrustCoeff);
	
	dTurbulenceIntensity = min_of(dTurbulenceIntensity, 50.0); // to avoid turbines with high TIs having no wake
	
	double Dm, Dmi;
	
	// Von Karman constant
	const double K = 0.4; 										// Ainslee 1988 (notation)
	
	// dimensionless constant K1
	const double K1 = 0.015;									// Ainslee 1988 (page 217: input parameters)
	
	double F, x = MIN_DIAM_EV; // actual distance in rotor diameters

	// Filter function F
	if(x>=5.5 || !m_bFilter)
		F=1.0;
	else
		x < 4.5 ? F=0.65-pow(-(x - 4.5)/23.32,1.0/3.0) : F=0.65+pow((x - 4.5)/23.32,1.0/3.0);
		
	// calculate the ambient eddy viscocity term
	double Km = F*K*K*dTurbulenceIntensity/100.0;  // also known as the ambient eddy viscosity???
	
	// calculate the initial centreline velocity deficit at 2 rotor diameters downstream
	Dm = Dmi = max_of(0.0, dThrustCoeff - 0.05 - ((16.0*dThrustCoeff - 0.5)*dTurbulenceIntensity/1000.0));		// Ainslee 1988 (5)
	
	if(Dmi<=0.0)
		return true;
	
	double Uc = dVelocityAtTurbine-Dmi*dVelocityAtTurbine; // assuming Uc is the initial centreline velocity at 2 diameters downstream
	
	// now make Dmi relative to the freestream
	Dm = Dmi = (dAmbientVelocity-Uc)/dAmbientVelocity;

	// calculate the initial (2D) wake width (1.89 x the half-width of the guassian profile
	double Bw = sqrt(3.56*dThrustCoeff/(8.0*Dmi*(1.0 - 0.5*Dmi)));			// Ainslee 1988 (6)
	// Dmi must be as a fraction of dAmbientVelocity or the above line would cause an error sqrt(-ve)
	// Bw must be in rotor diameters.
	
	// the eddy viscosity is then
	double E = F*K1*Bw*Dm*EV_SCALE+Km;  

	// Start major departure from Eddy-Viscosity solution using Crank-Nicolson
	std::vector<double> m_d2U(matEVWakeDeficits.ncols());
	m_d2U[0] = EV_SCALE*(1.0-Dmi);
	
	matEVWakeDeficits.at(iTurbineNumber,0) = Dmi;
	matEVWakeWidths.at(iTurbineNumber,0) = Bw;

	// j = 0 is initial conditions, j = 1 is the first step into the unknown
//	int iterations = 5;
	for(size_t j=0; j<matEVWakeDeficits.ncols()-1; j++)
	{
		x = MIN_DIAM_EV + (double)(j) * m_dAxialResolution;	
		
		// deficit = Dm at the beginning of each timestep

		if(x>=5.5 || !m_bFilter)
			F=1.0;
		else
			x < 4.5 ? F=0.65-pow(-(x - 4.5)/23.32,1.0/3.0) : F=0.65+pow((x - 4.5)/23.32,1.0/3.0); // for some reason pow() does not deal with -ve numbers even though excel does

		Km = F*K*K*dTurbulenceIntensity/100.0;
		
		// first calculate the eddy viscosity
		E = F*K1*Bw*(Dm*EV_SCALE)+Km;

		// calculate the change in velocity at distance x downstream
		double dUdX = 16.0*(pow(m_d2U[j],3.0) - pow(m_d2U[j], 2.0) - m_d2U[j] + 1.0)*E / (m_d2U[j]*dThrustCoeff);
		m_d2U[j+1] = m_d2U[j] + dUdX*m_dAxialResolution;

		// calculate Dm at distance X downstream....
		Dm = (EV_SCALE - m_d2U[j+1])/EV_SCALE; 

		// now calculate wake width using Dm
		Bw = sqrt(3.56*dThrustCoeff/(8.0*Dm*(1.0 - 0.5*Dm)));

		// ok now store the answers for later use	
		matEVWakeDeficits.at(iTurbineNumber, j+1) = Dm; // fractional deficit
		matEVWakeWidths.at(iTurbineNumber, j+1) = Bw; // diameters

		// if the deficit is below min (a setting), or distance x is past the furthest downstream turbine, or we're out of room to store answers, we're done
		if(Dm <= m_dMinDeficit || x > dMetersToFurthestDownwindTurbine+m_dAxialResolution || j >= matEVWakeDeficits.ncols()-2)
			break;
	}

	return true;
}
Example #13
0
int wind_power_calculator::wind_power(/*INPUTS */ double dWindSpeed, double dWindDirDeg, double dAirPressureAtm, double TdryC,
									  /*OUTPUTS*/ double *FarmP, double aPower[], double aThrust[], double aEff[], double adWindSpeed[], double aTI[],
									  double aDistanceDownwind[], double aDistanceCrosswind[])
{
	if ( (m_iNumberOfTurbinesInFarm > MAX_WIND_TURBINES) || (m_iNumberOfTurbinesInFarm < 1) )
	{
		m_sErrDetails = "The number of wind turbines was greater than the maximum allowed in the wake model.";
		return 0;
	}

	size_t i,j;
	//unsigned char wt_id[MAX_WIND_TURBINES], wid; // unsigned char has 256 limit
	size_t wt_id[MAX_WIND_TURBINES], wid;

	for (i=0; i<m_iNumberOfTurbinesInFarm; i++)
		wt_id[i] = i;

	// convert barometric pressure in ATM to air density
	double fAirDensity = (dAirPressureAtm * physics::Pa_PER_Atm)/(physics::R_Gas * physics::CelciusToKelvin(TdryC));   //!Air Density, kg/m^3
	double fTurbine_output, fThrust_coeff;
	turbine_power(dWindSpeed, fAirDensity, &fTurbine_output, &fThrust_coeff );

	// initialize values before possible exit from the function
	for (i=0;i<m_iNumberOfTurbinesInFarm;i++)
	{
		aPower[i] = 0.0;
		aThrust[i] = 0.0;
		aEff[i] = 0.0;
		adWindSpeed[i] = dWindSpeed;
		aTI[i] = m_dTurbulenceIntensity;
	}

	// if there is only one turbine, we're done
	if (m_iNumberOfTurbinesInFarm < 2)
	{
		*FarmP = fTurbine_output;
		return 1;
	}

	// if power output of first turbine is zero, then it will be for the rest: we're done
	if (fTurbine_output <= 0.0)
	{
		*FarmP = 0.0;
		return (int)m_iNumberOfTurbinesInFarm;
	}

	// ok, let's calculate the farm output
	//!Convert to d (downwind - axial), c (crosswind - radial) coordinates
	double d, c;
	//std::vector<double> aDistanceDownwind(m_iNumberOfTurbinesInFarm);	// downwind coordinate of each WT
	//std::vector<double> aDistanceCrosswind(m_iNumberOfTurbinesInFarm);	// crosswind coordinate of each WT
	for (i=0;i<m_iNumberOfTurbinesInFarm;i++)
	{
		coordtrans(m_adYCoords[i], m_adXCoords[i], dWindDirDeg, &d, &c );
		aDistanceDownwind[i] = d;
		aDistanceCrosswind[i] = c;
	}

	 // Remove negative numbers from downwind, crosswind coordinates 	
 	double Dmin = aDistanceDownwind[0];
	double Cmin = aDistanceCrosswind[0];

	for (j=1;j<m_iNumberOfTurbinesInFarm;j++)
	{
		Dmin = min_of(aDistanceDownwind[j],Dmin);
		Cmin = min_of(aDistanceCrosswind[j],Cmin);
	}
	for (j=0;j<m_iNumberOfTurbinesInFarm;j++)
	{
		aDistanceDownwind[j] = aDistanceDownwind[j]-Dmin; // Final downwind coordinates, meters
		aDistanceCrosswind[j] = aDistanceCrosswind[j]-Cmin; // Final crosswind coordinates, meters
	}

	// Convert downwind, crosswind measurements from meters into wind turbine radii
	for (i=0;i<m_iNumberOfTurbinesInFarm;i++)
	{
		aDistanceDownwind[i] = 2.0*aDistanceDownwind[i]/m_dRotorDiameter;
		aDistanceCrosswind[i] = 2.0*aDistanceCrosswind[i]/m_dRotorDiameter;
	}
	
	// Record the output for the most upwind turbine (already calculated above)
	aPower[0] = fTurbine_output;
	aThrust[0] = fThrust_coeff;
	aEff[0] = ( fTurbine_output < 1.0 ) ? 0.0 : 100.0;


	// Sort aDistanceDownwind, aDistanceCrosswind arrays by downwind distance, aDistanceDownwind[0] is smallest downwind distance, presumably zero
	for (j=1;j<m_iNumberOfTurbinesInFarm;j++) 
	{
		d = aDistanceDownwind[j]; // pick out each element
		c = aDistanceCrosswind[j];
		wid = wt_id[j];

		i=j;
		while (i > 0 && aDistanceDownwind[i-1] > d) // look for place to insert item
		{
			aDistanceDownwind[i] = aDistanceDownwind[i-1];
			aDistanceCrosswind[i] = aDistanceCrosswind[i-1];
			wt_id[i] = wt_id[i-1];
			i--;
		}

		aDistanceDownwind[i] = d; // insert it
		aDistanceCrosswind[i] = c;
		wt_id[i] = wid;
	}

	// run the wake model
	switch (m_iWakeModelChoice)
	{
		case PAT_QUINLAN_WAKE_MODEL:
			wake_calculations_pat_quinlan_mod(fAirDensity, &aDistanceDownwind[0], &aDistanceCrosswind[0], aPower, aThrust, aEff, adWindSpeed, aTI);
			break;

		case PARK_WAKE_MODEL:
			wake_calculations_Park(fAirDensity, &aDistanceDownwind[0], &aDistanceCrosswind[0], aPower, aThrust, aEff, adWindSpeed);
			break;

		case SIMPLE_EDDY_VISCOSITY_WAKE_MODEL:
			if (!wake_calculations_EddyViscosity_Simple(fAirDensity, &aDistanceDownwind[0], &aDistanceCrosswind[0], aPower, aThrust, aEff, adWindSpeed, aTI))
				return 0;
			break;

		case OLD_PQ:
			wake_calculations_pat_quinlan_old(fAirDensity, &aDistanceDownwind[0], &aDistanceCrosswind[0], aPower, aThrust, aEff, adWindSpeed, aTI);
			break;

		default:
			m_sErrDetails = "Unknown wake model encountered in wind_power_calculator::wind_power.";
			return 0;
	}
		
	// calculate total farm power
	*FarmP = 0;
	for (i=0;i<m_iNumberOfTurbinesInFarm;i++)
		*FarmP += aPower[i];

	// Update down/cross wind distance units for turbine zero (convert from radii to meters)
	aDistanceDownwind[0] *= m_dRotorDiameter/2;
	aDistanceCrosswind[0] *= m_dRotorDiameter/2;

	// Resort output arrays by wind turbine ID (0..nwt-1)
	// for consistent reporting
	double p,t,e,w,b,dd,dc;
	for (j=1;j<m_iNumberOfTurbinesInFarm;j++) 
	{
		p = aPower[j];// pick out each element
		t = aThrust[j];
		e = aEff[j];
		w = adWindSpeed[j];
		b = aTI[j];
		dd = aDistanceDownwind[j] * m_dRotorDiameter/2; // convert back to meters from radii
		dc = aDistanceCrosswind[j] * m_dRotorDiameter/2;
		wid = wt_id[j];

		i=j;
		while (i > 0 && wt_id[i-1] > wid) // look for place to insert item
		{
			aPower[i] = aPower[i-1];
			aThrust[i] = aThrust[i-1];
			aEff[i] = aEff[i-1];
			adWindSpeed[i] = adWindSpeed[i-1];
			aTI[i] = aTI[i-1];
			aDistanceDownwind[i] = aDistanceDownwind[i-1];
			aDistanceCrosswind[i] = aDistanceCrosswind[i-1];
			wt_id[i] = wt_id[i-1];
			i--;
		}

		aPower[i] = p;
		aThrust[i] = t;
		aEff[i] = e;
		adWindSpeed[i] = w;
		aTI[i] = b;
		aDistanceDownwind[i] = dd;
		aDistanceCrosswind[i] = dc;
		wt_id[i] = wid;
	}
	
	return (int)m_iNumberOfTurbinesInFarm;
}
Example #14
0
        inline void contour2d(const MATRIX        &d,
                              const unit_t         ilb,
                              const unit_t         iub,
                              const unit_t         jlb,
                              const unit_t         jub,
                              const ARRAY         &x,
                              const ARRAY         &y,
                              const array<double> &z,
                              void (*proc)(double,double,double,double,double,void *),
                              void  *args
                              )
        {
#define xsect(p1,p2) (h[p2]*xh[p1]-h[p1]*xh[p2])/(h[p2]-h[p1])
#define ysect(p1,p2) (h[p2]*yh[p1]-h[p1]*yh[p2])/(h[p2]-h[p1])
            int m3,case_value;
            double x1=0,x2=0,y1=0,y2=0;
            double h[5];
            int    sh[5];
            double xh[5],yh[5];
            static const unit_t im[4] = {0,1,1,0},jm[4]={0,0,1,1};
            static const int    castab[3][3][3] =
            {
                { {0,0,8},{0,2,5},{7,6,9} },
                { {0,3,4},{1,3,1},{4,3,0} },
                { {9,6,7},{5,2,0},{8,0,0} }
            };
            double temp1,temp2;
            
            const size_t nc  = z.size();
            const double zlo = z[1];
            const double zhi = z[nc];
            for(unit_t j=(jub-1);j>=jlb;--j)
            {
                for(unit_t i=ilb;i<iub;++i)
                {
                    temp1 = min_of<double>(d[i][j],d[i][j+1]);
                    temp2 = min_of<double>(d[i+1][j],d[i+1][j+1]);
                    const double dmin  = min_of(temp1,temp2);
                    temp1 = max_of<double>(d[i][j],d[i][j+1]);
                    temp2 = max_of<double>(d[i+1][j],d[i+1][j+1]);
                    const double dmax  = max_of(temp1,temp2);
                    if( (dmax<zlo) || (dmin>zhi) )
                    {
                        continue;
                    }
                    for(size_t k=1;k<=nc;k++)
                    {
                        const double level = z[k];
                        if ( level<dmin || level>dmax )
                        {
                            continue;
                        }
                        for(int m=4;m>=0;--m)
                        {
                            if (m > 0)
                            {
                                h[m]  = double(d[i+im[m-1]][j+jm[m-1]])-level;
                                xh[m] = double(x[i+im[m-1]]);
                                yh[m] = double(y[j+jm[m-1]]);
                            }
                            else
                            {
                                h[0]  = 0.25 * (h[1]+h[2]+h[3]+h[4]);
                                xh[0] = 0.50 * (double(x[i])+double(x[i+1]));
                                yh[0] = 0.50 * (double(y[j])+double(y[j+1]));
                            }
                            if (h[m] > 0.0)
                                sh[m] = 1;
                            else if (h[m] < 0.0)
                                sh[m] = -1;
                            else
                                sh[m] = 0;
                        }
                        
                        /*
                         Note: at this stage the relative heights of the corners and the
                         centre are in the h array, and the corresponding coordinates are
                         in the xh and yh arrays. The centre of the box is indexed by 0
                         and the 4 corners by 1 to 4 as shown below.
                         Each triangle is then indexed by the parameter m, and the 3
                         vertices of each triangle are indexed by parameters m1,m2,and m3.
                         It is assumed that the centre of the box is always vertex 2
                         though this isimportant only when all 3 vertices lie exactly on
                         the same contour level, in which case only the side of the box
                         is drawn.
                         vertex 4 +-------------------+ vertex 3
                         | \               / |
                         |   \    m-3    /   |
                         |     \       /     |
                         |       \   /       |
                         |  m=2    X   m=2   |       the centre is vertex 0
                         |       /   \       |
                         |     /       \     |
                         |   /    m=1    \   |
                         | /               \ |
                         vertex 1 +-------------------+ vertex 2
                         */
                        /* Scan each triangle in the box */
                        for(int m=1;m<=4;m++) {
                            const int m1 = m;
                            const int m2 = 0;
                            if (m != 4)
                            {
                                m3 = m + 1;
                            }
                            else
                            {
                                m3 = 1;
                            }
                            m3 = (m!=4) ? (m+1) : 1;
                            if ((case_value = castab[sh[m1]+1][sh[m2]+1][sh[m3]+1]) == 0)
                                continue;
                            switch (case_value) {
                                case 1: /* Line between vertices 1 and 2 */
                                    x1 = xh[m1];
                                    y1 = yh[m1];
                                    x2 = xh[m2];
                                    y2 = yh[m2];
                                    break;
                                case 2: /* Line between vertices 2 and 3 */
                                    x1 = xh[m2];
                                    y1 = yh[m2];
                                    x2 = xh[m3];
                                    y2 = yh[m3];
                                    break;
                                case 3: /* Line between vertices 3 and 1 */
                                    x1 = xh[m3];
                                    y1 = yh[m3];
                                    x2 = xh[m1];
                                    y2 = yh[m1];
                                    break;
                                case 4: /* Line between vertex 1 and side 2-3 */
                                    x1 = xh[m1];
                                    y1 = yh[m1];
                                    x2 = xsect(m2,m3);
                                    y2 = ysect(m2,m3);
                                    break;
                                case 5: /* Line between vertex 2 and side 3-1 */
                                    x1 = xh[m2];
                                    y1 = yh[m2];
                                    x2 = xsect(m3,m1);
                                    y2 = ysect(m3,m1);
                                    break;
                                case 6: /* Line between vertex 3 and side 1-2 */
                                    x1 = xh[m3];
                                    y1 = yh[m3];
                                    x2 = xsect(m1,m2);
                                    y2 = ysect(m1,m2);
                                    break;
                                case 7: /* Line between sides 1-2 and 2-3 */
                                    x1 = xsect(m1,m2);
                                    y1 = ysect(m1,m2);
                                    x2 = xsect(m2,m3);
                                    y2 = ysect(m2,m3);
                                    break;
                                case 8: /* Line between sides 2-3 and 3-1 */
                                    x1 = xsect(m2,m3);
                                    y1 = ysect(m2,m3);
                                    x2 = xsect(m3,m1);
                                    y2 = ysect(m3,m1);
                                    break;
                                case 9: /* Line between sides 3-1 and 1-2 */
                                    x1 = xsect(m3,m1);
                                    y1 = ysect(m3,m1);
                                    x2 = xsect(m1,m2);
                                    y2 = ysect(m1,m2);
                                    break;
                                default:
                                    break;
                            }
                            
                            /* Finally draw the line */
                            if(proc)
                            {
                                proc(x1,y1,x2,y2,level,args);
                            }
                        } /* m */
                    } /* k - contour */
                } /* i */
            } /* j */
        }