// 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); }
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 */
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)); }
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))); }
// 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; }
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]); } } }
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); }
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 }
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; }
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; }
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 */ }