ENH: Added new rotorDiskSource momentum source model for rotor blades/airfoils

This commit is contained in:
andy
2011-10-20 16:40:04 +01:00
parent 3b0e45371e
commit dd506c3f14
14 changed files with 2249 additions and 0 deletions

View File

@ -390,6 +390,12 @@ $(basicSource)/actuationDiskSource/actuationDiskSource.C
$(basicSource)/radialActuationDiskSource/radialActuationDiskSource.C
$(basicSource)/explicitSource/explicitSource.C
$(basicSource)/explicitSetValue/explicitSetValue.C
$(basicSource)/rotorDiskSource/rotorDiskSource.C
$(basicSource)/rotorDiskSource/bladeModel/bladeModel.C
$(basicSource)/rotorDiskSource/profileModel/profileModel.C
$(basicSource)/rotorDiskSource/profileModel/profileModelList.C
$(basicSource)/rotorDiskSource/profileModel/lookup/lookupProfile.C
$(basicSource)/rotorDiskSource/profileModel/series/seriesProfile.C
LIB = $(FOAM_LIBBIN)/libfiniteVolume

View File

@ -0,0 +1,195 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "bladeModel.H"
#include "unitConversion.H"
#include "Tuple2.H"
#include "vector.H"
#include "IFstream.H"
// * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
bool Foam::bladeModel::readFromFile() const
{
return fName_ != fileName::null;
}
void Foam::bladeModel::interpolateWeights
(
const scalar& xIn,
const List<scalar>& values,
label& i1,
label& i2,
scalar& ddx
) const
{
scalar x = -GREAT;
label nElem = values.size();
i2 = 0;
while ((x < xIn) && (i2 < nElem))
{
x = values[i2];
i2++;
}
if (i2 == 0)
{
i1 = i2;
ddx = 0.0;
return;
}
else if (i2 == values.size())
{
i2 = values.size() - 1;
i1 = i2;
ddx = 0.0;
return;
}
else
{
i1 = i2 - 1;
ddx = (xIn - values[i1])/(values[i2] - values[i1]);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::bladeModel::bladeModel(const dictionary& dict)
:
profileName_(),
profileID_(),
radius_(),
twist_(),
chord_(),
fName_(fileName::null)
{
List<Tuple2<word, vector> > data;
if (readFromFile())
{
IFstream is(fName_);
is >> data;
}
else
{
dict.lookup("data") >> data;
}
if (data.size() > 0)
{
profileName_.setSize(data.size());
profileID_.setSize(data.size());
radius_.setSize(data.size());
twist_.setSize(data.size());
chord_.setSize(data.size());
forAll(data, i)
{
profileName_[i] = data[i].first();
profileID_[i] = -1;
radius_[i] = data[i].second()[0];
twist_[i] = degToRad(data[i].second()[1]);
chord_[i] = data[i].second()[2];
}
}
else
{
FatalErrorIn
(
"Foam::bladeModel::bladeModel"
"("
"const dictionary&, "
"const word&"
")"
) << "No blade data specified" << exit(FatalError);
}
}
// * * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * //
Foam::bladeModel::~bladeModel()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
const Foam::List<Foam::word>& Foam::bladeModel::profileName() const
{
return profileName_;
}
const Foam::List<Foam::label>& Foam::bladeModel::profileID() const
{
return profileID_;
}
const Foam::List<Foam::scalar>& Foam::bladeModel::radius() const
{
return radius_;
}
const Foam::List<Foam::scalar>& Foam::bladeModel::twist() const
{
return twist_;
}
const Foam::List<Foam::scalar>& Foam::bladeModel::chord() const
{
return chord_;
}
Foam::List<Foam::label>& Foam::bladeModel::profileID()
{
return profileID_;
}
void Foam::bladeModel::interpolate
(
const scalar radius,
scalar& twist,
scalar& chord,
label& i1,
label& i2,
scalar& invDr
) const
{
interpolateWeights(radius, radius_, i1, i2, invDr);
twist = invDr*(twist_[i2] - twist_[i1]) + twist_[i1];
chord = invDr*(chord_[i2] - chord_[i1]) + chord_[i1];
}
// ************************************************************************* //

View File

@ -0,0 +1,151 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::bladeModel
Description
Blade model class
SourceFiles
bladeModel.C
\*---------------------------------------------------------------------------*/
#ifndef bladeModel_H
#define bladeModel_H
#include "List.H"
#include "dictionary.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class bladeModel Declaration
\*---------------------------------------------------------------------------*/
class bladeModel
{
protected:
// Protected data
//- Corresponding profile name per section
List<word> profileName_;
//- Corresponding profile ID per section
List<label> profileID_;
//- Radius [m]
List<scalar> radius_;
//- Twist [deg] on input, converted to [rad]
List<scalar> twist_;
//- Chord [m]
List<scalar> chord_;
//- File name (optional)
fileName fName_;
// Protected Member Functions
//- Return ture if file name is set
bool readFromFile() const;
//- Return the interpolation indices and gradient
void interpolateWeights
(
const scalar& xIn,
const List<scalar>& values,
label& i1,
label& i2,
scalar& ddx
) const;
public:
//- Constructor
bladeModel(const dictionary& dict);
//- Destructor
virtual ~bladeModel();
// Member functions
// Access
//- Return const access to the profile name list
const List<word>& profileName() const;
//- Return const access to the profile ID list
const List<label>& profileID() const;
//- Return const access to the radius list
const List<scalar>& radius() const;
//- Return const access to the twist list
const List<scalar>& twist() const;
//- Return const access to the chord list
const List<scalar>& chord() const;
// Edit
//- Return non-const access to the profile ID list
List<label>& profileID();
// Evaluation
//- Return the twist and chord for a given radius
virtual void interpolate
(
const scalar radius,
scalar& twist,
scalar& chord,
label& i1,
label& i2,
scalar& invDr
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,148 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "lookupProfile.H"
#include "addToRunTimeSelectionTable.H"
#include "vector.H"
#include "unitConversion.H"
#include "IFstream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(lookupProfile, 0);
addToRunTimeSelectionTable(profileModel, lookupProfile, dictionary);
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::lookupProfile::interpolateWeights
(
const scalar& xIn,
const List<scalar>& values,
label& i1,
label& i2,
scalar& ddx
) const
{
scalar x = -GREAT;
label nElem = values.size();
i2 = 0;
while ((x < xIn) && (i2 < nElem))
{
x = values[i2];
i2++;
}
if (i2 == 0)
{
i1 = i2;
ddx = 0.0;
return;
}
else if (i2 == values.size())
{
i2 = values.size() - 1;
i1 = i2;
ddx = 0.0;
return;
}
else
{
i1 = i2 - 1;
ddx = (xIn - values[i1])/(values[i2] - values[i1]);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::lookupProfile::lookupProfile
(
const dictionary& dict,
const word& modelName
)
:
profileModel(dict, modelName),
AOA_(),
Cd_(),
Cl_()
{
List<vector> data;
if (readFromFile())
{
IFstream is(fName_);
is >> data;
}
else
{
dict.lookup("data") >> data;
}
if (data.size() > 0)
{
AOA_.setSize(data.size());
Cd_.setSize(data.size());
Cl_.setSize(data.size());
forAll(data, i)
{
AOA_[i] = degToRad(data[i][0]);
Cd_[i] = data[i][1];
Cl_[i] = data[i][2];
}
}
else
{
FatalErrorIn
(
"Foam::lookupProfile::lookupProfile"
"("
"const dictionary&, "
"const word&"
")"
) << "No profile data specified" << exit(FatalError);
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::lookupProfile::Cdl(const scalar alpha, scalar& Cd, scalar& Cl) const
{
label i1 = -1;
label i2 = -1;
scalar invAlpha = -1.0;
interpolateWeights(alpha, AOA_, i1, i2, invAlpha);
Cd = invAlpha*(Cd_[i2] - Cd_[i1]) + Cd_[i1];
Cl = invAlpha*(Cl_[i2] - Cl_[i1]) + Cl_[i1];
}
// ************************************************************************* //

View File

@ -0,0 +1,124 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::lookupProfile
Description
Look-up based profile data - drag and lift coefficients are lineraly
interpolated based on the supplied angle of attack
Input in list format:
data
(
(AOA1 Cd1 Cl2)
(AOA2 Cd2 Cl2)
...
(AOAN CdN CdN)
);
where:
AOA = angle of attack [deg] converted to [rad] internally
Cd = drag coefficient
Cl = lift coefficient
SourceFiles
lookupProfile.C
\*---------------------------------------------------------------------------*/
#ifndef lookupProfile_H
#define lookupProfile_H
#include "profileModel.H"
#include "List.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class lookupProfile Declaration
\*---------------------------------------------------------------------------*/
class lookupProfile
:
public profileModel
{
protected:
// Protected data
//- List of angle-of-attack values [deg] on input, converted to [rad]
List<scalar> AOA_;
//- List of drag coefficient values
List<scalar> Cd_;
//- List of lift coefficient values
List<scalar> Cl_;
// Protected Member Functions
//- Return the interpolation indices and gradient
void interpolateWeights
(
const scalar& xIn,
const List<scalar>& values,
label& i1,
label& i2,
scalar& ddx
) const;
public:
//- Runtime type information
TypeName("lookup");
//- Constructor
lookupProfile(const dictionary& dict, const word& modelName);
// Member functions
// Evaluation
//- Return the Cd and Cl for a given angle-of-attack
virtual void Cdl(const scalar alpha, scalar& Cd, scalar& Cl) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,99 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "profileModel.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(profileModel, 0);
defineRunTimeSelectionTable(profileModel, dictionary);
}
// * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
bool Foam::profileModel::readFromFile() const
{
return fName_ != fileName::null;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::profileModel::profileModel(const dictionary& dict, const word& name)
:
dict_(dict),
name_(name),
fName_(fileName::null)
{
dict.readIfPresent("fileName", fName_);
}
// * * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * //
Foam::profileModel::~profileModel()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
const Foam::word& Foam::profileModel::name() const
{
return name_;
}
Foam::autoPtr<Foam::profileModel> Foam::profileModel::New
(
const dictionary& dict
)
{
const word& modelName(dict.dictName());
const word modelType(dict.lookup("type"));
Info<< " - creating " << modelType << " profile " << modelName << endl;
dictionaryConstructorTable::iterator cstrIter =
dictionaryConstructorTablePtr_->find(modelType);
if (cstrIter == dictionaryConstructorTablePtr_->end())
{
FatalErrorIn("profileModel::New(const dictionary&)")
<< "Unknown profile model type " << modelType
<< nl << nl
<< "Valid model types are :" << nl
<< dictionaryConstructorTablePtr_->sortedToc()
<< exit(FatalError);
}
return autoPtr<profileModel>(cstrIter()(dict, modelName));
}
// ************************************************************************* //

View File

@ -0,0 +1,136 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::profileModel
Description
Base class for profile models
SourceFiles
profileModel.C
\*---------------------------------------------------------------------------*/
#ifndef profileModel_H
#define profileModel_H
#include "autoPtr.H"
#include "runTimeSelectionTables.H"
#include "dictionary.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class profileModel Declaration
\*---------------------------------------------------------------------------*/
class profileModel
{
protected:
// Protected data
//- Coefficients dictionary
const dictionary dict_;
//- Name of profile model
const word name_;
//- File name (optional)
fileName fName_;
// Protected Member Functions
//- Return ture if file name is set
bool readFromFile() const;
public:
//- Runtime type information
TypeName("profileModel");
// Declare run-time constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
profileModel,
dictionary,
(
const dictionary& dict,
const word& modelName
),
(dict, modelName)
);
// Selectors
//- Return a reference to the selected basicSource model
static autoPtr<profileModel> New(const dictionary& dict);
//- Constructor
profileModel(const dictionary& dict, const word& modelName);
//- Destructor
virtual ~profileModel();
// Member functions
// Access
//- Return const access to the source name
const word& name() const;
// Evaluation
//- Return the Cd and Cl for a given angle-of-attack
virtual void Cdl
(
const scalar alpha,
scalar& Cd,
scalar& Cl
) const = 0;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,121 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "profileModelList.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::profileModelList::profileModelList
(
const dictionary& dict,
const bool readFields
)
:
PtrList<profileModel>(),
dict_(dict)
{
if (readFields)
{
wordList modelNames(dict.toc());
Info<< " Constructing blade profiles:" << endl;
if (modelNames.size() > 0)
{
this->setSize(modelNames.size());
forAll(modelNames, i)
{
const word& modelName = modelNames[i];
this->set
(
i,
profileModel::New(dict.subDict(modelName))
);
}
}
else
{
Info<< " none" << endl;
}
}
}
// * * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * //
Foam::profileModelList::~profileModelList()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::profileModelList::connectBlades
(
const List<word>& names,
List<label>& addr
) const
{
// construct the addressing between blade sections and profiles
forAll(names, bI)
{
label index = -1;
const word& profileName = names[bI];
forAll(*this, pI)
{
const profileModel& pm = this->operator[](pI);
if (pm.name() == profileName)
{
index = pI;
break;
}
}
if (index == -1)
{
List<word> profileNames(size());
forAll(*this, i)
{
const profileModel& pm = this->operator[](i);
profileNames[i] = pm.name();
}
FatalErrorIn("void Foam::connectBlades(List<word>& names) const")
<< "Profile " << profileName << " could not be found "
<< "in profile list. Available profiles are"
<< profileNames << exit(FatalError);
}
else
{
addr[bI] = index;
}
}
}
// ************************************************************************* //

View File

@ -0,0 +1,91 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::profileModelList
Description
Base class for profile models
SourceFiles
profileModel.C
\*---------------------------------------------------------------------------*/
#ifndef profileModelList_H
#define profileModelList_H
#include "PtrList.H"
#include "profileModel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class profileModelList Declaration
\*---------------------------------------------------------------------------*/
class profileModelList
:
public PtrList<profileModel>
{
protected:
// Protected data
//- Dictionary
const dictionary dict_;
public:
//- Constructor
profileModelList(const dictionary& dict, const bool readFields = true);
//- Destructor
~profileModelList();
// Member Functions
//- Set blade->profile addressing
void connectBlades
(
const List<word>& names,
List<label>& addr
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,116 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "seriesProfile.H"
#include "addToRunTimeSelectionTable.H"
#include "IFstream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(seriesProfile, 0);
addToRunTimeSelectionTable(profileModel, seriesProfile, dictionary);
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
Foam::scalar Foam::seriesProfile::evaluate
(
const scalar& xIn,
const List<scalar>& values
) const
{
scalar result = 0.0;
forAll(values, i)
{
result += values[i]*cos((i+1)*xIn);
}
return result;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::seriesProfile::seriesProfile
(
const dictionary& dict,
const word& modelName
)
:
profileModel(dict, modelName),
CdCoeffs_(),
ClCoeffs_()
{
if (readFromFile())
{
IFstream is(fName_);
is >> CdCoeffs_ >> ClCoeffs_;
}
else
{
dict.lookup("CdCoeffs") >> CdCoeffs_;
dict.lookup("ClCoeffs") >> ClCoeffs_;
}
if (CdCoeffs_.empty())
{
FatalErrorIn
(
"Foam::seriesProfile::seriesProfile"
"("
"const dictionary&, "
"const word&"
")"
) << "CdCoeffs must be specified" << exit(FatalError);
}
if (ClCoeffs_.empty())
{
FatalErrorIn
(
"Foam::seriesProfile::seriesProfile"
"("
"const dictionary&, "
"const word&"
")"
) << "ClCoeffs must be specified" << exit(FatalError);
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::seriesProfile::Cdl(const scalar alpha, scalar& Cd, scalar& Cl) const
{
Cd = evaluate(alpha, CdCoeffs_);
Cl = evaluate(alpha, ClCoeffs_);
}
// ************************************************************************* //

View File

@ -0,0 +1,116 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::seriesProfile
Description
Series-up based profile data - drag and lift coefficients computed as
sum of cosine series
Cd = sum_i(CdCoeff)*cos(i*AOA)
Cl = sum_i(ClCoeff)*cos(i*AOA)
where:
AOA = angle of attack [deg] converted to [rad] internally
Cd = drag coefficent
Cl = lift coefficent
Input in two (arbitrary length) lists:
CdCoeffs (coeff1 coeff2 ... coeffN);
ClCoeffs (coeff1 coeff2 ... coeffN);
SourceFiles
seriesProfile.C
\*---------------------------------------------------------------------------*/
#ifndef seriesProfile_H
#define seriesProfile_H
#include "profileModel.H"
#include "List.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class seriesProfile Declaration
\*---------------------------------------------------------------------------*/
class seriesProfile
:
public profileModel
{
protected:
// Protected data
//- List of drag coefficient values
List<scalar> CdCoeffs_;
//- List of lift coefficient values
List<scalar> ClCoeffs_;
// Protected Member Functions
//- Evaluate
scalar evaluate
(
const scalar& xIn,
const List<scalar>& values
) const;
public:
//- Runtime type information
TypeName("series");
//- Constructor
seriesProfile(const dictionary& dict, const word& modelName);
// Member functions
// Evaluation
//- Return the Cd and Cl for a given angle-of-attack
virtual void Cdl(const scalar alpha, scalar& Cd, scalar& Cl) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,492 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "rotorDiskSource.H"
#include "addToRunTimeSelectionTable.H"
#include "mathematicalConstants.H"
#include "unitConversion.H"
#include "geometricOneField.H"
using namespace Foam::constant;
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(rotorDiskSource, 0);
addToRunTimeSelectionTable(basicSource, rotorDiskSource, dictionary);
template<> const char* NamedEnum<rotorDiskSource::geometryModeType, 2>::
names[] =
{
"auto",
"specified"
};
const NamedEnum<rotorDiskSource::geometryModeType, 2>
rotorDiskSource::geometryModeTypeNames_;
template<> const char* NamedEnum<rotorDiskSource::inletFlowType, 3>::
names[] =
{
"fixed",
"surfaceNormal",
"local"
};
const NamedEnum<rotorDiskSource::inletFlowType, 3>
rotorDiskSource::inletFlowTypeNames_;
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::rotorDiskSource::checkData()
{
switch (selectionMode())
{
case smCellSet:
case smCellZone:
case smAll:
{
// set the profile ID for each blade section
profiles_.connectBlades(blade_.profileName(), blade_.profileID());
switch (inletFlow_)
{
case ifFixed:
{
coeffs_.lookup("inletVelocity") >> inletVelocity_;
break;
}
case ifSurfaceNormal:
{
scalar UIn(readScalar(coeffs_.lookup("inletNormalVelocity")));
inletVelocity_ = -coordSys_.e3()*UIn;
break;
}
case ifLocal:
{
// do nothing
break;
}
default:
{
FatalErrorIn("void rotorDiskSource::checkData()")
<< "Unknown inlet velocity type" << abort(FatalError);
}
}
break;
}
default:
{
FatalErrorIn("void rotorDiskSource::checkData()")
<< "Source cannot be used with '"
<< selectionModeTypeNames_[selectionMode()]
<< "' mode. Please use one of: " << nl
<< selectionModeTypeNames_[smCellSet] << nl
<< selectionModeTypeNames_[smCellZone] << nl
<< selectionModeTypeNames_[smAll]
<< exit(FatalError);
}
}
}
void Foam::rotorDiskSource::setFaceArea(vector& axis, const bool correct)
{
// calculate rotor face areas
const vectorField& Sf = mesh_.Sf();
const scalarField& magSf = mesh_.magSf();
boolList selectedCells(mesh_.nCells(), false);
boolList processedFaces(mesh_.nFaces(), false);
UIndirectList<bool>(selectedCells, cells_) = boolList(cells_.size(), true);
vector n = vector::zero;
label nFace = 0;
area_ = 0.0;
forAll(cells_, i)
{
const label cellI = cells_[i];
const cell& cFaces = mesh_.cells()[cellI];
forAll(cFaces, j)
{
const label faceI = cFaces[j];
label own = mesh_.owner()[faceI];
label nbr = mesh_.neighbour()[faceI];
if
(
!processedFaces[faceI]
&& (selectedCells[own] != selectedCells[nbr])
)
{
if (selectedCells[own])
{
if (((Sf[faceI]/magSf[faceI]) & axis) > 0.8)
{
area_[i] += magSf[faceI];
n += Sf[faceI];
nFace++;
}
}
else if (selectedCells[nbr])
{
if (((-Sf[faceI]/magSf[faceI]) & axis) > 0.8)
{
area_[i] += magSf[faceI];
n -= Sf[faceI];
nFace++;
}
}
processedFaces[faceI] = true;
}
}
}
if (correct && (nFace > 0))
{
axis = n/mag(n);
}
}
void Foam::rotorDiskSource::createCoordinateSystem()
{
// construct the local rotor co-prdinate system
vector origin(vector::zero);
vector axis(vector::zero);
vector refDir(vector::zero);
geometryModeType gm =
geometryModeTypeNames_.read(coeffs_.lookup("geometryMode"));
switch (gm)
{
case gmAuto:
{
// determine rotation origin
scalar sumV = 0.0;
const scalarField& V = mesh_.V();
const vectorField& C = mesh_.C();
forAll(cells_, i)
{
const label cellI = cells_[i];
sumV += V[cellI];
origin += V[cellI]*C[cellI];
}
origin /= sumV;
// determine first radial vector
vector dx1(vector::zero);
scalar magR = -GREAT;
forAll(cells_, i)
{
const label cellI = cells_[i];
vector test = C[cellI] - origin;
if (mag(test) > magR)
{
dx1 = test;
magR = mag(test);
}
}
// determine second radial vector and cross to determine axis
forAll(cells_, i)
{
const label cellI = cells_[i];
vector dx2 = C[cellI] - origin;
if (mag(dx2) > 0.5*magR)
{
axis = dx1 ^ dx2;
if (mag(axis) > SMALL)
{
break;
}
}
}
axis /= mag(axis);
// axis direction is somewhat arbitrary - check if user needs
// needs to reverse
bool reverse(readBool(coeffs_.lookup("reverseAxis")));
if (reverse)
{
axis *= -1.0;
}
coeffs_.lookup("refDirection") >> refDir;
// set the face areas and apply correction to calculated axis
// e.g. if cellZone is more than a single layer in thickness
setFaceArea(axis, true);
break;
}
case gmSpecified:
{
coeffs_.lookup("origin") >> origin;
coeffs_.lookup("axis") >> axis;
coeffs_.lookup("refDirection") >> refDir;
setFaceArea(axis, false);
break;
}
default:
{
FatalErrorIn
(
"rotorDiskSource::createCoordinateSystem(const geometryMode&);"
) << "Unknown geometryMode " << geometryModeTypeNames_[gm]
<< ". Available geometry modes include " << geometryModeTypeNames_
<< exit(FatalError);
}
}
coordSys_ = cylindricalCS("rotorCoordSys", origin, axis, refDir, false);
const scalar sumArea = gSum(area_);
const scalar diameter = Foam::sqrt(4.0*sumArea/mathematical::pi);
Info<< " Rotor gometry:" << nl
<< " - disk diameter = " << diameter << nl
<< " - disk area = " << sumArea << nl
<< " - origin = " << coordSys_.origin() << nl
<< " - r-axis = " << coordSys_.e1() << nl
<< " - psi-axis = " << coordSys_.e2() << nl
<< " - z-axis = " << coordSys_.e3() << endl;
}
void Foam::rotorDiskSource::constructGeometry()
{
const vectorField& C = mesh_.C();
const vector rDir = coordSys_.e1();
const vector zDir = coordSys_.e3();
forAll(cells_, i)
{
const label cellI = cells_[i];
// position in rotor co-ordinate system
x_[i] = coordSys_.localPosition(C[cellI]);
// cache max radius
rMax_ = max(rMax_, x_[i].x());
// determine swept angle relative to rDir axis
scalar psi = x_[i].y() - rDir.y();
// blade flap angle
scalar beta = flap_.beta0 - flap_.beta1*cos(psi) - flap_.beta2*sin(psi);
// determine rotation tensor to convert into the rotor cone plane
scalar c = cos(-beta);
scalar s = sin(-beta);
R_[i] = tensor(1, 0, 0, 0, c, s, 0, -s, c);
// geometric angle of attack - not including twist
alphag_[i] = trim_.alphaC - trim_.A*cos(psi) - trim_.B*sin(psi);
}
}
Foam::tmp<Foam::vectorField> Foam::rotorDiskSource::inflowVelocity
(
const volVectorField& U
) const
{
switch (inletFlow_)
{
case ifFixed:
case ifSurfaceNormal:
{
return tmp<vectorField>
(
new vectorField(mesh_.nCells(), inletVelocity_)
);
break;
}
case ifLocal:
{
return U.internalField();
break;
}
default:
{
FatalErrorIn
(
"Foam::tmp<Foam::vectorField> "
"Foam::rotorDiskSource::inflowVelocity"
"(const volVectorField&) const"
) << "Unknown inlet flow specification" << abort(FatalError);
}
}
return tmp<vectorField>(new vectorField(mesh_.nCells(), vector::zero));
}
// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
Foam::rotorDiskSource::rotorDiskSource
(
const word& name,
const word& modelType,
const dictionary& dict,
const fvMesh& mesh
)
:
basicSource(name, modelType, dict, mesh),
coeffs_(dict_.subDict(type() + "Coeffs")),
rhoName_("none"),
omega_(0.0),
nBlades_(0),
inletFlow_(ifLocal),
inletVelocity_(vector::zero),
tipEffect_(1.0),
flap_(),
trim_(),
blade_(coeffs_.subDict("blade")),
profiles_(coeffs_.subDict("profiles")),
x_(cells_.size(), vector::zero),
R_(cells_.size(), I),
alphag_(cells_.size(), 0.0),
area_(cells_.size(), 0.0),
coordSys_(false),
rMax_(0.0)
{
read(dict);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::rotorDiskSource::~rotorDiskSource()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::rotorDiskSource::addSu(fvMatrix<vector>& UEqn)
{
// add source to lhs of eqn
const volVectorField& U = UEqn.psi();
if (UEqn.dimensions() == dimForce)
{
coeffs_.lookup("rhoName") >> rhoName_;
const volScalarField& rho =
mesh_.lookupObject<volScalarField>(rhoName_);
UEqn += calculateForces
(
rho.internalField(),
inflowVelocity(U),
dimForce/dimVolume
);
}
else
{
UEqn += calculateForces
(
oneField(),
inflowVelocity(U),
dimForce/dimVolume/dimDensity
);
}
}
void Foam::rotorDiskSource::addSu(fvMatrix<scalar>& UEqn)
{
// do nothing
}
void Foam::rotorDiskSource::writeData(Ostream& os) const
{
os << indent << name_ << endl;
dict_.write(os);
}
bool Foam::rotorDiskSource::read(const dictionary& dict)
{
if (basicSource::read(dict))
{
coeffs_ = dict.subDict(type() + "Coeffs");
scalar rpm(readScalar(coeffs_.lookup("rpm")));
omega_ = rpm/60.0*mathematical::twoPi;
coeffs_.lookup("nBlades") >> nBlades_;
inletFlow_ = inletFlowTypeNames_.read(coeffs_.lookup("inletFlowType"));
coeffs_.lookup("tipEffect") >> tipEffect_;
const dictionary& flapCoeffs(coeffs_.subDict("flapCoeffs"));
flapCoeffs.lookup("beta0") >> flap_.beta0;
flapCoeffs.lookup("beta1") >> flap_.beta1;
flapCoeffs.lookup("beta2") >> flap_.beta2;
flap_.beta0 = degToRad(flap_.beta0);
const dictionary& trimCoeffs(coeffs_.subDict("trimCoeffs"));
trimCoeffs.lookup("alphaC") >> trim_.alphaC;
trimCoeffs.lookup("A") >> trim_.A;
trimCoeffs.lookup("B") >> trim_.B;
trim_.alphaC = degToRad(trim_.alphaC);
checkData();
createCoordinateSystem();
constructGeometry();
if (debug)
{
writeField("alphag", alphag_, true);
writeField("faceArea", area_, true);
}
return true;
}
else
{
return false;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,249 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::rotorDiskSource
Description
Cell-zone based momemtum source
Source approximates the mean effects of rotor forces on a cylindrical
region within the domain
SourceFiles
rotorDiskSource.C
rotorDiskSourceTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef rotorDiskSource_H
#define rotorDiskSource_H
#include "basicSource.H"
#include "cylindricalCS.H"
#include "NamedEnum.H"
#include "bladeModel.H"
#include "profileModelList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class rotorDiskSource Declaration
\*---------------------------------------------------------------------------*/
class rotorDiskSource
:
public basicSource
{
public:
enum geometryModeType
{
gmAuto,
gmSpecified
};
static const NamedEnum<geometryModeType, 2> geometryModeTypeNames_;
enum inletFlowType
{
ifFixed,
ifSurfaceNormal,
ifLocal
};
static const NamedEnum<inletFlowType, 3> inletFlowTypeNames_;
protected:
// Helper structures to encapsulate flap and trim data
struct flapData
{
scalar beta0; // coning angle [deg]
scalar beta1; // lateral flapping coeff
scalar beta2; // longitudinal flapping coeff
};
struct trimData
{
scalar alphaC; // collective pitch angle [deg]
scalar A; // lateral cyclic coeff
scalar B; // longitudinal cyclic coeff
};
// Protected data
//- Coefficients dictionary
dictionary coeffs_;
//- Name of density field
word rhoName_;
//- Rotational speed [rad/s]
scalar omega_;
//- Number of blades
label nBlades_;
//- Inlet flow type
inletFlowType inletFlow_;
//- Inlet velocity for specified iinflow
vector inletVelocity_;
//- Tip effect [0-1]
// Ratio of blade radius beyond which lift=0
scalar tipEffect_;
//- Blade flap coefficients [rad/s]
flapData flap_;
//- Blad trim coefficients
trimData trim_;
//- Blade data
bladeModel blade_;
//- Profile data
profileModelList profiles_;
//- Cell centre positions in local rotor frame (Cartesian x, y, z)
List<point> x_;
//- Rotation tensor for flap angle
List<tensor> R_;
//- Geometric angle of attack [deg]
List<scalar> alphag_;
//- Area [m2]
List<scalar> area_;
//- Rotor co-ordinate system (r, theta, z)
cylindricalCS coordSys_;
//- Maximum radius
scalar rMax_;
// Protected Member Functions
//- Check data
void checkData();
//- Set the face areas per cell, and optionally correct the rotor axis
void setFaceArea(vector& axis, const bool correct);
//- Create the co-ordinate system
void createCoordinateSystem();
//- Construct geometry
void constructGeometry();
//- Return the inlet flow field
tmp<vectorField> inflowVelocity(const volVectorField& U) const;
//- Calculate forces
template<class RhoType>
tmp<volVectorField> calculateForces
(
const RhoType& rho,
const vectorField& U,
const dimensionSet& dims
);
//- Helper function to write rotor values
template<class Type>
void writeField
(
const word& name,
const List<Type>& values,
const bool writeNow = false
) const;
public:
//- Runtime type information
TypeName("rotorDisk");
// Constructors
//- Construct from components
rotorDiskSource
(
const word& name,
const word& modelType,
const dictionary& dict,
const fvMesh& mesh
);
//- Destructor
virtual ~rotorDiskSource();
// Member Functions
// Source term addition
//- Source term to fvMatrix<vector>
virtual void addSu(fvMatrix<vector>& UEqn);
//- Source term to fvMatrix<scalar>
virtual void addSu(fvMatrix<scalar>& UEqn);
// I-O
//- Write the source properties
virtual void writeData(Ostream&) const;
//- Read source dictionary
virtual bool read(const dictionary& dict);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "rotorDiskSourceTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,205 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "rotorDiskSource.H"
#include "addToRunTimeSelectionTable.H"
#include "mathematicalConstants.H"
#include "unitConversion.H"
using namespace Foam::constant;
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template<class Type>
void Foam::rotorDiskSource::writeField
(
const word& name,
const List<Type>& values,
const bool writeNow
) const
{
typedef GeometricField<Type, fvPatchField, volMesh> fieldType;
if (mesh_.time().outputTime() || writeNow)
{
tmp<fieldType> tfld
(
new fieldType
(
IOobject
(
name,
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensioned<Type>("zero", dimless, pTraits<Type>::zero)
)
);
Field<Type>& fld = tfld().internalField();
if (cells_.size() != values.size())
{
FatalErrorIn("") << "cells_.size() != values_.size()"
<< abort(FatalError);
}
forAll(cells_, i)
{
const label cellI = cells_[i];
fld[cellI] = values[i];
}
tfld().write();
}
}
template<class RhoType>
Foam::tmp<Foam::volVectorField> Foam::rotorDiskSource::calculateForces
(
const RhoType& rho,
const vectorField& U,
const dimensionSet& dims
)
{
tmp<volVectorField> tForce
(
new volVectorField
(
IOobject
(
"rotorForce",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedVector("zero", dims, vector::zero)
)
);
vectorField& force = tForce().internalField();
const scalarField& V = mesh_.V();
// logging info
scalar dragEff = 0.0;
scalar liftEff = 0.0;
scalar AOAmin = GREAT;
scalar AOAmax = -GREAT;
forAll(cells_, i)
{
if (area_[i] > ROOTVSMALL)
{
const label cellI = cells_[i];
const scalar radius = x_[i].x();
// apply correction due to flap in cartesian frame
vector Uc = R_[i] & U[cellI];
// velocity in local reference frame
Uc = coordSys_.localVector(Uc);
// set radial component of velocity to zero
Uc.x() = 0.0;
// remove blade linear velocity from blade normal component
Uc.y() -= radius*omega_;
// velocity magnitude
scalar magUc = mag(Uc);
// determine blade data for this radius
// i1 = index of upper bound data point in blade list
scalar twist = 0.0;
scalar chord = 0.0;
label i1 = -1;
label i2 = -1;
scalar invDr = 0.0;
blade_.interpolate(radius, twist, chord, i1, i2, invDr);
// effective angle of attack
scalar alphaEff = alphag_[i] + twist - atan(Uc.z()/Uc.y());
AOAmin = min(AOAmin, alphaEff);
AOAmax = max(AOAmax, alphaEff);
// determine profile data for this radius and angle of attack
const label profile1 = blade_.profileID()[i1];
const label profile2 = blade_.profileID()[i2];
scalar Cd1 = 0.0;
scalar Cl1 = 0.0;
profiles_[profile1].Cdl(alphaEff, Cd1, Cl1);
scalar Cd2 = 0.0;
scalar Cl2 = 0.0;
profiles_[profile2].Cdl(alphaEff, Cd2, Cl2);
scalar Cd = invDr*(Cd2 - Cd1) + Cd1;
scalar Cl = invDr*(Cl2 - Cl1) + Cl1;
// apply tip effect for blade lift
scalar tipFactor = 1.0;
if (radius/rMax_ > tipEffect_)
{
tipFactor = 0.0;
}
// calculate forces
scalar pDyn = 0.5*rho[cellI]*sqr(magUc);
scalar f = pDyn*chord*nBlades_*area_[i]/(mathematical::twoPi);
vector localForce = vector(0.0, f*Cd, tipFactor*f*Cl);
// accumulate forces
dragEff += localForce.y();
liftEff += localForce.z();
// convert force to global cartesian co-ordinate system
force[cellI] = coordSys_.globalVector(localForce);
force[cellI] /= V[cellI];
}
}
Info<< type() << " output:" << nl
<< " min/max(AOA) = " << radToDeg(AOAmin) << ", "
<< radToDeg(AOAmax) << nl
<< " Effective drag = " << dragEff << nl
<< " Effective lift = " << liftEff << endl;
return tForce;
}
// ************************************************************************* //