PSD Class Reference

Contains a vector with radii and probabilities of a user defined particle size distribution (PSD) More...

#include <PSD.h>

Public Types

enum class  TYPE {
  CUMULATIVE_NUMBER_DISTRIBUTION , CUMULATIVE_LENGTH_DISTRIBUTION , CUMULATIVE_VOLUME_DISTRIBUTION , CUMULATIVE_AREA_DISTRIBUTION ,
  PROBABILITYDENSITY_NUMBER_DISTRIBUTION , PROBABILITYDENSITY_LENGTH_DISTRIBUTION , PROBABILITYDENSITY_AREA_DISTRIBUTION , PROBABILITYDENSITY_VOLUME_DISTRIBUTION
}
 Enum class which stores the possible types of CDFs and PDFs. Particle size distributions can be represented by different probabilities based on number of particles, length of particles, surface area of particles or volume of particles. More...
 

Public Member Functions

 PSD ()
 Constructor; sets everything to 0 or default. More...
 
 PSD (std::unique_ptr< PSD > psdPtr)
 Constructor; sets everything to 0 or default. This constructor is mainly used in MercuryPBM where smart pointers are used. More...
 
 PSD (const PSD &other)
 Copy constructor with deep copy. More...
 
 ~PSD ()
 Destructor; default destructor. More...
 
PSDcopy () const
 Creates a copy on the heap and returns a pointer. More...
 
void printPSD () const
 Prints radii and probabilities of the PSD vector. More...
 
Mdouble drawSample ()
 Draw a sample radius from a CUMULATIVE_NUMBER_DISTRIBUTION. More...
 
Mdouble insertManuallyByVolume (Mdouble volume)
 Draw sample radius manually per size class and check the volumeAllowed of each size class to insert the PSD as accurate as possible. More...
 
void validateCumulativeDistribution ()
 Validates if a CDF starts with zero and adds up to unity. More...
 
void validateProbabilityDensityDistribution ()
 Validates if the integral of the PDF equals to unity. More...
 
void setPSDFromVector (std::vector< DistributionElements > psd, TYPE PSDType)
 Sets the PSD from a vector with DistributionElements. More...
 
void setPSDFromCSV (const std::string &fileName, TYPE PSDType, bool headings=false, Mdouble unitScalingFactorRadii=1.0)
 read in the PSD vector with probabilities and radii saved in a .csv file. More...
 
void setDistributionUniform (Mdouble radMin, Mdouble radMax, int numberOfBins)
 create a PSD vector for a uniform distribution. More...
 
void setDistributionNormal (Mdouble mean, Mdouble standardDeviation, int numberOfBins)
 create a PSD vector for a normal distribution. More...
 
void setDistributionLogNormal (Mdouble mean, Mdouble standardDeviation, int numberOfBins)
 create a PSD vector for a normal distribution. More...
 
void setDistributionPhiNormal (Mdouble D50, Mdouble standardDeviationinPhi, int numberOfBins)
 create a PSD vector for a normal distribution in Phi Units that has the demanded D50. More...
 
void convertProbabilityDensityToCumulative ()
 Converts a PDF to a CDF by integration. More...
 
void convertCumulativeToProbabilityDensity ()
 Converts a CDF to a PDF by derivation. More...
 
void convertProbabilityDensityToProbabilityDensityNumberDistribution (TYPE PDFType)
 Convert any PDF to a PROBABILITYDENSITY_NUMBER_DISTRIBUTION. More...
 
void convertProbabilityDensityNumberDistributionToProbabilityDensity (TYPE PDFType)
 Convert a PROBABILITYDENSITY_NUMBER_DISTRIBUTION to any PDF. More...
 
MERCURYDPM_DEPRECATED void convertProbabilityDensityNumberDistributionToProbabilityDensityVolumeDistribution ()
 convert a PROBABILITYDENSITY_NUMBER_DISTRIBUTION to a PROBABILITYDENSITY_VOLUME_DISTRIBUTION. More...
 
void convertCumulativeToCumulativeNumberDistribution (TYPE CDFType)
 Convert any CDF to a CUMULATIVE_NUMBER_DISTRIBUTION. More...
 
void convertCumulativeNumberDistributionToCumulative (TYPE CDFType)
 Convert a CUMULATIVE_NUMBER_DISTRIBUTION to any CDF. More...
 
MERCURYDPM_DEPRECATED void cutoffCumulativeNumber (Mdouble quantileMin, Mdouble quantileMax, Mdouble minPolydispersity=0.1)
 cutoff the PSD at given quantiles. More...
 
void cutoffCumulativeDistribution (TYPE CDFType, Mdouble quantileMin, Mdouble quantileMax, Mdouble minPolydispersity=0.1)
 Cut off the PSD at the given quantiles, with the PSD in the provided CDF form. More...
 
MERCURYDPM_DEPRECATED void cutoffAndSqueezeCumulative (Mdouble quantileMin, Mdouble quantileMax, Mdouble squeeze, Mdouble minPolydispersity=0.1)
 cutoff the PSD at given quantiles and make it less polydisperse by squeezing it. More...
 
void cutoffAndSqueezeCumulativeDistribution (TYPE CDFType, Mdouble quantileMin, Mdouble quantileMax, Mdouble squeeze, Mdouble minPolydispersity=0.1)
 Cut off the PSD at the given quantiles, with the PSD in the provided CDF form, and make it less polydisperese by squeezing it. More...
 
Mdouble getMinRadius () const
 Get smallest radius of the PSD. More...
 
Mdouble getMaxRadius () const
 Get largest radius of the PSD. More...
 
std::vector< DistributionElementsgetParticleSizeDistribution () const
 Get the PSD vector. More...
 
std::vector< DistributionElementsgetParticleSizeDistributionByType (TYPE psdType, Mdouble scalingFactor=1.0) const
 Gets the PSD vector, converted to the preferred type. More...
 
MERCURYDPM_DEPRECATED void setParticleSizeDistribution (std::vector< DistributionElements >)
 set the PSD by a suitable vector. More...
 
void scaleParticleSize (double scale)
 Scales all particle sizes by a factor. More...
 
double scaleParticleSizeAuto (int numberOfParticles, double targetVolume, bool allowScaleDown=false)
 Scales all particle sizes, such that the total volume of N particles approximately equals the target volume. More...
 
int getInsertedParticleNumber () const
 Get the number of particles already inserted into the simulation. More...
 
void decrementNParticlesPerClass ()
 Decrement nParticlesPerClass_ counter. More...
 
void decrementVolumePerClass (Mdouble volume)
 Decrement volumePerClass_ counter. More...
 
Mdouble getRadius (int index) const
 get a radius at a certain index of the particleSizeDistribution_ More...
 
Mdouble getNumberDx (Mdouble x) const
 Calculate a certain diameter (e.g. D10, D50, D90, etc.) from a percentile x of the number based PSD. More...
 
Mdouble getLengthDx (Mdouble x) const
 Calculate a certain diameter (e.g. D10, D50, D90, etc.) from a percentile x of the length based PSD. More...
 
Mdouble getAreaDx (Mdouble x) const
 Calculate a certain diameter (e.g. D10, D50, D90, etc.) from a percentile x of the area based PSD. More...
 
Mdouble getVolumeDx (Mdouble x) const
 Calculate a certain diameter (e.g. D10, D50, D90, etc.) from a percentile x of the volume based PSD. More...
 
Mdouble getRadiusByQuantile (Mdouble quantile) const
 Calculate the quantile of the PSD. More...
 
Mdouble getQuantileByRadius (Mdouble radius) const
 Calculates the quantile corresponding to a certain radius. More...
 
Mdouble getVolumetricMeanRadius () const
 get a volumetric mean radius of the PSD. More...
 
Mdouble getSizeRatio () const
 get the size ratio (width) of the PSD. More...
 
void cutHighSizeRatio ()
 Check if the size ratio is too high and cut it. More...
 
std::vector< std::pair< Mdouble, Mdouble > > convertPdfPhiToPdfMeter (Mdouble meaninPhi, Mdouble standardDeviationinPhi, int numberOfBins)
 compute central momenta of the user defined PSD. ‍/ void computeCentralMomenta(); More...
 
Mdouble computeD50 (std::vector< std::pair< Mdouble, Mdouble > > vectorOfPair)
 compute the mass-based D_50 of the paired diameter and probabilityDensity. More...
 
void setFixedSeed (int seed)
 set a fixed seed for the random number generator; this is used for the PSDSelfTest to reproduce results More...
 

Static Public Member Functions

static PSD getDistributionNormal (Mdouble mean, Mdouble standardDeviation, int numberOfBins)
 
static PSD getDistributionLogNormal (Mdouble mean, Mdouble standardDeviation, int numberOfBins)
 
static std::vector< Mdoublelinspace (Mdouble Min, Mdouble Max, int numberOfBins)
 create a vector of linearly spaced values. More...
 

Private Attributes

std::vector< DistributionElementsparticleSizeDistribution_
 
std::vector< intnParticlesPerClass_
 
std::vector< MdoublevolumePerClass_
 
int index_
 
RNG random_
 

Friends

bool operator< (const DistributionElements &l, const DistributionElements &r)
 determines if a certain value of the PSD vector is lower than another one. Used for std::lower_bound() More...
 
bool operator< (const DistributionElements &l, Mdouble r)
 determines if a certain value of the PSD vector is lower than a double. More...
 
std::ostream & operator<< (std::ostream &os, DistributionElements &p)
 Writes to output stream. More...
 
std::istream & operator>> (std::istream &is, DistributionElements &p)
 Reads from input stream. More...
 
Mdouble operator== (DistributionElements l, Mdouble r)
 Determines if a certain value of the PSD vector is equal to a double. More...
 

Detailed Description

Contains a vector with radii and probabilities of a user defined particle size distribution (PSD)

Stores radii and probabilities of a particle size distribution (PSD) in a vector of type DistributionElements and converts them to a PSD which can be used by insertionBoundaries which insert particles into a simulation:

Cumulative distribution function (CDF): gives percentage of particles p_i whose radius r is less than a certain radius r_i. It requires p_0 = 0 and p_end = 1. The CDF's probabilities can be number, length, area or volume based. The cumulative number distribution function (CUMULATIVE_NUMBER_DISTRIBUTION) is used as PSD in MercuryDPM, as it can be interpreted as the probability that a particle's radius is less than r_i: CDF(r<r_i) = p_i.

Probability density function (PDF): p_i is the percentage of particles whose radius is between r_i-1 and r_i. It requires p_0=0 and sum(p_i)=1. The PDF's probabilities can also be number, length, area or volume based. PDF's are utilized to convert any type of PDF to a probability number density function (PROBABILITYDENSITY_NUMBER_DISTRIBUTION) which in a next step are converted to the default CUMULATIVE_NUMBER_DISTRIBUTION.

Sieve data: p_i is the percentage of particles whose radius is between r_i and r_i+1. It requires sum(p_i)=1. relation to PDF: p_i = p(PDF)_i-1. Sieve data is not yet used in this class.

Default distribution is the CUMULATIVE_NUMBER_DISTRIBUTION.

Member Enumeration Documentation

◆ TYPE

enum PSD::TYPE
strong

Enum class which stores the possible types of CDFs and PDFs. Particle size distributions can be represented by different probabilities based on number of particles, length of particles, surface area of particles or volume of particles.

Enumerator
CUMULATIVE_NUMBER_DISTRIBUTION 
CUMULATIVE_LENGTH_DISTRIBUTION 
CUMULATIVE_VOLUME_DISTRIBUTION 
CUMULATIVE_AREA_DISTRIBUTION 
PROBABILITYDENSITY_NUMBER_DISTRIBUTION 
PROBABILITYDENSITY_LENGTH_DISTRIBUTION 
PROBABILITYDENSITY_AREA_DISTRIBUTION 
PROBABILITYDENSITY_VOLUME_DISTRIBUTION 
56  {
57  CUMULATIVE_NUMBER_DISTRIBUTION,
58  CUMULATIVE_LENGTH_DISTRIBUTION,
59  CUMULATIVE_VOLUME_DISTRIBUTION,
60  CUMULATIVE_AREA_DISTRIBUTION,
61  PROBABILITYDENSITY_NUMBER_DISTRIBUTION,
62  PROBABILITYDENSITY_LENGTH_DISTRIBUTION,
63  PROBABILITYDENSITY_AREA_DISTRIBUTION,
64  PROBABILITYDENSITY_VOLUME_DISTRIBUTION
65  };

Constructor & Destructor Documentation

◆ PSD() [1/3]

PSD::PSD ( )

Constructor; sets everything to 0 or default.

Default constructor; sets every data member to 0 or default.

11 {
12 // for (auto& momenta: momenta_)
13 // momenta = 0;
14  index_ = 0;
15  // default seed is zero for reproducibility
17 }
RNG random_
Definition: PSD.h:441
int index_
Definition: PSD.h:436
void setRandomSeed(unsigned long int new_seed)
This is the seed for the random number generator (note the call to seed_LFG is only required really i...
Definition: RNG.cc:32

References index_, random_, and RNG::setRandomSeed().

Referenced by copy().

◆ PSD() [2/3]

PSD::PSD ( std::unique_ptr< PSD psdPtr)
inline

Constructor; sets everything to 0 or default. This constructor is mainly used in MercuryPBM where smart pointers are used.

Parameters
[in]psdPtrsmart pointer to a PSD object.
77  : particleSizeDistribution_(psdPtr->particleSizeDistribution_),
78  nParticlesPerClass_(psdPtr->nParticlesPerClass_),
79  volumePerClass_(psdPtr->volumePerClass_),
80  index_(psdPtr->index_),
81  random_(psdPtr->random_) {}
std::vector< Mdouble > volumePerClass_
Definition: PSD.h:431
std::vector< int > nParticlesPerClass_
Definition: PSD.h:422
std::vector< DistributionElements > particleSizeDistribution_
Definition: PSD.h:415

◆ PSD() [3/3]

PSD::PSD ( const PSD other)

Copy constructor with deep copy.

Copy constructor

23 {
25 // momenta_ = other.momenta_;
26  index_ = other.index_;
27  random_ = other.random_;
28 }

References index_, particleSizeDistribution_, and random_.

◆ ~PSD()

PSD::~PSD ( )
default

Destructor; default destructor.

Destructor. Since there are no pointers in this class, there is no need for any actions here.

Member Function Documentation

◆ computeD50()

Mdouble PSD::computeD50 ( std::vector< std::pair< Mdouble, Mdouble > >  vectorOfPair)

compute the mass-based D_50 of the paired diameter and probabilityDensity.

computes the mass-based D50 of the paired diameter and probabilityDensity

Parameters
[in]vectorOfPairvector of pair containing paired data of diameter and probabilityDensity
479  {
480  Mdouble D_50 = 0.0;
481  int numberOfBins = vectorOfPair.size();
482  std::vector<Mdouble> Vcum(numberOfBins, 0);
483  Mdouble Vint=0;
484  for (int i = 0; i < Vcum.size()-1; i++)
485  {
486  Mdouble dD = fabs(vectorOfPair[i+1].first-vectorOfPair[i].first);
487  Mdouble V = 0.5*(pow(vectorOfPair[i].first, 3.0) * vectorOfPair[i].second +
488  pow(vectorOfPair[i+1].first, 3.0) * vectorOfPair[i+1].second) * dD;
489  Vint = Vint + V;
490  Vcum[i+1] = Vint;
491  }
492 
493  for(int j=0; j<Vcum.size()-1; ++j){
494  if(Vcum[j]/Vint*100<=50 && Vcum[j+1]/Vint*100>50){
495  D_50 = vectorOfPair[j].first + fabs(vectorOfPair[j+1].first-vectorOfPair[j].first)/(Vcum[j+1]/Vint*100-Vcum[j]/Vint*100)
496  *(50-Vcum[j]/Vint*100);
497  }
498  }
499  return D_50;
500  }
int i
Definition: BiCGSTAB_step_by_step.cpp:9
MatrixXcd V
Definition: EigenSolver_EigenSolver_MatrixType.cpp:15
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 pow(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:625
Real fabs(const Real &a)
Definition: boostmultiprec.cpp:117
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2

References boost::multiprecision::fabs(), i, j, Eigen::bfloat16_impl::pow(), and V.

Referenced by setDistributionPhiNormal().

◆ convertCumulativeNumberDistributionToCumulative()

void PSD::convertCumulativeNumberDistributionToCumulative ( TYPE  CDFType)

Convert a CUMULATIVE_NUMBER_DISTRIBUTION to any CDF.

Parameters
CDFTypeThe CDF type to convert to.
795 {
796  // Ignore the default case.
798  return;
799 
801 
804  else if (CDFType == TYPE::CUMULATIVE_AREA_DISTRIBUTION)
806  else if (CDFType == TYPE::CUMULATIVE_VOLUME_DISTRIBUTION)
808  else
809  logger(ERROR, "Wrong CDFType");
810 
812 }
Logger< MERCURYDPM_LOGLEVEL > logger("MercuryKernel")
Definition of different loggers with certain modules. A user can define its own custom logger here.
@ ERROR
void convertProbabilityDensityNumberDistributionToProbabilityDensity(TYPE PDFType)
Convert a PROBABILITYDENSITY_NUMBER_DISTRIBUTION to any PDF.
Definition: PSD.cc:706
void convertCumulativeToProbabilityDensity()
Converts a CDF to a PDF by derivation.
Definition: PSD.cc:630
void convertProbabilityDensityToCumulative()
Converts a PDF to a CDF by integration.
Definition: PSD.cc:615
@ PROBABILITYDENSITY_VOLUME_DISTRIBUTION
@ CUMULATIVE_AREA_DISTRIBUTION
@ CUMULATIVE_VOLUME_DISTRIBUTION
@ PROBABILITYDENSITY_LENGTH_DISTRIBUTION
@ PROBABILITYDENSITY_AREA_DISTRIBUTION
@ CUMULATIVE_LENGTH_DISTRIBUTION
@ CUMULATIVE_NUMBER_DISTRIBUTION

References convertCumulativeToProbabilityDensity(), convertProbabilityDensityNumberDistributionToProbabilityDensity(), convertProbabilityDensityToCumulative(), CUMULATIVE_AREA_DISTRIBUTION, CUMULATIVE_LENGTH_DISTRIBUTION, CUMULATIVE_NUMBER_DISTRIBUTION, CUMULATIVE_VOLUME_DISTRIBUTION, ERROR, logger, PROBABILITYDENSITY_AREA_DISTRIBUTION, PROBABILITYDENSITY_LENGTH_DISTRIBUTION, and PROBABILITYDENSITY_VOLUME_DISTRIBUTION.

Referenced by cutoffCumulativeDistribution(), getAreaDx(), getLengthDx(), and getVolumeDx().

◆ convertCumulativeToCumulativeNumberDistribution()

void PSD::convertCumulativeToCumulativeNumberDistribution ( TYPE  CDFType)

Convert any CDF to a CUMULATIVE_NUMBER_DISTRIBUTION.

Converts any of the CDFTypes to a the default CUMULATIVE_NUMBER_DISTRIBUTION based on their TYPE.

Parameters
[in]CDFTypeType of the PDF: CUMULATIVE_LENGTH_DISTRIBUTION, CUMULATIVE_AREA_DISTRIBUTION or CUMULATIVE_VOLUME_DISTRIBUTION.
772 {
773  // Ignore the default case.
775  return;
776 
778 
781  else if (CDFType == TYPE::CUMULATIVE_AREA_DISTRIBUTION)
783  else if (CDFType == TYPE::CUMULATIVE_VOLUME_DISTRIBUTION)
785  else
786  logger(ERROR, "Wrong CDFType");
787 
789 }
void convertProbabilityDensityToProbabilityDensityNumberDistribution(TYPE PDFType)
Convert any PDF to a PROBABILITYDENSITY_NUMBER_DISTRIBUTION.
Definition: PSD.cc:649

References convertCumulativeToProbabilityDensity(), convertProbabilityDensityToCumulative(), convertProbabilityDensityToProbabilityDensityNumberDistribution(), CUMULATIVE_AREA_DISTRIBUTION, CUMULATIVE_LENGTH_DISTRIBUTION, CUMULATIVE_NUMBER_DISTRIBUTION, CUMULATIVE_VOLUME_DISTRIBUTION, ERROR, logger, PROBABILITYDENSITY_AREA_DISTRIBUTION, PROBABILITYDENSITY_LENGTH_DISTRIBUTION, and PROBABILITYDENSITY_VOLUME_DISTRIBUTION.

Referenced by cutoffCumulativeDistribution().

◆ convertCumulativeToProbabilityDensity()

void PSD::convertCumulativeToProbabilityDensity ( )

Converts a CDF to a PDF by derivation.

Convert any type of CDF to a PDF. Probabilities are derivated for each radius by substracting the CDF probabilities (i.e. pPDF_i = pCDF_i - pCDF_i-1).

631 {
632  // subtract cumulative probabilities
633  Mdouble probabilityOld = 0, probabilityCDF;
634  for (auto& it : particleSizeDistribution_)
635  {
636  probabilityCDF = it.probability;
637  it.probability -= probabilityOld;
638  probabilityOld = probabilityCDF;
639  }
640  // check whether probability density distribution is valid
642 }
void validateProbabilityDensityDistribution()
Validates if the integral of the PDF equals to unity.
Definition: PSD.cc:246

References particleSizeDistribution_, and validateProbabilityDensityDistribution().

Referenced by convertCumulativeNumberDistributionToCumulative(), convertCumulativeToCumulativeNumberDistribution(), getParticleSizeDistributionByType(), getVolumetricMeanRadius(), insertManuallyByVolume(), and setPSDFromVector().

◆ convertPdfPhiToPdfMeter()

std::vector< std::pair< Mdouble, Mdouble > > PSD::convertPdfPhiToPdfMeter ( Mdouble  meanInPhi,
Mdouble  standardDeviationInPhi,
int  numberOfBins 
)

compute central momenta of the user defined PSD. ‍/ void computeCentralMomenta();

     \brief compute raw momenta of the user defined PSD.
    &zwj;/

void computeRawMomenta();

/*!

/*!

compute standardised momenta of the user defined PSD. ‍/ void computeStandardisedMomenta();

/*!

get momenta of the user defined PSD. ‍/ std::array<Mdouble, 6> getMomenta() const;

/*!

convert the probabilityDensity of diameter in Phi to the probabilityDensity of diameter in Meter.

generates a normal particle size distribution in Phi units and converts it to the distribution in meters.

Parameters
[in]meanInPhiDouble representing the mean diameter of the particle size distribution in phi units
[in]standardDeviationInPhiDouble representing the standard deviation of the particle size distribution (diameter) in phi units
[in]numberOfBinsInteger determining the number of bins (aka. particle size classes or resolution) of the particle size distribution
446  {
447  Mdouble dMin = meanInPhi - 6 * standardDeviationInPhi;
448  Mdouble dMax = meanInPhi + 6 * standardDeviationInPhi;
449  std::vector<Mdouble> diameterPhi = helpers::linspace(dMin, dMax, numberOfBins);
450  std::vector<Mdouble> pdfPhi;
451  for (int i = 0; i < diameterPhi.size(); i++) {
452  Mdouble probability = 1 / (standardDeviationInPhi * sqrt(2.0 * constants::pi)) *
453  exp(-0.5 * pow((diameterPhi[i] - meanInPhi) / standardDeviationInPhi, 2));
454  pdfPhi.push_back(probability);
455  }
456  std::vector<Mdouble> diameter;
457  std::vector<Mdouble> pdf(pdfPhi.size());
458  for(int i = 0; i < diameterPhi.size(); i++){
459  Mdouble D = pow(2, -diameterPhi[i])/1000.0;
460  diameter.push_back(D);
461  }
462  pdf[0] = 0;
463  for(int i= 0; i < diameterPhi.size()-1; i++){
464  Mdouble area = (diameterPhi[i+1]-diameterPhi[i]) * 0.5*(pdfPhi[i+1]+pdfPhi[i]);
465  Mdouble dD = fabs(diameter[i+1]-diameter[i]);
466  pdf[i+1] = 2.0*area/dD - pdf[i];
467  }
468  std::vector< std::pair <Mdouble,Mdouble> > vect;
469  for (int i=0; i<diameter.size(); i++)
470  vect.push_back(std::make_pair(diameter[i],pdf[i]));
471  return vect;
472 }
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
dominoes D
Definition: Domino.cpp:55
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 exp(const bfloat16 &a)
Definition: BFloat16.h:615
const Mdouble pi
Definition: ExtendedMath.h:23
std::vector< Mdouble > linspace(Mdouble a, Mdouble b, int N)
creates a 1D linear space partition
Definition: MathHelpers.cc:13

References D, Eigen::bfloat16_impl::exp(), boost::multiprecision::fabs(), i, helpers::linspace(), constants::pi, Eigen::bfloat16_impl::pow(), and sqrt().

Referenced by setDistributionPhiNormal().

◆ convertProbabilityDensityNumberDistributionToProbabilityDensity()

void PSD::convertProbabilityDensityNumberDistributionToProbabilityDensity ( TYPE  PDFType)

Convert a PROBABILITYDENSITY_NUMBER_DISTRIBUTION to any PDF.

This is a helper function to have full flexibility in converting from a PROBABILITYDENSITY_NUMBER_DISTRIBUTION type to any other PDF type. This can be useful e.g. when wanting to output the PSD with a certain type.

Parameters
PDFTypeThe PDF type to convert to.
707 {
708  Mdouble sum = 0;
709  switch (PDFType)
710  {
711  default:
712  logger(ERROR, "Wrong PDFType");
713  break;
715  for (auto it = particleSizeDistribution_.begin() + 1; it != particleSizeDistribution_.end(); ++it)
716  {
717  it->probability *= 0.5 * (it->internalVariable + (it - 1)->internalVariable);
718  // old conversion
719  //p.probability *= p.internalVariable;
720  // sum up probabilities
721  sum += it->probability;
722  }
723  break;
725  for (auto it = particleSizeDistribution_.begin() + 1; it != particleSizeDistribution_.end(); ++it)
726  {
727  it->probability *=
728  1.0 / 3.0 * (square(it->internalVariable) + it->internalVariable * (it - 1)->internalVariable +
729  square((it - 1)->internalVariable));
730  // old conversion
731  //p.probability *= square(p.internalVariable);
732  // sum up probabilities
733  sum += it->probability;
734  }
735  break;
737  for (auto it = particleSizeDistribution_.begin() + 1; it != particleSizeDistribution_.end(); ++it)
738  {
739  it->probability *=
740  0.25 * (square(it->internalVariable) + square((it - 1)->internalVariable)) *
741  (it->internalVariable + (it - 1)->internalVariable);
742  // old conversion
743  //p.probability *= cubic(p.internalVariable);
744  // sum up probabilities
745  sum += it->probability;
746  }
747  break;
748  }
749 
750  // normalize
751  for (auto& p : particleSizeDistribution_)
752  {
753  p.probability /= sum;
754  }
755 }
float * p
Definition: Tutorial_Map_using.cpp:9
squared absolute sa ArrayBase::abs2 DOXCOMMA MatrixBase::cwiseAbs2 square(power 2)

References ERROR, logger, p, particleSizeDistribution_, PROBABILITYDENSITY_AREA_DISTRIBUTION, PROBABILITYDENSITY_LENGTH_DISTRIBUTION, PROBABILITYDENSITY_VOLUME_DISTRIBUTION, and Eigen::square().

Referenced by convertCumulativeNumberDistributionToCumulative(), convertProbabilityDensityNumberDistributionToProbabilityDensityVolumeDistribution(), getParticleSizeDistributionByType(), getVolumetricMeanRadius(), and insertManuallyByVolume().

◆ convertProbabilityDensityNumberDistributionToProbabilityDensityVolumeDistribution()

MERCURYDPM_DEPRECATED void PSD::convertProbabilityDensityNumberDistributionToProbabilityDensityVolumeDistribution ( )

convert a PROBABILITYDENSITY_NUMBER_DISTRIBUTION to a PROBABILITYDENSITY_VOLUME_DISTRIBUTION.

Deprecated:
Use convertProbabilityDensityNumberDistributionToProbabilityDensity(TYPE::PROBABILITYDENSITY_VOLUME_DISTRIBUTION) instead.

converts a PROBABILITYDENSITY_NUMBER_DISTRIBUTION to a PROBABILITYDENSITY_VOLUME_DISTRIBUTION. Used for getVolumetricMeanRadius() and insertManuallyByVolume().

References convertProbabilityDensityNumberDistributionToProbabilityDensity(), and PROBABILITYDENSITY_VOLUME_DISTRIBUTION.

◆ convertProbabilityDensityToCumulative()

void PSD::convertProbabilityDensityToCumulative ( )

Converts a PDF to a CDF by integration.

Convert any type of PDF to a CDF. Probabilities are integrated for each radius by cumulatively summing them up (i.e. p_i = p_i + p_i-1).

616 {
617  // add up probabilities
618  for (auto it = particleSizeDistribution_.begin() + 1; it != particleSizeDistribution_.end(); ++it)
619  {
620  it->probability += (it - 1)->probability;
621  }
622  // check whether cumulative distribution is valid
624 }
void validateCumulativeDistribution()
Validates if a CDF starts with zero and adds up to unity.
Definition: PSD.cc:191

References particleSizeDistribution_, and validateCumulativeDistribution().

Referenced by convertCumulativeNumberDistributionToCumulative(), convertCumulativeToCumulativeNumberDistribution(), getParticleSizeDistributionByType(), insertManuallyByVolume(), setDistributionPhiNormal(), and setPSDFromVector().

◆ convertProbabilityDensityToProbabilityDensityNumberDistribution()

void PSD::convertProbabilityDensityToProbabilityDensityNumberDistribution ( TYPE  PDFType)

Convert any PDF to a PROBABILITYDENSITY_NUMBER_DISTRIBUTION.

Converts any of the PDFTypes to a PROBABILITYDENSITY_NUMBER_DISTRIBUTION based on their TYPE. This is a helper function which enables the convertProbabilityDensityToCumulative function to convert the psd into the default TYPE (CUMULATIVE_NUMBER_DISTRIBUTION).

Parameters
[in]PDFTypeType of the PDF: PROBABILITYDENSITY_LENGTH_DISTRIBUTION, PROBABILITYDENSITY_AREA_DISTRIBUTION or PROBABILITYDENSITY_VOLUME_DISTRIBUTION.
650 {
651  Mdouble sum = 0;
652  switch (PDFType)
653  {
654  default:
655  logger(ERROR, "Wrong PDFType");
656  break;
658  for (auto it = particleSizeDistribution_.begin() + 1; it != particleSizeDistribution_.end(); ++it)
659  {
660  it->probability /= 0.5 * (it->internalVariable + (it - 1)->internalVariable);
661  // old conversion
662  //p.probability /= p.internalVariable;
663  // sum up probabilities
664  sum += it->probability;
665  }
666  break;
668  for (auto it = particleSizeDistribution_.begin() + 1; it != particleSizeDistribution_.end(); ++it)
669  {
670  it->probability /=
671  1.0 / 3.0 * (square(it->internalVariable) + it->internalVariable * (it - 1)->internalVariable +
672  square((it - 1)->internalVariable));
673  // old conversion
674  //p.probability /= square(p.internalVariable);
675  // sum up probabilities
676  sum += it->probability;
677  }
678  break;
680  for (auto it = particleSizeDistribution_.begin() + 1; it != particleSizeDistribution_.end(); ++it)
681  {
682  it->probability /=
683  0.25 * (square(it->internalVariable) + square((it - 1)->internalVariable)) *
684  (it->internalVariable + (it - 1)->internalVariable);
685  // old conversion
686  //p.probability /= cubic(p.internalVariable);
687  // sum up probabilities
688  sum += it->probability;
689  }
690  break;
691  }
692 
693  // normalize
694  for (auto& p : particleSizeDistribution_)
695  {
696  p.probability /= sum;
697  }
698 }

References ERROR, logger, p, particleSizeDistribution_, PROBABILITYDENSITY_AREA_DISTRIBUTION, PROBABILITYDENSITY_LENGTH_DISTRIBUTION, PROBABILITYDENSITY_VOLUME_DISTRIBUTION, and Eigen::square().

Referenced by convertCumulativeToCumulativeNumberDistribution(), insertManuallyByVolume(), and setPSDFromVector().

◆ copy()

PSD * PSD::copy ( ) const

Creates a copy on the heap and returns a pointer.

Copy method; creates a copy on the heap and returns its pointer.

Returns
pointer to the copy on the heap
43 {
44 #ifdef DEBUG_CONSTRUCTOR
45  std::cout << "PSD::copy() const finished" << std::endl;
46 #endif
47  return new PSD(*this);
48 }
PSD()
Constructor; sets everything to 0 or default.
Definition: PSD.cc:10

References PSD().

◆ cutHighSizeRatio()

void PSD::cutHighSizeRatio ( )

Check if the size ratio is too high and cut it.

Checks if the Size ratio of the PSD is too high and cuts the PSD at head and tail by 10 percent to avoid inaccurate results.

1024 {
1025  Mdouble SR = getSizeRatio();
1026  if (SR > 100)
1027  {
1028  logger(WARN, "Size ratio > 100; Cutting the PSD to avoid inaccurate results");
1030  }
1031 }
@ WARN
void cutoffCumulativeDistribution(TYPE CDFType, Mdouble quantileMin, Mdouble quantileMax, Mdouble minPolydispersity=0.1)
Cut off the PSD at the given quantiles, with the PSD in the provided CDF form.
Definition: PSD.cc:821
Mdouble getSizeRatio() const
get the size ratio (width) of the PSD.
Definition: PSD.cc:1012

References CUMULATIVE_NUMBER_DISTRIBUTION, cutoffCumulativeDistribution(), getSizeRatio(), logger, and WARN.

◆ cutoffAndSqueezeCumulative()

MERCURYDPM_DEPRECATED void PSD::cutoffAndSqueezeCumulative ( Mdouble  quantileMin,
Mdouble  quantileMax,
Mdouble  squeeze,
Mdouble  minPolydispersity = 0.1 
)
inline

cutoff the PSD at given quantiles and make it less polydisperse by squeezing it.

Deprecated:
Instead use cutoffAndSqueezeCumulativeDistribution(TYPE::CUMULATIVE_NUMBER_DISTRIBUTION, quantileMin, quantileMax, squeeze, minPolydispersity)
226  {
227  cutoffAndSqueezeCumulativeDistribution(TYPE::CUMULATIVE_NUMBER_DISTRIBUTION, quantileMin, quantileMax, squeeze, minPolydispersity);
228  }
void cutoffAndSqueezeCumulativeDistribution(TYPE CDFType, Mdouble quantileMin, Mdouble quantileMax, Mdouble squeeze, Mdouble minPolydispersity=0.1)
Cut off the PSD at the given quantiles, with the PSD in the provided CDF form, and make it less polyd...
Definition: PSD.cc:863

References CUMULATIVE_NUMBER_DISTRIBUTION, and cutoffAndSqueezeCumulativeDistribution().

◆ cutoffAndSqueezeCumulativeDistribution()

void PSD::cutoffAndSqueezeCumulativeDistribution ( PSD::TYPE  CDFType,
Mdouble  quantileMin,
Mdouble  quantileMax,
Mdouble  squeeze,
Mdouble  minPolydispersity = 0.1 
)

Cut off the PSD at the given quantiles, with the PSD in the provided CDF form, and make it less polydisperese by squeezing it.

Cuts off the CDF at given minimum and maximum quantiles, applies a minimum polydispersity at the base and squeezes the distribution to make it less polydisperse.

Parameters
[in]CDFTypeThe CDF form the PSD should have when applying the cut off and squeeze.
[in]quantileMinUndersize quantile to cut off the lower part of the CDF.
[in]quantileMaxOversize quantile to cut off the upper part of the CDF.
[in]squeezeApplies a squeezing factor ([0,1]) which determines the degree the PDF gets squeezed.
[in]minPolydispersityApplies a minimum polydispersity ([0,1]) at the base of the CDF.
865 {
866  Mdouble r50;
868  r50 = 0.5 * PSD::getNumberDx(50);
869  else if (CDFType == TYPE::CUMULATIVE_LENGTH_DISTRIBUTION)
870  r50 = 0.5 * PSD::getLengthDx(50);
871  else if (CDFType == TYPE::CUMULATIVE_AREA_DISTRIBUTION)
872  r50 = 0.5 * PSD::getAreaDx(50);
873  else if (CDFType == TYPE::CUMULATIVE_VOLUME_DISTRIBUTION)
874  r50 = 0.5 * PSD::getVolumeDx(50);
875  else
876  logger(ERROR, "Wrong CDFType");
877 
878  // cut off
879  cutoffCumulativeDistribution(CDFType, quantileMin, quantileMax, minPolydispersity);
880  // squeeze psd
881  for (auto& p: particleSizeDistribution_)
882  {
883  p.internalVariable = r50 + (p.internalVariable - r50) * squeeze;
884  }
885 }
Mdouble getVolumeDx(Mdouble x) const
Calculate a certain diameter (e.g. D10, D50, D90, etc.) from a percentile x of the volume based PSD.
Definition: PSD.cc:929
Mdouble getNumberDx(Mdouble x) const
Calculate a certain diameter (e.g. D10, D50, D90, etc.) from a percentile x of the number based PSD.
Definition: PSD.cc:892
Mdouble getAreaDx(Mdouble x) const
Calculate a certain diameter (e.g. D10, D50, D90, etc.) from a percentile x of the area based PSD.
Definition: PSD.cc:916
Mdouble getLengthDx(Mdouble x) const
Calculate a certain diameter (e.g. D10, D50, D90, etc.) from a percentile x of the length based PSD.
Definition: PSD.cc:903

References CUMULATIVE_AREA_DISTRIBUTION, CUMULATIVE_LENGTH_DISTRIBUTION, CUMULATIVE_NUMBER_DISTRIBUTION, CUMULATIVE_VOLUME_DISTRIBUTION, cutoffCumulativeDistribution(), ERROR, getAreaDx(), getLengthDx(), getNumberDx(), getVolumeDx(), logger, p, and particleSizeDistribution_.

Referenced by cutoffAndSqueezeCumulative().

◆ cutoffCumulativeDistribution()

void PSD::cutoffCumulativeDistribution ( PSD::TYPE  CDFType,
Mdouble  quantileMin,
Mdouble  quantileMax,
Mdouble  minPolydispersity = 0.1 
)

Cut off the PSD at the given quantiles, with the PSD in the provided CDF form.

Cuts off the CDF at given minimum and maximum quantiles and applies a minimum polydispersity at the base.

Parameters
[in]CDFTypeThe CDF form the PSD should have when applying the cut off.
[in]quantileMinUndersize quantile to cut off the lower part of the CDF.
[in]quantileMaxOversize quantile to cut off the upper part of the CDF.
[in]minPolydispersityApplies a minimum polydispersity ([0,1]) at the base of the CDF.
822 {
823  // Convert the default CUMULATIVE_NUMBER_DISTRIBUTION to the provided CDF type.
825 
826  Mdouble radiusMin = getRadiusByQuantile(quantileMin);
827  Mdouble radiusMax = getRadiusByQuantile(quantileMax);
828  // to get a minimum polydispersity at the base
829  Mdouble radiusMinCut = std::min(radiusMin * (1 + minPolydispersity), radiusMax);
830  // cut off min
831  while (particleSizeDistribution_.front().internalVariable <= radiusMinCut)
832  {
834  }
835  particleSizeDistribution_.insert(particleSizeDistribution_.begin(), {radiusMinCut, quantileMin});
836  particleSizeDistribution_.insert(particleSizeDistribution_.begin(), {radiusMin, 0});
837  // cut off max
838  while (particleSizeDistribution_.back().internalVariable >= radiusMax)
839  {
840  particleSizeDistribution_.pop_back();
841  }
842  Mdouble radiusMaxCut = std::max(radiusMax - (1 - minPolydispersity) * (radiusMax - particleSizeDistribution_.back()
843  .internalVariable), radiusMin);
844  particleSizeDistribution_.push_back({radiusMaxCut, quantileMax});
845  particleSizeDistribution_.push_back({radiusMax, 1});
846 
847  // Convert the provided CDF type back to the default CUMULATIVE_NUMBER_DISTRIBUTION.
849 
850  logger(INFO, "PSD was cut successfully and now has a size ratio of %", getSizeRatio());
851 }
@ INFO
void convertCumulativeToCumulativeNumberDistribution(TYPE CDFType)
Convert any CDF to a CUMULATIVE_NUMBER_DISTRIBUTION.
Definition: PSD.cc:771
void convertCumulativeNumberDistributionToCumulative(TYPE CDFType)
Convert a CUMULATIVE_NUMBER_DISTRIBUTION to any CDF.
Definition: PSD.cc:794
Mdouble getRadiusByQuantile(Mdouble quantile) const
Calculate the quantile of the PSD.
Definition: PSD.cc:942
#define min(a, b)
Definition: datatypes.h:22
#define max(a, b)
Definition: datatypes.h:23

References convertCumulativeNumberDistributionToCumulative(), convertCumulativeToCumulativeNumberDistribution(), getRadiusByQuantile(), getSizeRatio(), INFO, logger, max, min, and particleSizeDistribution_.

Referenced by cutHighSizeRatio(), cutoffAndSqueezeCumulativeDistribution(), and cutoffCumulativeNumber().

◆ cutoffCumulativeNumber()

MERCURYDPM_DEPRECATED void PSD::cutoffCumulativeNumber ( Mdouble  quantileMin,
Mdouble  quantileMax,
Mdouble  minPolydispersity = 0.1 
)
inline

cutoff the PSD at given quantiles.

Deprecated:
Instead use cutoffCumulativeDistribution(PSD::TYPE::CUMULATIVE_NUMBER_DISTRIBUTION, quantileMin, quantileMax, minPolydispersity)
210  {
211  cutoffCumulativeDistribution(TYPE::CUMULATIVE_NUMBER_DISTRIBUTION, quantileMin, quantileMax, minPolydispersity);
212  }

References CUMULATIVE_NUMBER_DISTRIBUTION, and cutoffCumulativeDistribution().

◆ decrementNParticlesPerClass()

void PSD::decrementNParticlesPerClass ( )

Decrement nParticlesPerClass_ counter.

Decrement the nParticlesPerClass_ counter of the last inserted class by 1. This is utilized when a particle is generated but failed to be placed into an insertionBoundary.

994 {
996 }

References index_, and nParticlesPerClass_.

◆ decrementVolumePerClass()

void PSD::decrementVolumePerClass ( Mdouble  volume)

Decrement volumePerClass_ counter.

Decrement the volumePerClass_ counter of the last inserted class by the volume of the particle. This is utilized when a particle is generated but failed to be placed into an insertionBoundary.

Parameters
[in]volumeVolume of the particle which failed to be inserted.
1004 {
1005  volumePerClass_[index_]-= volume;
1006 }

References index_, and volumePerClass_.

◆ drawSample()

Mdouble PSD::drawSample ( )

Draw a sample radius from a CUMULATIVE_NUMBER_DISTRIBUTION.

Draws a sample probability of a real uniform distribution. A random number is generated in range [0,1] and by linear interpolation a suitable radius is returned. This function is only valid for CumulativeNumberDistributions as particles are drawn and not volumes, areas or lengths.

Returns
A Radius for a randomly assigned probability.
93 {
94  // draw a number between 0 and 1, uniformly distributed
95  Mdouble prob = random_.getRandomNumber(0, 1);
96  // find the interval [low,high] of the psd in which the number sits
97  auto high = std::lower_bound(particleSizeDistribution_.begin(), particleSizeDistribution_.end(), prob);
98  auto low = std::max(particleSizeDistribution_.begin(), high - 1);
99  Mdouble rMin = low->internalVariable;
100  Mdouble rMax = high->internalVariable;
101  Mdouble pMin = low->probability;
102  Mdouble pMax = high->probability;
103  // interpolate linearly between [low.radius,high.radius] (assumption: CDF is piecewise linear)
104  Mdouble a = (prob - pMin) / (pMax - pMin);
105  return a * rMin + (1 - a) * rMax;
106 }
Mdouble getRandomNumber()
This is a random generating routine can be used for initial positions.
Definition: RNG.cc:123
const Scalar * a
Definition: level2_cplx_impl.h:32

References a, RNG::getRandomNumber(), max, particleSizeDistribution_, and random_.

◆ getAreaDx()

Mdouble PSD::getAreaDx ( Mdouble  x) const

Calculate a certain diameter (e.g. D10, D50, D90, etc.) from a percentile x of the area based PSD.

Gets the diameter from a certain percentile of the area based PSD.

Returns
A double which is the diameter corresponding to a certain percentile.
Parameters
[in]xdouble [0, 100] which determines the obtained diameter as a percentile of the PSD.
917 {
918  logger.assert_always(x >= 0 && x <= 100, "Percentile % is not between 0 and 100.", x);
919  PSD psd = *this;
921  return 2.0 * psd.getRadiusByQuantile(x / 100);
922 }
Contains a vector with radii and probabilities of a user defined particle size distribution (PSD)
Definition: PSD.h:47
list x
Definition: plotDoE.py:28

References convertCumulativeNumberDistributionToCumulative(), CUMULATIVE_AREA_DISTRIBUTION, getRadiusByQuantile(), logger, and plotDoE::x.

Referenced by cutoffAndSqueezeCumulativeDistribution().

◆ getDistributionLogNormal()

static PSD PSD::getDistributionLogNormal ( Mdouble  mean,
Mdouble  standardDeviation,
int  numberOfBins 
)
inlinestatic
156  {
157  PSD psd;
158  psd.setDistributionLogNormal(mean, standardDeviation, numberOfBins);
159  return psd;
160  }
void setDistributionLogNormal(Mdouble mean, Mdouble standardDeviation, int numberOfBins)
create a PSD vector for a normal distribution.
Definition: PSD.cc:353

References setDistributionLogNormal().

Referenced by DistributionSelfTest::setupInitialConditions().

◆ getDistributionNormal()

static PSD PSD::getDistributionNormal ( Mdouble  mean,
Mdouble  standardDeviation,
int  numberOfBins 
)
inlinestatic
145  {
146  PSD psd;
147  psd.setDistributionNormal(mean, standardDeviation, numberOfBins);
148  return psd;
149  }
void setDistributionNormal(Mdouble mean, Mdouble standardDeviation, int numberOfBins)
create a PSD vector for a normal distribution.
Definition: PSD.cc:318

References setDistributionNormal().

Referenced by Material::setPSD(), Drum::setupInitialConditions(), and RotatingDrumWet::setupInitialConditions().

◆ getInsertedParticleNumber()

int PSD::getInsertedParticleNumber ( ) const

Get the number of particles already inserted into the simulation.

Gets the number of particles already inserted into the simulation by summing up the particles inserted in each class.

Returns
An integer containing the number of particles already inserted into the simulation.
1191 {
1192  int sum = 0;
1193  for (auto& it: nParticlesPerClass_)
1194  sum += it;
1195  return sum;
1196 }

References nParticlesPerClass_.

◆ getLengthDx()

Mdouble PSD::getLengthDx ( Mdouble  x) const

Calculate a certain diameter (e.g. D10, D50, D90, etc.) from a percentile x of the length based PSD.

Gets the diameter from a certain percentile of the length based PSD.

Returns
A double which is the diameter corresponding to a certain percentile.
Parameters
[in]xdouble [0, 100] which determines the obtained diameter as a percentile of the PSD.
904 {
905  logger.assert_always(x >= 0 && x <= 100, "Percentile % is not between 0 and 100.", x);
906  PSD psd = *this;
908  return 2.0 * psd.getRadiusByQuantile(x / 100);
909 }

References convertCumulativeNumberDistributionToCumulative(), CUMULATIVE_LENGTH_DISTRIBUTION, getRadiusByQuantile(), logger, and plotDoE::x.

Referenced by cutoffAndSqueezeCumulativeDistribution().

◆ getMaxRadius()

Mdouble PSD::getMaxRadius ( ) const

Get largest radius of the PSD.

Gets the maximum radius of the PSD.

Returns
A double which corresponds to the maximum radius of the PSD.
1047 {
1048  return particleSizeDistribution_.back().internalVariable;
1049 }

References particleSizeDistribution_.

Referenced by getSizeRatio(), GranuDrum::GranuDrum(), and GranuHeap::GranuHeap().

◆ getMinRadius()

Mdouble PSD::getMinRadius ( ) const

Get smallest radius of the PSD.

Gets the minimal radius of the PSD.

Returns
A double which corresponds to the minimal radius of the PSD.
1038 {
1039  return particleSizeDistribution_[0].internalVariable;
1040 }

References particleSizeDistribution_.

Referenced by getSizeRatio(), GranuHeap::GranuHeap(), Calibration::setSpecies(), and Material::setSpecies().

◆ getNumberDx()

Mdouble PSD::getNumberDx ( Mdouble  x) const

Calculate a certain diameter (e.g. D10, D50, D90, etc.) from a percentile x of the number based PSD.

Gets the diameter from a certain percentile of the number based PSD.

Returns
A double which is the diameter corresponding to a certain percentile.
Parameters
[in]xdouble [0, 100] which determines the obtained diameter as a percentile of the PSD.
893 {
894  logger.assert_always(x >= 0 && x <= 100, "Percentile % is not between 0 and 100.", x);
895  return 2.0 * getRadiusByQuantile(x / 100);
896 }

References getRadiusByQuantile(), logger, and plotDoE::x.

Referenced by cutoffAndSqueezeCumulativeDistribution(), and GranuHeap::GranuHeap().

◆ getParticleSizeDistribution()

std::vector< DistributionElements > PSD::getParticleSizeDistribution ( ) const

Get the PSD vector.

Gets the vector containing radii and probabilities of the PSD.

Returns
A vector containing radii and probabilities of the PSD.
1056 {
1058 }

References particleSizeDistribution_.

Referenced by getParticleSizeDistributionByType(), DistributionPhiNormalSelfTest::setupInitialConditions(), and SetDistributionPhiNormalSelfTest::setupInitialConditions().

◆ getParticleSizeDistributionByType()

std::vector< DistributionElements > PSD::getParticleSizeDistributionByType ( TYPE  PSDType,
Mdouble  scalingFactor = 1.0 
) const

Gets the PSD vector, converted to the preferred type.

This returns the PSD vector converted to the specified type, with an optional scale factor for the internal variable. This can be used e.g. to output the PSD with a certain type.

Parameters
PSDTypeThe type the PSD should be.
scalingFactorThe scale factor by which the the internal variable is multiplied.
Returns
The converted PSD vector.
1068 {
1069  PSD psd = *this;
1070 
1071  switch (PSDType)
1072  {
1073  // default case is a CUMULATIVE_NUMBER_DISTRIBUTION
1074  default:
1075  break;
1080  break;
1085  break;
1090  break;
1093  break;
1097  break;
1101  break;
1105  break;
1106  }
1107 
1108  auto psdVector = psd.getParticleSizeDistribution();
1109  for (auto& de : psdVector)
1110  de.internalVariable *= scalingFactor;
1111 
1112  return psdVector;
1113 }
std::vector< DistributionElements > getParticleSizeDistribution() const
Get the PSD vector.
Definition: PSD.cc:1055
@ PROBABILITYDENSITY_NUMBER_DISTRIBUTION

References convertCumulativeToProbabilityDensity(), convertProbabilityDensityNumberDistributionToProbabilityDensity(), convertProbabilityDensityToCumulative(), CUMULATIVE_AREA_DISTRIBUTION, CUMULATIVE_LENGTH_DISTRIBUTION, CUMULATIVE_VOLUME_DISTRIBUTION, getParticleSizeDistribution(), PROBABILITYDENSITY_AREA_DISTRIBUTION, PROBABILITYDENSITY_LENGTH_DISTRIBUTION, PROBABILITYDENSITY_NUMBER_DISTRIBUTION, and PROBABILITYDENSITY_VOLUME_DISTRIBUTION.

Referenced by ParticleHandler::saveNumberPSDtoCSV(), and testPSD().

◆ getQuantileByRadius()

Mdouble PSD::getQuantileByRadius ( Mdouble  radius) const

Calculates the quantile corresponding to a certain radius.

Calculates the quantile corresponding to a certain radius.

Parameters
radiusThe radius to find the quantile for.
Returns
The quantile found.
962 {
963  auto high = std::lower_bound(particleSizeDistribution_.begin(), particleSizeDistribution_.end(),
964  radius, [](const DistributionElements& rp, Mdouble value){ return rp.internalVariable < value; });
965  auto low = std::max(particleSizeDistribution_.begin(), high - 1);
966  if (high->internalVariable == low->internalVariable)
967  return high->probability;
968  else
969  return low->probability + (high->probability - low->probability) * (radius - low->internalVariable) / (high->internalVariable - low->internalVariable);
970 }
class of DistributionElements which stores internalVariables and probabilities of a distribution....
Definition: DistributionElements.h:13
squared absolute value
Definition: GlobalFunctions.h:87
radius
Definition: UniformPSDSelfTest.py:15

References max, particleSizeDistribution_, UniformPSDSelfTest::radius, and Eigen::value.

◆ getRadius()

Mdouble PSD::getRadius ( int  index) const

get a radius at a certain index of the particleSizeDistribution_

 \details Compute the raw momenta of the inserted PSD by converting it to a PDF, calculating the moments m_i according
 to \f$ m_i = \sum_{j=0}^n \f$ scaling it by the number
 of particles inserted into the simulation (moments are computed from a PROBABILITYDENSITY_NUMBER_DISTRIBUTION) and
 converting it back to a CDF.
 See <a href="https://en.wikipedia.org/wiki/Moment_(mathematics)#Significance_of_the_moments">Wikipedia</a> for
 details.
&zwj;/

void PSD::computeRawMomenta() { convertCumulativeToProbabilityDensity(); for (size_t im = 0; im < momenta_.size(); ++im) { // prevent summing up of moments for each time step of the simulation momenta_[im] = 0; for (auto& it : particleSizeDistribution_) { momenta_[im] += std::pow(it.internalVariable, im) * it.probability; } } // zeroth-moment equals particle number for a PROBABILITYDENSITY_NUMBER_DISTRIBUTION momenta_[0] *= getInsertedParticleNumber(); convertProbabilityDensityToCumulative(); }

/*!

Compute the central momenta of the PSD from their respective raw momenta. ‍/ void PSD::computeCentralMomenta() { computeRawMomenta(); Mdouble mean = momenta_[1]; momenta_[5] += -5 * mean * momenta_[4] + 10 * mean * mean * momenta_[3]

  • 10 * mean * mean * mean * momenta_[2] + 4 * mean * mean * mean * mean * mean; momenta_[4] += -4 * mean * momenta_[3] + 6 * mean * mean * momenta_[2] - 3 * mean * mean * mean * mean; momenta_[3] += -3 * mean * momenta_[2] + 2 * mean * mean * mean; momenta_[2] += -mean * mean; }

/*!

Compute the standardised momenta of the PSD from their respective central momenta. ‍/ void PSD::computeStandardisedMomenta() { computeCentralMomenta(); Mdouble std = std::sqrt(momenta_[2]); momenta_[3] /= std * std * std; momenta_[4] /= std * std * std * std; momenta_[5] /= std * std * std * std * std; }

/*!

Gets the radius of a particle from the PSD.

Parameters
[in]iAn integer which is the index of the vector containing the radius.
Returns
A double which corresponds to the radius of the particle.
1255 {
1256  return particleSizeDistribution_[index].internalVariable;
1257 }

References particleSizeDistribution_.

◆ getRadiusByQuantile()

Mdouble PSD::getRadiusByQuantile ( Mdouble  quantile) const

Calculate the quantile of the PSD.

gets the radius from a certain quantile of the PSD

Returns
A double which is the radius corresponding to a certain quantile of the PSD.
Parameters
[in]quantiledouble which determines the returned radius as a quantile of the PSD.
943 {
944  logger.assert_always(quantile <= 1 && quantile >= 0, "quantile is not between 0 and 1");
945  // find the quantile corresponding to the PSD
946  auto high = std::lower_bound(particleSizeDistribution_.begin(), particleSizeDistribution_.end(), quantile);
947  auto low = std::max(particleSizeDistribution_.begin(), high - 1);
948  if (high->probability == low->probability)
949  return high->internalVariable;
950  else
951  return low->internalVariable +
952  (high->internalVariable - low->internalVariable) * (quantile - low->probability) /
953  (high->probability - low->probability);
954 }

References logger, max, and particleSizeDistribution_.

Referenced by cutoffCumulativeDistribution(), getAreaDx(), getLengthDx(), getNumberDx(), and getVolumeDx().

◆ getSizeRatio()

Mdouble PSD::getSizeRatio ( ) const

get the size ratio (width) of the PSD.

Gets the size ratio (width) of the PSD defined by the ratio of minimum to maximum particle radius.

Returns
A double which corresponds to the size ratio of the PSD.
1013 {
1014  Mdouble rMin = getMaxRadius();
1015  Mdouble rMax = getMinRadius();
1016  return rMin / rMax;
1017 }
Mdouble getMinRadius() const
Get smallest radius of the PSD.
Definition: PSD.cc:1037
Mdouble getMaxRadius() const
Get largest radius of the PSD.
Definition: PSD.cc:1046

References getMaxRadius(), and getMinRadius().

Referenced by cutHighSizeRatio(), cutoffCumulativeDistribution(), and setPSDFromCSV().

◆ getVolumeDx()

Mdouble PSD::getVolumeDx ( Mdouble  x) const

Calculate a certain diameter (e.g. D10, D50, D90, etc.) from a percentile x of the volume based PSD.

Gets the diameter from a certain percentile of the volume based PSD.

Returns
A double which is the diameter corresponding to a certain percentile.
Parameters
[in]xdouble [0, 100] which determines the obtained diameter as a percentile of the PSD.
930 {
931  logger.assert_always(x >= 0 && x <= 100, "Percentile % is not between 0 and 100.", x);
932  PSD psd = *this;
934  return 2.0 * psd.getRadiusByQuantile(x / 100);
935 }

References convertCumulativeNumberDistributionToCumulative(), CUMULATIVE_VOLUME_DISTRIBUTION, getRadiusByQuantile(), logger, and plotDoE::x.

Referenced by cutoffAndSqueezeCumulativeDistribution(), GranuDrum::GranuDrum(), GranuHeap::GranuHeap(), Calibration::setSpecies(), and Material::setSpecies().

◆ getVolumetricMeanRadius()

Mdouble PSD::getVolumetricMeanRadius ( ) const

get a volumetric mean radius of the PSD.

Gets a radius such that a monodisperse system has the same number of particles as a polydisperse system. (i.e. mean += p_i * 0.5*(r_i^3 + r_i-1^3)

Returns
A double which corresponds to the volumetric mean radius.
978 {
979  PSD psd = *this;
982  Mdouble mean = 0;
983  for (auto it = particleSizeDistribution_.begin() + 1; it != particleSizeDistribution_.end(); ++it)
984  mean += it->probability * 0.5 * (cubic(it->internalVariable) + cubic((it - 1)->internalVariable));
985  mean = pow(mean, 1. / 3.);
986  return mean;
987 }
T cubic(const T val)
calculates the cube of a number
Definition: ExtendedMath.h:95

References convertCumulativeToProbabilityDensity(), convertProbabilityDensityNumberDistributionToProbabilityDensity(), mathsFunc::cubic(), particleSizeDistribution_, Eigen::bfloat16_impl::pow(), and PROBABILITYDENSITY_VOLUME_DISTRIBUTION.

◆ insertManuallyByVolume()

Mdouble PSD::insertManuallyByVolume ( Mdouble  volume)

Draw sample radius manually per size class and check the volumeAllowed of each size class to insert the PSD as accurate as possible.

Draws a sample probability of a real uniform distribution within a given size class. A random number is generated in the size class range [r_i,r_i+1] and by linear interpolation a suitable radius is returned. from a CUMULATIVE_VOLUME_DISTRIBUTION the volumeAllowed of each class is checked to insert the PSD as accurate as possible. This function is only valid for cumulativeNumberDistributions as particles are drawn and not volumes, areas or lengths. Furthermore this insertion routine is most accurate for non-continuous particle insertion.

Parameters
[in]volumevolume of the geometry to be filled.
Returns
A Radius for a randomly assigned probability of a specific size class.
118 {
119  // initialize the particleNumberPerClass vector if empty.
120  if (nParticlesPerClass_.empty())
122  // initialize the particleNumberPerClass vector if empty.
123  if (volumePerClass_.empty())
125 
126  for (auto it = particleSizeDistribution_.end() - 1; it != particleSizeDistribution_.begin(); --it)
127  {
128  static std::mt19937 gen(0);
129  static std::uniform_real_distribution<Mdouble> dist(0, 1);
130  Mdouble prob = dist(gen);
131  // map the probability to the current class interval
132  prob = (it - 1)->probability + (it->probability - (it - 1)->probability) * prob;
133  // find the interval [low,high] of the psd in which the number sits
134  auto high = std::lower_bound(particleSizeDistribution_.begin(), particleSizeDistribution_.end(), prob);
135  auto low = std::max(particleSizeDistribution_.begin(), high - 1);
136  Mdouble rMin = low->internalVariable;
137  Mdouble rMax = high->internalVariable;
138  Mdouble pMin = low->probability;
139  Mdouble pMax = high->probability;
140  // interpolate linearly between [low.internalVariable,high.internalVariable] (assumption: CDF is piecewise linear)
141  index_ = std::distance(particleSizeDistribution_.begin(), high);
142  Mdouble a = (prob - pMin) / (pMax - pMin);
143  Mdouble rad = a * rMin + (1 - a) * rMax;
144  //\todo generalize this to work for non-spherical particles
145  // Compare inserted volume against volumeAllowed (only works for spherical at the moment)
146  Mdouble radVolume = 4.0 / 3.0 * constants::pi * rad * rad * rad;
149  Mdouble volumeAllowed = particleSizeDistribution_[index_].probability * volume;
152  if (volumePerClass_[index_] > volumeAllowed)
153  {
154  continue;
155  }
156  else if (radVolume + volumePerClass_[index_] > volumeAllowed)
157  {
158  Mdouble differenceVolumeLow = -(volumePerClass_[index_] - volumeAllowed);
159  Mdouble differenceVolumeHigh = radVolume + volumePerClass_[index_] - volumeAllowed;
160  Mdouble volumeRatio = differenceVolumeLow / differenceVolumeHigh;
161  // If volumeRatio > 1 it will insert anyways, because it should be no problem for the distribution
162  prob = dist(gen);
163  if (prob <= volumeRatio)
164  {
166  volumePerClass_[index_] += radVolume;
167  return rad;
168  }
169  else
170  {
171  continue;
172  }
173  }
174  else
175  {
177  volumePerClass_[index_] += radVolume;
178  return rad;
179  }
180 
181  }
182  return 0;
183 }

References a, convertCumulativeToProbabilityDensity(), convertProbabilityDensityNumberDistributionToProbabilityDensity(), convertProbabilityDensityToCumulative(), convertProbabilityDensityToProbabilityDensityNumberDistribution(), index_, max, nParticlesPerClass_, particleSizeDistribution_, constants::pi, PROBABILITYDENSITY_VOLUME_DISTRIBUTION, and volumePerClass_.

◆ linspace()

static std::vector<Mdouble> PSD::linspace ( Mdouble  Min,
Mdouble  Max,
int  numberOfBins 
)
static

create a vector of linearly spaced values.

◆ printPSD()

void PSD::printPSD ( ) const

Prints radii and probabilities of the PSD vector.

Prints the radii [m] and probabilities [%] of the psd vector. It currently supports nanometers, micrometers, milimeters and meters as size units.

55 {
56  if (particleSizeDistribution_.front().internalVariable > 1e-1)
57  {
58  for (const auto p: particleSizeDistribution_)
59  {
60  logger(INFO, "%m\t %\%", p.internalVariable, p.probability * 100);
61  }
62  }
63  else if (particleSizeDistribution_.front().internalVariable > 1e-4)
64  {
65  for (const auto p: particleSizeDistribution_)
66  {
67  logger(INFO, "%mm\t %\%", p.internalVariable * 1000, p.probability * 100);
68  }
69  }
70  else if (particleSizeDistribution_.front().internalVariable > 1e-7)
71  {
72  for (const auto p: particleSizeDistribution_)
73  {
74  logger(INFO, "%um\t %\%", p.internalVariable * 1e6, p.probability * 100);
75  }
76  }
77  else
78  {
79  for (const auto p: particleSizeDistribution_)
80  {
81  logger(INFO, "%nm\t %\%", p.internalVariable * 1e9, p.probability * 100);
82  }
83  }
84 }
Array< double, 1, 3 > e(1./3., 0.5, 2.)

References e(), INFO, logger, p, and particleSizeDistribution_.

◆ scaleParticleSize()

void PSD::scaleParticleSize ( double  scale)

Scales all particle sizes by a factor.

1125 {
1126  for (auto& p : particleSizeDistribution_) {
1127  p.internalVariable *= scale;
1128  }
1129 }

References p, and particleSizeDistribution_.

Referenced by scaleParticleSizeAuto().

◆ scaleParticleSizeAuto()

double PSD::scaleParticleSizeAuto ( int  numberOfParticles,
double  targetVolume,
bool  allowScaleDown = false 
)

Scales all particle sizes, such that the total volume of N particles approximately equals the target volume.

Parameters
numberOfParticlesThe number of particles N.
targetVolumeThe volume to match.
allowScaleDownWhether or not to scale down the particle sizes when the scale factor is smaller than 1.
Returns
The scale factor used.
1132 {
1133  // Calculate the mean particle volume, using the Mean Value Theorem for Integrals. I.e. the mean particle volume
1134  // over an infinite number of particles.
1135  double meanParticleVolume = 0.0;
1136  for (auto it = particleSizeDistribution_.begin(); it < particleSizeDistribution_.end() - 1; it++)
1137  {
1138  double radiusLeft = it->internalVariable;
1139  double radiusRight = (it+1)->internalVariable;
1140  double probabilityLeft = it->probability;
1141  double probabilityRight = (it+1)->probability;
1142 
1143  double meanVolume;
1144  if (radiusLeft != radiusRight)
1145  {
1146  // The CDF is assumed piecewise linear, so the radius is linearly interpolated.
1147  // Integrate the volume from radius left to right, i.e. integral of 4/3 pi r^3 gives 1/3 pi (r_r^4 - r_l^4).
1148  double volumeIntegral = (std::pow(radiusRight, 4) - std::pow(radiusLeft, 4)) * constants::pi / 3.0;
1149  // Calculate the mean volume that represents this bin.
1150  meanVolume = volumeIntegral / (radiusRight - radiusLeft);
1151  }
1152  else
1153  {
1154  meanVolume = std::pow(radiusLeft, 3) * constants::pi * 4.0 / 3.0;
1155  }
1156 
1157  // Calculate the volume that this bin accounts for, and add to total.
1158  meanParticleVolume += meanVolume * (probabilityRight - probabilityLeft);
1159  }
1160 
1161  // The volume that the number of particles currently fills, and the scale factor to make it match the target volume.
1162  double totalParticleVolume = numberOfParticles * meanParticleVolume;
1163  double scale = std::cbrt(targetVolume / totalParticleVolume);
1164 
1165  // The number of (unscaled) particles needed to fill the target volume.
1166  unsigned long long numberOfParticlesExpected = std::pow(scale, 3) * numberOfParticles;
1167  logger(INFO, "Rescaling the particle size based on number of particles %, and target volume %.", numberOfParticles, targetVolume);
1168  logger(INFO, "Expected number of particles %, scale factor %.", numberOfParticlesExpected, scale);
1169 
1170  // Always scale up, only scale down when requested.
1171  if (scale > 1.0 || allowScaleDown)
1172  {
1173  scaleParticleSize(scale);
1174  logger(INFO, "Rescaling applied.");
1175  }
1176  else
1177  {
1178  logger(INFO, "Rescaling not applied, since scale factor is less than or equal to 1.");
1179  scale = 1.0; // Reassign so that the returned value is correct.
1180  }
1181 
1182  return scale;
1183 }
void scaleParticleSize(double scale)
Scales all particle sizes by a factor.
Definition: PSD.cc:1124
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T cbrt(const T &x)
Definition: MathFunctions.h:1320

References Eigen::numext::cbrt(), INFO, logger, particleSizeDistribution_, constants::pi, Eigen::bfloat16_impl::pow(), and scaleParticleSize().

◆ setDistributionLogNormal()

void PSD::setDistributionLogNormal ( Mdouble  mean,
Mdouble  standardDeviation,
int  numberOfBins 
)

create a PSD vector for a normal distribution.

sets the particle size distribution to a discretised lognormal cumulative number distribution, which generates random values of radius following a lognormal distribution and iterates until the mass-based D50 is close to two times the user-defined mean radius.

Parameters
[in]meanDouble representing the mean of the particle size distribution in meters (radius)
[in]standardDeviationDouble representing the standard deviation of the particle size distribution in meters (radius)
[in]numberOfBinsInteger determining the number of bins (aka. particle size classes or resolution) of the particle size distribution See https://en.cppreference.com/w/cpp/numeric/random/lognormal_distribution
354 {
355  //setDistributionNormal(mean, standardDeviation, numberOfBins);
356  if (!particleSizeDistribution_.empty())
357  {
359  }
360  Mdouble radMin = mean - 3 * standardDeviation;
361  Mdouble radMax = mean + 3 * standardDeviation;
362  std::vector<Mdouble> radii = helpers::linspace(radMin, radMax, numberOfBins);
363  std::vector<Mdouble> probabilities;
364  for (int i = 0; i < radii.size(); i++)
365  {
366  Mdouble probability = 0.5 * (1 + erf((radii[i] - mean) / (sqrt(2) * standardDeviation)));
367  probabilities.push_back(probability);
368  }
369  for (int j = 0; j < radii.size(); j++)
370  {
371  particleSizeDistribution_.push_back({radii[j], probabilities[j]});
372  }
374  for (auto& p: particleSizeDistribution_)
375  {
376  p.internalVariable = exp(p.internalVariable);
377  }
378 }

References Eigen::bfloat16_impl::exp(), i, j, helpers::linspace(), p, particleSizeDistribution_, sqrt(), and validateCumulativeDistribution().

Referenced by getDistributionLogNormal().

◆ setDistributionNormal()

void PSD::setDistributionNormal ( Mdouble  mean,
Mdouble  standardDeviation,
int  numberOfBins 
)

create a PSD vector for a normal distribution.

sets the particle size distribution to a discretised normal (gaussian) cumulative number distribution, which covers the range of 3 * standardDeviation (99,73% of all values covered).

Parameters
[in]meanDouble representing the mean of the particle size distribution
[in]standardDeviationDouble representing the standard deviation of the particle size distribution
[in]numberOfBinsInteger determining the number of bins (aka. particle size classes or resolution) of the particle size distribution
319 {
320  logger.assert_always(mean > 3 * standardDeviation,
321  "Reduce standardDeviation of your normal distribution to avoid negative radii; The mean "
322  "should be greater than 3*standardDeviation");
323  if (!particleSizeDistribution_.empty())
324  {
326  }
327  Mdouble radMin = mean - 3 * standardDeviation;
328  Mdouble radMax = mean + 3 * standardDeviation;
329  std::vector<Mdouble> radii = helpers::linspace(radMin, radMax, numberOfBins);
330  std::vector<Mdouble> probabilities;
331  for (int i = 0; i < radii.size(); i++)
332  {
333  Mdouble probability = 0.5 * (1 + erf((radii[i] - mean) / (sqrt(2) * standardDeviation)));
334  probabilities.push_back(probability);
335  }
336  for (int j = 0; j < radii.size(); j++)
337  {
338  particleSizeDistribution_.push_back({radii[j], probabilities[j]});
339  }
341 }

References i, j, helpers::linspace(), logger, particleSizeDistribution_, sqrt(), and validateCumulativeDistribution().

Referenced by getDistributionNormal(), and DistributionToPSDSelfTest::setupInitialConditions().

◆ setDistributionPhiNormal()

void PSD::setDistributionPhiNormal ( Mdouble  D50,
Mdouble  standardDeviationInPhi,
int  numberOfBins 
)

create a PSD vector for a normal distribution in Phi Units that has the demanded D50.

sets the particle size distribution to a discretised cumulative number distribution, which is a normal distribution in phi units and has the demanded D50. D50 is the mass-based median grain size, while the Phi scale is a logarithmic scale computed by: Phi = -log2(1000*D). It can be used for visualizing sediment grain size distributions over a wide range of grain sizes. The combination of D50 and standardDeviation in Phi units is a representative measure of grain size distribution in the field of Sedimentology. Source: Donoghue, J.F. (2016). Phi Scale. In: Kennish, M.J. (eds) Encyclopedia of Estuaries. Encyclopedia of Earth Sciences Series. Springer, Dordrecht. https://doi.org/10.1007/978-94-017-8801-4_277

Parameters
[in]D50Double representing the mass-based D50 of the particle size distribution in meters
[in]standardDeviationInPhiDouble representing the standard deviation of the particle size distribution (diameter) in phi units
[in]numberOfBinsInteger determining the number of bins (aka. particle size classes or resolution) of the particle size distribution
393  {
394  Mdouble PhiMean = -log2(1000*D50);
395  std::vector<std::pair<Mdouble,Mdouble>> vect = convertPdfPhiToPdfMeter(PhiMean, standardDeviationInPhi, numberOfBins);
396  std::sort(vect.begin(), vect.end());
397  Mdouble D50Test = computeD50(vect);
398  Mdouble res = D50Test - D50;
399  Mdouble tol = D50*1e-5;
400  int itter = 0;
401  Mdouble dPhiMean, slope, res_old;
402  while (res > tol && itter < 100) {
403  if(itter==0) dPhiMean = 0.1;
404  else {
405  slope = (res - res_old)/dPhiMean;
406  dPhiMean = -res/slope;
407  }
408  PhiMean = PhiMean+dPhiMean;
409  vect = convertPdfPhiToPdfMeter(PhiMean, standardDeviationInPhi, numberOfBins);
410  std::sort(vect.begin(), vect.end());
411  D50Test = computeD50(vect);
412  res_old = res;
413  res = D50Test - D50;
414  itter++;
415  }
416  logger(INFO, "D50 %, Final D50Test %", D50, D50Test);
417 
418  Mdouble probTot=0;
419  for(int i = 0; i < vect.size(); i++){
420  probTot += vect[i].second;
421  }
422  for (int i = 0; i < vect.size(); i++)
423  {
424  vect[i].second = vect[i].second/probTot;
425  }
426 
427  if (!particleSizeDistribution_.empty())
428  {
430  }
431  for (int j = 0; j < vect.size(); j++)
432  {
433  particleSizeDistribution_.push_back({vect[j].first*0.5, vect[j].second});
434  }
437 }
cout<< "Here is the matrix m:"<< endl<< m<< endl;Matrix< ptrdiff_t, 3, 1 > res
Definition: PartialRedux_count.cpp:3
Mdouble computeD50(std::vector< std::pair< Mdouble, Mdouble > > vectorOfPair)
compute the mass-based D_50 of the paired diameter and probabilityDensity.
Definition: PSD.cc:478
std::vector< std::pair< Mdouble, Mdouble > > convertPdfPhiToPdfMeter(Mdouble meaninPhi, Mdouble standardDeviationinPhi, int numberOfBins)
compute central momenta of the user defined PSD. ‍/ void computeCentralMomenta();
Definition: PSD.cc:446
Scalar log2(Scalar x)
Definition: packetmath.cpp:754

References computeD50(), convertPdfPhiToPdfMeter(), convertProbabilityDensityToCumulative(), e(), i, INFO, j, log2(), logger, particleSizeDistribution_, res, and validateCumulativeDistribution().

Referenced by DistributionPhiNormalSelfTest::setupInitialConditions(), and SetDistributionPhiNormalSelfTest::setupInitialConditions().

◆ setDistributionUniform()

void PSD::setDistributionUniform ( Mdouble  radMin,
Mdouble  radMax,
int  numberOfBins 
)

create a PSD vector for a uniform distribution.

sets the particle size distribution to a discretised uniform (linear) cumulative number distribution

Parameters
[in]radMinDouble representing The smallest particle radius of the particle size distribution
[in]radMaxDouble representing the biggest particle radius of the particle size distribution
[in]numberOfBinsInteger determining the number of bins (aka. particle size classes or resolution) of the particle size distribution
295 {
296  if (!particleSizeDistribution_.empty())
297  {
299  }
300  std::vector<Mdouble> probabilities = helpers::linspace(0.0, 1.0, numberOfBins);
301  std::vector<Mdouble> radii = helpers::linspace(radMin, radMax, numberOfBins);
302  // combine radii and probabilities
303  for (int i = 0; i < radii.size(); ++i)
304  {
305  particleSizeDistribution_.push_back({radii[i], probabilities[i]});
306  }
308 }

References i, helpers::linspace(), particleSizeDistribution_, and validateCumulativeDistribution().

Referenced by BoundariesSelfTest::BoundariesSelfTest(), FluxBoundarySelfTest::FluxBoundarySelfTest(), RandomClusterInsertionBoundary::set(), HopperInsertionBoundary::set(), CylinderInsertionBoundary::set(), SphereInsertionBoundary::set(), ChuteInsertionBoundary::set(), CubeInsertionBoundary::set(), InsertionBoundarySelfTest::setupInitialConditions(), FullRestartTest::setupInitialConditions(), Chute::setupInitialConditions(), ChuteWithHopper::setupInitialConditions(), and T_protectiveWall::T_protectiveWall().

◆ setFixedSeed()

void PSD::setFixedSeed ( int  seed)
inline

set a fixed seed for the random number generator; this is used for the PSDSelfTest to reproduce results

381  {
382 // random_.setLinearCongruentialGeneratorParmeters(0,0,1);
383  random_.setRandomSeed(seed);
384  }

References random_, and RNG::setRandomSeed().

◆ setParticleSizeDistribution()

void PSD::setParticleSizeDistribution ( std::vector< DistributionElements particleSizeDistribution)

set the PSD by a suitable vector.

Deprecated:
Use setPSDFromVector() instead.

sets the PSD from a vector of the DistributionElements class; used to read in PSDs from a restart file.

Parameters
[in]particleSizeDistributionvector containing the radii and probabilities specifying the PSD.
1120 {
1121  particleSizeDistribution_ = particleSizeDistribution;
1122 }

References particleSizeDistribution_.

◆ setPSDFromCSV()

void PSD::setPSDFromCSV ( const std::string &  fileName,
TYPE  PSDType,
bool  headings = false,
Mdouble  unitScalingFactorRadii = 1.0 
)

read in the PSD vector with probabilities and radii saved in a .csv file.

creates the PSD vector from probabilities and radii saved in a .csv file. Radii should be located at the first column and probabilities at the second column of the file. The Type of PSD will be converted to the default cumulative number distribution function (CUMULATIVE_NUMBER_DISTRIBUTION) for further processing.

Parameters
[in]fileNameName of the .csv file containing the radii and probabilities of the PSD.
[in]PSDTypeType of the PSD: CUMULATIVE_VOLUME_DISTRIBUTION, CUMULATIVE_NUMBER_DISTRIBUTION, CUMULATIVE_LENGTH_DISTRIBUTION, CUMULATIVE_AREA_DISTRIBUTION, PROBABILITYDENSITY_VOLUME_DISTRIBUTION, PROBABILITYDENSITY_NUMBER_DISTRIBUTION, PROBABILITYDENSITY_LENGTH_DISTRIBUTION PROBABILITYDENSITY_AREA_DISTRIBUTION.
[in]headingsIf TRUE the file is assumed to have headings and the first row will be skipped. If FALSE the file has no headings and the file will be read in as is. Default is FALSE.
[in]unitScalingFactorRadiiScaling factor of radii to match SI-units.
591 {
592  // read in csv file using the csvReader class
593  csvReader csv;
594  csv.setHeader(headings);
595  csv.read(fileName);
596  std::vector<Mdouble> radii = csv.getFirstColumn(unitScalingFactorRadii);
597  std::vector<Mdouble> probabilities = csv.getSecondColumn(1.0);
598  logger.assert_always(radii.size() == probabilities.size(), "The radii and probabilities vector have to be the "
599  "same size");
600  // combine radii and probabilities
601  std::vector<DistributionElements> psd;
602  for (int i = 0; i < radii.size(); ++i)
603  {
604  psd.push_back({radii[i], probabilities[i]});
605  }
606  logger.assert_always(!psd.empty(), "PSD cannot be empty");
607  setPSDFromVector(psd, PSDType);
608  logger(INFO, "A PSD with size ratio % is now ready to be set", getSizeRatio());
609 }
void setPSDFromVector(std::vector< DistributionElements > psd, TYPE PSDType)
Sets the PSD from a vector with DistributionElements.
Definition: PSD.cc:513
Enables reading of .csv files into MercuryDPM.
Definition: csvReader.h:25
std::vector< Mdouble > getSecondColumn(Mdouble scalingFactor)
Get second column of a .csv file and return it as a double.
Definition: csvReader.cc:124
void read(const std::string &filename)
Reads .csv files into Mercury.
Definition: csvReader.cc:19
void setHeader(bool headings)
Set the boolean hasHeader_.
Definition: csvReader.cc:88
std::vector< Mdouble > getFirstColumn(Mdouble scalingFactor)
Get first column of a .csv file and return it as a double.
Definition: csvReader.cc:107
string fileName
Definition: UniformPSDSelfTest.py:10

References UniformPSDSelfTest::fileName, csvReader::getFirstColumn(), csvReader::getSecondColumn(), getSizeRatio(), i, INFO, logger, csvReader::read(), csvReader::setHeader(), and setPSDFromVector().

Referenced by MultiplePSDSelfTest::setupInitialConditions(), PSDManualInsertionSelfTest::setupInitialConditions(), and PSDSelfTest::setupInitialConditions().

◆ setPSDFromVector()

void PSD::setPSDFromVector ( std::vector< DistributionElements psdVector,
TYPE  PSDType 
)

Sets the PSD from a vector with DistributionElements.

creates the psd vector from radii and probabilities filled in by hand. The Type of PSD will be converted to the default cumulative number distribution function (CUMULATIVE_NUMBER_DISTRIBUTION) for further processing.

Parameters
[in]psdVectorVector containing radii and probabilities ([0,1]).
[in]PSDTypeType of the PSD: CUMULATIVE_VOLUME_DISTRIBUTION, CUMULATIVE_NUMBER_DISTRIBUTION, CUMULATIVE_LENGTH_DISTRIBUTION, CUMULATIVE_AREA_DISTRIBUTION, PROBABILITYDENSITY_VOLUME_DISTRIBUTION, PROBABILITYDENSITY_NUMBER_DISTRIBUTION, PROBABILITYDENSITY_LENGTH_DISTRIBUTION, PROBABILITYDENSITY_AREA_DISTRIBUTION.
Todo:
JWB: Is a PSD ever allowed to be empty? drawSample() will cause a segfault in that case. I'm not throwing an error here, as that causes the UnitTests/FullRestartSelfTest to fail, due to the InsertionBoundary being allowed to use (and defaults to using) an empty PSD.
514 {
515  particleSizeDistribution_ = psdVector;
516 
517  // To prevent errors when the PSD is empty, throw a warning and return.
521  if (particleSizeDistribution_.empty())
522  {
523  logger(WARN, "Setting an empty PSD!");
524  return;
525  }
526 
527  switch (PSDType)
528  {
529  // default case is a CUMULATIVE_NUMBER_DISTRIBUTION
530  default:
532  break;
539  break;
545  break;
552  break;
556  break;
561  break;
566  break;
571  break;
572  }
573 }

References convertCumulativeToProbabilityDensity(), convertProbabilityDensityToCumulative(), convertProbabilityDensityToProbabilityDensityNumberDistribution(), CUMULATIVE_AREA_DISTRIBUTION, CUMULATIVE_LENGTH_DISTRIBUTION, CUMULATIVE_VOLUME_DISTRIBUTION, logger, particleSizeDistribution_, PROBABILITYDENSITY_AREA_DISTRIBUTION, PROBABILITYDENSITY_LENGTH_DISTRIBUTION, PROBABILITYDENSITY_NUMBER_DISTRIBUTION, PROBABILITYDENSITY_VOLUME_DISTRIBUTION, validateCumulativeDistribution(), validateProbabilityDensityDistribution(), and WARN.

Referenced by convertPSD2ToPSD(), ParticleHandler::getPSD(), Calibration::setPSD(), Material::setPSD(), setPSDFromCSV(), PSDSelfTest::setupInitialConditions(), and testPSD().

◆ validateCumulativeDistribution()

void PSD::validateCumulativeDistribution ( )

Validates if a CDF starts with zero and adds up to unity.

Validates if a distribution is cumulative by first checking if the psd vector is empty and that the scaling of probabilities is in the range [0,1]. Also it checks if each consecutive value is higher than the latter value (i.e. assuming piecewise linear CDF: p_i > p_i-1). Further it replaces probabilities if the CDF does not start with zero or does not end with unity (i.e. p_0=0 and p_end=1)

192 {
193  // check whether the distribution is cumulative
194  for (auto it = particleSizeDistribution_.begin() + 1; it != particleSizeDistribution_.end(); ++it)
195  {
196  logger.assert_always(it->probability >= (it - 1)->probability,
197  "psd is not cumulative: radius % %, probabilities % %", (it - 1)->internalVariable,
198  it->internalVariable, (it - 1)->probability, it->probability);
199  }
200  // set negative probabilities to 0
201  for (auto& rp : particleSizeDistribution_)
202  {
203  if (rp.probability < 0)
204  {
205  logger(INFO, "negative probability % has been set to 0", rp.probability);
206  rp.probability = 0;
207  }
208  }
209  // ensure interval of probabilities to be [0,1]
210  for (auto p = 0; p < particleSizeDistribution_.size(); ++p)
211  particleSizeDistribution_[p].probability /= particleSizeDistribution_.back().probability;
212  // cdf needs to start with a probability of zero
213  if (particleSizeDistribution_[0].probability != 0)
214  {
215  logger(INFO, "adding a zero at the beginning of the psd");
217  {std::max(1e-3 * particleSizeDistribution_[0].internalVariable,
218  2 * particleSizeDistribution_[0].internalVariable -
219  particleSizeDistribution_[1].internalVariable), 0});
220  }
221  // cdf needs to end with a probability of one
222  if (particleSizeDistribution_.back().probability < 1)
223  {
224  logger(INFO, "adding a one at the end of the psd");
225  particleSizeDistribution_.push_back({particleSizeDistribution_.back().internalVariable, 1});
226  }
227  // cut off equal subsequent values on the end of the cdf to remove zero size classes.
228  for (auto i = particleSizeDistribution_.end() - 1; i != particleSizeDistribution_.begin(); i--)
229  {
230  if (i->probability == (i - 1)->probability)
231  {
233  .end(), i));
234  }
235  else
236  {
237  break;
238  }
239  }
240 }

References i, INFO, logger, p, and particleSizeDistribution_.

Referenced by convertProbabilityDensityToCumulative(), setDistributionLogNormal(), setDistributionNormal(), setDistributionPhiNormal(), setDistributionUniform(), and setPSDFromVector().

◆ validateProbabilityDensityDistribution()

void PSD::validateProbabilityDensityDistribution ( )

Validates if the integral of the PDF equals to unity.

Validates if a PDF is valid by first checking if the PDF starts with zero (i.e. p_0=0). Further it checks if the integral is equal to unity (i.e. assuming piecewise constant PDF: sum(p_i)=1).

247 {
248  // set negative probabilities to 0
249  for (auto& rp : particleSizeDistribution_)
250  {
251  if (rp.probability < 0)
252  {
253  logger(INFO, "negative probability % has been set to 0", rp.probability);
254  rp.probability = 0;
255  }
256  }
257  Mdouble sum = 0;
258  // check if the psd starts with zero probability (i.e. p_0=0)
259  if (particleSizeDistribution_[0].probability != 0)
260  {
261  logger(INFO, "adding a zero at the beginning of PDF");
263  {std::max(1e-3 * particleSizeDistribution_[0].internalVariable,
264  2 * particleSizeDistribution_[0].internalVariable -
265  particleSizeDistribution_[1].internalVariable), 0});
266  }
267  // sum up probabilities to check if it equals to unity (sum(p_i)=1)
268  for (auto& it : particleSizeDistribution_)
269  {
270  sum += it.probability;
271  }
272  // ensure interval of probabilities to be [0,1] by normalization.
273  for (auto& it : particleSizeDistribution_)
274  it.probability /= sum;
275  // if the sum of probabilities is not equal to unity, sum up the normalized probabilities again
276  if (sum - 1 > 1e-6)
277  {
278  sum = 0;
279  for (auto& it: particleSizeDistribution_)
280  {
281  sum += it.probability;
282  }
283  }
284  logger.assert_debug(sum - 1 < 1e-6, "PDF is not valid: Integral of PDF is not equal to unity");
285 }

References e(), INFO, logger, and particleSizeDistribution_.

Referenced by convertCumulativeToProbabilityDensity(), and setPSDFromVector().

Friends And Related Function Documentation

◆ operator< [1/2]

bool operator< ( const DistributionElements l,
const DistributionElements r 
)
friend

determines if a certain value of the PSD vector is lower than another one. Used for std::lower_bound()

Required to use std::lower_bound for finding when the probability is higher than a certain value.

Returns
TRUE if probability from a vector of type DistributionElements is higher than a certain value from a vector of type DistributionElements and FALSE in the opposite case.
1265 {
1266  return l.probability < r.probability;
1267 }
Mdouble probability
Definition: DistributionElements.h:16
r
Definition: UniformPSDSelfTest.py:20

◆ operator< [2/2]

bool operator< ( const DistributionElements l,
Mdouble  r 
)
friend

determines if a certain value of the PSD vector is lower than a double.

required to use std::lower_bound for finding when the probability provided as a double is higher than a certain value.

Returns
TRUE if probability as double is higher than a certain value from a DistributionElements vector and FALSE in the opposite case.
1276 {
1277  return l.probability < prob;
1278 }

◆ operator<<

std::ostream& operator<< ( std::ostream &  os,
DistributionElements p 
)
friend

Writes to output stream.

Writes to output stream. This function is used for restart files.

Returns
a reference to an output stream.
1305 {
1306  os << p.internalVariable << ' ' << p.probability << ' ';
1307  return os;
1308 }

◆ operator==

Mdouble operator== ( DistributionElements  l,
Mdouble  r 
)
friend

Determines if a certain value of the PSD vector is equal to a double.

Required to use std::distance to find the index of the PSD size class in which a particle has to be inserted

Returns
A double which determines the size class (radius) a particle will be inserted to.
1285 {
1286  return l.internalVariable == r;
1287 }
Mdouble internalVariable
Definition: DistributionElements.h:15

◆ operator>>

std::istream& operator>> ( std::istream &  is,
DistributionElements p 
)
friend

Reads from input stream.

reads from input stream. This function is used for restart files.

Returns
a reference to an input stream.
1294 {
1295  is >> p.internalVariable;
1296  is >> p.probability;
1297  return is;
1298 }

Member Data Documentation

◆ index_

int PSD::index_
private

Integer which determines the class in which a particle has to be inserted for the manual insertion routine.

Referenced by decrementNParticlesPerClass(), decrementVolumePerClass(), insertManuallyByVolume(), and PSD().

◆ nParticlesPerClass_

std::vector<int> PSD::nParticlesPerClass_
private

Vector of integers which represents the number of inserted particles in each size class. The classes in this vector are defined to contain the particles between size r_i and r_i-1. (e.g. size class 12 consists of particles between size class 12 and 11 of the PDF)

Referenced by decrementNParticlesPerClass(), getInsertedParticleNumber(), and insertManuallyByVolume().

◆ particleSizeDistribution_

◆ random_

RNG PSD::random_
private

Mercury random number generator object used to draw random numbers from a random initial seed

Referenced by drawSample(), PSD(), and setFixedSeed().

◆ volumePerClass_

std::vector<Mdouble> PSD::volumePerClass_
private

Vector of doubles which stores the volume of inserted particles for each size class. This vector is used in the insertManuallyByVolume() function to check if the volumeAllowed per class is exceeded and thus no further particles should be added to a certain class. The classes in this vector are defined to contain the volume of particles between size r_i and r_i-1. (e.g. size class 12 consists of the particles' volume between size class 12 and 11 of the PDF)

Referenced by decrementVolumePerClass(), and insertManuallyByVolume().


The documentation for this class was generated from the following files: