Merge branch 'feature-noise' into 'develop'

Feature noise

New functionality includes:
- run-time selectable noise models: point|surface
- run-time selectable window models: Hanning (+ options symmetric, extended), uniform
- calculates PSD (Pa^2/Hz) and dB/HZ; SPL (Pa^2) and dB
- calculates 1/3 octave data, with centre frequency 1kHz

surfaceNoise only:
- reads ascii/binary ensight surface data (requires collateTimes option)
- generates graphs for surface average quantities
- operates in parallel

See merge request !50
This commit is contained in:
Andrew Heather
2016-06-29 21:44:36 +01:00
41 changed files with 4709 additions and 902 deletions

View File

@ -0,0 +1,14 @@
#!/bin/sh
cd ${0%/*} || exit 1 # run from this directory
if [ -f "$FFTW_ARCH_PATH/include/fftw3.h" ] || \
[ "${FFTW_ARCH_PATH##*-}" = system -a -f "/usr/include/fftw3.h" ]
then
wmake
else
echo
echo "Skipping dnsFoam solver (no FFTW)"
echo
fi
#------------------------------------------------------------------------------

View File

@ -0,0 +1,14 @@
#!/bin/sh
cd ${0%/*} || exit 1 # run from this directory
if [ -f "$FFTW_ARCH_PATH/include/fftw3.h" ] || \
[ "${FFTW_ARCH_PATH##*-}" = system -a -f "/usr/include/fftw3.h" ]
then
wmake
else
echo
echo "Skipping noise utility (no FFTW)"
echo
fi
#------------------------------------------------------------------------------

View File

@ -1,6 +1,7 @@
EXE_INC = \ EXE_INC = \
-I$(LIB_SRC)/randomProcesses/lnInclude \ -I$(LIB_SRC)/randomProcesses/lnInclude \
-I$(LIB_SRC)/sampling/lnInclude -I$(LIB_SRC)/sampling/lnInclude \
-I$(LIB_SRC)/surfMesh/lnInclude
EXE_LIBS = \ EXE_LIBS = \
-lrandomProcesses \ -lrandomProcesses \

View File

@ -2,8 +2,8 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -28,157 +28,103 @@ Group
grpPostProcessingUtilities grpPostProcessingUtilities
Description Description
Utility to perform noise analysis of pressure data using the noiseFFT Utility to perform noise analysis of pressure data.
library.
Control settings are read from the $FOAM_CASE/system/noiseDict dictionary, The utility provides a light wrapper around the run-time selectable
or user-specified dictionary using the -dict option. Pressure data is noise model. Current options include:
read using a CSV reader: - point, and
- surface noise.
\heading Usage \heading Example usage
\verbatim \verbatim
pRef 101325; noiseModel surfaceNoise; // pointNoise
N 65536;
nw 100;
f1 25;
fU 10000;
graphFormat raw;
pressureData surfaceNoiseCoeffs
{ {
fileName "pressureData" windowModel Hanning;
nHeaderLine 1; // number of header lines
refColumn 0; // reference column index HanningCoeffs
componentColumns (1); // component column indices {
separator " "; // optional (defaults to ",") // Window overlap percentage
mergeSeparators no; // merge multiple separators overlapPercent 50;
outOfBounds clamp; // optional out-of-bounds handling symmetric yes;
interpolationScheme linear; // optional interpolation scheme extended yes;
// Optional number of windows, default = all available
nWindow 5;
}
// Input file
inputFile "postProcessing/faceSource1/surface/patch/patch.case";
// Surface reader
reader ensight;
// Surface writer
writer ensight;
// Collate times for ensight output - ensures geometry is only written once
writeOptions
{
ensight
{
collateTimes 1;
}
}
// Number of samples in sampling window
// Must be a power of 2, default = 2^16 (=65536)
N 4096;
// Write interval for FFT data, default = 1
fftWriteInterval 100;
} }
\endverbatim \endverbatim
where
\table
Property | Description | Required | Default value
pRef | Reference pressure | no | 0
N | Number of samples in sampling window | no | 65536
nw | Number of sampling windows | no | 100
fl | Lower frequency band | no | 25
fU | Upper frequency band | no | 10000
graphFormat | Output graph format | no | raw
\endtable
Current graph outputs include:
- FFT of the pressure data
- narrow-band PFL (pressure-fluctuation level) spectrum
- one-third-octave-band PFL spectrum
- one-third-octave-band pressure spectrum
SeeAlso SeeAlso
CSV.H
noiseFFT.H noiseFFT.H
noiseModel.H
windowModel.H
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "noiseFFT.H"
#include "argList.H" #include "argList.H"
#include "Time.H" #include "Time.H"
#include "functionObjectFile.H" #include "noiseModel.H"
#include "CSV.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
using namespace Foam; using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Foam::scalar checkUniformTimeStep(const scalarField& t)
{
// check that a uniform time step has been applied
scalar deltaT = -1.0;
if (t.size() > 1)
{
for (label i = 1; i < t.size(); i++)
{
scalar dT = t[i] - t[i-1];
if (deltaT < 0)
{
deltaT = dT;
}
if (mag(deltaT - dT) > SMALL)
{
FatalErrorInFunction
<< "Unable to process data with a variable time step"
<< exit(FatalError);
}
}
}
else
{
FatalErrorInFunction
<< "Unable to create FFT with a single value"
<< exit(FatalError);
}
return deltaT;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
argList::noParallel();
#include "addDictOption.H" #include "addDictOption.H"
#include "setRootCase.H" #include "setRootCase.H"
#include "createTime.H" #include "createTime.H"
#include "createFields.H"
Info<< "Reading data file" << endl; fileName dictName(runTime.system()/"noiseDict");
Function1Types::CSV<scalar> pData("pressure", dict, "Data"); if (args.optionFound("dict"))
// time history data
const scalarField t(pData.x());
// pressure data
const scalarField p(pData.y());
if (t.size() < N)
{ {
FatalErrorInFunction dictName = args["dict"];
<< "Block size N = " << N
<< " is larger than number of data = " << t.size()
<< exit(FatalError);
} }
Info<< " read " << t.size() << " values" << nl << endl; IOdictionary dict
(
IOobject
(
dictName,
runTime,
IOobject::MUST_READ
)
);
autoPtr<noiseModel> model(noiseModel::New(dict));
Info<< "Creating noise FFT" << endl; model->calculate();
noiseFFT nfft(checkUniformTimeStep(t), p);
nfft -= pRef;
fileName baseFileName(pData.fName().lessExt());
graph Pf(nfft.RMSmeanPf(N, min(nfft.size()/N, nw)));
Info<< " Creating graph for " << Pf.title() << endl;
Pf.write(baseFileName + graph::wordify(Pf.title()), graphFormat);
graph Lf(nfft.Lf(Pf));
Info<< " Creating graph for " << Lf.title() << endl;
Lf.write(baseFileName + graph::wordify(Lf.title()), graphFormat);
graph Ldelta(nfft.Ldelta(Lf, f1, fU));
Info<< " Creating graph for " << Ldelta.title() << endl;
Ldelta.write(baseFileName + graph::wordify(Ldelta.title()), graphFormat);
graph Pdelta(nfft.Pdelta(Pf, f1, fU));
Info<< " Creating graph for " << Pdelta.title() << endl;
Pdelta.write(baseFileName + graph::wordify(Pdelta.title()), graphFormat);
Info<< nl << "End\n" << endl; Info<< nl << "End\n" << endl;

View File

@ -0,0 +1,136 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: plus |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object noiseDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
noiseModel surfaceNoise;
surfaceNoiseCoeffs
{
windowModel Hanning;
HanningCoeffs
{
// Window overlap percentage
overlapPercent 50;
symmetric yes;
extended yes;
// Optional number of windows, default = all available
// nWindow 1;
}
/*
windowModel uniform;
uniformCoeffs
{
// Window overlap percentage
overlapPercent 50;
value 1;
// Optional number of windows, default = all available
// nWindow 1;
}
*/
// Input file
inputFile "postProcessing/faceSource1/surface/patch_motorBike_rider-helmet%65/patch_motorBike_rider-helmet%65.case";
// Surface reader
reader ensight;
// Surface writer
writer ensight;
// Collate times for ensight output - ensures geometry is only written once
writeOptions
{
ensight
{
collateTimes 1;
}
}
// Reference density (to convert from kinematic to static pressure)
rhoRef 1.205;
// Number of samples in sampling window
// Must be a power of 2, default = 2^16 (=65536)
N 4096; // 8192; // 4096;
// Lower frequency limit, default = 25Hz
//fl 25;
// Upper frequency limit, default = 10kHz
fu 15000;
// Start time, default = 0s
//startTime 0;
// Write interval for FFT data, default = 1
// fftWriteInterval 100;
}
pointNoiseCoeffs
{
csvFileData
{
fileName "pressureData";
nHeaderLine 1;
refColumn 0;
componentColumns (1);
separator " ";
mergeSeparators yes;
}
HanningCoeffs
{
// Window overlap percentage
overlapPercent 50;
symmetric yes;
extended yes;
// Optional number of windows, default = all available
//nWindow 5;
}
// Graph format, default = raw
graphFormat raw;
// Reference density (to convert from kinematic to static pressure)
rhoRef 1.2;
// Number of samples in sampling window
// Must be a power of 2, default = 2^16 (=65536)
N 4096;
// Lower frequency limit, default = 25Hz
//fl 25;
// Upper frequency limit, default = 10kHz
//fu 10000;
// Start time, default = 0s
//startTime 0;
// Write interval for FFT data, default = 1
fftWriteInterval 100;
}
// ************************************************************************* //

View File

@ -0,0 +1,14 @@
#!/bin/sh
cd ${0%/*} || exit 1 # run from this directory
if [ -f "$FFTW_ARCH_PATH/include/fftw3.h" ] || \
[ "${FFTW_ARCH_PATH##*-}" = system -a -f "/usr/include/fftw3.h" ]
then
wmake
else
echo
echo "Skipping boxTurb utility (no FFTW)"
echo
fi
#------------------------------------------------------------------------------

View File

@ -31,7 +31,7 @@
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
setenv WM_PROJECT OpenFOAM setenv WM_PROJECT OpenFOAM
setenv WM_PROJECT_VERSION plus setenv WM_PROJECT_VERSION stage
################################################################################ ################################################################################
# USER EDITABLE PART: Changes made here may be lost with the next upgrade # USER EDITABLE PART: Changes made here may be lost with the next upgrade

View File

@ -1,5 +1,6 @@
ensight/file/ensightFile.C ensight/file/ensightFile.C
ensight/file/ensightGeoFile.C ensight/file/ensightGeoFile.C
ensight/readFile/ensightReadFile.C
ensight/part/ensightPart.C ensight/part/ensightPart.C
ensight/part/ensightPartIO.C ensight/part/ensightPartIO.C
ensight/part/ensightPartCells.C ensight/part/ensightPartCells.C

View File

@ -0,0 +1,157 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenCFD Ltd.
\\/ 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 "ensightReadFile.H"
#include <sstream>
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::ensightReadFile::ensightReadFile
(
const fileName& pathname,
IOstream::streamFormat format
)
:
IFstream(pathname, format)
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::ensightReadFile::~ensightReadFile()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::Istream& Foam::ensightReadFile::read
(
char* buf,
std::streamsize count
)
{
stdStream().read(buf, count);
return *this;
}
Foam::Istream& Foam::ensightReadFile::read(string& value)
{
if (format() == IOstream::BINARY)
{
char buf[80];
read(reinterpret_cast<char*>(buf), sizeof(buf));
string strBuf(value);
const size_t iEnd = strBuf.find('\0', 0);
if (iEnd == string::npos)
{
value = buf;
}
else
{
value = strBuf.substr(0, iEnd - 1);
}
}
else
{
value = "";
while (value.empty() && !eof())
{
getLine(value);
}
}
return *this;
}
Foam::Istream& Foam::ensightReadFile::read(label& value)
{
int ivalue;
if (format() == IOstream::BINARY)
{
read
(
reinterpret_cast<char*>(&ivalue),
sizeof(ivalue)
);
}
else
{
stdStream() >> ivalue;
}
value = ivalue;
return *this;
}
Foam::Istream& Foam::ensightReadFile::read(scalar& value)
{
float fvalue;
if (format() == IOstream::BINARY)
{
read
(
reinterpret_cast<char*>(&fvalue),
sizeof(fvalue)
);
value = fvalue;
}
else
{
stdStream() >> value;
}
return *this;
}
Foam::Istream& Foam::ensightReadFile::readKeyword(string& key)
{
read(key);
return *this;
}
Foam::Istream& Foam::ensightReadFile::readBinaryHeader()
{
if (format() == IOstream::BINARY)
{
string buffer;
read(buffer);
}
return *this;
}
// ************************************************************************* //

View File

@ -0,0 +1,110 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenCFD Ltd.
\\/ 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::ensightReadFile
Description
Ensight output with specialized read() for strings, integers and floats.
Correctly handles binary read as well.
\*---------------------------------------------------------------------------*/
#ifndef ensightReadFile_H
#define ensightReadFile_H
#include "IFstream.H"
#include "IOstream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class ensightReadFile Declaration
\*---------------------------------------------------------------------------*/
class ensightReadFile
:
public IFstream
{
// Private Member Functions
//- Disallow default bitwise assignment
void operator=(const ensightReadFile&);
//- Disallow default copy constructor
ensightReadFile(const ensightReadFile&);
public:
// Constructors
//- Construct from pathname
ensightReadFile
(
const fileName& pathname,
IOstream::streamFormat format=IOstream::BINARY
);
//- Destructor
~ensightReadFile();
// Output
//- Inherit read from Istream
using Istream::read;
//- Binary read
virtual Istream& read(char* buf, std::streamsize count);
//- Read string as "%80s" or as binary
Istream& read(string& value);
//- Read integer as "%10d" or as binary
Istream& read(label& value);
//- Read float as "%12.5e" or as binary
Istream& read(scalar& value);
//- Read element keyword
virtual Istream& readKeyword(string& key);
//- Read "C Binary" for binary files (eg, geometry/measured)
Istream& readBinaryHeader();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

18
src/randomProcesses/Allwmake Executable file
View File

@ -0,0 +1,18 @@
#!/bin/sh
cd ${0%/*} || exit 1 # run from this directory
# Parse arguments for library compilation
targetType=libso
. $WM_PROJECT_DIR/wmake/scripts/AllwmakeParseArguments
if [ -f "$FFTW_ARCH_PATH/include/fftw3.h" ] || \
[ "${FFTW_ARCH_PATH##*-}" = system -a -f "/usr/include/fftw3.h" ]
then
wmake $targetType
else
echo
echo "Skipping randomProcesses library (no FFTW)"
echo
fi
#------------------------------------------------------------------------------

View File

@ -1,25 +1,31 @@
Kmesh = Kmesh Kmesh = Kmesh
fft = fft
processes = processes
UOprocess = $(processes)/UOprocess
turbulence = turbulence
noise = noise
$(Kmesh)/Kmesh.C $(Kmesh)/Kmesh.C
fft = fft
$(fft)/fft.C $(fft)/fft.C
$(fft)/fftRenumber.C
$(fft)/calcEk.C $(fft)/calcEk.C
$(fft)/kShellIntegration.C $(fft)/kShellIntegration.C
processes = processes
UOprocess = $(processes)/UOprocess
$(UOprocess)/UOprocess.C $(UOprocess)/UOprocess.C
turbulence = turbulence
$(turbulence)/turbGen.C $(turbulence)/turbGen.C
$(noise)/noiseFFT.C noise = noise
$(noise)/noiseFFT/noiseFFT.C
$(noise)/noiseModels/noiseModel/noiseModel.C
$(noise)/noiseModels/noiseModel/noiseModelNew.C
$(noise)/noiseModels/pointNoise/pointNoise.C
$(noise)/noiseModels/surfaceNoise/surfaceNoise.C
windowModels = windowModels
$(windowModels)/windowModel/windowModel.C
$(windowModels)/windowModel/windowModelNew.C
$(windowModels)/Hanning/Hanning.C
$(windowModels)/uniform/uniform.C
LIB = $(FOAM_LIBBIN)/librandomProcesses LIB = $(FOAM_LIBBIN)/librandomProcesses

View File

@ -1,5 +1,11 @@
EXE_INC = \ EXE_INC = \
-I$(LIB_SRC)/finiteVolume/lnInclude -I$(FFTW_ARCH_PATH)/include \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/sampling/lnInclude \
-I$(LIB_SRC)/surfMesh/lnInclude
LIB_LIBS = \ LIB_LIBS = \
-lfiniteVolume -L$(FFTW_ARCH_PATH)/lib$(WM_COMPILER_LIB_ARCH) -lfftw3 \
-lfiniteVolume \
-lsampling \
-lsurfMesh

View File

@ -2,8 +2,8 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -24,7 +24,8 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "fft.H" #include "fft.H"
#include "fftRenumber.H"
#include <fftw3.h>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -33,16 +34,11 @@ namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#define SWAP(a,b) tempr=(a); (a)=(b); (b)=tempr
#define TWOPI 6.28318530717959
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
void fft::transform void fft::transform
( (
complexField& field, complexField& field,
const labelList& nn, const labelList& nn,
transformDirection isign transformDirection dir
) )
{ {
forAll(nn, idim) forAll(nn, idim)
@ -59,128 +55,58 @@ void fft::transform
} }
} }
const label ndim = nn.size(); // Copy field into fftw containers
label N = field.size();
label i1, i2, i3, i2rev, i3rev, ip1, ip2, ip3, ifp1, ifp2; fftw_complex in[N], out[N];
label ibit, k1, k2, n, nprev, nrem, idim;
scalar tempi, tempr;
scalar theta, wi, wpi, wpr, wr, wtemp;
scalar* data = reinterpret_cast<scalar*>(field.begin()) - 1;
// if inverse transform : renumber before transform
if (isign == REVERSE_TRANSFORM)
{
fftRenumber(field, nn);
}
label ntot = 1;
forAll(nn, idim)
{
ntot *= nn[idim];
}
nprev = 1;
for (idim=ndim; idim>=1; idim--)
{
n = nn[idim-1];
nrem = ntot/(n*nprev);
ip1 = nprev << 1;
ip2 = ip1*n;
ip3 = ip2*nrem;
i2rev = 1;
for (i2=1; i2<=ip2; i2+=ip1)
{
if (i2 < i2rev)
{
for (i1=i2; i1<=i2 + ip1 - 2; i1+=2)
{
for (i3=i1; i3<=ip3; i3+=ip2)
{
i3rev = i2rev + i3 - i2;
SWAP(data[i3], data[i3rev]);
SWAP(data[i3 + 1], data[i3rev + 1]);
}
}
}
ibit = ip2 >> 1;
while (ibit >= ip1 && i2rev > ibit)
{
i2rev -= ibit;
ibit >>= 1;
}
i2rev += ibit;
}
ifp1 = ip1;
while (ifp1 < ip2)
{
ifp2 = ifp1 << 1;
theta = isign*TWOPI/(ifp2/ip1);
wtemp = sin(0.5*theta);
wpr = -2.0*wtemp*wtemp;
wpi = sin(theta);
wr = 1.0;
wi = 0.0;
for (i3 = 1; i3 <= ifp1; i3 += ip1)
{
for (i1 = i3; i1 <= i3 + ip1 - 2; i1 += 2)
{
for (i2 = i1; i2 <= ip3; i2 += ifp2)
{
k1 = i2;
k2 = k1 + ifp1;
tempr = scalar(wr*data[k2]) - scalar(wi*data[k2 + 1]);
tempi = scalar(wr*data[k2 + 1]) + scalar(wi*data[k2]);
data[k2] = data[k1] - tempr;
data[k2 + 1] = data[k1 + 1] - tempi;
data[k1] += tempr;
data[k1 + 1] += tempi;
}
}
wr = (wtemp = wr)*wpr - wi*wpi + wr;
wi = wi*wpr + wtemp*wpi + wi;
}
ifp1 = ifp2;
}
nprev *= n;
}
// if forward transform : renumber after transform
if (isign == FORWARD_TRANSFORM)
{
fftRenumber(field, nn);
}
// scale result (symmetric scale both forward and inverse transform)
scalar recRootN = 1.0/sqrt(scalar(ntot));
forAll(field, i) forAll(field, i)
{ {
field[i] *= recRootN; in[i][0] = field[i].Re();
in[i][1] = field[i].Im();
} }
// Create the plan
// FFTW_FORWARD = -1
// FFTW_BACKWARD = 1
// 1-D plan
// fftw_plan plan =
// fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
// Generic 1..3-D plan
label rank = nn.size();
fftw_plan plan =
fftw_plan_dft(rank, nn.begin(), in, out, dir, FFTW_ESTIMATE);
// Compute the FFT
fftw_execute(plan);
forAll(field, i)
{
field[i].Re() = out[i][0];
field[i].Im() = out[i][1];
}
fftw_destroy_plan(plan);
/*
fftw_real in[N], out[N];
// Create a plan for real data input
// - generates 1-sided FFT
// - direction given by FFTW_R2HC or FFTW_HC2R.
// - in[N] is the array of real input val ues
// - out[N] is the array of N/2 real valuea followed by N/2 complex values
// - 0 component = DC component
fftw_plan plan = fftw_plan_r2r_2d(N, in, out, FFTW_R2HC, FFTW_ESTIMATE)
// Compute the FFT
fftw_execute(plan);
fftw_destroy_plan(plan);
*/
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#undef SWAP
#undef TWOPI
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
tmp<complexField> fft::forwardTransform tmp<complexField> fft::forwardTransform

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -25,11 +25,10 @@ Class
Foam::fft Foam::fft
Description Description
Fast fourier transform derived from the Numerical Fast fourier transform using the fftw library.
Recipes in C routine.
The complex transform field is returned in the field supplied. The The complex transform field is returned in the field supplied. The
direction of transform is supplied as an argument (1 = forward, -1 = direction of transform is supplied as an argument (-1 = forward, 1 =
reverse). The dimensionality and organisation of the array of values reverse). The dimensionality and organisation of the array of values
in space is supplied in the nn indexing array. in space is supplied in the nn indexing array.
@ -56,8 +55,8 @@ public:
enum transformDirection enum transformDirection
{ {
FORWARD_TRANSFORM = 1, FORWARD_TRANSFORM = -1,
REVERSE_TRANSFORM = -1 REVERSE_TRANSFORM = 1
}; };

View File

@ -1,124 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 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/>.
Description
Multi-dimensional renumbering used in the Numerical Recipes
fft routine. This version is recursive, so works in n-d :
determined by the length of array nn
\*---------------------------------------------------------------------------*/
#include "fftRenumber.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
void Foam::fftRenumberRecurse
(
List<complex>& data,
List<complex>& renumData,
const labelList& nn,
label nnprod,
label ii,
label l1,
label l2
)
{
if (ii == nn.size())
{
// we've worked out the renumbering scheme. Now copy
// the components across
data[l1] = complex(renumData[l2].Re(),renumData[l2].Im());
}
else
{
// do another level of folding. First work out the
// multiplicative value of the index
nnprod /= nn[ii];
label i_1(0);
for (label i=0; i<nn[ii]; i++)
{
// now evaluate the indices (both from array 1 and to
// array 2). These get multiplied by nnprod to (cumulatively)
// find the real position in the list corresponding to
// this set of indices.
if (i<nn[ii]/2)
{
i_1 = i + nn[ii]/2;
}
else
{
i_1 = i - nn[ii]/2;
}
// go to the next level of recursion.
fftRenumberRecurse
(
data,
renumData,
nn,
nnprod,
ii+1,
l1+i*nnprod,
l2+i_1*nnprod
);
}
}
}
void Foam::fftRenumber
(
List<complex>& data,
const labelList& nn
)
{
List<complex> renumData(data);
label nnprod(1);
forAll(nn, i)
{
nnprod *= nn[i];
}
label ii(0), l1(0), l2(0);
fftRenumberRecurse
(
data,
renumData,
nn,
nnprod,
ii,
l1,
l2
);
}
// ************************************************************************* //

View File

@ -1,454 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 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 "noiseFFT.H"
#include "IFstream.H"
#include "DynamicList.H"
#include "fft.H"
#include "SubField.H"
#include "mathematicalConstants.H"
// * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * //
Foam::scalar Foam::noiseFFT::p0 = 2e-5;
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::noiseFFT::noiseFFT
(
const scalar deltat,
const scalarField& pressure
)
:
scalarField(pressure),
deltat_(deltat)
{}
Foam::noiseFFT::noiseFFT(const fileName& pFileName, const label skip)
:
scalarField(),
deltat_(0.0)
{
// Construct pressure data file
IFstream pFile(pFileName);
// Check pFile stream is OK
if (!pFile.good())
{
FatalErrorInFunction
<< "Cannot read file " << pFileName
<< exit(FatalError);
}
if (skip)
{
scalar dummyt, dummyp;
for (label i=0; i<skip; i++)
{
pFile >> dummyt;
if (!pFile.good() || pFile.eof())
{
FatalErrorInFunction
<< "Number of points in file " << pFileName
<< " is less than the number to be skipped = " << skip
<< exit(FatalError);
}
pFile >> dummyp;
}
}
scalar t = 0, T = 0;
DynamicList<scalar> pData(100000);
label i = 0;
while (!(pFile >> t).eof())
{
T = t;
pFile >> pData(i++);
}
deltat_ = T/pData.size();
this->transfer(pData);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::graph Foam::noiseFFT::pt() const
{
scalarField t(size());
forAll(t, i)
{
t[i] = i*deltat_;
}
return graph
(
"p(t)",
"t [s]",
"p(t) [Pa]",
t,
*this
);
}
Foam::tmp<Foam::scalarField> Foam::noiseFFT::window
(
const label N,
const label ni
) const
{
label windowOffset = N;
if ((N + ni*windowOffset) > size())
{
FatalErrorInFunction
<< "Requested window is outside set of data" << endl
<< "number of data = " << size() << endl
<< "size of window = " << N << endl
<< "window = " << ni
<< exit(FatalError);
}
tmp<scalarField> tpw(new scalarField(N));
scalarField& pw = tpw.ref();
label offset = ni*windowOffset;
forAll(pw, i)
{
pw[i] = operator[](i + offset);
}
return tpw;
}
Foam::tmp<Foam::scalarField> Foam::noiseFFT::Hanning(const label N) const
{
scalarField t(N);
forAll(t, i)
{
t[i] = i*deltat_;
}
scalar T = N*deltat_;
return 2*(0.5 - 0.5*cos(constant::mathematical::twoPi*t/T));
}
Foam::tmp<Foam::scalarField> Foam::noiseFFT::Pf
(
const tmp<scalarField>& tpn
) const
{
tmp<scalarField> tPn2
(
mag
(
fft::reverseTransform
(
ReComplexField(tpn),
labelList(1, tpn().size())
)
)
);
tpn.clear();
tmp<scalarField> tPn
(
new scalarField
(
scalarField::subField(tPn2(), tPn2().size()/2)
)
);
scalarField& Pn = tPn.ref();
Pn *= 2.0/sqrt(scalar(tPn2().size()));
Pn[0] /= 2.0;
return tPn;
}
Foam::graph Foam::noiseFFT::meanPf
(
const label N,
const label nw
) const
{
if (N > size())
{
FatalErrorInFunction
<< "Requested window is outside set of data" << nl
<< "number of data = " << size() << nl
<< "size of window = " << N << nl
<< "window = " << nw
<< exit(FatalError);
}
scalarField MeanPf(N/2, 0.0);
scalarField Hwf(Hanning(N));
for (label wi=0; wi<nw; ++wi)
{
MeanPf += Pf(Hwf*window(N, wi));
}
MeanPf /= nw;
scalarField f(MeanPf.size());
scalar deltaf = 1.0/(N*deltat_);
forAll(f, i)
{
f[i] = i*deltaf;
}
return graph
(
"P(f)",
"f [Hz]",
"P(f) [Pa]",
f,
MeanPf
);
}
Foam::graph Foam::noiseFFT::RMSmeanPf
(
const label N,
const label nw
) const
{
if (N > size())
{
FatalErrorInFunction
<< "Requested window is outside set of data" << endl
<< "number of data = " << size() << endl
<< "size of window = " << N << endl
<< "window = " << nw
<< exit(FatalError);
}
scalarField RMSMeanPf(N/2, 0.0);
scalarField Hwf(Hanning(N));
for (label wi=0; wi<nw; ++wi)
{
RMSMeanPf += sqr(Pf(Hwf*window(N, wi)));
}
RMSMeanPf = sqrt(RMSMeanPf/nw);
scalarField f(RMSMeanPf.size());
scalar deltaf = 1.0/(N*deltat_);
forAll(f, i)
{
f[i] = i*deltaf;
}
return graph
(
"P(f)",
"f [Hz]",
"P(f) [Pa]",
f,
RMSMeanPf
);
}
Foam::graph Foam::noiseFFT::Lf(const graph& gPf) const
{
return graph
(
"L(f)",
"f [Hz]",
"L(f) [dB]",
gPf.x(),
20*log10(gPf.y()/p0)
);
}
Foam::graph Foam::noiseFFT::Ldelta
(
const graph& gLf,
const scalar f1,
const scalar fU
) const
{
const scalarField& f = gLf.x();
const scalarField& Lf = gLf.y();
scalarField ldelta(Lf.size(), 0.0);
scalarField fm(ldelta.size());
scalar fratio = cbrt(2.0);
scalar deltaf = 1.0/(2*Lf.size()*deltat_);
scalar fl = f1/sqrt(fratio);
scalar fu = fratio*fl;
label istart = label(fl/deltaf);
label j = 0;
for (label i = istart; i<Lf.size(); i++)
{
scalar fmi = sqrt(fu*fl);
if (fmi > fU + 1) break;
if (f[i] >= fu)
{
fm[j] = fmi;
ldelta[j] = 10*log10(ldelta[j]);
j++;
fl = fu;
fu *= fratio;
}
ldelta[j] += pow(10, Lf[i]/10.0);
}
fm.setSize(j);
ldelta.setSize(j);
return graph
(
"Ldelta",
"fm [Hz]",
"Ldelta [dB]",
fm,
ldelta
);
}
Foam::graph Foam::noiseFFT::Pdelta
(
const graph& gPf,
const scalar f1,
const scalar fU
) const
{
const scalarField& f = gPf.x();
const scalarField& Pf = gPf.y();
scalarField pdelta(Pf.size(), 0.0);
scalarField fm(pdelta.size());
scalar fratio = cbrt(2.0);
scalar deltaf = 1.0/(2*Pf.size()*deltat_);
scalar fl = f1/sqrt(fratio);
scalar fu = fratio*fl;
label istart = label(fl/deltaf + 1.0 - SMALL);
label j = 0;
for (label i = istart; i<Pf.size(); i++)
{
scalar fmi = sqrt(fu*fl);
if (fmi > fU + 1) break;
if (f[i] >= fu)
{
fm[j] = fmi;
pdelta[j] = sqrt((2.0/3.0)*pdelta[j]);
j++;
fl = fu;
fu *= fratio;
}
pdelta[j] += sqr(Pf[i]);
}
fm.setSize(j);
pdelta.setSize(j);
return graph
(
"Pdelta",
"fm [Hz]",
"Pdelta [dB]",
fm,
pdelta
);
}
Foam::scalar Foam::noiseFFT::Lsum(const graph& gLf) const
{
const scalarField& Lf = gLf.y();
scalar lsum = 0.0;
forAll(Lf, i)
{
lsum += pow(10, Lf[i]/10.0);
}
lsum = 10*log10(lsum);
return lsum;
}
Foam::scalar Foam::noiseFFT::dbToPa(const scalar db) const
{
return p0*pow(10.0, db/20.0);
}
Foam::tmp<Foam::scalarField> Foam::noiseFFT::dbToPa
(
const tmp<scalarField>& db
) const
{
return p0*pow(10.0, db/20.0);
}
// ************************************************************************* //

View File

@ -0,0 +1,474 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 "noiseFFT.H"
#include "IFstream.H"
#include "DynamicList.H"
#include "SubField.H"
#include "mathematicalConstants.H"
#include "HashSet.H"
#include "fft.H"
using namespace Foam::constant;
// * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * //
Foam::scalar Foam::noiseFFT::p0 = 2e-5;
Foam::tmp<Foam::scalarField> Foam::noiseFFT::frequencies
(
const label N,
const scalar deltaT
)
{
tmp<scalarField> tf(new scalarField(N/2, 0));
scalarField& f = tf.ref();
scalar deltaf = 1.0/(N*deltaT);
forAll(f, i)
{
f[i] = i*deltaf;
}
return tf;
}
Foam::tmp<Foam::scalarField> Foam::noiseFFT::PSD(const scalarField& PSDf)
{
return 10*log10(PSDf/sqr(p0));
}
Foam::tmp<Foam::scalarField> Foam::noiseFFT::SPL(const scalarField& Prms2)
{
return 10*log10(Prms2/sqr(p0));
}
void Foam::noiseFFT::octaveBandInfo
(
const scalarField& f,
const scalar fLower,
const scalar fUpper,
const scalar octave,
labelList& fBandIDs,
scalarField& fCentre
)
{
// Set the indices of to the lower frequency bands for the input frequency
// range. Ensure that the centre frequency passes though 1000 Hz
// Low frequency bound given by:
// fLow = f0*(2^(0.5*bandI/octave))
// Initial (lowest centre frequency)
scalar fTest = 15.625;
const scalar fRatio = pow(2, 1.0/octave);
const scalar fRatioL2C = pow(2, 0.5/octave);
// IDs of band IDs
labelHashSet bandIDs(f.size());
// Centre frequencies
DynamicList<scalar> fc;
// Convert to lower band limit
fTest /= fRatioL2C;
forAll(f, i)
{
if (f[i] >= fTest)
{
// Advance band if appropriate
while (f[i] > fTest)
{
fTest *= fRatio;
}
fTest /= fRatio;
if (bandIDs.insert(i))
{
// Also store (next) centre frequency
fc.append(fTest*fRatioL2C);
}
fTest *= fRatio;
if (fTest > fUpper)
{
break;
}
}
}
fBandIDs = bandIDs.toc();
// Remove the last centre frequency (beyond upper frequency limit)
fc.remove();
fCentre.transfer(fc);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::noiseFFT::noiseFFT
(
const scalar deltaT,
const scalarField& pressure
)
:
scalarField(pressure),
deltaT_(deltaT)
{
scalarField& p = *this;
p -= average(p);
}
Foam::noiseFFT::noiseFFT(const fileName& pFileName, const label skip)
:
scalarField(),
deltaT_(0.0)
{
// Construct pressure data file
IFstream pFile(pFileName);
// Check pFile stream is OK
if (!pFile.good())
{
FatalErrorInFunction
<< "Cannot read file " << pFileName
<< exit(FatalError);
}
if (skip)
{
scalar dummyt, dummyp;
for (label i = 0; i < skip; i++)
{
pFile >> dummyt;
if (!pFile.good() || pFile.eof())
{
FatalErrorInFunction
<< "Number of points in file " << pFileName
<< " is less than the number to be skipped = " << skip
<< exit(FatalError);
}
pFile >> dummyp;
}
}
scalar t = 0, T0 = 0, T1 = 0;
DynamicList<scalar> pData(100000);
label i = 0;
while (!(pFile >> t).eof())
{
if (i == 0)
{
T0 = t;
}
T1 = t;
pFile >> pData(i++);
}
// Note: assumes fixed time step
deltaT_ = (T1 - T0)/pData.size();
this->transfer(pData);
scalarField& p = *this;
p -= average(p);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::graph Foam::noiseFFT::pt() const
{
scalarField t(size());
forAll(t, i)
{
t[i] = i*deltaT_;
}
return graph
(
"p(t)",
"t [s]",
"p(t) [Pa]",
t,
*this
);
}
Foam::tmp<Foam::scalarField> Foam::noiseFFT::Pf
(
const tmp<scalarField>& tpn
) const
{
// Calculate the 2-sided fft
// Note: result not scaled
tmp<scalarField> tPn2
(
mag
(
fft::reverseTransform
(
ReComplexField(tpn),
labelList(1, tpn().size())
)
)
);
tpn.clear();
// Only storing the positive half
// Note: storing (N/2) values, DC component at position (0)
tmp<scalarField> tPn
(
new scalarField
(
scalarField::subField(tPn2(), tPn2().size()/2 + 1)
)
);
return tPn;
}
Foam::graph Foam::noiseFFT::meanPf(const windowModel& window) const
{
const label N = window.nSamples();
const label nWindow = window.nWindow();
scalarField meanPf(N/2 + 1, 0.0);
for (label windowI = 0; windowI < nWindow; ++windowI)
{
meanPf += Pf(window.apply<scalar>(*this, windowI));
}
meanPf /= scalar(nWindow);
scalar deltaf = 1.0/(N*deltaT_);
scalarField f(meanPf.size());
forAll(f, i)
{
f[i] = i*deltaf;
}
return graph
(
"P(f)",
"f [Hz]",
"P(f) [Pa]",
f,
meanPf
);
}
Foam::graph Foam::noiseFFT::RMSmeanPf(const windowModel& window) const
{
const label N = window.nSamples();
const label nWindow = window.nWindow();
scalarField RMSMeanPf(N/2 + 1, 0.0);
for (label windowI = 0; windowI < nWindow; ++windowI)
{
RMSMeanPf += sqr(Pf(window.apply<scalar>(*this, windowI)));
}
RMSMeanPf = sqrt(RMSMeanPf/scalar(nWindow))/scalar(N);
scalar deltaf = 1.0/(N*deltaT_);
scalarField f(RMSMeanPf.size());
forAll(f, i)
{
f[i] = i*deltaf;
}
return graph
(
"Prms(f)",
"f [Hz]",
"Prms(f) [Pa]",
f,
RMSMeanPf
);
}
Foam::graph Foam::noiseFFT::PSDf(const windowModel& window) const
{
const label N = window.nSamples();
const label nWindow = window.nWindow();
scalarField psd(N/2 + 1, 0.0);
for (label windowI = 0; windowI < nWindow; ++windowI)
{
psd += sqr(Pf(window.apply<scalar>(*this, windowI)));
}
scalar deltaf = 1.0/(N*deltaT_);
scalar fs = 1.0/deltaT_;
psd /= scalar(nWindow)*fs*N;
// Scaling due to use of 1-sided FFT
// Note: do not scale DC component
psd *= 2;
psd.first() /= 2;
psd.last() /= 2;
scalarField f(psd.size());
if (0) // if (debug)
{
Pout<< "Average PSD: " << average(psd) << endl;
}
forAll(f, i)
{
f[i] = i*deltaf;
}
return graph
(
"PSD(f)",
"f [Hz]",
"PSD(f) [PaPa_Hz]",
f,
psd
);
}
Foam::graph Foam::noiseFFT::PSD(const graph& gPSDf) const
{
return graph
(
"PSD(f)",
"f [Hz]",
"PSD_dB(f) [dB_Hz]",
gPSDf.x(),
10*log10(gPSDf.y()/sqr(p0))
);
}
Foam::graph Foam::noiseFFT::octaves
(
const graph& g,
const labelList& freqBandIDs,
bool integrate
) const
{
if (freqBandIDs.size() < 2)
{
WarningInFunction
<< "Octave frequency bands are not defined "
<< "- skipping octaves calculation"
<< endl;
return graph
(
"octave",
"x",
"y",
scalarField(),
scalarField()
);
}
const scalarField& f = g.x();
const scalarField& data = g.y();
scalarField octData(freqBandIDs.size() - 1, 0.0);
scalarField fm(freqBandIDs.size() -1, 0.0);
for (label bandI = 0; bandI < freqBandIDs.size() - 1; bandI++)
{
label fb0 = freqBandIDs[bandI];
label fb1 = freqBandIDs[bandI+1];
fm[bandI] = f[fb0];
if (fb0 == fb1) continue;
if (integrate)
{
for (label freqI = fb0; freqI < fb1; freqI++)
{
label f0 = f[freqI];
label f1 = f[freqI + 1];
scalar dataAve = 0.5*(data[freqI] + data[freqI + 1]);
octData[bandI] += dataAve*(f1 - f0);
}
}
else
{
for (label freqI = fb0; freqI < fb1; freqI++)
{
octData[bandI] += data[freqI];
}
}
}
return graph
(
"octaves(f)",
"fm [Hz]",
"octave data",
fm,
octData
);
}
Foam::scalar Foam::noiseFFT::dbToPa(const scalar db) const
{
return p0*pow(10.0, db/20.0);
}
Foam::tmp<Foam::scalarField> Foam::noiseFFT::dbToPa
(
const tmp<scalarField>& db
) const
{
return p0*pow(10.0, db/20.0);
}
// ************************************************************************* //

View File

@ -2,8 +2,8 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -25,11 +25,26 @@ Class
Foam::noiseFFT Foam::noiseFFT
Description Description
FFT of the pressure field Performs FFT of pressure field to generate noise data.
General functionality:
- Pf: fft of the pressure data
- meanPf: multi-window mean fft
- RMSmeanPf: multi-window RMS mean fft
- PSDf: multi-window power spectral density (PSD) in frequency domain
- PSD: power spectral density in dB/Hz
- SPL: sound pressure level in dB
Octave-based data:
- PSD spectrum
- SPL spectrum
SourceFiles SourceFiles
noiseFFT.C noiseFFT.C
SeeAlso
windowModel.H
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef noiseFFT_H #ifndef noiseFFT_H
@ -37,6 +52,7 @@ SourceFiles
#include "scalarField.H" #include "scalarField.H"
#include "graph.H" #include "graph.H"
#include "windowModel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -44,7 +60,7 @@ namespace Foam
{ {
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class noiseFFT Declaration Class noiseFFT Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
class noiseFFT class noiseFFT
@ -54,7 +70,18 @@ class noiseFFT
// Private data // Private data
//- Time spacing of the raw data //- Time spacing of the raw data
scalar deltat_; scalar deltaT_;
struct octaveBandInfo
{
label octave;
// IDs of bin boundaries in pressure data
labelList binIDs;
// Centre frequencies for each bin
scalarField centreFreq;
};
public: public:
@ -81,37 +108,61 @@ public:
// Member Functions // Member Functions
//- Return the graph of p(t) //- Return the FFT frequencies
static tmp<scalarField> frequencies
(
const label N,
const scalar deltaT
);
//- Return the PSD [dB/Hz]
// Input PSD in [Pa^2/Hz]
static tmp<scalarField> PSD(const scalarField& PSDf);
//- Return the SPL [dB]
// Input P(rms)^2 in [Pa^2]
static tmp<scalarField> SPL(const scalarField& Prms2);
//- Return a list of the frequency indices wrt f field that
// correspond to the bands limits for a given octave
static void octaveBandInfo
(
const scalarField& f,
const scalar fLower,
const scalar fUpper,
const scalar octave,
labelList& fBandIDs,
scalarField& fCentre
);
//- Return the graph of pressure as a function of time
graph pt() const; graph pt() const;
//- Return the nth window
tmp<scalarField> window(const label N, const label n) const;
//- Return the Hanning window function
tmp<scalarField> Hanning(const label N) const;
//- Return the fft of the given pressure data //- Return the fft of the given pressure data
tmp<scalarField> Pf(const tmp<scalarField>& pn) const; tmp<scalarField> Pf(const tmp<scalarField>& pn) const;
//- Return the multi-window mean fft of the complete pressure data //- Return the multi-window mean fft of the complete pressure data [Pa]
graph meanPf(const label N, const label nw) const; graph meanPf(const windowModel& window) const;
//- Return the multi-window RMS mean fft of the complete pressure data //- Return the multi-window RMS mean fft of the complete pressure
graph RMSmeanPf(const label N, const label nw) const; // data [Pa]
graph RMSmeanPf(const windowModel& window) const;
//- Return the narrow-band PFL (pressure-fluctuation level) spectrum //- Return the multi-window PSD (power spectral density) of the complete
graph Lf(const graph& gPf) const; // pressure data [Pa^2/Hz]
graph PSDf(const windowModel& window) const;
//- Return the one-third-octave-band PFL spectrum //- Return the PSD [dB/Hz]
// starting at octave with mean frequency f1 // Takes PSD in [Pa^2/Hz]
graph Ldelta(const graph& gLf, const scalar f1, const scalar fU) const; graph PSD(const graph& gPSDf) const;
//- Return the one-third-octave-band pressure spectrum //- Generate octave data
// starting at octave with mean frequency f1 graph octaves
graph Pdelta(const graph& gLf, const scalar f1, const scalar fU) const; (
const graph& g,
//- Return the total PFL as the sum of Lf over all frequencies const labelList& freqBandIDs,
scalar Lsum(const graph& gLf) const; bool integrate
) const;
//- Convert the db into Pa //- Convert the db into Pa
scalar dbToPa(const scalar db) const; scalar dbToPa(const scalar db) const;

View File

@ -0,0 +1,151 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd.
\\/ 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 "noiseModel.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(noiseModel, 0);
defineRunTimeSelectionTable(noiseModel, dictionary);
}
// * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
Foam::scalar Foam::noiseModel::checkUniformTimeStep
(
const scalarList& times
) const
{
scalar deltaT = -1.0;
if (times.size() > 1)
{
for (label i = 1; i < times.size(); i++)
{
scalar dT = times[i] - times[i-1];
if (deltaT < 0)
{
deltaT = dT;
}
if (mag(deltaT - dT) > SMALL)
{
FatalErrorInFunction
<< "Unable to process data with a variable time step"
<< exit(FatalError);
}
}
}
else
{
FatalErrorInFunction
<< "Unable to create FFT with a single value"
<< exit(FatalError);
}
return deltaT;
}
Foam::label Foam::noiseModel::findStartTimeIndex
(
const instantList& allTimes,
const scalar startTime
) const
{
forAll(allTimes, timeI)
{
const instant& i = allTimes[timeI];
if (i.value() >= startTime)
{
return timeI;
}
}
return 0;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::noiseModel::noiseModel(const dictionary& dict)
:
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"))
{
// Check number of samples - must be a power of 2 for our FFT
bool powerOf2 = ((nSamples_ != 0) && !(nSamples_ & (nSamples_ - 1)));
if (!powerOf2)
{
FatalIOErrorInFunction(dict)
<< "N: Number of samples in sampling windows must be a "
<< "power of 2"
<< exit(FatalIOError);
}
if (fLower_ < 0)
{
FatalIOErrorInFunction(dict)
<< "fl: lower frequency bound must be greater than zero"
<< exit(FatalIOError);
}
if (fUpper_ < 0)
{
FatalIOErrorInFunction(dict)
<< "fu: upper frequency bound must be greater than zero"
<< exit(FatalIOError);
}
if (fUpper_ < fLower_)
{
FatalIOErrorInFunction(dict)
<< "fu: upper frequency bound must be greater than lower "
<< "frequency bound (fl)"
<< exit(FatalIOError);
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::noiseModel::~noiseModel()
{}
// ************************************************************************* //

View File

@ -0,0 +1,179 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd.
\\/ 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::noiseModel
Description
Base class for noise models.
Data is read from a dictionary, e.g.
\verbatim
rhoRef 0;
N 4096;
fl 25;
fu 25;
startTime 0;
\endverbatim
where
\table
Property | Description | Required | Default value
rhoRef | Reference density | no | 1
N | Number of samples in sampling window | no | 65536 (2^16)
fl | Lower frequency bounds | no | 25
fu | Upper frequency bounds | no | 10000
startTime | Start time | no | 0
graphFormat | Graph format | no | raw
\endtable
Note
The number of samples in the sampling window must be a power of 2
SourceFiles
noiseModel.C
\*---------------------------------------------------------------------------*/
#ifndef noiseModel_H
#define noiseModel_H
#include "dictionary.H"
#include "scalarList.H"
#include "instantList.H"
#include "windowModel.H"
#include "runTimeSelectionTables.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class noiseModel Declaration
\*---------------------------------------------------------------------------*/
class noiseModel
{
private:
// Private Member Functions
//- Disallow default bitwise copy construct
noiseModel(const noiseModel&);
//- Disallow default bitwise assignment
void operator=(const noiseModel&);
protected:
// Protected Data
//- Copy of dictionary used for construction
const dictionary dict_;
//- Reference density (to convert from kinematic to static pressure)
scalar rhoRef_;
//- Number of samples in sampling window, default = 2^16
label nSamples_;
//- Lower frequency limit, default = 25Hz
scalar fLower_;
//- Upper frequency limit, default = 10kHz
scalar fUpper_;
//- Start time, default = 0s
scalar startTime_;
//- Window model
autoPtr<windowModel> windowModelPtr_;
//- Graph format
word graphFormat_;
// Protected Member Functions
//- Check and return uniform time step
scalar checkUniformTimeStep
(
const scalarList& times
) const;
//- Find and return start time index
label findStartTimeIndex
(
const instantList& allTimes,
const scalar startTime
) const;
public:
//- Runtime type information
TypeName("noiseModel");
//- Run time selection table
declareRunTimeSelectionTable
(
autoPtr,
noiseModel,
dictionary,
(
const dictionary& dict
),
(dict)
);
//- Selector
static autoPtr<noiseModel> New(const dictionary& dict);
//- Constructor
noiseModel(const dictionary& dict);
//- Destructor
virtual ~noiseModel();
// Public Member Functions
//- Abstract call to calculate
virtual void calculate() = 0;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,53 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenCFD Ltd.
\\/ 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 "noiseModel.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::autoPtr<Foam::noiseModel> Foam::noiseModel::New(const dictionary& dict)
{
const word modelType(dict.lookup("noiseModel"));
Info<< "Selecting noiseModel " << modelType << endl;
dictionaryConstructorTable::iterator cstrIter =
dictionaryConstructorTablePtr_->find(modelType);
if (cstrIter == dictionaryConstructorTablePtr_->end())
{
FatalErrorInFunction
<< "Unknown noiseModel type "
<< modelType << nl << nl
<< "Valid noiseModel types are:" << nl
<< dictionaryConstructorTablePtr_->sortedToc()
<< exit(FatalError);
}
return autoPtr<noiseModel>(cstrIter()(dict.subDict(modelType + "Coeffs")));
}
// ************************************************************************* //

View File

@ -0,0 +1,207 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd.
\\/ 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 "pointNoise.H"
#include "noiseFFT.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace noiseModels
{
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
defineTypeNameAndDebug(pointNoise, 0);
addToRunTimeSelectionTable(noiseModel, pointNoise, dictionary);
// * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
void pointNoise::filterTimeData
(
const Function1Types::CSV<scalar>& pData,
scalarField& t,
scalarField& p
)
{
const scalarField t0(pData.x());
const scalarField p0(pData.y());
DynamicList<scalar> tf(t0.size());
DynamicList<scalar> pf(t0.size());
forAll(t0, timeI)
{
if (t0[timeI] >= startTime_)
{
tf.append(t0[timeI]);
pf.append(p0[timeI]);
}
}
t.transfer(tf);
p.transfer(pf);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void pointNoise::calculate()
{
// Point data only handled by master
if (!Pstream::master())
{
return;
}
Info<< "Reading data file" << endl;
Function1Types::CSV<scalar> pData("pressure", dict_, "Data");
// Time and pressure history data
scalarField t, p;
filterTimeData(pData, t, p);
p *= rhoRef_;
Info<< " read " << t.size() << " values" << nl << endl;
Info<< "Creating noise FFT" << endl;
const scalar deltaT = checkUniformTimeStep(t);
// Determine the windowing
windowModelPtr_->validate(t.size());
const windowModel& win = windowModelPtr_();
const scalar deltaf = 1.0/(deltaT*win.nSamples());
fileName outDir(fileName("postProcessing")/"noise"/typeName);
// Create the fft
noiseFFT nfft(deltaT, p);
// Narrow band data
// ----------------
// RMS pressure [Pa]
graph Prmsf(nfft.RMSmeanPf(win));
Info<< " Creating graph for " << Prmsf.title() << endl;
Prmsf.write(outDir, graph::wordify(Prmsf.title()), graphFormat_);
// PSD [Pa^2/Hz]
graph PSDf(nfft.PSDf(win));
Info<< " Creating graph for " << PSDf.title() << endl;
PSDf.write(outDir, graph::wordify(PSDf.title()), graphFormat_);
// PSD [dB/Hz]
graph PSDg
(
"PSD_dB_Hz(f)",
"f [Hz]",
"PSD(f) [dB_Hz]",
Prmsf.x(),
noiseFFT::PSD(PSDf.y())
);
Info<< " Creating graph for " << PSDg.title() << endl;
PSDg.write(outDir, graph::wordify(PSDg.title()), graphFormat_);
// SPL [dB]
graph SPLg
(
"SPL_dB(f)",
"f [Hz]",
"SPL(f) [dB]",
Prmsf.x(),
noiseFFT::SPL(PSDf.y()*deltaf)
);
Info<< " Creating graph for " << SPLg.title() << endl;
SPLg.write(outDir, graph::wordify(SPLg.title()), graphFormat_);
labelList octave13BandIDs;
scalarField octave13FreqCentre;
noiseFFT::octaveBandInfo
(
Prmsf.x(),
fLower_,
fUpper_,
3,
octave13BandIDs,
octave13FreqCentre
);
// 1/3 octave data
// ---------------
// PSD [Pa^2/Hz]
graph PSD13f(nfft.octaves(PSDf, octave13BandIDs, false));
// Integrated PSD = P(rms)^2 [Pa^2]
graph Prms13f2(nfft.octaves(PSDf, octave13BandIDs, true));
graph PSD13g
(
"PSD13_dB_Hz(fm)",
"fm [Hz]",
"PSD(fm) [dB_Hz]",
octave13FreqCentre,
noiseFFT::PSD(PSD13f.y())
);
Info<< " Creating graph for " << PSD13g.title() << endl;
PSD13g.write(outDir, graph::wordify(PSD13g.title()), graphFormat_);
graph SPL13g
(
"SPL13_dB(fm)",
"fm [Hz]",
"SPL(fm) [dB]",
octave13FreqCentre,
noiseFFT::SPL(Prms13f2.y())
);
Info<< " Creating graph for " << SPL13g.title() << endl;
SPL13g.write(outDir, graph::wordify(SPL13g.title()), graphFormat_);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
pointNoise::pointNoise(const dictionary& dict)
:
noiseModel(dict)
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
pointNoise::~pointNoise()
{}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace noiseModels
} // End namespace Foam
// ************************************************************************* //

View File

@ -0,0 +1,142 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd.
\\/ 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::noiseModels::pointNoise
Description
Perform noise analysis on point-based pressure data.
Input data is read from a dictionary, e.g.
\verbatim
// Pressure reference
pRef 0;
// Number of samples in sampling window
// Must be a power of 2, default = 2^16 (=65536)
N 4096;
// Lower frequency bounds
fl 25;
// Upper frequency bounds
fu 25;
// Start time
startTime 0;
windowModel <modelType>
<modelType>Coeffs
{
...
}
// Pressure data supplied in CSV file format
csvFileData
{
fileName "pressureData";
nHeaderLine 1;
refColumn 0;
componentColumns (1);
separator " ";
mergeSeparators yes;
}
graphFormat raw;
\endverbatim
SourceFiles
pointNoise.C
SeeAlso
noiseModel.H
windowModel.H
\*---------------------------------------------------------------------------*/
#ifndef pointNoise_H
#define pointNoise_H
#include "noiseModel.H"
#include "CSV.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace noiseModels
{
/*---------------------------------------------------------------------------*\
Class pointNoise Declaration
\*---------------------------------------------------------------------------*/
class pointNoise
:
public noiseModel
{
protected:
// Protected Member Functions
void filterTimeData
(
const Function1Types::CSV<scalar>& pData,
scalarField& t,
scalarField& p
);
public:
//- Runtime type information
TypeName("pointNoise");
//- Constructor
pointNoise(const dictionary& dict);
//- Destructor
virtual ~pointNoise();
// Public Member Functions
//- Calculate
virtual void calculate();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace noiseModels
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,705 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd.
\\/ 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 "surfaceNoise.H"
#include "surfaceReader.H"
#include "surfaceWriter.H"
#include "noiseFFT.H"
#include "graph.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace noiseModels
{
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
defineTypeNameAndDebug(surfaceNoise, 0);
addToRunTimeSelectionTable(noiseModel, surfaceNoise, dictionary);
// * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
void surfaceNoise::initialise(const dictionary& dict)
{
label nAvailableTimes = 0;
// All reading performed on the master processor only
if (Pstream::master())
{
// Create the surface reader
const word readerType(dict.lookup("reader"));
readerPtr_.reset(surfaceReader::New(readerType, inputFileName_).ptr());
// Find the index of the pressure data
const word pName(dict.lookupOrDefault<word>("pName", "p"));
const List<word> fieldNames(readerPtr_->fieldNames(0));
pIndex_ = findIndex(fieldNames, pName);
if (pIndex_ == -1)
{
FatalErrorInFunction
<< "Unable to find pressure field name " << pName
<< " in list of available fields: " << fieldNames
<< exit(FatalError);
}
// Create the surface writer
// - 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();
startTimeIndex_ = findStartTimeIndex(allTimes, startTime_);
// Determine the windowing
nAvailableTimes = allTimes.size() - startTimeIndex_;
}
Pstream::scatter(pIndex_);
Pstream::scatter(startTimeIndex_);
Pstream::scatter(nAvailableTimes);
// Note: all processors should call the windowing validate function
label nRequiredTimes = windowModelPtr_->validate(nAvailableTimes);
if (Pstream::master())
{
// Restrict times
const instantList allTimes = readerPtr_->times();
times_.setSize(nRequiredTimes);
forAll(times_, timeI)
{
times_[timeI] = allTimes[timeI + startTimeIndex_].value();
}
deltaT_ = checkUniformTimeStep(times_);
// Read the surface geometry
const meshedSurface& surf = readerPtr_->geometry();
nFace_ = surf.size();
}
Pstream::scatter(times_);
Pstream::scatter(deltaT_);
Pstream::scatter(nFace_);
}
void surfaceNoise::readSurfaceData
(
const labelList& procFaceOffset,
List<scalarField>& pData
)
{
// Data is stored as pressure on surface at a given time. Now we need to
// pivot the data so that we have the complete pressure time history per
// surface face. In serial mode, this results in all pressure data being
// loaded into memory (!)
Info << "Reading pressure data" << endl;
if (Pstream::parRun())
{
PstreamBuffers pBufs(Pstream::nonBlocking);
// Procedure:
// 1. Master processor reads pressure data for all faces for all times
// 2. Master sends each processor a subset of faces
// 3. Local processor reconstructs the full time history for the subset
// of faces
// Note: reading all data on master to avoid potential NFS problems...
const label myProcI = Pstream::myProcNo();
const label nLocalFace =
procFaceOffset[myProcI + 1] - procFaceOffset[myProcI];
// Complete pressure time history data for subset of faces
pData.setSize(nLocalFace);
const label nTimes = times_.size();
forAll(pData, faceI)
{
pData[faceI].setSize(nTimes);
}
// Read and send data
forAll(times_, i)
{
pBufs.clear();
if (Pstream::master())
{
label timeI = i + startTimeIndex_;
Info<< " time: " << times_[i] << endl;
// Read pressure at all faces for time timeI
scalarField p(readerPtr_->field(timeI, pIndex_, scalar(0)));
// Apply conversions
p *= rhoRef_;
// Send subset of faces to each processor
for (label procI = 0; procI < Pstream::nProcs(); procI++)
{
label face0 = procFaceOffset[procI];
label nLocalFace =
procFaceOffset[procI + 1] - procFaceOffset[procI];
UOPstream toProc(procI, pBufs);
toProc << SubList<scalar>(p, nLocalFace, face0);
}
}
pBufs.finishedSends();
// Receive data from the master
UIPstream fromProc(0, pBufs);
scalarList pSlice(fromProc);
forAll(pSlice, faceI)
{
pData[faceI][i] = pSlice[faceI];
}
}
}
else
{
const label nLocalFace = procFaceOffset[0];
pData.setSize(nLocalFace);
forAll(times_, timeI)
{
forAll(pData, faceI)
{
pData[faceI].setSize(times_.size());
}
}
forAll(times_, i)
{
label timeI = i + startTimeIndex_;
Info<< " time: " << times_[i] << endl;
const scalarField p(readerPtr_->field(timeI, pIndex_, scalar(0)));
forAll(p, faceI)
{
pData[faceI][i] = p[faceI]*rhoRef_;
}
}
}
Info<< "Read "
<< returnReduce(pData.size(), sumOp<label>())
<< " pressure traces with "
<< times_.size()
<< " time values" << nl << endl;
}
Foam::scalar surfaceNoise::writeSurfaceData
(
const word& fName,
const word& groupName,
const word& title,
const scalar freq,
const scalarField& data,
const labelList& procFaceOffset
) const
{
Info<< " processing " << title << " for frequency " << freq << endl;
fileName outDir
(
fileName("postProcessing")/"noise"/groupName/Foam::name(freq)
);
if (Pstream::parRun())
{
// Collect the surface data so that we can output the surfaces
PstreamBuffers pBufs(Pstream::nonBlocking);
if (!Pstream::master())
{
UOPstream toProc(0, pBufs);
toProc << data;
}
pBufs.finishedSends();
scalar areaAverage = 0;
if (Pstream::master())
{
const meshedSurface& surf = readerPtr_->geometry();
scalarField allData(surf.size());
forAll(data, faceI)
{
// Master procFaceOffset is zero...
allData[faceI] = data[faceI];
}
for (label procI = 1; procI < Pstream::nProcs(); procI++)
{
UIPstream fromProc(procI, pBufs);
scalarList dataSlice(fromProc);
forAll(dataSlice, i)
{
label faceI = procFaceOffset[procI] + i;
allData[faceI] = dataSlice[i];
}
}
fileName outFileName = writerPtr_->write
(
outDir,
fName,
surf.points(),
surf.faces(),
title,
allData,
false
);
// TODO: Move faceAreas to demand-driven function in MeshedSurface
// scalarField faceAreas(surf.faces().size());
// forAll(faceAreas, i)
// {
// faceAreas[i] = surf.faces()[i].mag(surf.points());
// }
//
// areaAverage = sum(allData*faceAreas)/sum(faceAreas);
areaAverage = sum(allData)/allData.size();
}
Pstream::scatter(areaAverage);
return areaAverage;
}
else
{
const meshedSurface& surf = readerPtr_->geometry();
writerPtr_->write
(
outDir,
fName,
surf.points(),
surf.faces(),
title,
data,
false
);
// TODO: Move faceAreas to demand-driven function in MeshedSurface
// scalarField faceAreas(surf.faces().size());
// forAll(faceAreas, i)
// {
// faceAreas[i] = surf.faces()[i].mag(surf.points());
// }
//
// return sum(data*faceAreas)/sum(faceAreas);
return sum(data)/data.size();
}
}
Foam::scalar surfaceNoise::surfaceAverage
(
const scalarField& data,
const labelList& procFaceOffset
) const
{
if (Pstream::parRun())
{
// Collect the surface data so that we can output the surfaces
PstreamBuffers pBufs(Pstream::nonBlocking);
if (!Pstream::master())
{
UOPstream toProc(0, pBufs);
toProc << data;
}
pBufs.finishedSends();
scalar areaAverage = 0;
if (Pstream::master())
{
const meshedSurface& surf = readerPtr_->geometry();
scalarField allData(surf.size());
forAll(data, faceI)
{
// Master procFaceOffset is zero...
allData[faceI] = data[faceI];
}
for (label procI = 1; procI < Pstream::nProcs(); procI++)
{
UIPstream fromProc(procI, pBufs);
scalarList dataSlice(fromProc);
forAll(dataSlice, i)
{
label faceI = procFaceOffset[procI] + i;
allData[faceI] = dataSlice[i];
}
}
// TODO: Move faceAreas to demand-driven function in MeshedSurface
scalarField faceAreas(surf.faces().size());
forAll(faceAreas, i)
{
faceAreas[i] = surf.faces()[i].mag(surf.points());
}
// areaAverage = sum(allData*faceAreas)/sum(faceAreas);
areaAverage = sum(allData)/allData.size();
}
Pstream::scatter(areaAverage);
return areaAverage;
}
else
{
const meshedSurface& surf = readerPtr_->geometry();
// TODO: Move faceAreas to demand-driven function in MeshedSurface
scalarField faceAreas(surf.faces().size());
forAll(faceAreas, i)
{
faceAreas[i] = surf.faces()[i].mag(surf.points());
}
// return sum(data*faceAreas)/sum(faceAreas);
return sum(data)/data.size();
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
surfaceNoise::surfaceNoise(const dictionary& dict)
:
noiseModel(dict),
inputFileName_(dict.lookup("inputFile")),
pIndex_(0),
times_(),
deltaT_(0),
startTimeIndex_(0),
nFace_(0),
fftWriteInterval_(dict.lookupOrDefault("fftWriteInterval", 1))
{
initialise(dict);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
surfaceNoise::~surfaceNoise()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void surfaceNoise::calculate()
{
// Container for pressure time history data per face
List<scalarField> pData;
// Processor procFaceOffsets
labelList procFaceOffset;
if (Pstream::parRun())
{
const label nProcs = Pstream::nProcs();
const label nFacePerProc = floor(nFace_/nProcs) + 1;
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);
// Process the pressure data, and store results as surface values per
// frequency so that it can be output using the surface writer
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)
{
surfPrmsf[freqI].setSize(nLocalFace);
surfPSDf[freqI].setSize(nLocalFace);
}
// Storage for 1/3 octave data
labelList octave13BandIDs;
scalarField octave13FreqCentre;
noiseFFT::octaveBandInfo
(
freq1,
fLower_,
fUpper_,
3,
octave13BandIDs,
octave13FreqCentre
);
List<scalarField> surfPSD13f(octave13BandIDs.size() - 1);
List<scalarField> surfPrms13f2(octave13BandIDs.size() - 1);
forAll(surfPSD13f, freqI)
{
surfPSD13f[freqI].setSize(nLocalFace);
surfPrms13f2[freqI].setSize(nLocalFace);
}
const windowModel& win = windowModelPtr_();
forAll(pData, faceI)
{
const scalarField& p = pData[faceI];
noiseFFT nfft(deltaT_, p);
graph Prmsf(nfft.RMSmeanPf(win));
graph PSDf(nfft.PSDf(win));
// Store the frequency results in slot for face of surface
forAll(surfPrmsf, i)
{
label freqI = (i + 1)*fftWriteInterval_ - 1;
surfPrmsf[i][faceI] = Prmsf.y()[freqI];
surfPSDf[i][faceI] = PSDf.y()[freqI];
}
// PSD [Pa^2/Hz]
graph PSD13f(nfft.octaves(PSDf, octave13BandIDs, false));
// Integrated PSD = P(rms)^2 [Pa^2]
graph Prms13f2(nfft.octaves(PSDf, octave13BandIDs, true));
// Store the 1/3 octave results in slot for face of surface
forAll(surfPSD13f, freqI)
{
surfPSD13f[freqI][faceI] = PSD13f.y()[freqI];
surfPrms13f2[freqI][faceI] = Prms13f2.y()[freqI];
}
// Free the storage for p
// p.clear();
}
// 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);
forAll(surfPrmsf, i)
{
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
);
PSDfAve[i] = writeSurfaceData
(
fName,
gName,
"PSDf",
freq1[freqI],
surfPSDf[i],
procFaceOffset
);
writeSurfaceData
(
fName,
gName,
"PSD",
freq1[freqI],
noiseFFT::PSD(surfPSDf[i]),
procFaceOffset
);
writeSurfaceData
(
fName,
gName,
"SPL",
freq1[freqI],
noiseFFT::SPL(surfPSDf[i]*deltaf),
procFaceOffset
);
}
graph Prmsfg
(
"Average Prms(f)",
"f [Hz]",
"P(f) [Pa]",
fOut,
PrmsfAve
);
Prmsfg.write(outDir, graph::wordify(Prmsfg.title()), graphFormat_);
graph PSDfg
(
"Average PSD_f(f)",
"f [Hz]",
"PSD(f) [PaPa_Hz]",
fOut,
PSDfAve
);
PSDfg.write(outDir, graph::wordify(PSDfg.title()), graphFormat_);
graph PSDg
(
"Average PSD_dB_Hz(f)",
"f [Hz]",
"PSD(f) [dB_Hz]",
fOut,
noiseFFT::PSD(PSDfAve)
);
PSDg.write(outDir, graph::wordify(PSDg.title()), graphFormat_);
graph SPLg
(
"Average SPL_dB(f)",
"f [Hz]",
"SPL(f) [dB]",
fOut,
noiseFFT::SPL(PSDfAve*deltaf)
);
SPLg.write(outDir, graph::wordify(SPLg.title()), graphFormat_);
}
Info<< "Writing one-third octave surface data" << endl;
{
scalarField PSDfAve(surfPSD13f.size(), 0);
scalarField Prms13f2Ave(surfPSD13f.size(), 0);
forAll(surfPSD13f, i)
{
const word& fName = inputFileName_.name(true);
const word gName = "oneThirdOctave";
PSDfAve[i] = writeSurfaceData
(
fName,
gName,
"PSD13f",
octave13FreqCentre[i],
surfPSD13f[i],
procFaceOffset
);
writeSurfaceData
(
fName,
gName,
"PSD13",
octave13FreqCentre[i],
noiseFFT::PSD(surfPSD13f[i]),
procFaceOffset
);
writeSurfaceData
(
fName,
gName,
"SPL13",
octave13FreqCentre[i],
noiseFFT::SPL(surfPrms13f2[i]),
procFaceOffset
);
Prms13f2Ave[i] = surfaceAverage(surfPrms13f2[i], procFaceOffset);
}
graph PSD13g
(
"Average PSD13_dB_Hz(fm)",
"fm [Hz]",
"PSD(fm) [dB_Hz]",
octave13FreqCentre,
noiseFFT::PSD(PSDfAve)
);
PSD13g.write(outDir, graph::wordify(PSD13g.title()), graphFormat_);
graph SPL13g
(
"Average SPL13_dB(fm)",
"fm [Hz]",
"SPL(fm) [dB]",
octave13FreqCentre,
noiseFFT::SPL(Prms13f2Ave)
);
SPL13g.write(outDir, graph::wordify(SPL13g.title()), graphFormat_);
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace noiseModels
} // End namespace Foam
// ************************************************************************* //

View File

@ -0,0 +1,208 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd.
\\/ 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::noiseModels::surfaceNoise
Description
Perform noise analysis on surface-based pressure data.
Input data is read from a dictionary, e.g.
\verbatim
// Pressure reference
pRef 0;
// Number of samples in sampling window
// Must be a power of 2, default = 2^16 (=65536)
N 4096;
// Lower frequency bounds
fl 25;
// Upper frequency bounds
fu 25;
// Start time
startTime 0;
windowModel <modelType>
<modelType>Coeffs
{
...
}
// Input file
inputFile "postProcessing/faceSource1/surface/patch/patch.case";
// Write interval for FFT data, default = 1
fftWriteInterval 100;
// Surface reader
reader ensight;
// Surface writer
writer ensight;
// Collate times for ensight output - ensures geometry is only written once
writeOptions
{
ensight
{
collateTimes 1;
}
}
\endverbatim
SourceFiles
surfaceNoise.C
SeeAlso
noiseModel.H
\*---------------------------------------------------------------------------*/
#ifndef surfaceNoise_H
#define surfaceNoise_H
#include "noiseModel.H"
#include "labelList.H"
#include "scalarField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of classes
class surfaceReader;
class surfaceWriter;
namespace noiseModels
{
/*---------------------------------------------------------------------------*\
Class surfaceNoise Declaration
\*---------------------------------------------------------------------------*/
class surfaceNoise
:
public noiseModel
{
protected:
// Protected Data
//- Input file name
const fileName inputFileName_;
//- Index of pressure field in reader field list
label pIndex_;
//- Sample times
scalarList times_;
//- Time step (constant)
scalar deltaT_;
//- Start time index
label startTimeIndex_;
//- Number of surface faces
label nFace_;
//- Frequency data output interval, default = 1
// nSamples/2 data points are returned from the FFT, which can
// result in a very large number of output files (1 per frequency)
label fftWriteInterval_;
//- Pointer to the surface reader
mutable autoPtr<surfaceReader> readerPtr_;
//- Pointer to the surface writer
autoPtr<surfaceWriter> writerPtr_;
// Protected Member Functions
//- Initialise
void initialise(const dictionary& dict);
//- Read surface data
void readSurfaceData
(
const labelList& procFaceOffset,
List<scalarField>& pData
);
//- Write surface data to file
// Returns the area average value
scalar writeSurfaceData
(
const word& fName,
const word& groupName,
const word& title,
const scalar freq,
const scalarField& data,
const labelList& procFaceOffset
) const;
//- Calculate the area average value
scalar surfaceAverage
(
const scalarField& data,
const labelList& procFaceOffset
) const;
public:
//- Runtime type information
TypeName("surfaceNoise");
//- Constructor
surfaceNoise(const dictionary& dict);
//- Destructor
virtual ~surfaceNoise();
// Public Member Functions
//- Calculate
virtual void calculate();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace noiseModels
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,122 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenCFD Ltd.
\\/ 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 "Hanning.H"
#include "addToRunTimeSelectionTable.H"
#include "mathematicalConstants.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace windowModels
{
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
defineTypeNameAndDebug(Hanning, 0);
addToRunTimeSelectionTable(windowModel, Hanning, dictionary);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Hanning::Hanning(const dictionary& dict, const label nSamples)
:
windowModel(dict, nSamples),
symmetric_(readBool(dict.lookup("symmetric"))),
extended_(readBool(dict.lookup("extended"))),
alpha_(dict.lookupOrDefault("alpha", 0.5)) // Hamming = 0.54
{
// Extend range if required
label offset = extended_ ? 1 : 0;
scalar m = nSamples - 1 + 2*offset;
scalarField t(nSamples);
forAll(t, i)
{
t[i] = i + offset;
}
scalarField& wf = *this;
wf = alpha_ - (1 - alpha_)*cos(constant::mathematical::twoPi*t/m);
// Reset second half of window if symmetric
if (symmetric_)
{
label midPointI = 0;
if (nSamples % 2 == 0)
{
midPointI = nSamples/2;
}
else
{
midPointI = (nSamples + 1)/2;
}
for (label i = 0; i < midPointI; i++)
{
wf[nSamples - i - 1] = wf[i];
}
}
scalar sumSqr = sum(sqr(wf));
// Normalisation
wf *= sqrt(nSamples/sumSqr);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Hanning::~Hanning()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Hanning::symmetric() const
{
return symmetric_;
}
bool Hanning::extended() const
{
return extended_;
}
Foam::scalar Hanning::alpha() const
{
return alpha_;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace windowModels
} // End namespace Foam
// ************************************************************************* //

View File

@ -0,0 +1,125 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenCFD Ltd.
\\/ 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::windowModels::Hanning
Description
Hanning window
The window is described by the function
\f[
wf = (1 - \alpha) - \alpha cos(2 \pi t/m);
\f]
Where:
\vartable
\alpha | Coefficient with a default value of 0.5
t | time
m | window width
\endvartable
The window can be further manipulated by the controls:
- \c symmetric: force the window to be symmetric
- \c extended: extend the window by 1 element at start and end to produce
non-zero values at the start and end positions. Note: window is
normalised to preserve energy content
SourceFiles
Hanning.C
\*---------------------------------------------------------------------------*/
#ifndef Hanning_H
#define Hanning_H
#include "autoPtr.H"
#include "runTimeSelectionTables.H"
#include "windowModel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace windowModels
{
/*---------------------------------------------------------------------------*\
Class Hanning Declaration
\*---------------------------------------------------------------------------*/
class Hanning
:
public windowModel
{
protected:
// Protected Member Data
//- Symmetric switch
bool symmetric_;
//- Extended switch
bool extended_;
//- Window coefficient, default = 0.5
scalar alpha_;
public:
//- Runtime type information
TypeName("Hanning");
//- Construct from dictionary
Hanning(const dictionary& dict, const label nSamples);
//- Destuctor
virtual ~Hanning();
// Public Member Functions
//- Return the symmetric flag
bool symmetric() const;
//- Return the extended flag
bool extended() const;
//- Return the window coefficient
scalar alpha() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace windowModels
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,66 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenCFD Ltd.
\\/ 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 "uniform.H"
#include "addToRunTimeSelectionTable.H"
#include "mathematicalConstants.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace windowModels
{
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
defineTypeNameAndDebug(uniform, 0);
addToRunTimeSelectionTable(windowModel, uniform, dictionary);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
uniform::uniform(const dictionary& dict, const label nSamples)
:
windowModel(dict, nSamples),
value_(readScalar(dict.lookup("value")))
{
scalarField& wf = *this;
wf = value_;
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
uniform::~uniform()
{}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace windowModels
} // End namespace Foam
// ************************************************************************* //

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation \\ / A nd | Copyright (C) 2016 OpenCFD Ltd.
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -21,57 +21,65 @@ License
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Global Class
fftRenumber Foam::windowModels::uniform
Description Description
Multi-dimensional renumbering used in the Numerical Recipes A window that applies uniform scaling.
fft routine.
SourceFiles SourceFiles
fftRenumber.C uniform.C
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef fftRenumber_H #ifndef uniform_H
#define fftRenumber_H #define uniform_H
#include "complex.H" #include "autoPtr.H"
#include "List.H" #include "runTimeSelectionTables.H"
#include "labelList.H" #include "windowModel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam namespace Foam
{ {
namespace windowModels
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // /*---------------------------------------------------------------------------*\
Class uniform Declaration
\*---------------------------------------------------------------------------*/
// Recursively evaluate the indexing necessary to do the folding of the fft class uniform
// data. We recurse until we have the indexing ncessary for the folding in all :
// directions. public windowModel
void fftRenumberRecurse {
(
List<complex>& data, protected:
List<complex>& renumData,
const labelList& nn, // Protected data
label nnprod,
label ii, //- Uniform value
label l1, scalar value_;
label l2
);
// Fold the n-d data array to get the fft components in the right places. public:
void fftRenumber
( //- Runtime type information
List<complex>& data, TypeName("uniform");
const labelList& nn
);
//- Construct from dictionary
uniform(const dictionary& dict, const label nSamples);
//- Destuctor
virtual ~uniform();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace windowModels
} // End namespace Foam } // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -0,0 +1,125 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd.
\\/ 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 "windowModel.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(windowModel, 0);
defineRunTimeSelectionTable(windowModel, dictionary);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::windowModel::windowModel(const dictionary& dict, const label nSamples)
:
scalarField(nSamples),
nOverlapSamples_(0),
nWindow_(dict.lookupOrDefault("nWindow", -1))
{
scalar prc = readScalar(dict.lookup("overlapPercent"));
nOverlapSamples_ = floor(prc/scalar(100)*nSamples);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::windowModel::~windowModel()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::label Foam::windowModel::nSamples() const
{
return size();
}
Foam::label Foam::windowModel::nWindow() const
{
return nWindow_;
}
Foam::label Foam::windowModel::nWindowsTotal(label nSamplesTotal) const
{
const label nSamples = this->nSamples();
return floor((nSamplesTotal - nSamples)/(nSamples - nOverlapSamples_)) + 1;
}
Foam::label Foam::windowModel::validate(const label nSamplesTotal)
{
label nSamples = this->nSamples();
if (nSamplesTotal < nSamples)
{
FatalErrorInFunction
<< "Block size N = " << nSamples
<< " is larger than total number of data points = " << nSamplesTotal
<< exit(FatalError);
}
label nWindowAvailable = nWindowsTotal(nSamplesTotal);
if (nWindow_ == -1)
{
nWindow_ = nWindowAvailable;
}
if (nWindow_ > nWindowAvailable)
{
FatalErrorInFunction
<< "Number of data points calculated with " << nWindow_
<< " windows greater than the total number of data points"
<< nl
<< " Block size, N = " << nSamples << nl
<< " Total number of data points = " << nSamplesTotal << nl
<< " Maximum number of windows = " << nWindowAvailable << nl
<< " Requested number of windows = " << nWindow_
<< exit(FatalError);
}
label nRequiredSamples =
nWindow_*nSamples - (nWindow_ - 1)*nOverlapSamples_;
Info<< "Windowing:" << nl
<< " Total samples : " << nSamplesTotal << nl
<< " Samples per window : " << nSamples << nl
<< " Number of windows : " << nWindow_ << nl
<< " Overlap size : " << nOverlapSamples_ << nl
<< " Required number of samples : " << nRequiredSamples
<< endl;
return nRequiredSamples;
}
// ************************************************************************* //

View File

@ -0,0 +1,143 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
-------------------------------------------------------------------------------
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::windowModel
Description
Base class for windowing models
SourceFiles
noiseFFT.C
\*---------------------------------------------------------------------------*/
#ifndef windowModel_H
#define windowModel_H
#include "autoPtr.H"
#include "runTimeSelectionTables.H"
#include "scalarField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class windowModel Declaration
\*---------------------------------------------------------------------------*/
class windowModel
:
public scalarField
{
protected:
// Protected Data
//- Number of overlap samples per window
label nOverlapSamples_;
//- Number of windows
label nWindow_;
public:
//- Runtime type information
TypeName("windowModel");
// Declare runtime constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
windowModel,
dictionary,
(
const dictionary& dict,
const label nSamples
),
(dict, nSamples)
);
//- Construct from dictionary
windowModel(const dictionary& dict, const label nSamples);
// Selectors
//- Return a reference to the selected window model
static autoPtr<windowModel> New
(
const dictionary& dict,
const label nSamples
);
//- Destuctor
virtual ~windowModel();
// Public Member Functions
//- Return the number of samples in the window
label nSamples() const;
//- Return the number of windows
label nWindow() const;
//- Return the total number of windows for a given number of samples
label nWindowsTotal(label nSamplesTotal) const;
//- Validate that the window is applicable to the data set size, and
// return the number of required data points
label validate(label n);
//- Return the windowed data
template<class Type>
tmp<Field<Type> > apply
(
const Field<Type>& fld,
const label windowI
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "windowModelTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,63 @@
#/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenCFD Ltd.
\\/ 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 "windowModel.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::autoPtr<Foam::windowModel> Foam::windowModel::New
(
const dictionary& dict,
const label nSamples
)
{
const word modelType(dict.lookup("windowModel"));
Info<< "Selecting windowModel " << modelType << endl;
dictionaryConstructorTable::iterator cstrIter =
dictionaryConstructorTablePtr_->find(modelType);
if (cstrIter == dictionaryConstructorTablePtr_->end())
{
FatalErrorIn
(
"windowModel::New(const dictionary&, const label)"
) << "Unknown windowModel type "
<< modelType << nl << nl
<< "Valid windowModel types are:" << nl
<< dictionaryConstructorTablePtr_->sortedToc()
<< exit(FatalError);
}
return autoPtr<windowModel>
(
cstrIter()(dict.subDict(modelType + "Coeffs"), nSamples)
);
}
// ************************************************************************* //

View File

@ -0,0 +1,68 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd.
\\/ 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/>.
\*---------------------------------------------------------------------------*/
template<class Type>
Foam::tmp<Foam::Field<Type> > Foam::windowModel::apply
(
const Field<Type>& fld,
const label windowI
) const
{
label nSamples = this->nSamples();
if (nSamples > fld.size())
{
FatalErrorInFunction
<< "Number of samples in sampling window is greater than the "
<< "size of the input field" << nl
<< " input field size = " << fld.size() << nl
<< " window size = " << nSamples << nl
<< " requested window index = " << windowI
<< exit(FatalError);
}
tmp<Field<Type> > tresult(new Field<Type>(nSamples, pTraits<Type>::zero));
Field<Type>& result = tresult.ref();
label nWindow = nWindowsTotal(fld.size());
if (windowI >= nWindow)
{
FatalErrorInFunction
<< "Requested window " << windowI << " outside of range. "
<< "Number of available windows is " << nWindow
<< abort(FatalError);
}
label windowOffset = windowI*(nSamples - nOverlapSamples_);
const scalarField& wf = *this;
result = wf*SubField<Type>(fld, nSamples, windowOffset);
return tresult;
}
// ************************************************************************* //

View File

@ -51,6 +51,12 @@ $(surfWriters)/starcd/starcdSurfaceWriter.C
$(surfWriters)/vtk/vtkSurfaceWriter.C $(surfWriters)/vtk/vtkSurfaceWriter.C
$(surfWriters)/boundaryData/boundaryDataSurfaceWriter.C $(surfWriters)/boundaryData/boundaryDataSurfaceWriter.C
surfReaders = sampledSurface/readers
$(surfReaders)/surfaceReader.C
$(surfReaders)/surfaceReaderNew.C
$(surfReaders)/ensight/ensightSurfaceReader.C
graphField/writePatchGraph.C graphField/writePatchGraph.C
graphField/writeCellGraph.C graphField/writeCellGraph.C
graphField/makeGraph.C graphField/makeGraph.C

View File

@ -0,0 +1,515 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd.
\\/ 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 "ensightSurfaceReader.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(ensightSurfaceReader, 0);
addToRunTimeSelectionTable(surfaceReader, ensightSurfaceReader, fileName);
}
void Foam::ensightSurfaceReader::skip(const label n, IFstream& is) const
{
label i = 0;
token t;
while (is.good() && (i < n))
{
is >> t;
i++;
if (debug)
{
Info<< "Skipping token " << t << endl;
}
}
if (i != n)
{
WarningInFunction
<< "Requested to skip " << n << "tokens, but stream exited after "
<< i << " tokens. Last token read: " << t
<< endl;
}
}
void Foam::ensightSurfaceReader::readGeometryHeader(ensightReadFile& is) const
{
// Binary flag string if applicable
is.readBinaryHeader();
string buffer;
// Ensight Geometry File
is.read(buffer);
if (debug) Info<< "buffer: " << buffer << endl;
// Description - 1
is.read(buffer);
if (debug) Info<< "buffer: " << buffer << endl;
// Node info
is.read(buffer);
if (debug) Info<< "buffer: " << buffer << endl;
// Element info
is.read(buffer);
if (debug) Info<< "buffer: " << buffer << endl;
// Part
is.read(buffer);
if (debug) Info<< "buffer: " << buffer << endl;
// Part number
label ibuffer;
is.read(ibuffer);
if (debug) Info<< "ibuffer: " << ibuffer << endl;
// Description - 2
is.read(buffer);
if (debug) Info<< "buffer: " << buffer << endl;
// Co-ordinates
is.read(buffer);
if (debug) Info<< "buffer: " << buffer << endl;
}
void Foam::ensightSurfaceReader::debugSection
(
const word& expected,
IFstream& is
) const
{
word actual(is);
if (expected != actual)
{
FatalIOErrorInFunction(is)
<< "Expected section header '" << expected
<< "' but read the word '" << actual << "'"
<< exit(FatalIOError);
}
if (debug)
{
Info<< "Read section header: " << expected << endl;
}
}
void Foam::ensightSurfaceReader::readCase(IFstream& is)
{
if (debug)
{
InfoInFunction<< endl;
}
if (!is.good())
{
FatalErrorInFunction
<< "Cannot read file " << is.name()
<< exit(FatalError);
}
string buffer;
// Read the file
debugSection("FORMAT", is);
skip(3, is); // type: ensight gold
debugSection("GEOMETRY", is);
readSkip(is, 2, meshFileName_);
debugSection("VARIABLE", is);
DynamicList<word> fieldNames(10);
DynamicList<word> fieldFileNames(10);
word fieldName;
word fieldFileName;
while (is.good())
{
word primitiveType(is); // scalar, vector
if (primitiveType == "TIME")
{
break;
}
readSkip(is, 3, fieldName); // p, U etc
fieldNames.append(fieldName);
is >> fieldFileName; // surfaceName.****.fieldName
fieldFileNames.append(fieldFileName);
}
fieldNames_.transfer(fieldNames);
fieldFileNames_.transfer(fieldFileNames);
if (debug)
{
Info<< "fieldNames: " << fieldNames_ << nl
<< "fieldFileNames: " << fieldFileNames_ << endl;
}
// Start reading time information
skip(3, is); // time set: 1
readSkip(is, 3, nTimeSteps_);
readSkip(is, 3, timeStartIndex_);
readSkip(is, 2, timeIncrement_);
if (debug)
{
Info<< "nTimeSteps: " << nTimeSteps_ << nl
<< "timeStartIndex: " << timeStartIndex_ << nl
<< "timeIncrement: " << timeIncrement_ << endl;
}
// Read the time values
skip(2, is);
timeValues_.setSize(nTimeSteps_);
for (label i = 0; i < nTimeSteps_; i++)
{
scalar t(readScalar(is));
timeValues_[i].value() = t;
// TODO: use character representation of t directly instead of
// regenerating from scalar value
timeValues_[i].name() = Foam::name(t);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::ensightSurfaceReader::ensightSurfaceReader(const fileName& fName)
:
surfaceReader(fName),
streamFormat_(IOstream::ASCII),
baseDir_(fName.path()),
meshFileName_(),
fieldNames_(),
fieldFileNames_(),
nTimeSteps_(0),
timeStartIndex_(0),
timeIncrement_(1),
timeValues_(),
surfPtr_(NULL)
{
IFstream is(fName);
readCase(is);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::ensightSurfaceReader::~ensightSurfaceReader()
{}
// * * * * * * * * * * * * * Public Member Functions * * * * * * * * * * * //
const Foam::meshedSurface& Foam::ensightSurfaceReader::geometry()
{
if (debug)
{
InfoInFunction<< endl;
}
if (!surfPtr_.valid())
{
IFstream isBinary(baseDir_/meshFileName_, IOstream::BINARY);
if (!isBinary.good())
{
FatalErrorInFunction
<< "Cannot read file " << isBinary.name()
<< exit(FatalError);
}
streamFormat_ = IOstream::BINARY;
{
istream& is = isBinary.stdStream();
char buffer[80];
is.read(buffer, 80);
char test[80];
label nChar = 0;
for (label i = 0; i < 80; ++i)
{
if (buffer[i] == '\0')
{
break;
}
test[i] = buffer[i];
nChar++;
}
string testStr(test, nChar);
if
(
(testStr.find("binary", 0) == string::npos)
&& (testStr.find("Binary", 0) == string::npos)
)
{
streamFormat_ = IOstream::ASCII;
}
}
if (debug)
{
Info<< "stream format: ";
if (streamFormat_ == IOstream::ASCII)
{
Info<< "ascii" << endl;
}
else
{
Info<< "binary" << endl;
}
}
ensightReadFile is(baseDir_/meshFileName_, streamFormat_);
if (debug)
{
Info<< "File: " << is.name() << endl;
}
readGeometryHeader(is);
label nPoints;
is.read(nPoints);
if (debug)
{
Info<< "nPoints: " << nPoints << endl;
}
pointField points(nPoints);
{
scalarField x(nPoints);
for (label dir = 0; dir < 3; dir++)
{
forAll(points, pointI)
{
is.read(x[pointI]);
}
points.replace(dir, x);
}
}
// Read faces - may be a mix of tris, quads and polys
DynamicList<face> faces(ceil(nPoints/3));
DynamicList<Tuple2<string, label> > schema(faces.size());
string faceType = "";
label nFace = 0;
while (is.good()) // (is.peek() != EOF)
{
is.read(faceType);
if (!is.good())
{
break;
}
if (debug)
{
Info<< "faceType: " << faceType << endl;
}
if (faceType == "tria3")
{
is.read(nFace);
label np = 3;
for (label faceI = 0; faceI < nFace; ++faceI)
{
face f(np);
for (label fpI = 0; fpI < np; fpI++)
{
is.read(f[fpI]);
}
faces.append(f);
}
}
else if (faceType == "quad4")
{
is.read(nFace);
label np = 4;
for (label faceI = 0; faceI < nFace; ++faceI)
{
face f(np);
for (label fpI = 0; fpI < np; fpI++)
{
is.read(f[fpI]);
}
faces.append(f);
}
}
else if (faceType == "nsided")
{
is.read(nFace);
labelList np(nFace);
for (label faceI = 0; faceI < nFace; ++faceI)
{
is.read(np[faceI]);
}
for (label faceI = 0; faceI < nFace; ++faceI)
{
face f(np[faceI]);
for (label fpI = 0; fpI < f.size(); ++fpI)
{
is.read(f[fpI]);
}
faces.append(f);
}
}
else
{
if (debug)
{
WarningInFunction
<< "Unknown face type: " << faceType
<< ". Aborting read and continuing with current "
<< "elements only" << endl;
}
break;
}
schema.append(Tuple2<string, label>(faceType, nFace));
}
schema_.transfer(schema);
if (debug)
{
Info<< "read nFaces: " << faces.size() << nl
<< "file schema: " << schema_ << endl;
}
// Convert from 1-based Ensight addressing to 0-based OF addressing
forAll(faces, faceI)
{
face& f = faces[faceI];
forAll(f, fpI)
{
f[fpI]--;
}
}
surfPtr_.reset(new meshedSurface(xferMove(points), faces.xfer()));
}
return surfPtr_();
}
Foam::instantList Foam::ensightSurfaceReader::times() const
{
return timeValues_;
}
Foam::wordList Foam::ensightSurfaceReader::fieldNames
(
const label timeIndex
) const
{
return fieldNames_;
}
Foam::tmp<Foam::Field<Foam::scalar> > Foam::ensightSurfaceReader::field
(
const label timeIndex,
const label fieldIndex,
const scalar& refValue
) const
{
return readField<scalar>(timeIndex, fieldIndex);
}
Foam::tmp<Foam::Field<Foam::vector> > Foam::ensightSurfaceReader::field
(
const label timeIndex,
const label fieldIndex,
const vector& refValue
) const
{
return readField<vector>(timeIndex, fieldIndex);
}
Foam::tmp<Foam::Field<Foam::sphericalTensor> >
Foam::ensightSurfaceReader::field
(
const label timeIndex,
const label fieldIndex,
const sphericalTensor& refValue
) const
{
return readField<sphericalTensor>(timeIndex, fieldIndex);
}
Foam::tmp<Foam::Field<Foam::symmTensor> > Foam::ensightSurfaceReader::field
(
const label timeIndex,
const label fieldIndex,
const symmTensor& refValue
) const
{
return readField<symmTensor>(timeIndex, fieldIndex);
}
Foam::tmp<Foam::Field<Foam::tensor> > Foam::ensightSurfaceReader::field
(
const label timeIndex,
const label fieldIndex,
const tensor& refValue
) const
{
return readField<tensor>(timeIndex, fieldIndex);
}
// ************************************************************************* //

View File

@ -0,0 +1,201 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd.
\\/ 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::ensightensightSurfaceReader
Description
Ensight format surface reader
SourceFiles
ensightSurfaceReader.C
\*---------------------------------------------------------------------------*/
#ifndef ensightSurfaceReader_H
#define ensightSurfaceReader_H
#include "surfaceReader.H"
#include "ensightReadFile.H"
#include "Tuple2.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class ensightSurfaceReader Declaration
\*---------------------------------------------------------------------------*/
class ensightSurfaceReader
:
public surfaceReader
{
protected:
// Protected Data
//- Format flag
IOstream::streamFormat streamFormat_;
//- Base directory
fileName baseDir_;
//- Name of mesh file
word meshFileName_;
//- Field names
List<word> fieldNames_;
//- Field file names
List<word> fieldFileNames_;
//- Number of time steps
label nTimeSteps_;
//- Start time index
label timeStartIndex_;
//- Time increment
label timeIncrement_;
//- Times
instantList timeValues_;
//- Pointer to the surface
autoPtr<meshedSurface> surfPtr_;
List<Tuple2<string, label> > schema_;
// Protected Member Functions
//- Read and check a section header
void debugSection(const word& expected, IFstream& is) const;
//- Read the case file
void readCase(IFstream& is);
//- Helper function to skip forward n steps in stream
void skip(const label n, IFstream& is) const;
//- Read (and throw away) geometry file header
void readGeometryHeader(ensightReadFile& is) const;
//- Helper function to return Type after skipping n tokens
template<class Type>
void readSkip(IFstream& is, const label nSkip, Type& value) const;
//- Helper function to return a field
template<class Type>
tmp<Field<Type> > readField
(
const label timeIndex,
const label fieldIndex
) const;
public:
//- Runtime type information
TypeName("ensight");
// Constructors
//- Construct from fileName
ensightSurfaceReader(const fileName& fName);
//- Destructor
virtual ~ensightSurfaceReader();
// Member Functions
//- Return a reference to the surface geometry
virtual const meshedSurface& geometry();
//- Return a list of the available times
virtual instantList times() const;
//- Return a list of the available fields at a given time
virtual wordList fieldNames(const label timeIndex) const;
//- Return a scalar field at a given time
virtual tmp<Field<scalar> > field
(
const label timeIndex,
const label fieldIndex,
const scalar& refValue = pTraits<scalar>::zero
) const;
//- Return a scalar field at a given time
virtual tmp<Field<vector> > field
(
const label timeIndex,
const label fieldIndex,
const vector& refValue = pTraits<vector>::zero
) const;
//- Return a sphericalTensor field at a given time
virtual tmp<Field<sphericalTensor> > field
(
const label timeIndex,
const label fieldIndex,
const sphericalTensor& reValue = pTraits<sphericalTensor>::zero
) const;
//- Return a symmTensor field at a given time
virtual tmp<Field<symmTensor> > field
(
const label timeIndex,
const label fieldIndex,
const symmTensor& reValue = pTraits<symmTensor>::zero
) const;
//- Return a tensor field at a given time
virtual tmp<Field<tensor> > field
(
const label timeIndex,
const label fieldIndex,
const tensor& reValue = pTraits<tensor>::zero
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "ensightSurfaceReaderTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,161 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd.
\\/ 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 <iomanip>
#include <sstream>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type>
void Foam::ensightSurfaceReader::readSkip
(
IFstream& is,
const label nSkip,
Type& value
) const
{
skip(nSkip, is);
is >> value;
}
template<class Type>
Foam::tmp<Foam::Field<Type> > Foam::ensightSurfaceReader::readField
(
const label timeIndex,
const label fieldIndex
) const
{
if (debug)
{
InfoInFunction<< endl;
}
const word& fieldName(fieldNames_[fieldIndex]);
const label fileIndex = timeStartIndex_ + timeIndex*timeIncrement_;
fileName fieldFileName(fieldFileNames_[fieldIndex]);
std::ostringstream oss;
oss << std::setfill('0') << std::setw(4) << fileIndex;
const word indexStr = oss.str();
fieldFileName.replace("****", indexStr);
ensightReadFile is(baseDir_/fieldFileName, streamFormat_);
if (!is.good())
{
FatalErrorInFunction
<< "Cannot read file " << is.name()
<< " for field " << fieldName
<< exit(FatalError);
}
// Check that data type is as expected
string primitiveType;
is.read(primitiveType);
if (debug)
{
Info<< "primitiveType: " << primitiveType << endl;
}
if (primitiveType != pTraits<Type>::typeName)
{
FatalIOErrorInFunction(is)
<< "Expected " << pTraits<Type>::typeName << "values "
<< "but found type " << primitiveType
<< exit(FatalIOError);
}
scalar value;
string strValue;
label iValue;
// Read header info: part index, e.g. part 1
is.read(strValue);
is.read(iValue);
// Allocate storage for data as a list per component
List<DynamicList<scalar> > values(pTraits<Type>::nComponents);
label n = surfPtr_->size();
forAll(values, cmptI)
{
values.setSize(n);
}
// Read data file using schema generated while reading the surface
forAll(schema_, i)
{
if (debug)
{
const string& faceType = schema_[i].first();
Info<< "Reading face type " << faceType << " data" << endl;
}
const label nFace = schema_[i].second();
if (nFace != 0)
{
is.read(strValue);
for
(
direction cmptI=0;
cmptI < pTraits<Type>::nComponents;
++cmptI
)
{
for (label faceI = 0; faceI < nFace; ++faceI)
{
is.read(value);
values[cmptI].append(value);
}
}
}
}
tmp<Field<Type> > tField(new Field<Type>(n, pTraits<Type>::zero));
Field<Type>& field = tField.ref();
for
(
direction cmptI=0;
cmptI < pTraits<Type>::nComponents;
++cmptI
)
{
field.replace(cmptI, values[cmptI]);
values[cmptI].clear();
}
return tField;
}
// ************************************************************************* //

View File

@ -0,0 +1,51 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015 OpenCFD Ltd.
\\/ 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 "surfaceReader.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(surfaceReader, 0);
defineRunTimeSelectionTable(surfaceReader, fileName);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::surfaceReader::surfaceReader(const fileName& fName)
:
fileName_(fName)
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::surfaceReader::~surfaceReader()
{}
// ************************************************************************* //

View File

@ -0,0 +1,161 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015 OpenCFD Ltd.
\\/ 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::surfaceReader
Description
Base class for surface readers
SourceFiles
surfaceReader.C
\*---------------------------------------------------------------------------*/
#ifndef surfaceReader_H
#define surfaceReader_H
#include "typeInfo.H"
#include "autoPtr.H"
#include "MeshedSurfaces.H"
#include "runTimeSelectionTables.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class surfaceReader Declaration
\*---------------------------------------------------------------------------*/
class surfaceReader
{
protected:
//- File name
fileName fileName_;
public:
//- Runtime type information
TypeName("surfaceReader");
// Declare run-time constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
surfaceReader,
fileName,
(
const fileName& fName
),
(fName)
);
// Selectors
//- Return a reference to the selected surfaceReader
static autoPtr<surfaceReader> New
(
const word& readType,
const fileName& fName
);
// Constructors
//- Construct from fileName
surfaceReader(const fileName& fName);
//- Destructor
virtual ~surfaceReader();
// Member Functions
//- Return a reference to the surface geometry
virtual const meshedSurface& geometry() = 0;
//- Return a list of the available times
virtual instantList times() const = 0;
//- Return a list of the available fields at a given time
virtual wordList fieldNames(const label timeIndex) const = 0;
//- Return a scalar field at a given time
virtual tmp<Field<scalar> > field
(
const label timeIndex,
const label fieldIndex,
const scalar& refValue = pTraits<scalar>::zero
) const = 0;
//- Return a vector field at a given time
virtual tmp<Field<vector> > field
(
const label timeIndex,
const label fieldIndex,
const vector& refValue = pTraits<vector>::zero
) const = 0;
//- Return a sphericalTensor field at a given time
virtual tmp<Field<sphericalTensor> > field
(
const label timeIndex,
const label fieldIndex,
const sphericalTensor& reValue = pTraits<sphericalTensor>::zero
) const = 0;
//- Return a symmTensor field at a given time
virtual tmp<Field<symmTensor> > field
(
const label timeIndex,
const label fieldIndex,
const symmTensor& reValue = pTraits<symmTensor>::zero
) const = 0;
//- Return a tensor field at a given time
virtual tmp<Field<tensor> > field
(
const label timeIndex,
const label fieldIndex,
const tensor& reValue = pTraits<tensor>::zero
) const = 0;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,52 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd.
\\/ 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 "surfaceReader.H"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::autoPtr<Foam::surfaceReader> Foam::surfaceReader::New
(
const word& readerType,
const fileName& fName
)
{
fileNameConstructorTable::iterator cstrIter =
fileNameConstructorTablePtr_->find(readerType);
if (cstrIter == fileNameConstructorTablePtr_->end())
{
FatalErrorInFunction
<< "Unknown reader type \"" << readerType << "\"\n\n"
<< "Valid reader types: "
<< fileNameConstructorTablePtr_->sortedToc() << nl
<< exit(FatalError);
}
return autoPtr<surfaceReader>(cstrIter()(fName));
}
// ************************************************************************* //