Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 #include "distribution.H"
00027 
00028 namespace Foam
00029 {
00030 
00031 
00032 
00033 distribution::distribution()
00034 :
00035     Map<label>(),
00036     binWidth_(1)
00037 {}
00038 
00039 
00040 distribution::distribution(const scalar binWidth)
00041 :
00042     Map<label>(),
00043     binWidth_(binWidth)
00044 {}
00045 
00046 
00047 distribution::distribution(const distribution& d)
00048 :
00049     Map<label>(static_cast< Map<label> >(d)),
00050     binWidth_(d.binWidth())
00051 {}
00052 
00053 
00054 
00055 
00056 distribution::~distribution()
00057 {}
00058 
00059 
00060 
00061 
00062 label distribution::totalEntries() const
00063 {
00064     label sumOfEntries = 0;
00065 
00066     forAllConstIter(Map<label>, *this, iter)
00067     {
00068         sumOfEntries += iter();
00069 
00070         if (sumOfEntries < 0)
00071         {
00072             WarningIn("label distribution::totalEntries()")
00073                 << "Accumulated distribution values total has become negative: "
00074                 << "sumOfEntries = " << sumOfEntries
00075                 << ". This is most likely to be because too many samples "
00076                 << "have been added to the bins and the label has 'rolled "
00077                 << "round'. Try distribution::approxTotalEntries which "
00078                 << "returns a scalar." << endl;
00079 
00080             sumOfEntries = -1;
00081 
00082             break;
00083         }
00084     }
00085 
00086     return sumOfEntries;
00087 }
00088 
00089 
00090 scalar distribution::approxTotalEntries() const
00091 {
00092     scalar sumOfEntries = 0;
00093 
00094     forAllConstIter(Map<label>, *this, iter)
00095     {
00096         sumOfEntries += scalar(iter());
00097     }
00098 
00099     return sumOfEntries;
00100 }
00101 
00102 
00103 scalar distribution::mean() const
00104 {
00105     scalar runningSum = 0;
00106 
00107     scalar totEnt = approxTotalEntries();
00108 
00109     List<label> keys = toc();
00110 
00111     forAll(keys,k)
00112     {
00113         label key = keys[k];
00114 
00115         runningSum +=
00116             (0.5 + scalar(key))
00117            *binWidth_
00118            *scalar((*this)[key])
00119            /totEnt;
00120     }
00121 
00122     return runningSum;
00123 }
00124 
00125 
00126 scalar distribution::median()
00127 {
00128     
00129     
00130     
00131     
00132 
00133     scalar median = 0.0;
00134 
00135     scalar runningSum = 0.0;
00136 
00137     List<Pair<scalar> > normDist(normalised());
00138 
00139     if (normDist.size())
00140     {
00141         if (normDist.size() == 1)
00142         {
00143             median = normDist[0].first();
00144         }
00145         else if
00146         (
00147             normDist.size() > 1
00148          && normDist[0].second()*binWidth_ > 0.5
00149         )
00150         {
00151             scalar xk = normDist[1].first();
00152             scalar xkm1 = normDist[0].first();
00153             scalar Sk =
00154                 (normDist[0].second() + normDist[1].second())*binWidth_;
00155             scalar Skm1 = normDist[0].second()*binWidth_;
00156 
00157             median = (0.5 - Skm1)*(xk - xkm1)/(Sk - Skm1) + xkm1;
00158         }
00159         else
00160         {
00161             label lastNonZeroIndex = 0;
00162 
00163             forAll(normDist,nD)
00164             {
00165                 if (runningSum + (normDist[nD].second()*binWidth_) > 0.5)
00166                 {
00167                     scalar xk = normDist[nD].first();
00168                     scalar xkm1 = normDist[lastNonZeroIndex].first();
00169                     scalar Sk = runningSum + (normDist[nD].second()*binWidth_);
00170                     scalar Skm1 = runningSum;
00171 
00172                     median = (0.5 - Skm1)*(xk - xkm1)/(Sk - Skm1) + xkm1;
00173 
00174                     break;
00175                 }
00176                 else if (normDist[nD].second() > 0.0)
00177                 {
00178                     runningSum += normDist[nD].second()*binWidth_;
00179 
00180                     lastNonZeroIndex = nD;
00181                 }
00182             }
00183         }
00184     }
00185 
00186     return median;
00187 }
00188 
00189 
00190 void distribution::add(const scalar valueToAdd)
00191 {
00192     iterator iter(this->begin());
00193 
00194     label n = label(valueToAdd/binWidth_) - label(neg(valueToAdd/binWidth_));
00195 
00196     iter = find(n);
00197 
00198     if (iter == this->end())
00199     {
00200         this->insert(n,1);
00201     }
00202     else
00203     {
00204         (*this)[n]++;
00205     }
00206 
00207     if ((*this)[n] < 0)
00208     {
00209         FatalErrorIn("distribution::add(const scalar valueToAdd)")
00210             << "Accumulated distribution value has become negative: "
00211             << "bin = " << (0.5 + scalar(n)) * binWidth_
00212             << ", value = " << (*this)[n]
00213             << ". This is most likely to be because too many samples "
00214             << "have been added to a bin and the label has 'rolled round'"
00215             << abort(FatalError);
00216     }
00217 }
00218 
00219 
00220 void distribution::add(const label valueToAdd)
00221 {
00222     add(scalar(valueToAdd));
00223 }
00224 
00225 
00226 void distribution::insertMissingKeys()
00227 {
00228     iterator iter(this->begin());
00229 
00230     List<label> keys = toc();
00231 
00232     sort(keys);
00233 
00234     if (keys.size())
00235     {
00236         for (label k = keys[0]; k < keys[keys.size()-1]; k++)
00237         {
00238             iter = find(k);
00239 
00240             if (iter == this->end())
00241             {
00242                 this->insert(k,0);
00243             }
00244         }
00245     }
00246 }
00247 
00248 
00249 List< Pair<scalar> > distribution::normalised()
00250 {
00251     scalar totEnt = approxTotalEntries();
00252 
00253     insertMissingKeys();
00254 
00255     List<label> keys = toc();
00256 
00257     sort(keys);
00258 
00259     List<Pair<scalar> > normDist(size());
00260 
00261     forAll(keys,k)
00262     {
00263         label key = keys[k];
00264 
00265         normDist[k].first() = (0.5 + scalar(key))*binWidth_;
00266 
00267         normDist[k].second() = scalar((*this)[key])/totEnt/binWidth_;
00268     }
00269 
00270     return normDist;
00271 }
00272 
00273 
00274 List< Pair<scalar> > distribution::normalisedMinusMean()
00275 {
00276     return normalisedShifted(mean());
00277 }
00278 
00279 
00280 List< Pair<scalar> > distribution::normalisedShifted(const scalar shiftValue)
00281 {
00282     List<Pair<scalar> > oldDist(normalised());
00283 
00284     List<Pair<scalar> > newDist(oldDist.size());
00285 
00286     forAll(oldDist,u)
00287     {
00288         oldDist[u].first() -= shiftValue;
00289     }
00290 
00291     scalar lowestOldBin = oldDist[0].first()/binWidth_ - 0.5;
00292 
00293     label lowestNewKey = label
00294     (
00295         lowestOldBin + 0.5*sign(lowestOldBin)
00296     );
00297 
00298     scalar interpolationStartDirection =
00299         sign(scalar(lowestNewKey) - lowestOldBin);
00300 
00301     label newKey = lowestNewKey;
00302 
00303 
00304 
00305 
00306 
00307 
00308 
00309 
00310 
00311 
00312 
00313 
00314 
00315 
00316 
00317 
00318     forAll(oldDist,u)
00319     {
00320         newDist[u].first() = (0.5 + scalar(newKey)) * binWidth_;
00321 
00322         if (interpolationStartDirection < 0)
00323         {
00324             if (u == 0)
00325             {
00326                 newDist[u].second() =
00327                     (0.5 + scalar(newKey))*oldDist[u].second()
00328                   - oldDist[u].second()
00329                         *(oldDist[u].first() - binWidth_)/ binWidth_;
00330             }
00331             else
00332             {
00333                 newDist[u].second() =
00334                     (0.5 + scalar(newKey))
00335                    *(oldDist[u].second() - oldDist[u-1].second())
00336                   +
00337                     (
00338                         oldDist[u-1].second()*oldDist[u].first()
00339                       - oldDist[u].second()*oldDist[u-1].first()
00340                     )
00341                     /binWidth_;
00342             }
00343         }
00344         else
00345         {
00346             if (u == oldDist.size() - 1)
00347             {
00348                 newDist[u].second() =
00349                     (0.5 + scalar(newKey))*-oldDist[u].second()
00350                   + oldDist[u].second()*(oldDist[u].first() + binWidth_)
00351                    /binWidth_;
00352             }
00353             else
00354             {
00355                 newDist[u].second() =
00356                     (0.5 + scalar(newKey))
00357                    *(oldDist[u+1].second() - oldDist[u].second())
00358                   +
00359                     (
00360                         oldDist[u].second()*oldDist[u+1].first()
00361                       - oldDist[u+1].second()*oldDist[u].first()
00362                     )
00363                    /binWidth_;
00364             }
00365         }
00366 
00367         newKey++;
00368     }
00369 
00370 
00371 
00372 
00373 
00374 
00375 
00376 
00377 
00378 
00379     return newDist;
00380 }
00381 
00382 
00383 List<Pair<scalar> > distribution::raw()
00384 {
00385     insertMissingKeys();
00386 
00387     List<label> keys = toc();
00388 
00389     sort(keys);
00390 
00391     List<Pair<scalar> > rawDist(size());
00392 
00393     forAll(keys,k)
00394     {
00395         label key = keys[k];
00396 
00397         rawDist[k].first() = (0.5 + scalar(key))*binWidth_;
00398 
00399         rawDist[k].second() = scalar((*this)[key]);
00400     }
00401 
00402     return rawDist;
00403 }
00404 
00405 
00406 
00407 
00408 void distribution::operator=(const distribution& rhs)
00409 {
00410     
00411     if (this == &rhs)
00412     {
00413         FatalErrorIn("distribution::operator=(const distribution&)")
00414             << "Attempted assignment to self"
00415             << abort(FatalError);
00416     }
00417 
00418     Map<label>::operator=(rhs);
00419 
00420     binWidth_ = rhs.binWidth();
00421 }
00422 
00423 
00424 
00425 
00426 Ostream& operator<<(Ostream& os, const distribution& d)
00427 {
00428     os  << d.binWidth_
00429         << static_cast<const Map<label>&>(d);
00430 
00431     
00432     os.check
00433     (
00434         "Ostream& operator<<(Ostream&, "
00435         "const distribution&)"
00436     );
00437 
00438     return os;
00439 }
00440 
00441 
00442 
00443 
00444 } 
00445 
00446