46 {weightingType::none,
"dB"},
48 {weightingType::dBB,
"dBB"},
49 {weightingType::dBC,
"dBC"},
50 {weightingType::dBD,
"dBD"},
71 scalar fTest = 15.625;
73 const scalar fRatio =
pow(2, 1.0/octave);
74 const scalar fRatioL2C =
pow(2, 0.5/octave);
80 DynamicList<scalar> fc;
81 DynamicList<scalar> missedBins;
85 while (fTest < fLower)
98 if (stepi) missedBins.append(fTest/fRatio*fRatioL2C);
104 if (bandIDs.insert(i))
107 fc.append(fTest*fRatioL2C);
118 fBandIDs = bandIDs.sortedToc();
120 if (missedBins.size())
122 label nMiss = missedBins.size();
123 label nTotal = nMiss + fc.size() - 1;
125 <<
"Empty bands found: " << nMiss <<
" of " << nTotal
126 <<
" with centre frequencies " <<
flatOutput(missedBins)
135 fCentre.transfer(fc);
145 auto& result = tresult.ref();
190 if (times.size() > 1)
193 deltaT = (times.back() - times.front())/scalar(times.size() - 1);
195 bool nonUniform =
false;
196 for (label i = 1; i < times.size() && !nonUniform; ++i)
198 const scalar dT = times[i] - times[i-1];
200 nonUniform = (
mag(dT/deltaT - 1) > 1
e-8);
206 <<
"Detected non-uniform time step:"
207 <<
" resulting FFT may be incorrect"
208 <<
" (or the deltaT is just very small): " << deltaT
215 <<
"Unable to create FFT with 0 or 1 values"
227 if ((
p[i] < minPressure_) || (
p[i] > maxPressure_))
230 <<
"Pressure data at position " << i
231 <<
" is outside of permitted bounds:" <<
nl
232 <<
" pressure: " <<
p[i] <<
nl
233 <<
" minimum pressure: " << minPressure_ <<
nl
234 <<
" maximum pressure: " << maxPressure_ <<
nl
265 writeHeaderValue(
os,
"Lower frequency", fLower_);
266 writeHeaderValue(
os,
"Upper frequency", fUpper_);
267 writeHeaderValue(
os,
"Window model", windowModelPtr_->type());
268 writeHeaderValue(
os,
"Window number", windowModelPtr_->nWindow());
269 writeHeaderValue(
os,
"Window samples", windowModelPtr_->nSamples());
270 writeHeaderValue(
os,
"Window overlap %", windowModelPtr_->overlapPercent());
271 writeHeaderValue(
os,
"dBRef", dBRef_);
273 for (
const auto& hv : headerValues)
275 writeHeaderValue(
os, hv.first(), hv.second());
293 if (
f[i] >= fLower_ &&
f[i] <= fUpper_)
307 const auto& window = windowModelPtr_();
308 const label
N = window.nSamples();
313 const scalar deltaf = 1.0/(
N*deltaT);
320 if (
f[i] > fLower_ &&
f[i] < fUpper_)
326 if (
check && nFreq == 0)
329 <<
"No frequencies found in range "
330 << fLower_ <<
" to " << fUpper_
345 if (freqBandIDs.size() < 2)
348 <<
"Octave frequency bands are not defined "
349 <<
"- skipping octaves calculation"
356 auto& octData = toctData.ref();
358 bitSet bandUsed(freqBandIDs.size() - 1);
359 for (label bandI = 0; bandI < freqBandIDs.size() - 1; ++bandI)
361 label fb0 = freqBandIDs[bandI];
362 label fb1 = freqBandIDs[bandI+1];
364 if (fb0 == fb1)
continue;
366 for (label freqI = fb0; freqI < fb1; ++freqI)
369 label f1 =
f[freqI + 1];
370 scalar dataAve = 0.5*(data[freqI] + data[freqI + 1]);
371 octData[bandI] += dataAve*(f1 - f0);
378 labelList bandUnused = bandUsed.sortedToc();
379 if (bandUnused.size())
382 <<
"Empty bands found: " << bandUnused.size() <<
" of "
392 if (planInfo_.active)
394 if (
p.size() != planInfo_.windowSize)
397 <<
"Expected pressure data to have " << planInfo_.windowSize
398 <<
" values, but received " <<
p.size() <<
" values"
409 ::fftw_execute(planInfo_.plan);
411 const label
n = planInfo_.windowSize;
412 const label nBy2 =
n/2;
414 auto& result = tresult.ref();
419 for (label i = 1; i <= nBy2; ++i)
421 const auto re = out[i];
422 const auto im = out[
n - i];
423 result[i] =
sqrt(re*re + im*im);
435 const auto& window = windowModelPtr_();
436 const label
N = window.nSamples();
437 const label nWindow = window.nWindow();
440 auto& meanPf = tmeanPf.ref();
442 for (label windowI = 0; windowI < nWindow; ++windowI)
444 meanPf += Pf(window.apply<scalar>(
p, windowI));
447 meanPf /= scalar(nWindow);
458 const auto& window = windowModelPtr_();
459 const label
N = window.nSamples();
460 const label nWindow = window.nWindow();
463 for (label windowI = 0; windowI < nWindow; ++windowI)
465 RMSMeanPf +=
sqr(
Pf(window.apply<scalar>(
p, windowI)));
468 return sqrt(RMSMeanPf/scalar(nWindow))/scalar(
N);
478 const auto& window = windowModelPtr_();
479 const label
N = window.nSamples();
480 const label nWindow = window.nWindow();
483 auto& psd = tpsd.ref();
485 for (label windowI = 0; windowI < nWindow; ++windowI)
487 psd +=
sqr(Pf(window.apply<scalar>(
p, windowI)));
490 scalar fs = 1.0/deltaT;
491 psd /= scalar(nWindow)*fs*
N;
510 const scalar c1 =
sqr(12194.0);
511 const scalar c2 =
sqr(20.6);
512 const scalar c3 =
sqr(107.7);
513 const scalar c4 =
sqr(739.9);
515 const scalar f2 =
f*
f;
520 (f2 + c2)*
sqrt((f2 + c3)*(f2 + c4))*(f2 + c1)
538 const scalar c1 =
sqr(12194.0);
539 const scalar c2 =
sqr(20.6);
540 const scalar c3 =
sqr(158.5);
542 const scalar f2 =
f*
f;
547 (f2 + c2)*
sqrt(f2 + c3)*(f2 + c1)
565 const scalar c1 =
sqr(12194.0);
566 const scalar c2 =
sqr(20.6);
568 const scalar f2 =
f*
f;
570 return c1*f2/((f2 + c2)*(f2 + c1));
587 const scalar f2 =
f*
f;
590 (
sqr(1037918.48 - f2) + 1080768.16*f2)
591 /(
sqr(9837328 - f2) + 11723776*f2);
594 f/6.8966888496476e-5*
Foam::sqrt(hf/((f2 + 79919.29)*(f2 + 1345600)));
628 SPLweighting_(weightingType::
none),
630 minPressure_(-0.5*VGREAT),
631 maxPressure_(0.5*VGREAT),
681 <<
"Lower frequency bound must be greater than zero"
688 <<
"Upper frequency bound must be greater than zero"
692 if (fUpper_ < fLower_)
695 <<
"Upper frequency bound (" << fUpper_
696 <<
") must be greater than lower frequency bound ("
701 Info<<
" Frequency bounds:" <<
nl
702 <<
" lower: " << fLower_ <<
nl
703 <<
" upper: " << fUpper_ <<
nl
715 weightingTypeNames_.readIfPresent(
"SPLweighting",
dict, SPLweighting_);
717 Info<<
" Weighting: " << weightingTypeNames_[SPLweighting_] <<
endl;
721 Info<<
" Reference for dB calculation: " << dBRef_ <<
endl;
737 const label windowSize = windowModelPtr_->nSamples();
741 planInfo_.active =
true;
742 planInfo_.windowSize = windowSize;
743 planInfo_.in.setSize(windowSize);
744 planInfo_.out.setSize(windowSize);
752 planInfo_.out.data(),
754 windowSize <= 8192 ? FFTW_MEASURE : FFTW_ESTIMATE
782 switch (SPLweighting_)
784 case weightingType::none:
788 case weightingType::dBA:
793 case weightingType::dBB:
798 case weightingType::dBC:
803 case weightingType::dBD:
811 <<
"Unknown weighting " << weightingTypeNames_[SPLweighting_]
829 switch (SPLweighting_)
831 case weightingType::none:
835 case weightingType::dBA:
839 spl[i] += gainA(
f[i]);
843 case weightingType::dBB:
847 spl[i] += gainB(
f[i]);
851 case weightingType::dBC:
855 spl[i] += gainC(
f[i]);
859 case weightingType::dBD:
863 spl[i] += gainD(
f[i]);
870 <<
"Unknown weighting " << weightingTypeNames_[SPLweighting_]
881 if (planInfo_.active)
895 OFstream osA(
"noiseModel-weight-A");
896 OFstream osB(
"noiseModel-weight-B");
897 OFstream osC(
"noiseModel-weight-C");
898 OFstream osD(
"noiseModel-weight-D");
900 for (label
f = f0;
f <= f1; ++
f)
902 osA <<
f <<
" " << gainA(
f) <<
nl;
903 osB <<
f <<
" " << gainB(
f) <<
nl;
904 osC <<
f <<
" " << gainC(
f) <<
nl;
905 osD <<
f <<
" " << gainD(
f) <<
nl;
Info<< nl;Info<< "Write faMesh in vtk format:"<< nl;{ vtk::uindirectPatchWriter writer(aMesh.patch(), fileName(aMesh.time().globalPath()/vtkBaseFileName));writer.writeGeometry();globalIndex procAddr(aMesh.nFaces());labelList cellIDs;if(UPstream::master()) { cellIDs.resize(procAddr.totalSize());for(const labelRange &range :procAddr.ranges()) { auto slice=cellIDs.slice(range);slice=identity(range);} } writer.beginCellData(4);writer.writeProcIDs();writer.write("cellID", cellIDs);writer.write("area", aMesh.S().field());writer.write("normal", aMesh.faceAreaNormals());writer.beginPointData(1);writer.write("normal", aMesh.pointAreaNormals());Info<< " "<< writer.output().name()<< nl;}{ vtk::lineWriter writer(aMesh.points(), aMesh.edges(), fileName(aMesh.time().globalPath()/(vtkBaseFileName+"-edges")));writer.writeGeometry();writer.beginCellData(4);writer.writeProcIDs();{ Field< scalar > fld(faMeshTools::flattenEdgeField(aMesh.magLe(), true))
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
void pop_back(label n=1)
Reduce size by 1 or more elements. Can be called on an empty list.
void append(const T &val)
Copy append an element to the end of this list.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
List< Key > sortedToc() const
The table of contents (the keys) in sorted order.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
bool set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Output to file stream as an OSstream, normally using std::ofstream for the actual output.
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
label size() const noexcept
Number of entries.
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
T & back()
Access last element of the list, position [size()-1].
T & front()
Access first element of the list, position [0].
void size(const label n)
Older name for setAddressableSize.
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
void flip()
Invert all bits in the addressable region.
labelList sortedToc() const
The indices of the on bits as a sorted labelList.
void set(const bitSet &bitset)
Set specified bits from another bitset.
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
dictionary subOrEmptyDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX, const bool mandatory=false) const
Find and return a sub-dictionary as a copy, otherwise return an empty dictionary.
bool readIfPresentCompat(const word &keyword, std::initializer_list< std::pair< const char *, int > > compat, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry if present, and assign to T val using any compatibility names if needed....
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry if present, and assign to T val. FatalIOError if it is found and the number of tokens i...
static tmp< complexField > realTransform1D(const scalarField &field)
Transform real-value data.
A class for handling file names.
fileName baseFileDir() const
Return the base directory for output.
virtual void writeTabbed(Ostream &os, const string &str) const
Write a tabbed string to stream.
void writeHeaderValue(Ostream &os, const string &property, const Type &value) const
Write a (commented) header property and value pair.
writeFile(const objectRegistry &obr, const fileName &prefix, const word &name="undefined", const bool writeToFile=true, const string &ext=".dat")
Construct from objectRegistry, prefix, fileName.
virtual bool read(const dictionary &dict)
Read.
virtual void writeCommented(Ostream &os, const string &str) const
Write a commented string to stream.
Base class for noise models.
tmp< scalarField > uniformFrequencies(const scalar deltaT, const bool check) const
Create a field of equally spaced frequencies for the current set of data - assumes a constant time st...
scalar RAf(const scalar f) const
A weighting function.
scalar rhoRef_
Reference density (to convert from kinematic to static pressure).
label nSamples_
Number of samples in sampling window, default = 2^16.
tmp< scalarField > octaves(const scalarField &data, const scalarField &f, const labelUList &freqBandIDs) const
Generate octave data.
tmp< scalarField > RMSmeanPf(const scalarField &p) const
Return the multi-window RMS mean fft of the complete pressure data [Pa].
scalar fUpper_
Upper frequency limit, default = 10kHz.
scalar gainC(const scalar f) const
C weighting as gain in dB.
tmp< Foam::scalarField > PSD(const scalarField &PSDf) const
PSD [dB/Hz].
tmp< scalarField > meanPf(const scalarField &p) const
Return the multi-window mean fft of the complete pressure data [Pa].
scalar maxPressure_
Min pressure value.
bool writePSD_
Write PSD; default = yes.
scalar gainA(const scalar f) const
A weighting as gain in dB.
scalar minPressure_
Min pressure value.
static void setOctaveBands(const scalarField &f, const scalar fLower, const scalar fUpper, const scalar octave, labelList &fBandIDs, scalarField &fCentre)
Return a list of the frequency indices wrt f field that correspond to the bands limits for a given oc...
virtual bool read(const dictionary &dict)
Read from dictionary.
bool writeOctaves_
Write writeOctaves; default = yes.
fileName outputPrefix_
Output file prefix, default = ''.
scalar RDf(const scalar f) const
D weighting function.
tmp< scalarField > Pf(const scalarField &p) const
Return the fft of the given pressure data.
scalar RCf(const scalar f) const
C weighting function.
noiseModel(const noiseModel &)=delete
No copy construct.
tmp< scalarField > SPL(const scalarField &Prms2, const scalar f) const
SPL [dB].
planInfo planInfo_
Plan information for FFTW.
autoPtr< windowModel > windowModelPtr_
Window model.
static const Enum< weightingType > weightingTypeNames_
bool writeSPL_
Write SPL; default = yes.
const dictionary dict_
Copy of dictionary used for construction.
void writeFileHeader(Ostream &os, const string &x, const string &y, const UList< Tuple2< string, token > > &headerValues=UList< Tuple2< string, token > >::null()) const
Write output file header.
bool writePrmsf_
Write Prmsf; default = yes.
weightingType SPLweighting_
Weighting.
scalar checkUniformTimeStep(const scalarList ×) const
Check and return uniform time step.
bool writePSDf_
Write PSDf; default = yes.
scalar gainD(const scalar f) const
D weighting as gain in dB.
tmp< scalarField > PSDf(const scalarField &p, const scalar deltaT) const
Return the multi-window Power Spectral Density (PSD) of the complete pressure data [Pa^2/Hz].
void writeWeightings() const
Helper function to check weightings.
scalar startTime_
Start time, default = 0s.
scalar sampleFreq_
Prescribed sample frequency.
void cleanFFTW()
Clean up the FFTW.
scalar dBRef_
Reference for dB calculation, default = 2e-5.
void writeFreqDataToFile(Ostream &os, const scalarField &f, const scalarField &fx) const
bool validateBounds(const scalarList &p) const
Return true if all pressure data is within min/max bounds.
scalar fLower_
Lower frequency limit, default = 25Hz.
scalar gainB(const scalar f) const
B weighting as gain in dB.
scalar RBf(const scalar f) const
B weighting function.
Registry of regIOobjects.
Lookup type of boundary radiation properties.
A class for managing temporary objects.
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
T & ref() const
Return non-const reference to the contents of a non-null managed pointer.
static autoPtr< windowModel > New(const dictionary &dict, const label nSamples)
Return a reference to the selected window model.
A class for handling words, derived from Foam::string.
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
OBJstream os(runTime.globalPath()/outputName)
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionedScalar re
Classical electron radius: default SI units: [m].
Namespace for handling debugging switches.
Function objects are OpenFOAM utilities to ease workflow configurations and enhance workflows.
void readFields(const typename GeoFieldType::Mesh &mesh, const IOobjectList &objects, const NameMatchPredicate &selectedFields, DynamicList< regIOobject * > &storedObjects)
Read the selected GeometricFields of the templated type and store on the objectRegistry.
tmp< scalarField > safeLog10(const scalarField &fld)
List< label > labelList
A List of labels.
dimensionedSymmTensor sqr(const dimensionedVector &dv)
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
static void writeHeader(Ostream &os, const word &fieldName)
messageStream Info
Information stream (stdout output on master, null elsewhere).
static void check(const int retVal, const char *what)
dimensionedScalar log10(const dimensionedScalar &ds)
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Ostream & endl(Ostream &os)
Add newline and flush stream.
static void readWriteOption(const dictionary &dict, const word &lookup, bool &option)
dimensionedScalar sqrt(const dimensionedScalar &ds)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
errorManip< error > abort(error &err)
IOerror FatalIOError
Error stream (stdout output on all processes), with additional 'FOAM FATAL IO ERROR' header text and ...
static constexpr const zero Zero
Global zero (0).
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
errorManipArg< error, int > exit(error &err, const int errNo=1)
UList< label > labelUList
A UList of labels.
List< scalar > scalarList
List of scalar.
dimensioned< Type > average(const DimensionedField< Type, GeoMesh > &f1, const label comm)
constexpr char nl
The newline '\n' character (0x0a).
constexpr char tab
The tab '\t' character(0x09).
#define defineRunTimeSelectionTable(baseType, argNames)
Define run-time selection table.
#define forAll(list, i)
Loop across all elements in list.
const Vector< label > N(dict.get< Vector< label > >("N"))