1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2009-2011 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "Distribution.H"
30 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
33 Foam::Distribution<Type>::Distribution()
35 List< List<scalar> >(pTraits<Type>::nComponents),
36 binWidth_(pTraits<Type>::one),
37 listStarts_(pTraits<Type>::nComponents, 0)
42 Foam::Distribution<Type>::Distribution(const Type& binWidth)
44 List< List<scalar> >(pTraits<Type>::nComponents),
46 listStarts_(pTraits<Type>::nComponents, 0)
51 Foam::Distribution<Type>::Distribution(const Distribution<Type>& d)
53 List< List<scalar> >(static_cast< const List< List<scalar> >& >(d)),
54 binWidth_(d.binWidth()),
55 listStarts_(d.listStarts())
59 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
62 Foam::Distribution<Type>::~Distribution()
66 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
69 Foam::scalar Foam::Distribution<Type>::totalWeight(direction cmpt) const
71 const List<scalar>& cmptDistribution = (*this)[cmpt];
73 scalar sumOfWeights = 0.0;
75 forAll(cmptDistribution, i)
77 sumOfWeights += cmptDistribution[i];
85 Foam::List<Foam::label> Foam::Distribution<Type>::keys(direction cmpt) const
87 List<label> keys = identity((*this)[cmpt].size());
91 keys[k] += listStarts_[cmpt];
99 Foam::label Foam::Distribution<Type>::index
105 List<scalar>& cmptDistribution = (*this)[cmpt];
107 if (cmptDistribution.empty())
109 // Initialise this list with this value
111 cmptDistribution.setSize(2, 0.0);
113 listStarts_[cmpt] = n;
118 label listIndex = -1;
120 label& listStart = listStarts_[cmpt];
122 label testIndex = n - listStart;
126 // Underflow of this List, storage increase and remapping
129 List<scalar> newCmptDistribution(2*cmptDistribution.size(), 0.0);
131 label sOld = cmptDistribution.size();
133 forAll(cmptDistribution, i)
135 newCmptDistribution[i + sOld] = cmptDistribution[i];
138 cmptDistribution = newCmptDistribution;
142 // Recursively call this function in case another remap is required.
143 listIndex = index(cmpt, n);
145 else if (testIndex > cmptDistribution.size() - 1)
147 // Overflow of this List, storage increase required
149 cmptDistribution.setSize(2*cmptDistribution.size(), 0.0);
151 // Recursively call this function in case another storage
152 // alteration is required.
153 listIndex = index(cmpt, n);
157 listIndex = n - listStart;
165 Foam::Pair<Foam::label> Foam::Distribution<Type>::validLimits
170 const List<scalar>& cmptDistribution = (*this)[cmpt];
172 // limits.first(): lower bound, i.e. the first non-zero entry
173 // limits.second(): upper bound, i.e. the last non-zero entry
174 Pair<label> limits(-1, -1);
176 forAll(cmptDistribution, i)
178 if (cmptDistribution[i] > 0.0)
180 if (limits.first() == -1)
197 Type Foam::Distribution<Type>::mean() const
199 Type meanValue(pTraits<Type>::zero);
201 for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
203 const List<scalar>& cmptDistribution = (*this)[cmpt];
205 scalar totalCmptWeight = totalWeight(cmpt);
207 List<label> theKeys = keys(cmpt);
211 label key = theKeys[k];
213 setComponent(meanValue, cmpt) +=
215 *component(binWidth_, cmpt)
226 Type Foam::Distribution<Type>::median() const
228 Type medianValue(pTraits<Type>::zero);
230 List< List < Pair<scalar> > > normDistribution = normalised();
232 for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
234 List< Pair<scalar> >& normDist = normDistribution[cmpt];
238 if (normDist.size() == 1)
240 setComponent(medianValue, cmpt) = normDist[0].first();
245 && normDist[0].second()*component(binWidth_, cmpt) > 0.5
250 + 0.5*component(binWidth_, cmpt);
254 - 0.5*component(binWidth_, cmpt);
256 scalar Sk = (normDist[0].second())*component(binWidth_, cmpt);
258 setComponent(medianValue, cmpt) = 0.5*(xk - xkm1)/(Sk) + xkm1;
262 label previousNonZeroIndex = 0;
264 scalar cumulative = 0.0;
271 + (normDist[nD].second()*component(binWidth_, cmpt))
277 + 0.5*component(binWidth_, cmpt);
280 normDist[previousNonZeroIndex].first()
281 + 0.5*component(binWidth_, cmpt);
285 + (normDist[nD].second()*component(binWidth_, cmpt));
287 scalar Skm1 = cumulative;
289 setComponent(medianValue, cmpt) =
290 (0.5 - Skm1)*(xk - xkm1)/(Sk - Skm1) + xkm1;
294 else if (mag(normDist[nD].second()) > VSMALL)
297 normDist[nD].second()*component(binWidth_, cmpt);
299 previousNonZeroIndex = nD;
312 void Foam::Distribution<Type>::add
314 const Type& valueToAdd,
318 for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
320 List<scalar>& cmptDistribution = (*this)[cmpt];
323 label(component(valueToAdd, cmpt)/component(binWidth_, cmpt))
324 - label(neg(component(valueToAdd, cmpt)/component(binWidth_, cmpt)));
326 label listIndex = index(cmpt, n);
328 cmptDistribution[listIndex] += component(weight, cmpt);
334 Foam::List< Foam::List< Foam::Pair<Foam::scalar> > >Foam::
335 Distribution<Type>::normalised() const
337 List< List < Pair<scalar> > > normDistribution(pTraits<Type>::nComponents);
339 for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
341 const List<scalar>& cmptDistribution = (*this)[cmpt];
343 if (cmptDistribution.empty())
348 scalar totalCmptWeight = totalWeight(cmpt);
350 List<label> cmptKeys = keys(cmpt);
352 List< Pair<scalar> >& normDist = normDistribution[cmpt];
354 Pair<label> limits = validLimits(cmpt);
356 normDist.setSize(limits.second() - limits.first() + 1);
360 label k = limits.first(), i = 0;
361 k <= limits.second();
365 label key = cmptKeys[k];
367 normDist[i].first() =
368 (0.5 + scalar(key))*component(binWidth_, cmpt);
370 normDist[i].second() =
373 /component(binWidth_, cmpt);
377 return normDistribution;
382 Foam::List< Foam::List< Foam::Pair<Foam::scalar> > >Foam::
383 Distribution<Type>::raw() const
385 List< List < Pair<scalar> > > rawDistribution(pTraits<Type>::nComponents);
387 for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
389 const List<scalar>& cmptDistribution = (*this)[cmpt];
391 if (cmptDistribution.empty())
396 List<label> cmptKeys = keys(cmpt);
398 List< Pair<scalar> >& rawDist = rawDistribution[cmpt];
400 Pair<label> limits = validLimits(cmpt);
402 rawDist.setSize(limits.second() - limits.first() + 1);
406 label k = limits.first(), i = 0;
407 k <= limits.second();
411 label key = cmptKeys[k];
413 rawDist[i].first() = (0.5 + scalar(key))*component(binWidth_, cmpt);
415 rawDist[i].second() = cmptDistribution[k];
419 return rawDistribution;
424 Foam::List< Foam::List< Foam::Pair<Foam::scalar> > >Foam::
425 Distribution<Type>::cumulativeNormalised() const
427 List< List< Pair<scalar> > > normalisedDistribution = normalised();
429 List< List < Pair<scalar> > > cumulativeNormalisedDistribution =
430 normalisedDistribution;
432 for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
434 const List< Pair<scalar> >& normalisedCmpt =
435 normalisedDistribution[cmpt];
437 List< Pair<scalar> >& cumNormalisedCmpt =
438 cumulativeNormalisedDistribution[cmpt];
442 forAll(normalisedCmpt, i)
444 cumNormalisedCmpt[i].first() =
445 normalisedCmpt[i].first()
446 + 0.5*component(binWidth_, cmpt);
448 cumNormalisedCmpt[i].second() =
449 normalisedCmpt[i].second()*component(binWidth_, cmpt) + sum;
451 sum = cumNormalisedCmpt[i].second();
455 return cumulativeNormalisedDistribution;
460 Foam::List< Foam::List< Foam::Pair<Foam::scalar> > >Foam::
461 Distribution<Type>::cumulativeRaw() const
463 List< List< Pair<scalar> > > rawDistribution = raw();
465 List< List < Pair<scalar> > > cumulativeRawDistribution = rawDistribution;
467 for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
469 const List< Pair<scalar> >& rawCmpt = rawDistribution[cmpt];
471 List< Pair<scalar> >& cumRawCmpt = cumulativeRawDistribution[cmpt];
477 cumRawCmpt[i].first() =
479 + 0.5*component(binWidth_, cmpt);
481 cumRawCmpt[i].second() = rawCmpt[i].second() + sum;
483 sum = cumRawCmpt[i].second();
487 return cumulativeRawDistribution;
492 void Foam::Distribution<Type>::clear()
494 for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
496 (*this)[cmpt].clear();
498 listStarts_[cmpt] = 0;
504 void Foam::Distribution<Type>::write(const fileName& filePrefix) const
506 List< List< Pair<scalar> > > rawDistribution = raw();
508 List< List < Pair<scalar> > > normDistribution = normalised();
510 for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
512 const List< Pair<scalar> >& rawPairs = rawDistribution[cmpt];
514 const List< Pair<scalar> >& normPairs = normDistribution[cmpt];
516 OFstream os(filePrefix + '_' + pTraits<Type>::componentNames[cmpt]);
518 os << "# key normalised raw" << endl;
522 os << normPairs[i].first()
523 << ' ' << normPairs[i].second()
524 << ' ' << rawPairs[i].second()
529 List< List< Pair<scalar> > > rawCumDist = cumulativeRaw();
531 List< List < Pair<scalar> > > normCumDist = cumulativeNormalised();
533 for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
535 const List< Pair<scalar> >& rawPairs = rawCumDist[cmpt];
537 const List< Pair<scalar> >& normPairs = normCumDist[cmpt];
541 filePrefix + "_cumulative_" + pTraits<Type>::componentNames[cmpt]
544 os << "# key normalised raw" << endl;
548 os << normPairs[i].first()
549 << ' ' << normPairs[i].second()
550 << ' ' << rawPairs[i].second()
557 // * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * //
560 void Foam::Distribution<Type>::operator=
562 const Distribution<Type>& rhs
565 // Check for assignment to self
570 "Foam::Distribution<Type>::operator="
571 "(const Foam::Distribution<Type>&)"
572 ) << "Attempted assignment to self"
573 << abort(FatalError);
576 List< List<scalar> >::operator=(rhs);
578 binWidth_ = rhs.binWidth();
580 listStarts_ = rhs.listStarts();
584 // * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * * //
586 template <class Type>
587 Foam::Istream& Foam::operator>>
590 Distribution<Type>& d
593 is >> static_cast<List< List<scalar> >&>(d)
597 // Check state of Istream
598 is.check("Istream& operator>>(Istream&, Distribution<Type>&)");
605 Foam::Ostream& Foam::operator<<
608 const Distribution<Type>& d
611 os << static_cast<const List< List<scalar> >& >(d)
612 << d.binWidth_ << token::SPACE
615 // Check state of Ostream
616 os.check("Ostream& operator<<(Ostream&, " "const Distribution&)");
622 // * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * //
624 template <class Type>
625 Foam::Distribution<Type> Foam::operator+
627 const Distribution<Type>& d1,
628 const Distribution<Type>& d2
631 // The coarsest binWidth is the sensible choice
632 Distribution<Type> d(max(d1.binWidth(), d2.binWidth()));
634 List< List< List < Pair<scalar> > > > rawDists(2);
636 rawDists[0] = d1.raw();
637 rawDists[1] = d2.raw();
639 forAll(rawDists, rDI)
641 for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
643 List<scalar>& cmptDistribution = d[cmpt];
645 const List < Pair<scalar> >& cmptRaw = rawDists[rDI][cmpt];
649 scalar valueToAdd = cmptRaw[rI].first();
650 scalar cmptWeight = cmptRaw[rI].second();
655 component(valueToAdd, cmpt)
656 /component(d.binWidth(), cmpt)
660 neg(component(valueToAdd, cmpt)
661 /component(d.binWidth(), cmpt))
664 label listIndex = d.index(cmpt, n);
666 cmptDistribution[listIndex] += cmptWeight;
671 return Distribution<Type>(d);
675 // ************************************************************************* //