Esempio n. 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); 
}
Esempio n. 2
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));
}
Esempio n. 3
0
double wind_power_calculator::calc_EV_total_turbulence_intensity(double ambientTI, double additionalTI, double Uo, double Uw, double partial)
{
	if(Uw<=0.0)
		return ambientTI;

	double f = max_of(0.0,ambientTI*ambientTI + additionalTI*additionalTI);
	f = sqrt(f)*Uo/Uw;
	return (1.0-partial)*ambientTI + partial*f;
//	return f;
}
Esempio n. 4
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
}
Esempio n. 5
0
double wind_power_calculator::calc_EV_added_turbulence_intensity(double dTIAtUpstreamTurbine, double Ct, double deltaX, VMLN& vmln)
{
	if(!IMITATE_OPENWIND)
	{
		// TFF, Feb 2013 - if we're not imitating openWind then we use the Pat Quinlan method to get added TI
		// So this function will return in one of the next two lines
		if (deltaX==0) return 0.0; // if the distance downwind = 0, then no added turbulence
		return max_of(0.0, (Ct/7.0)*(1.0-(2.0/5.0)*log(deltaX/m_dRotorDiameter)) ); // this equation taken from Pat Quinlan's turbulence intensity calculations
	}

	// Original openWind code (calculation of vmln.Xn required knowing the RPM of the turbine at this wind speed)
	// Xn is in meters
	double Xn = max_of(0.0000000001, vmln.Xn);
	
	// this formula can be found in Wind Energy Handbook by Bossanyi, page 36
//	double Iadd = 5.7*pow(Ct,0.7)*pow(dTIAtUpstreamTurbine, 0.68)*pow(deltaX/Xn,-0.96);
	double Iadd = 5.7*pow(Ct,0.7)*pow(dTIAtUpstreamTurbine, 0.68)*pow(max_of(1.5, deltaX/Xn),-0.96);// limits X>=Xn
	return max_of(0.0, Iadd);
}
Esempio n. 6
0
void process_mmap(mboot_mmap_entry* entry, uint16_t* in_kernel) {

    uint64_t kernel_start = (uint64_t) text_phys_begin;
    uint64_t kernel_end = (uint64_t) bss_phys_end;
    uint64_t end_addr = entry->addr + entry->len - 1;

    if(!(*in_kernel)) {
        if(end_addr < kernel_start || entry->addr >= kernel_end) {
            if(mmap_size == 0 && entry->addr >= kernel_end) {
                add_kernel();
            }

            mmap[mmap_size].addr = entry->addr;
            mmap[mmap_size].len = entry->len;
            mmap[mmap_size].type = entry->type;
            ++mmap_size;
            return;
        }

        mmap[mmap_size].addr = entry->addr;
        mmap[mmap_size].len = kernel_start - entry->addr;
        mmap[mmap_size].type = entry->type;
        ++mmap_size;

        add_kernel();

        *in_kernel = 1;

        if(end_addr < kernel_end) {
            return;
        }

        mmap[mmap_size].addr = kernel_end;
        mmap[mmap_size].len = end_addr - kernel_end;
        mmap[mmap_size].type = entry->type;
        ++mmap_size;

        *in_kernel = 0;
        return;
    }

    if(end_addr < kernel_end) {
        return;
    }

    mmap[mmap_size].addr = max_of(kernel_end, entry->addr);
    mmap[mmap_size].len = end_addr - mmap[mmap_size].addr;//kernel_end;
    mmap[mmap_size].type = entry->type;
    ++mmap_size;

    *in_kernel = 0;
    return;

}
Esempio n. 7
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)));
}
Esempio n. 8
0
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;
}
Esempio n. 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;
}
Esempio n. 10
0
double wind_power_calculator::get_EV_wake_width(int iUpwindTurbine, double dAxialDistanceInDiameters)
{	// get the wake width from the upwind turbine's array describing its wake
	// based on the way the result is used in openWind, the wake widths stored in matEVWakeWidths must be a radial distance from the centerline

	// if we're too close, it's just the initial wake width
	double dDistPastMin = dAxialDistanceInDiameters - MIN_DIAM_EV; // in diameters
	if (dDistPastMin < 0.0)
		return m_dRotorDiameter * matEVWakeWidths.at(iUpwindTurbine,0);

	double dDistInResolutionUnits = dDistPastMin / m_dAxialResolution;
	int iLowerIndex = (int)dDistInResolutionUnits;
	size_t iUpperIndex = iLowerIndex+1;
	dDistInResolutionUnits -= iLowerIndex;
	
	if(iUpperIndex >= matEVWakeWidths.ncols())
		return 0.0;

	return m_dRotorDiameter * max_of(1.0,(  matEVWakeWidths.at(iUpwindTurbine, iLowerIndex) * (1.0-dDistInResolutionUnits) + matEVWakeWidths.at(iUpwindTurbine, iUpperIndex) * dDistInResolutionUnits));	// in meters
}
Esempio n. 11
0
// Implements a simplified Eddy-Viscosity model as per "Simplified Soultion To The Eddy Viscosity Wake Model" - 2009 by Dr Mike Anderson of RES
bool wind_power_calculator::wake_calculations_EddyViscosity_Simple(/*INPUTS */ double air_density, double aDistanceDownwind[], double aDistanceCrosswind[],
																   /*OUTPUTS*/ double Power[], double Thrust[], double Eff[], double adWindSpeed[], double aTurbulence_intensity[] )
{
	double dTurbineRadius = m_dRotorDiameter/2;
	matEVWakeDeficits.fill(0.0);
	matEVWakeWidths.fill(0.0);
	std::vector<VMLN> vmln(m_iNumberOfTurbinesInFarm);
	std::vector<double> Iamb(m_iNumberOfTurbinesInFarm, m_dTurbulenceIntensity);

	// Note that this 'i' loop starts with i=0, which is necessary to initialize stuff for turbine[0]
	for (size_t i=0; i<m_iNumberOfTurbinesInFarm; i++) // downwind turbines, but starting with most upwind and working downwind
	{
		double dDeficit = 0, Iadd = 0, dTotalTI = aTurbulence_intensity[i];
//		double dTOut=0, dThrustCoeff=0;
		for (size_t j=0; j<i; j++) // upwind turbines - turbines upwind of turbine[i]
		{
			// distance downwind = distance from turbine i to turbine j along axis of wind direction
			double dDistAxialInDiameters = fabs(aDistanceDownwind[i] - aDistanceDownwind[j])/2.0;
			if (dDistAxialInDiameters<=0.0)
				continue; // if this turbine isn't really upwind, move on to the next

			// separation crosswind between turbine i and turbine j
			double dDistRadialInDiameters = fabs(aDistanceCrosswind[i] - aDistanceCrosswind[j])/2.0;
			
			double dWakeRadiusMeters = get_EV_wake_width((int)j, dDistAxialInDiameters);  // the radius of the wake
			if (dWakeRadiusMeters<=0.0)
				continue;

			// calculate the wake deficit
			double dDef = wake_deficit_EV((int)j, dDistRadialInDiameters, dDistAxialInDiameters);
			double dWindSpeedWaked = adWindSpeed[0] * (1 - dDef); // wind speed = free stream * (1-deficit)

			// keep it if it's bigger
			dDeficit = max_of(dDeficit, dDef);

//			double temp1 = Iamb[j];
//			double temp2 = aTurbulence_intensity[j];
			Iadd = calc_EV_added_turbulence_intensity(Iamb[j], Thrust[j], dDistAxialInDiameters*m_dRotorDiameter, vmln[j]);
			
			double dFractionOfOverlap = simple_intersect(dDistRadialInDiameters*m_dRotorDiameter, dTurbineRadius, dWakeRadiusMeters);
			dTotalTI = max_of(dTotalTI, calc_EV_total_turbulence_intensity(aTurbulence_intensity[i], Iadd, adWindSpeed[0], dWindSpeedWaked, dFractionOfOverlap));
		}
		// use the max deficit found to calculate the turbine output
		adWindSpeed[i] = adWindSpeed[0]*(1-dDeficit);
		aTurbulence_intensity[i] = dTotalTI;
		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);

		// now that turbine[i] wind speed, output, thrust, etc. have been calculated, calculate wake characteristics for it, because downwind turbines will need the info
		if (!fill_turbine_wake_arrays_for_EV((int)i, adWindSpeed[0], adWindSpeed[i], Power[i], Thrust[i], aTurbulence_intensity[i], fabs(aDistanceDownwind[m_iNumberOfTurbinesInFarm-1] - aDistanceDownwind[i])*dTurbineRadius ) )
		{
			if(m_sErrDetails.length() == 0) m_sErrDetails = "Could not calculate the turbine wake arrays in the Eddy-Viscosity model.";
			return false;
		}

		if (IMITATE_OPENWIND)
			calc_EV_vm_for_turbine(adWindSpeed[i], Iamb[i], Thrust[i], air_density, vmln[i]);
			// TFF, Feb 2013 - if we're imitating openWind, then we fill a turbine RPM curve so this will work
			// TFF, Mar 8, 2013 - Iamb[i] never changes, it's always = m_dTurbulenceIntensity.  Really?
	}
	return true;
}
Esempio n. 12
0
        void EdgeDetector:: post_build(xpatches &xps)
        {
            edges.free();

            // get the global max
            Gmax = xps[1].as<float>();
            for(size_t i=xps.size();i>1;--i)
            {
                Gmax = max_of(Gmax,xps[i].as<float>());
            }


            if(Gmax>0)
            {
                //! normalize as probability
                xps.submit(this, &EdgeDetector::normalize );

                //! non local maxima suprresion
                xps.submit(this, &EdgeDetector::non_maxima_suppress);

                //! thresholds computation
                H.reset();
                H.update(E,xps);
                level_up = H.threshold();
                const size_t level_min   = level_lo/2;
                const size_t level_delta = size_t( floor( (level_up-level_min) * weak_intake + 0.5f) );
                level_lo = level_up-level_delta;

                //! apply threshold
                xps.submit(this, &EdgeDetector::apply_thresholds);

                //! build blobs
                tags.build(E,8);

                //! find individual edges
                edges.load(tags);


                // removing weak only edges
                pixmap<float> &G = *this;
                for(size_t i=edges.size();i>0;--i)
                {
                    particle &p = *edges[i];
                    assert(p.size>0);
                    assert(p.inside.size<=0);
                    assert(p.border.size<=0);
                    // detect if at least one strong connected edge
                    bool is_strong = false;
                    for(const vnode *node = p.head;node;node=node->next)
                    {
                        if(STRONG==E[node->vtx])
                        {
                            is_strong=true;
                            break;
                        }
                    }

                    // remove it !
                    if(!is_strong)
                    {
                        while(p.size)
                        {
                            vnode       *node = p.pop_back();
                            const vertex q    = node->vtx;

                            tags[q] = 0;
                            E[q]    = 0;
                            G[q]    = 0;

                            delete node;
                        }
                    }
                }
                remove_if(edges,__is_empty_particle);
                //std::cerr << "#edges=" << edges.size() << std::endl;
            }
            else
            {
                ldz();
                E.ldz();
                tags.ldz();
            }

        }
Esempio n. 13
0
void wind_power_calculator::turbine_power( double fWindVelocityAtDataHeight, double fAirDensity, double *fTurbineOutput, double *fThrustCoefficient )
{
	// default outputs to zero
	*fThrustCoefficient = 0.0;
	*fTurbineOutput = 0.0;

	//first, correct wind speeds in power curve for site air density. Using method 2 described in https://www.scribd.com/document/38818683/PO310-EWEC2010-Presentation
	//then, make sure to use corrected wind speeds when calculating power
	std::vector <double> temp_ws;
	for (size_t i = 0; i < m_adDensityCorrectedWS.size(); i++)
		m_adDensityCorrectedWS[i] = m_adPowerCurveWS[i] * pow((physics::AIR_DENSITY_SEA_LEVEL / fAirDensity), (1.0 / 3.0));

	//bug fix jmf 1/11/17- cut in and cut out wind speeds need to be inferred from the power curve, cut in was previously an input but shouldn't be because a) some users are using library turbines, which only have power curves, 
	//and b) it could be inconsistent with the input power curve. 
	int i = 0;
	while (m_adPowerCurveKW[i] == 0)
		i++; //find the index of the first non-zero power output in the power curve
	//the cut-in speed is defined where the turbine FIRST STARTS TO TURN, not where it first generates electricity! Therefore, assume that the cut-in speed is actually 1 speed BELOW where power is generated.
	//this is consistent with the NREL Cost & Scaling model- if you specify a cut-in speed of 4 m/s, the power curve value at 4 m/s is 0, and it starts producing power at 4.25.
	//HOWEVER, if you specify the cut-in speed BETWEEN the wind speed bins, then this method would improperly assume that the cut-in speed is lower than it actually is. But given the 0.25 m/s size of the bins, that type of
	//specification would be false accuracy anyways, so we'll ignore it for now.
	m_dCutInSpeed = m_adDensityCorrectedWS[i - 1];

	/*	//We will continue not to check cut-out speed because currently the model will interpolate between the last non-zero power point and zero, and we don't have a better definition of where the power cutoff should be.
	i = m_adPowerCurveKW.size() - 1; //last index in the array
	while (m_adPowerCurveKW[i] == 0)
		i--; //find the index of the last non-zero power output in the power curve
	m_dCutOutSpeed = m_adPowerCurveWS[i]; //unlike cut in speed, we want power to hard cut AFTER this wind speed value*/


	// If the wind speed measurement height (fDataHeight) differs from the turbine hub height (Hub_Ht), use the shear to correct it. 
	if (m_dShearExponent > 1.0) m_dShearExponent = 1.0/7.0;
	double fWindSpeedAtHubHeight = fWindVelocityAtDataHeight * pow(m_dHubHeight/m_dMeasurementHeight, m_dShearExponent);
	
	// Find power from turbine power curve
	double out_pwr=0.0;
	if ((fWindSpeedAtHubHeight > m_adDensityCorrectedWS[0]) && (fWindSpeedAtHubHeight < m_adDensityCorrectedWS[m_iLengthOfTurbinePowerCurveArray - 1]))
	{
		int j = 1;
		while (m_adDensityCorrectedWS[j] <= fWindSpeedAtHubHeight)
			j++; // find first m_adPowerCurveWS > fWindSpeedAtHubHeight

		out_pwr = util::interpolate(m_adDensityCorrectedWS[j - 1], m_adPowerCurveKW[j - 1], m_adDensityCorrectedWS[j], m_adPowerCurveKW[j], fWindSpeedAtHubHeight);
	}
	else if (fWindSpeedAtHubHeight == m_adDensityCorrectedWS[m_iLengthOfTurbinePowerCurveArray - 1])
		out_pwr = m_adPowerCurveKW[m_iLengthOfTurbinePowerCurveArray-1];

	// Check against turbine cut-in speed
	if ( fWindSpeedAtHubHeight < m_dCutInSpeed) out_pwr = 0.0; //this is effectively redundant, because the power at the cut-in speed is defined to be 0, above, so anything below that will also be 0, but leave in for completeness

	// wind turbine output corrected for site air density
	//removed 3.28.17 jmf. this was originally coded in ~2005, before the IEC standard was written. this correction is largely correct for stall regulated turbines, but the majority of modern turbines are now pitch-regulated.
	//out_pwr *= fAirDensity/physics::AIR_DENSITY_SEA_LEVEL; 

	// stall control (Ctl_Mode == 2) defaults to simple density ratio
	/*
	if ( (m_iControlMode == 1) || (m_iControlMode == 0) ) //1 = pitch control, 0= variable speed control
	{
		double NewVRat = m_dRatedSpeed * pow(fAirDensity/physics::AIR_DENSITY_SEA_LEVEL, 1.0/3.0);
		if (out_pwr > m_dRatedPower)
			out_pwr = m_dRatedPower;
		else if (fWindSpeedAtHubHeight > NewVRat)
			out_pwr = m_dRatedPower;
	}
	*/

	//if (out_pwr > (m_dRatedPower * 0.001)) // if calculated power is > 0.1% of rating, set outputs
	if (out_pwr > 0 )
	{
		out_pwr = out_pwr*(1.0-m_dLossesPercent) - m_dLossesAbsolute;
		double pden = 0.5*fAirDensity*pow(fWindSpeedAtHubHeight, 3.0);
		double area = physics::PI/4.0*m_dRotorDiameter*m_dRotorDiameter;
		double fPowerCoefficient = max_of( 0.0, 1000.0*out_pwr/(pden*area) );

		// set outputs to something other than zero
		*fTurbineOutput = out_pwr;
		if (fPowerCoefficient >= 0.0)
			*fThrustCoefficient = max_of( 0.0, -1.453989e-2 + 1.473506*fPowerCoefficient - 2.330823*pow(fPowerCoefficient,2) + 3.885123*pow(fPowerCoefficient,3) );		
	} // out_pwr > (rated power * 0.001)

	if (IMITATE_OPENWIND) // even if there's no power output, calculate the thrust coefficient
	{
		*fThrustCoefficient =  m_dMinThrustCoeff; // default value for low wind speeds

		// this is a curve specific to a particular turbine, ONLY USEFUL FOR COMPARING SAM TO openWind
		double dThrustCurve[26] = {0.0, 0.0, 0.0, 0.8, 0.8, 0.82, 0.84, 0.79, 0.72, 0.66, 0.59, 0.53, 0.46,0.40,0.33,0.28,0.23,0.20,0.16,0.13,0.12,0.12,0.11,0.11,0.10,0.10};
//		bool found=false;

		int i = (int) fabs(fWindSpeedAtHubHeight);
		if ( fabs(fWindSpeedAtHubHeight)>25 )
			*fThrustCoefficient = 0;
		else if (i==25)
			*fThrustCoefficient = dThrustCurve[i];
		else if (i>=2)
			*fThrustCoefficient = util::interpolate(i,dThrustCurve[i],i+1,dThrustCurve[i+1],fWindSpeedAtHubHeight);
	}
	return;
}
Esempio n. 14
0
int main(int argc, char const *argv[])
{
    printf("Banditore Started...\n\n\n");


    //max n resource each client 
    resource band_resources[MAX_CLIENT_R*MAX_CLIENT];
    int num_resources = 0;

    // reading resource
    if(band_load_resource("resource.txt", band_resources, &num_resources) < 0){
        perror("Error while opening the file \n");
        exit(EXIT_FAILURE);
    }

    // print resource
    printf("Resources loaded:\n");
    printTAO_resources(band_resources,num_resources);

    // Creation unique key
    int key;
    if((key=ftok("banditore.c", 'G')) == -1)
    {
        perror("Error ftok...");
        exit(EXIT_FAILURE);
    }

    //Creation message queue
    int qid = msgget(key, 0666|IPC_CREAT);
    if(qid==-1)
    {
        perror("Creation messagge queue... FAIL!");
        exit(EXIT_FAILURE);
    }

    printf("Premere un tasto per leggere le richieste ");
    getchar();
    printf("Banditore in attesa di richieste...\n");

//---

    msg1 m1;
    request req[MAX_CLIENT];
    int num_req = 0;

    int stop= -1 * TIME_FOR_REQUEST;
    while(stop)
    {
        int rd_bytes = msgrcv(qid, &m1, sizeof(msg1)-sizeof(long), RES_REQ_TYPE, IPC_NOWAIT);
        if(rd_bytes>0)
        {
            //ho letto il messaggio
            req[num_req].pid_applicant=m1.pid;
            req[num_req].num_res=m1.num_res;
            for(int i=0;i<m1.num_res;i++)
            {
                req[num_req].resource[i]=m1.data[i];
            }
            num_req++;
            printf("Ricevuto elenco da %d\n",m1.pid);
        }//rd_bytes <=0 non ho letto nulla dalla coda
        else if(errno == ENOMSG)
        {
            //La coda esiste, ma non contiene messaggi
            //oppure non contiene messaggi di tipo RES_REQ_TYPE
            //printf("\nNo request messagge in the queue...\n");
            sleep(1);
            stop++;
        }
        else if(errno==EINVAL || errno==EIDRM)
        {
            //la coda non esiste
            perror("\nQueue removed unexpectedly...");
            exit(EXIT_FAILURE);
        }
        else
        {
            perror("Other errors...");
            exit(EXIT_FAILURE);
        }
    }
    
    printf("\nIscrizioni chiuse, avvio tavoli delle offerte:\n\n");


    // Inizializzazioni
    msg1 winners[num_req];
    int tao[MAX_CLIENT_R*MAX_CLIENT],semid[MAX_CLIENT_R*MAX_CLIENT];

    for(int i=0; i<num_req; i++)
    {
        winners[i].type=req[i].pid_applicant;
        winners[i].num_res=0;
    }

    for(int i=0;i<(MAX_CLIENT_R*MAX_CLIENT);i++)
    {
        semid[i]=0;
        tao[i]=0;
    }

    //ALERT: Inizio for della morte


    for (int i = 0; i < MAX_CLIENT; i++) {
        printf("La req.pid [%d] contiene %d \n", i, req[i].pid_applicant);
        printf("La req.num_res [%d] contiene %d \n", i, req[i].num_res);  
        if (i == 0)
            for(int j=0; j < req[0].num_res; j++){
                printf("\tLe risorsa [j]: %s \n",  req[0].resource[j].name);
                printf("\tLe risorsa [j]: %d \n",  req[0].resource[j].quantity); 
                printf("\tLe risorsa [j]: %d \n",  req[0].resource[j].price);
            }    
    }

    for(int i=0;i<num_resources;i++)
    {
        //Per ogni risorsa:
        // - creo un tavolo delle offerte (shared memory)
        // - creo un semaforo per far accedere in mutua esclusione
        // - mando un messaggio ai clienti interessati      

        tao[i] = new_sharedMemory(SHMKEY+(2*i));//crea ed inizializza tao
        semid[i] = new_semaphore(SEMKEY+(2*i));//crea semaforo
        printf("Aperto TAO per %s\n",band_resources[i].name);

        if(!alert_clients(qid,SHMKEY+(2*i),SEMKEY+(2*i),req,num_req,band_resources[i]))
        {
            printf("Errore avviso cliente\n");
        }


        int n[MAX_CLIENT_R*MAX_CLIENT];//pid figli


        //per ogni tao una fork
        //il figlio tiene il timer
        //if i+1 ecc ecc allora ciclo con MAX_TAO wait
        //alla fine wait sui tao rimasti

        n[i] = fork();
        if(n[i]==-1)
        {
            perror("Error while generating tao controller...");
            exit(EXIT_FAILURE);
        }
        else if(!n[i]){
            // Codice figlio
            /* ALERT: Cosa serve sto signal? */
            signal(SIGINT,SIG_IGN);

            // Countdown
            int timer=TAO_LAST;
            while(timer)
            {
                /* ALERT: Il banditore Dorme? */
                if(timer<4)
                    printf("Countdown TAO per %s: %ds\n",band_resources[i].name,timer);
                timer--;
                sleep(1);
            }
            //qui si stabiliscono i vincitori dell'asta
            //p su semaforo
            
            P(semid[i],0);
            //analisi tao
            /*attach*/
            offer *o = (offer *)shmat(tao[i], NULL, 0);
            if(o==-1)
            {
                perror("Error shared memory attach...");
                exit(EXIT_FAILURE);
            }

            //analizza_tao(num_ric,risorse[i],o,&vincite);
            if(i==TAO_S)
                print_tao(o);
            int m,cont=0;
            resource temp;
            FILE *f=fopen(band_resources[i].name,"w");
            do
            {
                m=max_of(o);
                cont++;
                if(!(o+m)->prize_each) break;

                band_resources[i].quantity-=(o+m)->quantity;

                for(int k=0;k<num_req;k++)
                {
                  if(winners[k].type==((long)(o+m)->pid_offer))
                  {
                      temp=band_resources[i];
                      temp.price=(o+m)->prize_each;
                      if(band_resources[i].quantity>0)
                        temp.quantity=(o+m)->quantity;
                      else
                      {
                        temp.quantity=(o+m)->quantity+band_resources[i].quantity;
                        band_resources[i].quantity=0;
                      }
                      winners[k].data[winners[k].num_res]=temp;
                      winners[k].num_res++;
                                
                      fprintf(f,"%li %d %d\n",winners[k].type,temp.quantity,temp.price);            
                  }
                }
                (o+m)->prize_each=0;
            }while(band_resources[i].quantity>0 && cont<MAX_TAO_OF);
            
            fclose(f);
            /*detach*/
            if(shmdt(o))
            {
                perror("Error shared memory detach...");
                exit(EXIT_FAILURE);
            }  
            if(tao[i]) 
            {
                deallocate_tao(tao[i]);
                tao[i]=0;
            }
            //v su semaforo
            V(semid[i],0);

            deallocate_semaphore(semid[i]);
            semid[i]=0;         

            printf("TAO per %s deallocato\n",band_resources[i].name);
            exit(EXIT_SUCCESS);
          }
          if((i+1)%MAX_TAO==0)
          {
            int k;
            int status = getpid(n[i]);
            for(k=0;k<MAX_TAO;k++)
            {
                wait(&status);
                tao[i+k]=0;
                semid[i+k]=0;
            }
          }
    }


    //mando i messaggi per le risorse non disponibili
    int trial=0;
    for(int i=0;i<num_req;i++)
    {
        int j;
        for(j=0;j<req[i].num_res;j++)
        {                                           
            if(!contains(band_resources,num_resources,req[i].resource[j].name))
            {
                msg2 m1;
                m1.type=req[i].pid_applicant;
                m1.shm_key=0;
                m1.smp_key=0;
                m1.res=req[i].resource[j];
                trial=0;
                while(msgsnd(qid,&m1,sizeof(msg2)-sizeof(long),0)==-1)
                {
                    if(trial==MAX_CLIENT)
                        exit(EXIT_FAILURE);
                    perror("Trying to advert client... \n");
                    sleep(0.1);
                    trial++;
                }
            }
        }
    }

    //leggi vincite
    for(int i=0;i<num_resources;i++)
    {
        int pid;
        FILE *f=fopen(band_resources[i].name,"r");
        while(fscanf(f,"%d",&pid)!=EOF)
        {
            int k;
            for(k=0;k<num_req;k++)
                if(winners[k].type==pid)
                {
                    fscanf(f,"%d",&(winners[k].data[winners[k].num_res].quantity));
                    fscanf(f,"%d",&(winners[k].data[winners[k].num_res].price));
                    strcpy(winners[k].data[winners[k].num_res].name,band_resources[i].name);
                    winners[k].num_res++;
                    fgetc(f);
                }
        }
        fclose(f);
    }

    //comunica eventuali vincite
    trial=0;
    for(int i=0;i<num_req;i++)
    {
        while(msgsnd(qid,&winners[i],sizeof(msg1)-sizeof(long),0)==-1)
        {
            if(trial==MAX_CLIENT)
                exit(EXIT_FAILURE);
            perror("Trying to advert client... \n");
            sleep(0.1);
            trial++;
        }
    }
    sleep(3);
    deallocate_queue(qid);
    qid=0;
    exit(EXIT_SUCCESS);
    return 0;
}
Esempio n. 15
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;
}
Esempio n. 16
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 */
        }
Esempio n. 17
0
void Fish:: generateHead(  double Zmax, size_t N, double thickness)
{
    //--------------------------------------------------------------------------
    //
    // Setup: find the ratio of the last slice
    //
    //--------------------------------------------------------------------------

    clear();
    if(Zmax<=0||Zmax>0.5)
        throw exception("Invalid Zmax=%g",Zmax);

    zfunction<double> rfn( this, & Profile::getZ, Zmax);
    zfind<double>     solve(0);
    const double      rho_max =  solve(rfn.call,0,1);
    std::cerr << "rho_max=" << rho_max << std::endl;
    N = max_of<size_t>(1,N);

    const double delta = rho_max / (N);
    const size_t n     = max_of<size_t>(2,ceil(maxP/delta))-2;
    const size_t M     = 2+2*n;
    std::cerr << "\tn=" << n << ", M=" << M << std::endl;

    //--------------------------------------------------------------------------
    //
    // Outer Shell
    //
    //--------------------------------------------------------------------------
    {
        //______________________________________________________________________
        //
        // compute the slices position
        //______________________________________________________________________
        for(size_t i=1;i<=N;++i)
        {
            const double ratio = i*delta;
            const pSlice pS( new Slice( getZ(ratio) ) );
            slices.push_back(pS);
        }

        //______________________________________________________________________
        //
        // head point
        //______________________________________________________________________
        pPoint p0( new Point() );
        points.push_back(p0);

        //______________________________________________________________________
        //
        // body points
        //______________________________________________________________________
        for(size_t i=1;i<=N;++i)
        {

            Slice &slice = *slices[i];

            const double w = W(slice.z);
            const double h = H(slice.z);

            //std::cerr << "w=" << width << ", h=" << height << std::endl;
            for(size_t j=0;j<M;++j)
            {
                const double theta = (j*numeric<double>::two_pi)/M;
                pPoint pp( new Point() );

                pp->r.x = w * cos(theta);
                pp->r.y = h * sin(theta);
                pp->r.z = slice.z;

                slice.points.push_back(pp);
                points.push_back(pp);
            }

        }

        std::cerr << "-- Computing Triangles" << std::endl;
        std::cerr << "\t Head..." << std::endl;

        //______________________________________________________________________
        //
        // head
        //______________________________________________________________________
        {
            const Slice &slice = *slices[1];
            for(size_t i=1;i<=M;++i)
            {
                size_t   ip = i+1;
                if(ip>M) ip = 1;
                const Triangle tr(p0,slice.points[i],slice.points[ip]);
                triangles.push_back(tr);
            }
        }

        std::cerr << "\t Body..." << std::endl;
        //______________________________________________________________________
        //
        // inside
        //______________________________________________________________________
        for(size_t j=1;j<N;++j)
        {
            const array<pPoint> &P0 = slices[j]->points;
            const array<pPoint> &P1 = slices[j+1]->points;

            // loop over quads
            for(size_t i=1;i<=M;++i)
            {
                size_t   ip = i+1;
                if(ip>M) ip = 1;
                const pPoint  &P00 = P0[i];
                const pPoint  &P01 = P0[ip];
                const pPoint  &P10 = P1[i];
                const pPoint  &P11 = P1[ip];

                {
                    const Triangle tr(P00,P01,P11);
                    triangles.push_back(tr);
                }

                {
                    const Triangle tr(P00,P10,P11);
                    triangles.push_back(tr);
                }
            }
        }

    }

    pPoint pN( new Point);
    pN->r.z = Zmax;
    points.push_back(pN);

    // tail
    {
        const Slice &slice = *slices[N];
        for(size_t i=1;i<=M;++i)
        {
            size_t   ip = i+1;
            if(ip>M) ip = 1;
            Triangle tr(pN,slice.points[i],slice.points[ip]);
            tr.inverse();
            triangles.push_back(tr);
        }
    }



#if 0
    //--------------------------------------------------------------------------
    //
    // Inner Shell
    //
    //--------------------------------------------------------------------------
    {
        vector<pPoint>   inner_points;
        vector<pSlice>   inner_slices;
        vector<Triangle> inner_tr;

        pPoint p0( new Point() );
        inner_points.push_back(p0);

        rfn.target = thickness;
        const double rho_min = solve(rfn.call,0,1);
        p0->r.z = thickness;

        const double delta_in = (rho_max - rho_min)/N;
        //______________________________________________________________________
        //
        // inner slices
        //______________________________________________________________________
        for(size_t i=1;i<=N;++i)
        {
            const double ratio = rho_min + (i*delta_in);
            const pSlice pS( new Slice( getZ(ratio) ) );
            inner_slices.push_back(pS);
        }


        //______________________________________________________________________
        //
        // inner body points
        //______________________________________________________________________
        for(size_t i=1;i<=N;++i)
        {

            Slice &slice = *inner_slices[i];

            const double w0 = W(slice.z);
            const double h0 = H(slice.z);

            const double th = thickness;

            const double w = max_of(w0/2,w0 - th);
            const double h = max_of(h0/2,h0 - th);

            //std::cerr << "w=" << width << ", h=" << height << std::endl;
            for(size_t j=0;j<M;++j)
            {
                const double theta = (j*numeric<double>::two_pi)/M;
                pPoint pp( new Point() );

                pp->r.x = w * cos(theta);
                pp->r.y = h * sin(theta);
                pp->r.z = slice.z;

                slice.points.push_back(pp);
                inner_points.push_back(pp);
            }

        }

        std::cerr << "-- Computing Inner Triangles" << std::endl;
        std::cerr << "\t Head..." << std::endl;
        //______________________________________________________________________
        //
        // inner triangles head
        //______________________________________________________________________
        {
            const Slice &slice = *inner_slices[1];
            for(size_t i=1;i<=M;++i)
            {
                size_t   ip = i+1;
                if(ip>M) ip = 1;
                const Triangle tr(p0,slice.points[i],slice.points[ip]);
                inner_tr.push_back(tr);
            }
        }

        std::cerr << "\t Body..." << std::endl;
        //______________________________________________________________________
        //
        // inside
        //______________________________________________________________________
        for(size_t j=1;j<N;++j)
        {
            const array<pPoint> &P0 = inner_slices[j]->points;
            const array<pPoint> &P1 = inner_slices[j+1]->points;

            // loop over quads
            for(size_t i=1;i<=M;++i)
            {
                size_t   ip = i+1;
                if(ip>M) ip = 1;
                const pPoint  &P00 = P0[i];
                const pPoint  &P01 = P0[ip];
                const pPoint  &P10 = P1[i];
                const pPoint  &P11 = P1[ip];

                {
                    const Triangle tr(P00,P01,P11);
                    inner_tr.push_back(tr);
                }

                {
                    const Triangle tr(P00,P10,P11);
                    inner_tr.push_back(tr);
                }
            }
        }

        //______________________________________________________________________
        //
        // fusion of inner triangles with shell
        //______________________________________________________________________
        for(size_t i=1;i<=inner_points.size();++i)
        {
            points.push_back(inner_points[i]);
        }

        for(size_t i=1;i<=inner_tr.size();++i)
        {
            Triangle &tr = inner_tr[i];
            tr.inverse();
            triangles.push_back( inner_tr[i] );
        }

        //______________________________________________________________________
        //
        // closing the shell
        //______________________________________________________________________
        std::cerr << "-- Closing the shell" << std::endl;
        const Slice &S_out = *slices.back();
        const Slice &S_ins  = *inner_slices.back();
        {
            const array<pPoint> &P0 = S_out.points;
            const array<pPoint> &P1 = S_ins.points;

            // loop over quads
            for(size_t i=1;i<=M;++i)
            {
                size_t   ip = i+1;
                if(ip>M) ip = 1;
                const pPoint  &P00 = P0[i];
                const pPoint  &P01 = P0[ip];
                const pPoint  &P10 = P1[i];
                const pPoint  &P11 = P1[ip];
                
                {
                    Triangle tr(P00,P01,P11);
                    if(tr.n.z<=0) tr.inverse();

                    triangles.push_back(tr);
                }
                
                {
                    Triangle tr(P00,P10,P11);
                    if(tr.n.z<=0) tr.inverse();
                    triangles.push_back(tr);
                }
            }
        }

    }
#endif
    
}