From abd1ee0f1db6bc844b9053634952cf8d5f933853 Mon Sep 17 00:00:00 2001 From: graham <g.macpherson@opencfd.co.uk> Date: Thu, 11 Feb 2010 17:21:16 +0000 Subject: [PATCH] ENH: Distribution. Adding operator+ to allow reduce(dist, sumOp< Distribution<scalar> >()); operations for parallel data. Combines distributions using the coarsest binWidth. Changed write function to write normalised and raw to the same file. BUG: Distribution. Corrected inaccurate median calculation. --- .../test/Distribution/DistributionTest.C | 137 +++++--- .../Lists/Distribution/Distribution.C | 294 +++++++++++------- .../Lists/Distribution/Distribution.H | 51 +-- 3 files changed, 309 insertions(+), 173 deletions(-) diff --git a/applications/test/Distribution/DistributionTest.C b/applications/test/Distribution/DistributionTest.C index e59cb1af1ea..3d181b22fbb 100644 --- a/applications/test/Distribution/DistributionTest.C +++ b/applications/test/Distribution/DistributionTest.C @@ -45,7 +45,8 @@ Description #include "Distribution.H" #include "Random.H" #include "dimensionedTypes.H" - +#include "argList.H" +#include "PstreamReduceOps.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -53,6 +54,8 @@ using namespace Foam; int main(int argc, char *argv[]) { + # include "setRootCase.H" + Random R(918273); { @@ -76,7 +79,67 @@ int main(int argc, char *argv[]) << "Median " << dS.median() << endl; - dS.write("Distribution_scalar_test", dS.normalised()); + dS.write("Distribution_scalar_test_1"); + + Distribution<scalar> dS2(scalar(1e-2)); + + Info<< nl << "Distribution<scalar>" << nl + << "Sampling " + << randomDistributionTestSize + << " times from GaussNormal distribution." + << endl; + + for (label i = 0; i < randomDistributionTestSize; i++) + { + dS2.add(1.5*R.GaussNormal() -6.0); + } + + Info<< "Mean " << dS2.mean() << nl + << "Median " << dS2.median() + << endl; + + dS2.write("Distribution_scalar_test_2"); + + Info<< nl << "Adding previous two Distribution<scalar>" << endl; + + dS = dS + dS2; + + dS.write("Distribution_scalar_test_1+2"); + } + + if (Pstream::parRun()) + { + // scalar in parallel + label randomDistributionTestSize = 100000000; + + Distribution<scalar> dS(scalar(1e-1)); + + Pout<< "Distribution<scalar>" << nl + << "Sampling " + << randomDistributionTestSize + << " times from uniform distribution." + << endl; + + for (label i = 0; i < randomDistributionTestSize; i++) + { + dS.add(R.scalar01() + 10*Pstream::myProcNo()); + } + + Pout<< "Mean " << dS.mean() << nl + << "Median " << dS.median() + << endl; + + reduce(dS, sumOp< Distribution<scalar> >()); + + if (Pstream::master()) + { + Info<< "Reducing parallel Distribution<scalar>" << nl + << "Mean " << dS.mean() << nl + << "Median " << dS.median() + << endl; + + dS.write("Distribution_scalar_test_parallel_reduced"); + } } { @@ -114,40 +177,40 @@ int main(int argc, char *argv[]) << "Median " << dV.median() << endl; - dV.write("Distribution_vector_test", dV.normalised()); + dV.write("Distribution_vector_test"); } - { - // labelVector - Distribution<labelVector> dLV(labelVector::one*10); - - label randomDistributionTestSize = 2000000; - - Info<< nl << "Distribution<labelVector>" << nl - << "Sampling " - << randomDistributionTestSize - << " times from uniform distribution." - << endl; - - for (label i = 0; i < randomDistributionTestSize; i++) - { - dLV.add - ( - labelVector - ( - R.integer(-1000, 1000), - R.integer(-5000, 5000), - R.integer(-2000, 7000) - ) - ); - } - - Info<< "Mean " << dLV.mean() << nl - << "Median " << dLV.median() - << endl; - - dLV.write("Distribution_labelVector_test", dLV.normalised()); - } + // { + // // labelVector + // Distribution<labelVector> dLV(labelVector::one*10); + + // label randomDistributionTestSize = 2000000; + + // Info<< nl << "Distribution<labelVector>" << nl + // << "Sampling " + // << randomDistributionTestSize + // << " times from uniform distribution." + // << endl; + + // for (label i = 0; i < randomDistributionTestSize; i++) + // { + // dLV.add + // ( + // labelVector + // ( + // R.integer(-1000, 1000), + // R.integer(-5000, 5000), + // R.integer(-2000, 7000) + // ) + // ); + // } + + // Info<< "Mean " << dLV.mean() << nl + // << "Median " << dLV.median() + // << endl; + + // dLV.write("Distribution_labelVector_test"); + // } { // tensor @@ -170,7 +233,7 @@ int main(int argc, char *argv[]) << "Median " << dT.median() << endl; - dT.write("Distribution_tensor_test", dT.normalised()); + dT.write("Distribution_tensor_test"); } { @@ -194,7 +257,7 @@ int main(int argc, char *argv[]) << "Median " << dSyT.median() << endl; - dSyT.write("Distribution_symmTensor_test", dSyT.normalised()); + dSyT.write("Distribution_symmTensor_test"); } { @@ -218,7 +281,7 @@ int main(int argc, char *argv[]) << "Median " << dSpT.median() << endl; - dSpT.write("Distribution_sphericalTensor_test", dSpT.normalised()); + dSpT.write("Distribution_sphericalTensor_test"); } Info<< nl << "End" << nl << endl; diff --git a/src/OpenFOAM/containers/Lists/Distribution/Distribution.C b/src/OpenFOAM/containers/Lists/Distribution/Distribution.C index 263853428dd..d242feb11a1 100644 --- a/src/OpenFOAM/containers/Lists/Distribution/Distribution.C +++ b/src/OpenFOAM/containers/Lists/Distribution/Distribution.C @@ -28,7 +28,73 @@ License #include "OFstream.H" #include "ListOps.H" -// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * // +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +template<class Type> +Foam::Distribution<Type>::Distribution() +: + List< List<scalar> >(pTraits<Type>::nComponents), + binWidth_(pTraits<Type>::one), + listStarts_(pTraits<Type>::nComponents, 0) +{} + + +template<class Type> +Foam::Distribution<Type>::Distribution(const Type& binWidth) +: + List< List<scalar> >(pTraits<Type>::nComponents), + binWidth_(binWidth), + listStarts_(pTraits<Type>::nComponents, 0) +{} + + +template<class Type> +Foam::Distribution<Type>::Distribution(const Distribution<Type>& d) +: + List< List<scalar> >(static_cast< const List< List<scalar> >& >(d)), + binWidth_(d.binWidth()), + listStarts_(d.listStarts()) +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +template<class Type> +Foam::Distribution<Type>::~Distribution() +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +template<class Type> +Foam::scalar Foam::Distribution<Type>::totalWeight(direction cmpt) const +{ + const List<scalar>& cmptDistribution = (*this)[cmpt]; + + scalar sumOfWeights = 0.0; + + forAll(cmptDistribution, i) + { + sumOfWeights += cmptDistribution[i]; + } + + return sumOfWeights; +} + + +template<class Type> +Foam::List<Foam::label> Foam::Distribution<Type>::keys(direction cmpt) const +{ + List<label> keys = identity((*this)[cmpt].size()); + + forAll(keys, k) + { + keys[k] += listStarts_[cmpt]; + } + + return keys; +} + template<class Type> Foam::label Foam::Distribution<Type>::index @@ -128,73 +194,6 @@ Foam::Pair<Foam::label> Foam::Distribution<Type>::validLimits } -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -template<class Type> -Foam::Distribution<Type>::Distribution() -: - List< List<scalar> >(pTraits<Type>::nComponents), - binWidth_(pTraits<Type>::one), - listStarts_(pTraits<Type>::nComponents, 0) -{} - - -template<class Type> -Foam::Distribution<Type>::Distribution(const Type& binWidth) -: - List< List<scalar> >(pTraits<Type>::nComponents), - binWidth_(binWidth), - listStarts_(pTraits<Type>::nComponents, 0) -{} - - -template<class Type> -Foam::Distribution<Type>::Distribution(const Distribution<Type>& d) -: - List< List<scalar> >(static_cast< const List< List<scalar> >& >(d)), - binWidth_(d.binWidth()), - listStarts_(d.listStarts()) -{} - - -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -template<class Type> -Foam::Distribution<Type>::~Distribution() -{} - - -// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // - -template<class Type> -Foam::scalar Foam::Distribution<Type>::totalWeight(direction cmpt) const -{ - const List<scalar>& cmptDistribution = (*this)[cmpt]; - - scalar sumOfWeights = 0.0; - - forAll(cmptDistribution, i) - { - sumOfWeights += cmptDistribution[i]; - } - - return sumOfWeights; -} - -template<class Type> -Foam::List<Foam::label> Foam::Distribution<Type>::keys(direction cmpt) const -{ - List<label> keys = identity((*this)[cmpt].size()); - - forAll(keys, k) - { - keys[k] += listStarts_[cmpt]; - } - - return keys; -} - - template<class Type> Type Foam::Distribution<Type>::mean() const { @@ -225,7 +224,7 @@ Type Foam::Distribution<Type>::mean() const template<class Type> -Type Foam::Distribution<Type>::median() +Type Foam::Distribution<Type>::median() const { Type medianValue(pTraits<Type>::zero); @@ -247,18 +246,17 @@ Type Foam::Distribution<Type>::median() && normDist[0].second()*component(binWidth_, cmpt) > 0.5 ) { - scalar xk = normDist[1].first(); - - scalar xkm1 = normDist[0].first(); + scalar xk = + normDist[0].first() + + 0.5*component(binWidth_, cmpt); - scalar Sk = - (normDist[0].second() + normDist[1].second()) - *component(binWidth_, cmpt); + scalar xkm1 = + normDist[0].first() + - 0.5*component(binWidth_, cmpt); - scalar Skm1 = normDist[0].second()*component(binWidth_, cmpt); + scalar Sk = (normDist[0].second())*component(binWidth_, cmpt); - setComponent(medianValue, cmpt) = - (0.5 - Skm1)*(xk - xkm1)/(Sk - Skm1) + xkm1; + setComponent(medianValue, cmpt) = 0.5*(xk - xkm1)/(Sk) + xkm1; } else { @@ -266,7 +264,7 @@ Type Foam::Distribution<Type>::median() scalar cumulative = 0.0; - forAll(normDist,nD) + forAll(normDist, nD) { if ( @@ -275,9 +273,13 @@ Type Foam::Distribution<Type>::median() > 0.5 ) { - scalar xk = normDist[nD].first(); + scalar xk = + normDist[nD].first() + + 0.5*component(binWidth_, cmpt); - scalar xkm1 = normDist[previousNonZeroIndex].first(); + scalar xkm1 = + normDist[previousNonZeroIndex].first() + + 0.5*component(binWidth_, cmpt); scalar Sk = cumulative @@ -314,7 +316,6 @@ void Foam::Distribution<Type>::add const Type& weight ) { - for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++) { List<scalar>& cmptDistribution = (*this)[cmpt]; @@ -332,13 +333,13 @@ void Foam::Distribution<Type>::add template<class Type> Foam::List< Foam::List< Foam::Pair<Foam::scalar> > >Foam:: -Distribution<Type>::normalised() +Distribution<Type>::normalised() const { List< List < Pair<scalar> > > normDistribution(pTraits<Type>::nComponents); for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++) { - List<scalar>& cmptDistribution = (*this)[cmpt]; + const List<scalar>& cmptDistribution = (*this)[cmpt]; if (cmptDistribution.empty()) { @@ -380,13 +381,13 @@ Distribution<Type>::normalised() template<class Type> Foam::List< Foam::List< Foam::Pair<Foam::scalar> > >Foam:: -Distribution<Type>::raw() +Distribution<Type>::raw() const { List< List < Pair<scalar> > > rawDistribution(pTraits<Type>::nComponents); for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++) { - List<scalar>& cmptDistribution = (*this)[cmpt]; + const List<scalar>& cmptDistribution = (*this)[cmpt]; if (cmptDistribution.empty()) { @@ -433,37 +434,28 @@ void Foam::Distribution<Type>::clear() template<class Type> -void Foam::Distribution<Type>::write -( - const fileName& filePrefix, - const List< List< Pair<scalar> > >& pairs -) const +void Foam::Distribution<Type>::write(const fileName& filePrefix) const { - if (pairs.size() != pTraits<Type>::nComponents) - { - FatalErrorIn - ( - "Distribution::write" - "(" - "const fileName& filePrefix," - "const List< List< Pair<scalar> > >& pairs" - ")" - ) - << "List of pairs (" << pairs.size() - << ") is not the same size as the number of components (" - << pTraits<Type>::nComponents << ")." << nl - << abort(FatalError); - } + List< List<Pair<scalar> > > rawDistribution = raw(); + + List< List < Pair<scalar> > > normDistribution = normalised(); for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++) { - const List< Pair<scalar> >& cmptPairs = pairs[cmpt]; + const List< Pair<scalar> >& rawPairs = rawDistribution[cmpt]; + + const List< Pair<scalar> >& normPairs = normDistribution[cmpt]; OFstream os(filePrefix + '_' + pTraits<Type>::componentNames[cmpt]); - forAll(cmptPairs, i) + os << "# key normalised raw" << endl; + + forAll(normPairs, i) { - os << cmptPairs[i].first() << ' ' << cmptPairs[i].second() << nl; + os << normPairs[i].first() + << ' ' << normPairs[i].second() + << ' ' << rawPairs[i].second() + << nl; } } } @@ -491,11 +483,31 @@ void Foam::Distribution<Type>::operator= List< List<scalar> >::operator=(rhs); binWidth_ = rhs.binWidth(); + + listStarts_ = rhs.listStarts(); } // * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * * // +template <class Type> +Foam::Istream& Foam::operator>> +( + Istream& is, + Distribution<Type>& d +) +{ + is >> static_cast<List< List<scalar> >&>(d) + >> d.binWidth_ + >> d.listStarts_; + + // Check state of Istream + is.check("Istream& operator>>(Istream&, Distribution<Type>&)"); + + return is; +} + + template<class Type> Foam::Ostream& Foam::operator<< ( @@ -503,18 +515,68 @@ Foam::Ostream& Foam::operator<< const Distribution<Type>& d ) { - os << d.binWidth_ - << static_cast<const List< List<scalar> >& >(d); + os << static_cast<const List< List<scalar> >& >(d) + << d.binWidth_ << token::SPACE + << d.listStarts_; // Check state of Ostream - os.check - ( - "Ostream& operator<<(Ostream&, " - "const Distribution&)" - ); + os.check("Ostream& operator<<(Ostream&, " "const Distribution&)"); return os; } +// * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * // + +template <class Type> +Foam::Distribution<Type> Foam::operator+ +( + const Distribution<Type>& d1, + const Distribution<Type>& d2 +) +{ + // The coarsest binWidth is the sensible choice + Distribution<Type> d(max(d1.binWidth(), d2.binWidth())); + + List< List< List < Pair<scalar> > > > rawDists(2); + + rawDists[0] = d1.raw(); + rawDists[1] = d2.raw(); + + forAll(rawDists, rDI) + { + for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++) + { + List<scalar>& cmptDistribution = d[cmpt]; + + const List < Pair<scalar> >& cmptRaw = rawDists[rDI][cmpt]; + + forAll(cmptRaw, rI) + { + scalar valueToAdd = cmptRaw[rI].first(); + scalar cmptWeight = cmptRaw[rI].second(); + + label n = + label + ( + component(valueToAdd, cmpt) + /component(d.binWidth(), cmpt) + ) + - label + ( + neg(component(valueToAdd, cmpt) + /component(d.binWidth(), cmpt)) + ); + + label listIndex = d.index(cmpt, n); + + cmptDistribution[listIndex] += cmptWeight; + } + } + } + + return Distribution<Type>(d); +} + + // ************************************************************************* // diff --git a/src/OpenFOAM/containers/Lists/Distribution/Distribution.H b/src/OpenFOAM/containers/Lists/Distribution/Distribution.H index 5dbdb444c46..ef6ef25676c 100644 --- a/src/OpenFOAM/containers/Lists/Distribution/Distribution.H +++ b/src/OpenFOAM/containers/Lists/Distribution/Distribution.H @@ -50,6 +50,9 @@ namespace Foam template<class Type> class Distribution; +template<class Type> +Istream& operator>>(Istream&, Distribution<Type>&); + template<class Type> Ostream& operator<<(Ostream&, const Distribution<Type>&); @@ -70,15 +73,6 @@ class Distribution //- The start bin index of each component List<label> listStarts_; - // Private Member Functions - - //- Return the appropriate List index for the given bin index. - // Resizes the List if required - label index(direction cmpt, label n); - - //- Returns the indices of the first and last non-zero entries - Pair<label> validLimits(direction cmpt) const; - public: @@ -109,12 +103,19 @@ public: List<label> keys(direction cmpt) const; + //- Return the appropriate List index for the given bin index. + // Resizes the List if required + label index(direction cmpt, label n); + + //- Returns the indices of the first and last non-zero entries + Pair<label> validLimits(direction cmpt) const; + Type mean() const; // From http://mathworld.wolfram.com/StatisticalMedian.html // The statistical median is the value of the Distribution // variable where the cumulative Distribution = 0.5. - Type median(); + Type median() const; //- Add a value to the distribution, optionally specifying a weight void add @@ -124,10 +125,10 @@ public: ); //- Return the normalised distribution and bins - List< List<Pair<scalar> > > normalised(); + List< List<Pair<scalar> > > normalised() const; //- Return the distribution of the total bin weights - List< List < Pair<scalar> > > raw(); + List< List < Pair<scalar> > > raw() const; //- Resets the Distribution by clearing the stored lists. // Leaves the same number of them and the same binWidth. @@ -144,13 +145,9 @@ public: // Write - //- Write the distribution to file. Produces a separate file - // for each component. - void write - ( - const fileName& filePrefix, - const List< List<Pair<scalar> > >& pairs - ) const; + //- Write the distribution to file: key normalised raw. + // Produces a separate file for each component. + void write(const fileName& filePrefix) const; // Member Operators @@ -159,6 +156,12 @@ public: // IOstream Operators + friend Istream& operator>> <Type> + ( + Istream&, + Distribution<Type>& + ); + friend Ostream& operator<< <Type> ( Ostream&, @@ -167,7 +170,15 @@ public: }; -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +// * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * // + +template<class Type> +Distribution<Type> operator+ +( + const Distribution<Type>&, + const Distribution<Type>& +); + } // End namespace Foam -- GitLab