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