#include <mex.h>
#include <math.h>
#include <stdio.h>
#include <matrix.h>
#define wakeXYZ(i,j,k,l) WakeXYZ[(i-1)+((j-1)+((k-1)+(l-1)*NoOfSegments)*NoOfFilaments)*NoOfBlades]
#define be_RControl(i,j,k) BE_RControl[(i-1)+((j-1)+(k-1)*NoOfElements)*NoOfBlades]
#define rquarter(i,j,k) RQuarter[(i-1)+((j-1)+(k-1)*NoOfElements)*NoOfBlades]
#define be_Gamma(i) BE_Gamma[(i-1)]
/* The computational routine for FarTrailingSingleGC */
void FarTrailingSingleGC(const mwIndex InterestBE, const mwIndex Segment, const mwIndex Filament, const mwIndex BladeNo,
const double *WakeXYZ, const double *BE_RControl,
const mwSize NoOfBlades, const mwSize NoOfFilaments, const mwSize NoOfSegments, const mwSize NoOfWakeItems,
const mwSize NoOfElements,
const double conf_CompressibleBiot, const double conf_M, const double conf_CompressibleWakeMachMax,
double *GC)
{
...
Similar to TrailingSingleGC
...
}
/* The computational routine for TrailingSingleGC */
void TrailingSingleGC(const mwIndex InterestBE, const mwIndex Segment, const mwIndex Filament, const mwIndex BladeNo,
const double *WakeXYZ, const double *BE_RControl, const double *BE_Gamma,
const mwSize NoOfBlades, const mwSize NoOfFilaments, const mwSize NoOfSegments, const mwSize NoOfWakeItems,
const mwSize NoOfElements,
const double conf_CompressibleBiot, const double conf_M, const double conf_CompressibleWakeMachMax,
const double conf_VortexCoreOffset,
const double conf_VortexDelta,
const double conf_kin_visc,
const double conf_VatistasN,
double *GC)
{
const mwSize NoOfDimensions = 3;
double rA[3];
double rB[3];
double rp[3];
double Mach;
double CompreBeta;
double CompreMach;
double rm[3];
double rmp[3];
double lAB[3];
double r1[3];
double r2[3];
double lAB_dot_r1;
double lAB_dot_r2;
double lABxr1[3];
double cosTheta1;
double cosTheta2;
double height;
double tbase;
double BioConstant;
const double pi = 3.1415926535897932384626433832795;
//-----------------------------------------------------------
// Vortex core calculations
//-----------------------------------------------------------
double Omegam, AzimuthStart, vDelta, TrailGamma, Core0, MidAge, CoreRadius;
const double CoreAlpha = 1.25643;
// Calculate the segment center point velocity vector
Omegam = (wakeXYZ(BladeNo,Filament,Segment,6) + wakeXYZ(BladeNo,Filament,Segment,6))/2.;
// Calculate the vortex core radius
AzimuthStart = -conf_VortexCoreOffset;
if (be_Gamma(1)<-800.)
{
vDelta = -conf_VortexDelta;
}
else
{
if (Filament ==1)
{
TrailGamma = fabs(-be_Gamma(1));
}
else if (Filament ==NoOfElements+1)
{
TrailGamma = fabs(be_Gamma(NoOfElements));
}
else
{
TrailGamma = fabs(be_Gamma(Filament-1)-be_Gamma(Filament));
}
vDelta = 1. + 2.*pow(10.,-4.) * TrailGamma / conf_kin_visc;
}
Core0 = sqrt(4.*CoreAlpha*vDelta*conf_kin_visc*(-AzimuthStart/Omegam));
MidAge = (wakeXYZ(BladeNo,Filament,Segment,4) + wakeXYZ(BladeNo,Filament,Segment,4))/2.;
CoreRadius = sqrt(pow(Core0,2.) + 4.*CoreAlpha*conf_VortexDelta*conf_kin_visc*MidAge);
//-----------------------------------------------------------
// Calculate the compressibility correction factor
//-----------------------------------------------------------
if (conf_CompressibleBiot>=2)
{
if (conf_M > conf_CompressibleWakeMachMax)
{
CompreMach = conf_CompressibleWakeMachMax;
}
else
{
CompreMach = conf_M;
}
}
else
{
CompreMach = 0.;
}
CompreBeta = 1./sqrt(1.-pow(CompreMach,2.));
/* Get the rA position vector */
rA[0] = wakeXYZ(BladeNo,Filament,Segment,1);
rA[1] = wakeXYZ(BladeNo,Filament,Segment,2);
rA[2] = CompreBeta * wakeXYZ(BladeNo,Filament,Segment,3);
/* Get the rB position vector */
rB[0] = wakeXYZ(BladeNo,Filament,Segment+1,1);
rB[1] = wakeXYZ(BladeNo,Filament,Segment+1,2);
rB[2] = CompreBeta * wakeXYZ(BladeNo,Filament,Segment+1,3);
/* Get the rp position vector */
rp[0] = be_RControl(1,InterestBE,1);
rp[1] = be_RControl(1,InterestBE,2);
rp[2] = CompreBeta * be_RControl(1,InterestBE,3);
// Calculate the AB mean point
rm[0] = (rA[0] + rB[0]) / 2.;
rm[1] = (rA[1] + rB[1]) / 2.;
rm[2] = (rA[2] + rB[2]) / 2.;
// Calculate the distance from the center point
rmp[0] = rp[0] - rm[0];
rmp[1] = rp[1] - rm[1];
rmp[2] = rp[2] - rm[2];
// Calculate the segment length vector
lAB[0] = rB[0] - rA[0];
lAB[1] = rB[1] - rA[1];
lAB[2] = rB[2] - rA[2];
// Calculate the r1=rAP vector
r1[0] = rp[0] - rA[0];
r1[1] = rp[1] - rA[1];
r1[2] = rp[2] - rA[2];
// Calculate the r2=rBP vector
r2[0] = rp[0] - rB[0];
r2[1] = rp[1] - rB[1];
r2[2] = rp[2] - rB[2];
// Calculate the lAB r1 dot product
lAB_dot_r1 = lAB[0]*r1[0] + lAB[1]*r1[1] + lAB[2]*r1[2];
// Calculate the lAB r2 dot product
lAB_dot_r2 = lAB[0]*r2[0] + lAB[1]*r2[1] + lAB[2]*r2[2];
// Now calculate the lAB x r1 cross product vector
lABxr1[0] = lAB[1]*r1[2] - lAB[2]*r1[1];
lABxr1[1] = lAB[2]*r1[0] - lAB[0]*r1[2];
lABxr1[2] = lAB[0]*r1[1] - lAB[1]*r1[0];
// Calculate the cosTheta1
cosTheta1 = lAB_dot_r1 / ( sqrt(pow(lAB[0],2.) + pow(lAB[1],2.) + pow(lAB[2],2.)) * sqrt(pow(r1[0],2.) + pow(r1[1],2.) + pow(r1[2],2.)) );
// Calculate the cosTheta2
cosTheta2 = lAB_dot_r2 / ( sqrt(pow(lAB[0],2.) + pow(lAB[1],2.) + pow(lAB[2],2.)) * sqrt(pow(r2[0],2.) + pow(r2[1],2.) + pow(r2[2],2.)) );
// Calculate the triangle height
tbase = sqrt(pow(r1[0],2.) + pow(r1[1],2.) + pow(r1[2],2.)) * cosTheta1;
height = sqrt(pow(r1[0],2.) + pow(r1[1],2.) + pow(r1[2],2.) - pow(tbase,2.));
// Finaly calculate the geometry coefficient by the Biot-Savart law
if (conf_VortexCoreOffset<0)
{
// No vortex core is used
//BioConstant = (cosTheta1-cosTheta2)/(4.*pi*height) / sqrt(pow(lABxr1[0],2.)+pow(lABxr1[1],2.)+pow(lABxr1[2],2.));
BioConstant = cosTheta1/(4.*pi*height) / sqrt(pow(lABxr1[0],2.)+pow(lABxr1[1],2.)+pow(lABxr1[2],2.))
-cosTheta2/(4.*pi*height) / sqrt(pow(lABxr1[0],2.)+pow(lABxr1[1],2.)+pow(lABxr1[2],2.));
GC[0] = BioConstant * lABxr1[0];
GC[1] = BioConstant * lABxr1[1];
GC[2] = BioConstant * lABxr1[2];
}
else
{
// Calculation includes vortex core
//BioConstant = height/pow((pow(CoreRadius,(2.*conf_VatistasN)) + pow(height,(2.*conf_VatistasN))),(1./conf_VatistasN))*
// (cosTheta1-cosTheta2)/(4.*pi) / sqrt(pow(lABxr1[0],2.)+pow(lABxr1[1],2.)+pow(lABxr1[2],2.));
BioConstant = height/pow((pow(CoreRadius,(2.*conf_VatistasN)) + pow(height,(2.*conf_VatistasN))),(1./conf_VatistasN))*
cosTheta1/(4.*pi) / sqrt(pow(lABxr1[0],2.)+pow(lABxr1[1],2.)+pow(lABxr1[2],2.))
- height/pow((pow(CoreRadius,(2.*conf_VatistasN)) + pow(height,(2.*conf_VatistasN))),(1./conf_VatistasN))*
cosTheta2/(4.*pi) / sqrt(pow(lABxr1[0],2.)+pow(lABxr1[1],2.)+pow(lABxr1[2],2.));
GC[0] = BioConstant * lABxr1[0];
GC[1] = BioConstant * lABxr1[1];
GC[2] = BioConstant * lABxr1[2];
}
// A simple desingularisation
if ( isinf(GC[0]) || isnan(GC[0]) ) {
GC[0] = 0.;
}
if ( isinf(GC[1]) || isnan(GC[1]) ) {
GC[1] = 0.;
}
if ( isinf(GC[2]) || isnan(GC[2]) ) {
GC[2] = 0.;
}
}
/* The computational routine for BoundSingleGC */
void BoundSingleGC(const mwIndex InterestBE, const mwIndex BladeElement, const mwIndex BladeNo,
const double *WakeXYZ, const double *RQuarter, const double *BE_RControl, const double *BE_Gamma,
const mwSize NoOfBlades, const mwSize NoOfFilaments, const mwSize NoOfSegments, const mwSize NoOfWakeItems,
const mwSize NoOfElements,
const double conf_CompressibleBiot, const double conf_M, const double conf_CompressibleWakeMachMax,
const double conf_VortexCoreOffset,
const double conf_VortexDelta,
const double conf_kin_visc,
const double conf_VatistasN,
double *GC)
{
const mwSize NoOfDimensions = 3;
double rA[3];
double rB[3];
double rp[3];
double Mach;
double CompreBeta;
double CompreMach;
double rm[3];
double rmp[3];
double lAB[3];
double r1[3];
double r2[3];
double lAB_dot_r1;
double lAB_dot_r2;
double lABxr1[3];
double cosTheta1;
double cosTheta2;
double height;
double tbase;
double BioConstant;
const double pi = 3.1415926535897932384626433832795;
//-----------------------------------------------------------
// Vortex core calculations
//-----------------------------------------------------------
double Omegam, AzimuthStart, vDelta, TrailGamma, Core0, MidAge, CoreRadius;
const double CoreAlpha = 1.25643;
// Calculate the corresponding trailing vortex omega
Omegam = (wakeXYZ(BladeNo,NoOfElements+1,1,6) + wakeXYZ(BladeNo,NoOfElements+1,1,6))/2.;
// Calculate the vortex core radius
AzimuthStart = -conf_VortexCoreOffset;
// Calculate the bound vortex radius as equal to the starting radius
// of the corresponding trailing vortex
if (be_Gamma(1)<-800.)
{
vDelta = -conf_VortexDelta;
}
else
{
TrailGamma = fabs(be_Gamma(BladeElement));
vDelta = 1. + 2.*pow(10.,-4.) * TrailGamma / conf_kin_visc;
}
Core0 = sqrt(4.*CoreAlpha*vDelta*conf_kin_visc*(-AzimuthStart/Omegam));
CoreRadius = Core0;
//-----------------------------------------------------------
// Calculate the compressibility correction factor
//-----------------------------------------------------------
if (conf_CompressibleBiot>=2)
{
if (conf_M > conf_CompressibleWakeMachMax)
{
CompreMach = conf_CompressibleWakeMachMax;
}
else
{
CompreMach = conf_M;
}
}
else
{
CompreMach = 0.;
}
CompreBeta = 1./sqrt(1.-pow(CompreMach,2.));
/* Get the rA position vector */
rA[0] = rquarter(BladeNo,BladeElement,1);
rA[1] = rquarter(BladeNo,BladeElement,2);
rA[2] = CompreBeta * rquarter(BladeNo,BladeElement,3);
/* Get the rB position vector */
rB[0] = rquarter(BladeNo,BladeElement+1,1);
rB[1] = rquarter(BladeNo,BladeElement+1,2);
rB[2] = CompreBeta * rquarter(BladeNo,BladeElement+1,3);
/* Get the rp position vector */
rp[0] = be_RControl(1,InterestBE,1);
rp[1] = be_RControl(1,InterestBE,2);
rp[2] = CompreBeta * be_RControl(1,InterestBE,3);
// Calculate the AB mean point
rm[0] = (rA[0] + rB[0]) / 2.;
rm[1] = (rA[1] + rB[1]) / 2.;
rm[2] = (rA[2] + rB[2]) / 2.;
// Calculate the distance from the center point
rmp[0] = rp[0] - rm[0];
rmp[1] = rp[1] - rm[1];
rmp[2] = rp[2] - rm[2];
// Calculate the segment length vector
lAB[0] = rB[0] - rA[0];
lAB[1] = rB[1] - rA[1];
lAB[2] = rB[2] - rA[2];
// Calculate the r1=rAP vector
r1[0] = rp[0] - rA[0];
r1[1] = rp[1] - rA[1];
r1[2] = rp[2] - rA[2];
// Calculate the r2=rBP vector
r2[0] = rp[0] - rB[0];
r2[1] = rp[1] - rB[1];
r2[2] = rp[2] - rB[2];
// Calculate the lAB r1 dot product
lAB_dot_r1 = lAB[0]*r1[0] + lAB[1]*r1[1] + lAB[2]*r1[2];
// Calculate the lAB r2 dot product
lAB_dot_r2 = lAB[0]*r2[0] + lAB[1]*r2[1] + lAB[2]*r2[2];
// Now calculate the lAB x r1 cross product vector
lABxr1[0] = lAB[1]*r1[2] - lAB[2]*r1[1];
lABxr1[1] = lAB[2]*r1[0] - lAB[0]*r1[2];
lABxr1[2] = lAB[0]*r1[1] - lAB[1]*r1[0];
// Calculate the cosTheta1
cosTheta1 = lAB_dot_r1 / ( sqrt(pow(lAB[0],2.) + pow(lAB[1],2.) + pow(lAB[2],2.)) * sqrt(pow(r1[0],2.) + pow(r1[1],2.) + pow(r1[2],2.)) );
// Calculate the cosTheta2
cosTheta2 = lAB_dot_r2 / ( sqrt(pow(lAB[0],2.) + pow(lAB[1],2.) + pow(lAB[2],2.)) * sqrt(pow(r2[0],2.) + pow(r2[1],2.) + pow(r2[2],2.)) );
// Calculate the triangle height
tbase = sqrt(pow(r1[0],2.) + pow(r1[1],2.) + pow(r1[2],2.)) * cosTheta1;
height = sqrt(pow(r1[0],2.) + pow(r1[1],2.) + pow(r1[2],2.) - pow(tbase,2.));
// Finaly calculate the geometry coefficient by the Biot-Savart law
if (conf_VortexCoreOffset<0)
{
// No vortex core is used
//BioConstant = (cosTheta1-cosTheta2)/(4.*pi*height) / sqrt(pow(lABxr1[0],2.)+pow(lABxr1[1],2.)+pow(lABxr1[2],2.));
BioConstant = cosTheta1/(4.*pi*height) / sqrt(pow(lABxr1[0],2.)+pow(lABxr1[1],2.)+pow(lABxr1[2],2.))
-cosTheta2/(4.*pi*height) / sqrt(pow(lABxr1[0],2.)+pow(lABxr1[1],2.)+pow(lABxr1[2],2.));
GC[0] = BioConstant * lABxr1[0];
GC[1] = BioConstant * lABxr1[1];
GC[2] = BioConstant * lABxr1[2];
}
else
{
// Calculation includes vortex core
//BioConstant = height/pow((pow(CoreRadius,(2.*conf_VatistasN)) + pow(height,(2.*conf_VatistasN))),(1./conf_VatistasN))*
// (cosTheta1-cosTheta2)/(4.*pi) / sqrt(pow(lABxr1[0],2.)+pow(lABxr1[1],2.)+pow(lABxr1[2],2.));
BioConstant = height/pow((pow(CoreRadius,(2.*conf_VatistasN)) + pow(height,(2.*conf_VatistasN))),(1./conf_VatistasN))*
cosTheta1/(4.*pi) / sqrt(pow(lABxr1[0],2.)+pow(lABxr1[1],2.)+pow(lABxr1[2],2.))
- height/pow((pow(CoreRadius,(2.*conf_VatistasN)) + pow(height,(2.*conf_VatistasN))),(1./conf_VatistasN))*
cosTheta2/(4.*pi) / sqrt(pow(lABxr1[0],2.)+pow(lABxr1[1],2.)+pow(lABxr1[2],2.));
GC[0] = BioConstant * lABxr1[0];
GC[1] = BioConstant * lABxr1[1];
GC[2] = BioConstant * lABxr1[2];
}
if ((InterestBE==BladeElement) && (BladeNo==1))
{
GC[0] = 0.;
GC[1] = 0.;
GC[2] = 0.;
}
// A simple desingularisation
if ( isinf(GC[0]) || isnan(GC[0]) ) {
GC[0] = 0.;
}
if ( isinf(GC[1]) || isnan(GC[1]) ) {
GC[1] = 0.;
}
if ( isinf(GC[2]) || isnan(GC[2]) ) {
GC[2] = 0.;
}
}
/* The computational routine for TrailingFilamentGC */
void TrailingFilamentGC(const mwIndex InterestBE, const mwIndex Filament,
const double *WakeXYZ, const double *BE_RControl, const double *BE_Gamma,
const mwSize NoOfBlades, const mwSize NoOfFilaments, const mwSize NoOfSegments, const mwSize NoOfWakeItems,
const mwSize NoOfElements,
const double conf_CompressibleBiot, const double conf_M, const double conf_CompressibleWakeMachMax,
const double conf_VortexCoreOffset,
const double conf_VortexDelta,
const double conf_kin_visc,
const double conf_VatistasN,
double *GCTRfilament)
{
double GCsingle[3];
mwIndex Segment;
mwIndex BladeNo;
// Initialise the filament Geometric Coefficient
GCTRfilament[0] = 0.;
GCTRfilament[1] = 0.;
GCTRfilament[2] = 0.;
// Add influence for all blades and segments
for (BladeNo = 1; BladeNo <= NoOfBlades; BladeNo++)
{
for (Segment = 1; Segment <= NoOfSegments-1; Segment++)
{
GCsingle[0] = 0.;
GCsingle[1] = 0.;
GCsingle[2] = 0.;
/* call the single trailing segment routine */
if (Segment<=20)
{
TrailingSingleGC(InterestBE, Segment, Filament, BladeNo,
WakeXYZ, BE_RControl, BE_Gamma,
NoOfBlades, NoOfFilaments, NoOfSegments, NoOfWakeItems,
NoOfElements,
conf_CompressibleBiot, conf_M, conf_CompressibleWakeMachMax,
conf_VortexCoreOffset,
conf_VortexDelta,
conf_kin_visc,
conf_VatistasN,
GCsingle);
}
else
{
FarTrailingSingleGC(InterestBE, Segment, Filament, BladeNo,
WakeXYZ, BE_RControl,
NoOfBlades, NoOfFilaments, NoOfSegments, NoOfWakeItems,
NoOfElements,
conf_CompressibleBiot, conf_M, conf_CompressibleWakeMachMax,
GCsingle);
}
// Add the segment influence
GCTRfilament[0] += GCsingle[0];
GCTRfilament[1] += GCsingle[1];
GCTRfilament[2] += GCsingle[2];
}
}
}
/* The computational routine for BoundElementGC */
void BoundElementGC(const mwIndex InterestBE, const mwIndex BladeElement,
const double *WakeXYZ, const double *RQuarter, const double *BE_RControl, const double *BE_Gamma,
const mwSize NoOfBlades, const mwSize NoOfFilaments, const mwSize NoOfSegments, const mwSize NoOfWakeItems,
const mwSize NoOfElements,
const double conf_CompressibleBiot, const double conf_M, const double conf_CompressibleWakeMachMax,
const double conf_VortexCoreOffset,
const double conf_VortexDelta,
const double conf_kin_visc,
const double conf_VatistasN,
double *GCBoundElement)
{
double GCsingle[3];
mwIndex BladeNo;
// Initialise the bound element Geometric Coefficient
GCBoundElement[0] = 0.;
GCBoundElement[1] = 0.;
GCBoundElement[2] = 0.;
// Add influence for all blades
for (BladeNo = 1; BladeNo <= NoOfBlades; BladeNo++)
{
GCsingle[0] = 0.;
GCsingle[1] = 0.;
GCsingle[2] = 0.;
/* call the single bound segment routine */
BoundSingleGC(InterestBE, BladeElement, BladeNo,
WakeXYZ, RQuarter, BE_RControl, BE_Gamma,
NoOfBlades, NoOfFilaments, NoOfSegments, NoOfWakeItems,
NoOfElements,
conf_CompressibleBiot, conf_M, conf_CompressibleWakeMachMax,
conf_VortexCoreOffset,
conf_VortexDelta,
conf_kin_visc,
conf_VatistasN,
GCsingle);
// Add the segment influence
GCBoundElement[0] += GCsingle[0];
GCBoundElement[1] += GCsingle[1];
GCBoundElement[2] += GCsingle[2];
}
}
/* The computational routine for BoundElementGC */
//
// Calculate the Geometric Coefficient of a blade element on an
// Interest blade element
//
void BladeElementGC(const mwIndex InterestBE, const mwIndex BladeElement,
const double *WakeXYZ, const double *RQuarter, const double *BE_RControl, const double *BE_Gamma,
const mwSize NoOfBlades, const mwSize NoOfFilaments, const mwSize NoOfSegments, const mwSize NoOfWakeItems,
const mwSize NoOfElements,
const double conf_CompressibleBiot, const double conf_M, const double conf_CompressibleWakeMachMax,
const double conf_VortexCoreOffset,
const double conf_VortexDelta,
const double conf_kin_visc,
const double conf_VatistasN,
const double conf_BoundVorticity,
double *GCBladeElement)
{
mwIndex Filament;
double Temp1[3], Temp2[3], Temp3[3];
GCBladeElement[0] = 0.;
GCBladeElement[1] = 0.;
GCBladeElement[2] = 0.;
Filament = BladeElement;
TrailingFilamentGC(InterestBE, Filament,
WakeXYZ, BE_RControl, BE_Gamma,
NoOfBlades, NoOfFilaments, NoOfSegments, NoOfWakeItems,
NoOfElements,
conf_CompressibleBiot, conf_M, conf_CompressibleWakeMachMax,
conf_VortexCoreOffset,
conf_VortexDelta,
conf_kin_visc,
conf_VatistasN,
Temp1);
TrailingFilamentGC(InterestBE, Filament+1,
WakeXYZ, BE_RControl, BE_Gamma,
NoOfBlades, NoOfFilaments, NoOfSegments, NoOfWakeItems,
NoOfElements,
conf_CompressibleBiot, conf_M, conf_CompressibleWakeMachMax,
conf_VortexCoreOffset,
conf_VortexDelta,
conf_kin_visc,
conf_VatistasN,
Temp2);
if (conf_BoundVorticity>0)
{
BoundElementGC(InterestBE, BladeElement,
WakeXYZ, RQuarter, BE_RControl, BE_Gamma,
NoOfBlades, NoOfFilaments, NoOfSegments, NoOfWakeItems,
NoOfElements,
conf_CompressibleBiot, conf_M, conf_CompressibleWakeMachMax,
conf_VortexCoreOffset,
conf_VortexDelta,
conf_kin_visc,
conf_VatistasN,
Temp3);
}
else
{
Temp3[0] = 0.;
Temp3[1] = 0.;
Temp3[2] = 0.;
}
GCBladeElement[0] = Temp2[0] - Temp1[0] + Temp3[0];
GCBladeElement[1] = Temp2[1] - Temp1[1] + Temp3[1];
GCBladeElement[2] = Temp2[2] - Temp1[2] + Temp3[2];
}