Commit 00174405 authored by Andrew Heather's avatar Andrew Heather
Browse files

ENH: noiseModels - enable models to accept lists of file names

parent 7734d7ff
......@@ -204,7 +204,8 @@ Foam::Function1Types::CSV<Type>::CSV
(
const word& entryName,
const dictionary& dict,
const word& ext
const word& ext,
const fileName& fName
)
:
TableBase<Type>(entryName, dict.subDict(entryName + ext)),
......@@ -214,7 +215,7 @@ Foam::Function1Types::CSV<Type>::CSV
componentColumns_(coeffs_.lookup("componentColumns")),
separator_(coeffs_.lookupOrDefault<string>("separator", string(","))[0]),
mergeSeparators_(readBool(coeffs_.lookup("mergeSeparators"))),
fName_(coeffs_.lookup("fileName"))
fName_(fName != fileName::null ? fName : coeffs_.lookup("fileName"))
{
if (componentColumns_.size() != pTraits<Type>::nComponents)
{
......
......@@ -122,7 +122,8 @@ public:
(
const word& entryName,
const dictionary& dict,
const word& ext = "Coeffs"
const word& ext = "Coeffs",
const fileName& fName = fileName::null
);
//- Copy constructor
......
......@@ -94,17 +94,41 @@ Foam::label Foam::noiseModel::findStartTimeIndex
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::noiseModel::noiseModel(const dictionary& dict)
Foam::noiseModel::noiseModel(const dictionary& dict, const bool readFields)
:
dict_(dict),
rhoRef_(dict.lookupOrDefault<scalar>("rhoRef", 1)),
nSamples_(dict.lookupOrDefault<label>("N", 65536)),
fLower_(dict.lookupOrDefault<scalar>("fl", 25)),
fUpper_(dict.lookupOrDefault<scalar>("fu", 10000)),
startTime_(dict.lookupOrDefault<scalar>("startTime", 0)),
windowModelPtr_(windowModel::New(dict, nSamples_)),
graphFormat_(dict.lookupOrDefault<word>("graphFormat", "raw"))
rhoRef_(1),
nSamples_(65536),
fLower_(25),
fUpper_(10000),
startTime_(0),
windowModelPtr_(),
graphFormat_("raw")
{
if (readFields)
{
read(dict);
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::noiseModel::~noiseModel()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::noiseModel::read(const dictionary& dict)
{
dict.readIfPresent("rhoRef", rhoRef_);
dict.readIfPresent("N", nSamples_);
dict.readIfPresent("fl", fLower_);
dict.readIfPresent("fu", fUpper_);
dict.readIfPresent("startTime", startTime_);
dict.readIfPresent("graphFormat", graphFormat_);
// Check number of samples - must be a power of 2 for our FFT
bool powerOf2 = ((nSamples_ != 0) && !(nSamples_ & (nSamples_ - 1)));
if (!powerOf2)
......@@ -139,13 +163,11 @@ Foam::noiseModel::noiseModel(const dictionary& dict)
<< exit(FatalIOError);
}
}
windowModelPtr_ = windowModel::New(dict, nSamples_);
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::noiseModel::~noiseModel()
{}
return true;
}
// ************************************************************************* //
......@@ -124,7 +124,7 @@ protected:
scalar checkUniformTimeStep
(
const scalarList& times
) const;
) const;
//- Find and return start time index
label findStartTimeIndex
......@@ -139,7 +139,7 @@ public:
//- Runtime type information
TypeName("noiseModel");
//- Run time selection table
//- Run time selection table
declareRunTimeSelectionTable
(
autoPtr,
......@@ -155,7 +155,7 @@ public:
static autoPtr<noiseModel> New(const dictionary& dict);
//- Constructor
noiseModel(const dictionary& dict);
noiseModel(const dictionary& dict, const bool readFields = true);
//- Destructor
virtual ~noiseModel();
......@@ -163,6 +163,9 @@ public:
// Public Member Functions
//- Read from dictionary
virtual bool read(const dictionary& dict);
//- Abstract call to calculate
virtual void calculate() = 0;
};
......
......@@ -43,14 +43,12 @@ addToRunTimeSelectionTable(noiseModel, pointNoise, dictionary);
void pointNoise::filterTimeData
(
const Function1Types::CSV<scalar>& pData,
const scalarField& t0,
const scalarField& p0,
scalarField& t,
scalarField& p
)
) const
{
const scalarField t0(pData.x());
const scalarField p0(pData.y());
DynamicList<scalar> tf(t0.size());
DynamicList<scalar> pf(t0.size());
......@@ -68,23 +66,15 @@ void pointNoise::filterTimeData
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void pointNoise::calculate()
void pointNoise::processData(const Function1Types::CSV<scalar>& data)
{
// Point data only handled by master
if (!Pstream::master())
{
return;
}
Info<< "Reading data file " << data.fName() << endl;
Info<< "Reading data file" << endl;
Function1Types::CSV<scalar> pData("pressure", dict_, "Data");
const fileName& fNameBase = data.fName()(true);
// Time and pressure history data
scalarField t, p;
filterTimeData(pData, t, p);
filterTimeData(data.x(), data.y(), t, p);
p *= rhoRef_;
Info<< " read " << t.size() << " values" << nl << endl;
......@@ -96,7 +86,7 @@ void pointNoise::calculate()
windowModelPtr_->validate(t.size());
const windowModel& win = windowModelPtr_();
const scalar deltaf = 1.0/(deltaT*win.nSamples());
fileName outDir(fileName("postProcessing")/"noise"/typeName);
fileName outDir(fileName("postProcessing")/"noise"/typeName/fNameBase);
// Create the fft
noiseFFT nfft(deltaT, p);
......@@ -185,12 +175,45 @@ void pointNoise::calculate()
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void pointNoise::calculate()
{
// Point data only handled by master
if (!Pstream::master())
{
return;
}
if (inputFileNames_.size())
{
forAll(inputFileNames_, i)
{
const fileName fName = inputFileNames_[i].expand();
Function1Types::CSV<scalar> data("pressure", dict_, "Data", fName);
processData(data);
}
}
else
{
Function1Types::CSV<scalar> data("pressure", dict_, "Data");
processData(data);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
pointNoise::pointNoise(const dictionary& dict)
pointNoise::pointNoise(const dictionary& dict, const bool readFields)
:
noiseModel(dict)
{}
{
if (readFields)
{
read(dict);
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
......@@ -199,6 +222,18 @@ pointNoise::~pointNoise()
{}
bool pointNoise::read(const dictionary& dict)
{
if (noiseModel::read(dict))
{
dict.readIfPresent("inputFiles", inputFileNames_);
return true;
}
return false;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace noiseModels
......
......@@ -76,8 +76,8 @@ SeeAlso
\*---------------------------------------------------------------------------*/
#ifndef pointNoise_H
#define pointNoise_H
#ifndef noiseModels_pointNoise_H
#define noiseModels_pointNoise_H
#include "noiseModel.H"
#include "CSV.H"
......@@ -100,14 +100,24 @@ class pointNoise
protected:
// Protected data
//- Input file names - optional
List<fileName> inputFileNames_;
// Protected Member Functions
void filterTimeData
(
const Function1Types::CSV<scalar>& pData,
const scalarField& t0,
const scalarField& p0,
scalarField& t,
scalarField& p
);
) const;
//- Process the CSV data
void processData(const Function1Types::CSV<scalar>& data);
public:
......@@ -116,7 +126,7 @@ public:
TypeName("pointNoise");
//- Constructor
pointNoise(const dictionary& dict);
pointNoise(const dictionary& dict, const bool readFields = true);
//- Destructor
virtual ~pointNoise();
......@@ -124,6 +134,9 @@ public:
// Public Member Functions
//- Read from dictionary
virtual bool read(const dictionary& dict);
//- Calculate
virtual void calculate();
......
......@@ -44,12 +44,9 @@ addToRunTimeSelectionTable(noiseModel, surfaceNoise, dictionary);
// * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
void surfaceNoise::initialise(const dictionary& dict)
void surfaceNoise::initialise(const fileName& fName)
{
dict.lookup("inputFile") >> inputFileName_;
inputFileName_.expand();
dict.readIfPresent("fftWriteInterval", fftWriteInterval_);
Info<< "Reading data file " << fName << endl;
label nAvailableTimes = 0;
......@@ -57,17 +54,15 @@ void surfaceNoise::initialise(const dictionary& dict)
if (Pstream::master())
{
// Create the surface reader
const word readerType(dict.lookup("reader"));
readerPtr_.reset(surfaceReader::New(readerType, inputFileName_).ptr());
readerPtr_ = surfaceReader::New(readerType_, fName);
// Find the index of the pressure data
const word pName(dict.lookupOrDefault<word>("p", "p"));
const List<word> fieldNames(readerPtr_->fieldNames(0));
pIndex_ = findIndex(fieldNames, pName);
pIndex_ = findIndex(fieldNames, pName_);
if (pIndex_ == -1)
{
FatalErrorInFunction
<< "Unable to find pressure field name " << pName
<< "Unable to find pressure field name " << pName_
<< " in list of available fields: " << fieldNames
<< exit(FatalError);
}
......@@ -76,12 +71,6 @@ void surfaceNoise::initialise(const dictionary& dict)
// - Could be done later, but since this utility can process a lot of
// data we can ensure that the user-input is correct prior to doing
// the heavy lifting
const word writerType(dict.lookup("writer"));
dictionary optDict
(
dict.subOrEmptyDict("writeOptions").subOrEmptyDict(writerType)
);
writerPtr_.reset(surfaceWriter::New(writerType, optDict).ptr());
// Set the time range
const instantList allTimes = readerPtr_->times();
......@@ -404,18 +393,25 @@ Foam::scalar surfaceNoise::surfaceAverage
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
surfaceNoise::surfaceNoise(const dictionary& dict)
surfaceNoise::surfaceNoise(const dictionary& dict, const bool readFields)
:
noiseModel(dict),
inputFileName_("unknown-inputFile"),
noiseModel(dict, false),
inputFileNames_(),
pName_("p"),
pIndex_(0),
times_(),
deltaT_(0),
startTimeIndex_(0),
nFace_(0),
fftWriteInterval_(1)
fftWriteInterval_(1),
readerType_(word::null),
readerPtr_(nullptr),
writerPtr_(nullptr)
{
initialise(dict);
if (readFields)
{
read(dict);
}
}
......@@ -427,271 +423,307 @@ surfaceNoise::~surfaceNoise()
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void surfaceNoise::calculate()
bool surfaceNoise::read(const dictionary& dict)
{
// Container for pressure time history data per face
List<scalarField> pData;
// Processor procFaceOffsets
labelList procFaceOffset;
if (Pstream::parRun())
if (noiseModel::read(dict))
{
const label nProcs = Pstream::nProcs();
const label nFacePerProc = floor(nFace_/nProcs) + 1;
dict.lookup("inputFiles") >> inputFileNames_;
dict.readIfPresent("fftWriteInterval", fftWriteInterval_);
dict.readIfPresent("p", pName_);
procFaceOffset.setSize(nProcs + 1, 0);
for (label i = 1; i < procFaceOffset.size(); i++)
{
procFaceOffset[i] = min(i*nFacePerProc, nFace_);
}
}
else
{
procFaceOffset.setSize(1, nFace_);
}
// Read pressure data from file
readSurfaceData(procFaceOffset, pData);
dict.lookup("reader") >> readerType_;
// Process the pressure data, and store results as surface values per
// frequency so that it can be output using the surface writer
word writerType(dict.lookup("writer"));
dictionary optDict
(
dict.subOrEmptyDict("writeOptions").subOrEmptyDict(writerType)
);
Info<< "Creating noise FFTs" << endl;
writerPtr_ = surfaceWriter::New(writerType, optDict);
// Storage for FFT data
const label nLocalFace = pData.size();
const scalarField freq1(noiseFFT::frequencies(nSamples_, deltaT_));
const label nFFT = freq1.size()/fftWriteInterval_;
List<scalarField> surfPrmsf(nFFT);
List<scalarField> surfPSDf(nFFT);
forAll(surfPrmsf, freqI)
{
surfPrmsf[freqI].setSize(nLocalFace);
surfPSDf[freqI].setSize(nLocalFace);
return true;
}
// Storage for 1/3 octave data
labelList octave13BandIDs;
scalarField octave13FreqCentre;
noiseFFT::octaveBandInfo
(
freq1,
fLower_,
fUpper_,
3,
octave13BandIDs,
octave13FreqCentre
);
return false;
}
label bandSize = 0;
if (octave13BandIDs.empty())
{
WarningInFunction
<< "Ocatve band calculation failed (zero sized). "
<< "please check your input data"
<< endl;
}
else
{
bandSize = octave13BandIDs.size() - 1;
}
List<scalarField> surfPSD13f(bandSize);
List<scalarField> surfPrms13f2(bandSize);
forAll(surfPSD13f, freqI)
void surfaceNoise::calculate()
{
forAll(inputFileNames_, i)
{
surfPSD13f[freqI].setSize(nLocalFace);
surfPrms13f2[freqI].setSize(nLocalFace);
}
fileName fName = inputFileNames_[i];
const windowModel& win = windowModelPtr_();
initialise(fName.expand());
forAll(pData, faceI)
{
const scalarField& p = pData[faceI];
// Container for pressure time history data per face
List<scalarField> pData;
noiseFFT nfft(deltaT_, p);
graph Prmsf(nfft.RMSmeanPf(win));
graph PSDf(nfft.PSDf(win));
// Processor procFaceOffsets
labelList procFaceOffset;
if (Pstream::parRun())
{
const label nProcs = Pstream::nProcs();
const label nFacePerProc = floor(nFace_/nProcs) + 1;
// Store the frequency results in slot for face of surface
forAll(surfPrmsf, i)
procFaceOffset.setSize(nProcs + 1, 0);
for (label i = 1; i < procFaceOffset.size(); i++)
{
procFaceOffset[i] = min(i*nFacePerProc, nFace_);
}
}
else
{
label freqI = (i + 1)*fftWriteInterval_ - 1;
surfPrmsf[i][faceI] = Prmsf.y()[freqI];
surfPSDf[i][faceI] = PSDf.y()[freqI];
procFaceOffset.setSize(1, nFace_);
}
// PSD [Pa^2/Hz]
graph PSD13f(nfft.octaves(PSDf, octave13BandIDs, false));
// Read pressure data from file
readSurfaceData(procFaceOffset, pData);
// Integrated PSD = P(rms)^2 [Pa^2]
graph Prms13f2(nfft.octaves(PSDf, octave13BandIDs, true));
// Process the pressure data, and store results as surface values per
// frequency so that it can be output using the surface writer
// Store the 1/3 octave results in slot for face of surface
forAll(surfPSD13f, freqI)
Info<< "Creating noise FFTs" << endl;
// Storage for FFT data
const label nLocalFace = pData.size();
const scalarField freq1(noiseFFT::frequencies(nSamples_, deltaT_));
const label nFFT = freq1.size()/fftWriteInterval_;
List<scalarField> surfPrmsf(nFFT);
List<scalarField> surfPSDf(nFFT);
forAll(surfPrmsf, freqI)
{
surfPSD13f[freqI][faceI] = PSD13f.y()[freqI];
surfPrms13f2[freqI][faceI] = Prms13f2.y()[freqI];
surfPrmsf[freqI].setSize(nLocalFace);
surfPSDf[freqI].setSize(nLocalFace);
}
}
// Output directory for graphs
fileName outDir(fileName("postProcessing")/"noise"/typeName);
const scalar deltaf = 1.0/(deltaT_*win.nSamples());
Info<< "Writing fft surface data" << endl;
{
scalarField PrmsfAve(surfPrmsf.size(), 0);
scalarField PSDfAve(surfPrmsf.size(), 0);
scalarField fOut(surfPrmsf.size(), 0);
// Storage for 1/3 octave data
labelList octave13BandIDs;
scalarField octave13FreqCentre;
noiseFFT::octaveBandInfo
(
freq1,
fLower_,
fUpper_,
3,
octave13BandIDs,
octave13FreqCentre
);
forAll(surfPrmsf, i)
label bandSize = 0;
if (octave13BandIDs.empty())
{
label freqI = i*fftWriteInterval_;
fOut[i] = freq1[freqI];
const word& fName = inputFileName_.name(true);
const word gName = "fft";
PrmsfAve[i] = writeSurfaceData
(
fName,
gName,
"Prmsf",
freq1[freqI],
surfPrmsf[i],
procFaceOffset
);