32 m_TAG =
"ThermalModelCanonical";
35 m_InteractionModel =
Ideal;
61 for (
int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
85 if (computeFluctuations) {
98 std::cout <<
"BMAX = " <<
m_BMAX <<
"\tQMAX = " <<
m_QMAX <<
"\tSMAX = " <<
m_SMAX <<
"\tCMAX = " <<
m_CMAX << std::endl;
125 m_QuantumStats = stats;
126 for (
int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
127 m_TPS->Particle(i).UseStatistics(stats);
139 m_ConstrainMuB &= !
m_BCE;
140 m_ConstrainMuQ &= !
m_QCE;
141 m_ConstrainMuS &= !
m_SCE;
142 m_ConstrainMuC &= !
m_CCE;
148 m_ConstrainMuB &= !
m_BCE;
149 m_ConstrainMuQ &= !
m_QCE;
150 m_ConstrainMuS &= !
m_SCE;
151 m_ConstrainMuC &= !
m_CCE;
157 assert(m_IGFExtraConfig.MagneticField.B == 0.);
159 m_FluctuationsCalculated =
false;
166 m_Parameters.muB = 0.0;
167 m_Parameters.muQ = 0.0;
168 m_Parameters.muS = 0.0;
169 m_Parameters.muC = 0.0;
174 m_Parameters.muB = 0.0;
176 m_Parameters.muQ = 0.0;
178 m_Parameters.muS = 0.0;
180 m_Parameters.muC = 0.0;
187 for (
size_t i = 0; i < m_densities.size(); ++i) {
199 if (ind <
static_cast<int>(
m_Corr.size()))
205 if (ind <
static_cast<int>(
m_Corr.size()))
225 double totB = CalculateBaryonDensity() * m_Parameters.SVc;
226 if (fabs(m_Parameters.B - totB) > TOL) {
228 sprintf(cc,
"**WARNING** ThermalModelCanonical: Inaccurate calculation of total baryon number.\
232\n", m_Parameters.B, totB);
236 m_ValidityLog.append(cc);
238 m_LastCalculationSuccessFlag =
false;
244 double totQ = CalculateChargeDensity() * m_Parameters.SVc;
245 if (fabs(m_Parameters.Q - totQ) > TOL) {
246 sprintf(cc,
"**WARNING** ThermalModelCanonical: Inaccurate calculation of total electric charge.\
250\n", m_Parameters.Q, totQ);
254 m_ValidityLog.append(cc);
256 m_LastCalculationSuccessFlag =
false;
262 double totS = CalculateStrangenessDensity() * m_Parameters.SVc;
263 if (fabs(m_Parameters.S - totS) > TOL) {
264 sprintf(cc,
"**WARNING** ThermalModelCanonical: Inaccurate calculation of total strangeness.\
268\n", m_Parameters.S, totS);
272 m_ValidityLog.append(cc);
274 m_LastCalculationSuccessFlag =
false;
280 double totC = CalculateCharmDensity() * m_Parameters.SVc;
281 if (fabs(m_Parameters.C - totC) > TOL) {
282 sprintf(cc,
"**WARNING** ThermalModelCanonical: Inaccurate calculation of total charm.\
286\n", m_Parameters.C, totC);
290 m_ValidityLog.append(cc);
292 m_LastCalculationSuccessFlag =
false;
300 Vc = m_Parameters.SVc;
306 for (
int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
307 int i2 = m_TPS->PdgToId(-m_TPS->Particle(i).PdgId());
309 if (std::abs(m_Chem[i] - m_Chem[i2]) > 1.e-8) {
310 throw std::runtime_error(
"ThermalModelCanonical::CalculatePartitionFunctions: Partial chemical equilibrium canonical ensemble only supported if particle-antiparticle fugacities are symmetric!");
316 bool AllMuZero =
true;
317 for (
int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
329 for (
int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
335 throw std::invalid_argument(
"ThermalModelCanonical: neutral particle cannot have non-zero ce charges");
337 if (ind <
static_cast<int>(Nsx.size()))
344 if (ind <
static_cast<int>(Nsx.size())) {
347 Nsx[ind] += tdens * cosh(m_Chem[i] / m_Parameters.T);
348 Nsy[ind] += tdens * sinh(m_Chem[i] / m_Parameters.T);
360 if (ind <
static_cast<int>(Nsx.size())) {
363 Nsx[ind] += tdens * cosh(n * m_Chem[i] / m_Parameters.T);
364 Nsy[ind] += tdens * sinh(n * m_Chem[i] / m_Parameters.T);
376 for (
int i = 0; i < static_cast<int>(Nsx.size()); ++i) {
382 int nmax = max(3, (
int)sqrt(m_Parameters.B*m_Parameters.B + m_Parameters.Q*m_Parameters.Q + m_Parameters.S*m_Parameters.S + m_Parameters.C*m_Parameters.C));
383 if (m_Parameters.B == 0 && m_Parameters.Q == 0 && m_Parameters.S == 0 && m_Parameters.C == 0)
388 int nmaxB = max(4, m_Parameters.B);
389 int nmaxQ = max(4, m_Parameters.Q);
390 int nmaxS = max(4, m_Parameters.S);
391 int nmaxC = max(4, m_Parameters.C);
395 nmaxB = nmaxQ = nmaxS = nmaxC = nmax;
403 for (
size_t i = 0; i <
m_PartialZ.size(); ++i) {
411 int maxB = 2 * nmaxB;
415 for (
int iB = 0; iB < maxB; ++iB) {
417 vector<double> xlegB, wlegB;
420 double aB = iB * dphiB;
421 if (iB >= nmaxB) aB =
xMath::Pi() - (iB + 1) * dphiB;
422 double bB = aB + dphiB;
434 int maxS = 2 * nmaxS;
438 for (
int iS = 0; iS < maxS; ++iS) {
439 vector<double> xlegS, wlegS;
442 double aS = iS * dphiS;
443 if (iS >= nmaxS) aS =
xMath::Pi() - (iS + 1) * dphiS;
444 double bS = aS + dphiS;
459 for (
int iQ = 0; iQ < maxQ; ++iQ) {
460 vector<double> xlegQ, wlegQ;
463 double aQ = iQ * dphiQ;
464 double bQ = aQ + dphiQ;
475 int maxC = 2 * nmaxC;
479 for (
int iC = 0; iC < maxC; ++iC) {
480 vector<double> xlegC, wlegC;
482 double aC = iC * dphiC;
483 if (iC >= nmaxC) aC =
xMath::Pi() - (iC + 1) * dphiC;
484 double bC = aC + dphiC;
494 for (
size_t iBt = 0; iBt < xlegB.size(); ++iBt) {
495 for (
size_t iSt = 0; iSt < xlegS.size(); ++iSt) {
496 for (
size_t iQt = 0; iQt < xlegQ.size(); ++iQt) {
497 for (
size_t iCt = 0; iCt < xlegC.size(); ++iCt) {
499 double wx = 0., wy = 0., mx = 0., my = 0.;
500 for (
size_t i = 0; i <
m_PartialZ.size(); ++i) {
507 cosph[i] = cos(tS*xlegS[iSt] + tQ * xlegQ[iQt] + tC * xlegC[iCt]);
508 sinph[i] = sin(tS*xlegS[iSt] + tQ * xlegQ[iQt] + tC * xlegC[iCt]);
511 wx += Nsx[i] * cosph[i];
512 wy += Nsx[i] * sinph[i];
515 mx += Nsx[i] * (cosph[i] - 1.);
519 cosph[i] = cos(tB*xlegB[iBt] + tS * xlegS[iSt] + tQ * xlegQ[iQt] + tC * xlegC[iCt]);
520 mx += Nsx[i] * (cosph[i] - 1.);
523 sinph[i] = sin(tB*xlegB[iBt] + tS * xlegS[iSt] + tQ * xlegQ[iQt] + tC * xlegC[iCt]);
524 my += Nsy[i] * sinph[i];
533 wmod = sqrt(wx*wx + wy * wy);
534 warg = atan2(wy, wx);
537 for (
size_t iN = 0; iN <
m_PartialZ.size(); ++iN) {
538 int tBg = m_Parameters.B -
m_QNvec[iN].B;
539 int tQg = m_Parameters.Q -
m_QNvec[iN].Q;
540 int tSg = m_Parameters.S -
m_QNvec[iN].S;
541 int tCg = m_Parameters.C -
m_QNvec[iN].C;
545 m_PartialZ[iN] += wlegB[iBt] * wlegS[iSt] * wlegQ[iQt] * wlegC[iCt] *
546 cos(tBg * xlegB[iBt] + tSg * xlegS[iSt] + tQg * xlegQ[iQt] + tCg * xlegC[iCt] - tBg * warg) *
552 m_PartialZ[iN] += wlegB[iBt] * wlegS[iSt] * wlegQ[iQt] * wlegC[iCt] * cos(tBg*xlegB[iBt] + tSg * xlegS[iSt] + tQg * xlegQ[iQt] + tCg * xlegC[iCt]) * exp(mx);
554 m_PartialZ[iN] += wlegB[iBt] * wlegS[iSt] * wlegQ[iQt] * wlegC[iCt] * exp(mx)
555 * (cos(tBg*xlegB[iBt] + tSg * xlegS[iSt] + tQg * xlegQ[iQt] + tCg * xlegC[iCt]) * cos(my)
556 + sin(tBg*xlegB[iBt] + tSg * xlegS[iSt] + tQg * xlegQ[iQt] + tCg * xlegC[iCt]) * sin(my));
571 for (
size_t iN = 0; iN <
m_PartialZ.size(); ++iN) {
586 for (
size_t iN = 0; iN <
m_PartialZ.size(); ++iN) {
594 double ret1 = 0., ret2 = 0., ret3 = 0.;
597 return tpart.
ScaledVariance(m_Parameters, m_UseWidth, m_Chem[part]);
606 if (ind <
static_cast<int>(
m_Corr.size()) && ind2 <
static_cast<int>(
m_Corr.size()))
609 if (ind <
static_cast<int>(
m_Corr.size()))
613 double ret1num = 0., ret1zn = 0.;
619 if (ind <
static_cast<int>(
m_Corr.size())) {
620 ret1num +=
m_Corr[ind] * n * densityClusterN;
621 ret1zn +=
m_Corr[ind] * densityClusterN;
627 if (ind <
static_cast<int>(
m_Corr.size()) && ind2 <
static_cast<int>(
m_Corr.size()))
636 ret1 = ret1num / ret1zn;
637 ret2 = ret2 / ret1zn;
638 ret3 = -ret1zn * m_Parameters.SVc;
640 return ret1 + ret2 + ret3;
644 int NN = m_densities.size();
646 vector<double> yld(NN, 0);
647 vector<double> ret1num(NN, 0);
648 vector< vector<double> > ret2num(NN, vector<double>(NN, 0.));
650 for (
int i = 0; i < NN; ++i)
651 yld[i] = m_densities[i] * m_Parameters.SVc;
653 for (
int i = 0; i < NN; ++i) {
656 ret1num[i] = tpart.
ScaledVariance(m_Parameters, m_UseWidth, m_Chem[i]) * yld[i];
669 if (ind <
static_cast<int>(
m_Corr.size()))
670 ret1num[i] +=
m_Corr[ind] * n * densityClusterN * m_Parameters.SVc;
675 for (
int i = 0; i < NN; ++i) {
676 for (
int j = 0; j < NN; ++j) {
689 ret2num[i][j] = yld[i] * yld[j];
692 for (
int n1 = 1; n1 <= n1max; ++n1) {
693 for (
int n2 = 1; n2 <= n2max; ++n2) {
703 if (ind <
static_cast<int>(
m_Corr.size()))
704 ret2num[i][j] +=
m_Corr[ind] * densityClusterN1 * densityClusterN2 * m_Parameters.SVc * m_Parameters.SVc;
712 m_PrimCorrel.resize(NN);
713 for (
int i = 0; i < NN; ++i)
714 m_PrimCorrel[i].resize(NN);
715 m_TotalCorrel = m_PrimCorrel;
717 for (
int i = 0; i < NN; ++i) {
718 for (
int j = 0; j < NN; ++j) {
719 m_PrimCorrel[i][j] = 0.;
721 m_PrimCorrel[i][j] += ret1num[i] / yld[i];
722 m_PrimCorrel[i][j] += ret2num[i][j] / yld[i];
723 m_PrimCorrel[i][j] += -yld[j];
724 m_PrimCorrel[i][j] *= yld[i] / m_Parameters.SVc / m_Parameters.T;
726 m_PrimCorrel[i][j] = 0.;
730 for (
int i = 0; i < NN; ++i) {
731 m_wprim[i] = m_PrimCorrel[i][i];
732 if (m_densities[i] > 0.) m_wprim[i] *= m_Parameters.T / m_densities[i];
733 else m_wprim[i] = 1.;
745 m_FluctuationsCalculated =
true;
747 for (
size_t i = 0; i < m_wprim.size(); ++i) {
759 for (
int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
769 if (ind <
static_cast<int>(
m_Corr.size()))
775 if (ind <
static_cast<int>(
m_Corr.size()))
789 for (
int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
799 if (ind <
static_cast<int>(
m_Corr.size()))
806 if (ind <
static_cast<int>(
m_Corr.size()))
821 ret += -m_Parameters.muB / m_Parameters.T * m_Parameters.B / m_Parameters.SVc;
823 ret += -m_Parameters.muB * CalculateBaryonDensity() / m_Parameters.T;
826 ret += -m_Parameters.muQ / m_Parameters.T * m_Parameters.Q / m_Parameters.SVc;
828 ret += -m_Parameters.muQ * CalculateChargeDensity() / m_Parameters.T;
831 ret += -m_Parameters.muS / m_Parameters.T * m_Parameters.S / m_Parameters.SVc;
833 ret += -m_Parameters.muS * CalculateStrangenessDensity() / m_Parameters.T;
836 ret += -m_Parameters.muC / m_Parameters.T * m_Parameters.C / m_Parameters.SVc;
838 ret += -m_Parameters.muC * CalculateCharmDensity() / m_Parameters.T;
871 void ThermalModelCanonical::PrepareModelGCE()
880 m_Parameters.muB = 0.0;
883 m_Parameters.muS = m_Parameters.muB / 3.;
886 m_Parameters.muQ = -m_Parameters.muB / 30.;
888 m_Parameters.muC = 0.;
891 m_Parameters.muB, m_Parameters.muQ, m_Parameters.muS, m_Parameters.muC,
892 static_cast<bool>(
m_BCE),
893 static_cast<bool>(
m_QCE),
894 static_cast<bool>(
m_SCE),
895 static_cast<bool>(
m_CCE));
915 void ThermalModelCanonical::CleanModelGCE()
map< string, double > params
virtual void CalculateSusceptibilityMatrix()
Calculates the conserved charges susceptibility matrix.
virtual void FixParametersNoReset()
Method which actually implements ConstrainChemicalPotentialsNoReset() (for backward compatibility).
virtual void ChangeTPS(ThermalParticleSystem *TPS)
Change the particle list.
virtual void CalculateParticleChargeCorrelationMatrix()
Calculates the matrix of correlators between primordial (and also final) particle numbers and conserv...
bool UsePartialChemicalEquilibrium()
Whether partial chemical equilibrium with additional chemical potentials is used.
virtual bool SolveChemicalPotentials(double totB=0., double totQ=0., double totS=0., double totC=0., double muBinit=0., double muQinit=0., double muSinit=0., double muCinit=0., bool ConstrMuB=true, bool ConstrMuQ=true, bool ConstrMuS=true, bool ConstrMuC=true)
The procedure which calculates the chemical potentials which reproduce the specified total baryon,...
virtual void FillChemicalPotentials()
Sets the chemical potentials of all particles.
virtual void FixParameters()
Method which actually implements ConstrainChemicalPotentials() (for backward compatibility).
void SetUseWidth(bool useWidth)
Sets whether finite resonance widths are used. Deprecated.
virtual void SetChemicalPotentials(const std::vector< double > &chem=std::vector< double >(0))
Sets the chemical potentials of all particles.
virtual void ValidateCalculation()
Checks whether issues have occured during the calculation of particle densities in the CalculateDensi...
virtual void CalculateProxySusceptibilityMatrix()
Calculates the susceptibility matrix of conserved charges proxies.
ThermalModelBase(ThermalParticleSystem *TPS, const ThermalModelParameters ¶ms=ThermalModelParameters())
Construct a new ThermalModelBase object.
virtual void CalculateDensities()
Calculates the primordial and total (after decays) densities of all species.
const ThermalModelParameters & Parameters() const
virtual void CalculateTwoParticleFluctuationsDecays()
Computes particle number correlations and fluctuations for all final-state particles which are marked...
std::map< QuantumNumbers, int > m_QNMap
Maps QuantumNumbers combinations to a 1-dimensional index.
double m_MultExpBanalyt
Exponential multiplier for analytical baryon fugacity calculations.
int m_IntegrationIterationsMultiplier
A multiplier to increase the number of iterations during the numerical integration used to calculate ...
int m_BMAX
Maximum baryon number.
virtual void SetStatistics(bool stats)
std::vector< double > m_PartialZ
The computed canonical partition function.
int m_QCE
Flag indicating if electric charge is conserved canonically.
void ChangeTPS(ThermalParticleSystem *TPS)
Change the particle list.
virtual void CalculateTwoParticleCorrelations()
Computes the fluctuations and correlations of the primordial particle numbers.
int m_CCE
Flag indicating if charm is conserved canonically.
virtual void CalculateFluctuations()
Computes the fluctuation observables.
double m_MultExp
Exponential multiplier for canonical partition function calculations.
virtual double ParticleScaledVariance(int part)
std::vector< QuantumNumbers > m_QNvec
A set of QuantumNumbers combinations for which it is necessary to compute the canonical partition fun...
std::vector< double > m_Corr
A vector of chemical factors.
virtual double GetGCEDensity(int i) const
Density of particle species i in the grand-canonical ensemble.
virtual bool IsParticleCanonical(const ThermalParticle &part)
Determines whether the specified ThermalParticle is treat canonically or grand-canonically in the pre...
virtual double CalculateEntropyDensity()
virtual void CalculatePartitionFunctions(double Vc=-1.)
Calculates all necessary canonical partition functions.
virtual ~ThermalModelCanonical(void)
Destroy the ThermalModelCanonical object.
virtual void CalculateQuantumNumbersRange(bool computeFluctuations=false)
Calculates the range of quantum numbers values for which it is necessary to compute the canonical par...
virtual void FixParametersNoReset()
Method which actually implements ConstrainChemicalPotentialsNoReset() (for backward compatibility).
virtual double CalculatePressure()
int m_QMAX
Maximum electric charge.
int m_SMAX
Maximum strangeness.
int m_BCE
Flag indicating if baryon charge is conserved canonically.
ThermalModelIdeal * m_modelgce
Pointer to a ThermalModelIdeal object used for GCE calculations.
virtual void ValidateCalculation()
Checks whether issues have occured during the calculation of particle densities in the CalculateDensi...
virtual bool IsConservedChargeCanonical(ConservedCharge::Name charge) const
bool m_Banalyt
Flag indicating whether the analytical calculation of baryon fugacity is used.
int m_SCE
Flag indicating if strangeness is conserved canonically.
virtual double CalculateEnergyDensity()
virtual void FixParameters()
Method which actually implements ConstrainChemicalPotentials() (for backward compatibility).
virtual void CalculatePrimordialDensities()
Calculates the primordial densities of all species.
ThermalModelCanonical(ThermalParticleSystem *TPS, const ThermalModelParameters ¶ms=ThermalModelParameters())
Construct a new ThermalModelCanonical object.
Class implementing the Ideal HRG model.
Class containing all information about a particle specie.
int BaryonCharge() const
Particle's baryon number.
int Statistics() const
Particle's statistics.
int Strangeness() const
Particle's strangeness.
void SetCalculationType(IdealGasFunctions::QStatsCalculationType type)
Sets the CalculationType() method to evaluate quantum statistics.
double Density(const ThermalModelParameters ¶ms, IdealGasFunctions::Quantity type=IdealGasFunctions::ParticleDensity, bool useWidth=0, double mu=0.) const
Computes a specified ideal gas thermodynamic function.
IdealGasFunctions::QStatsCalculationType CalculationType() const
Method to evaluate quantum statistics.
int ElectricCharge() const
Particle's electric charge.
int Charm() const
Particle's charm.
int ClusterExpansionOrder() const
Number of terms in the cluster expansion method.
double DensityCluster(int n, const ThermalModelParameters ¶ms, IdealGasFunctions::Quantity type=IdealGasFunctions::ParticleDensity, bool useWidth=0, double mu=0.) const
double ScaledVariance(const ThermalModelParameters ¶ms, bool useWidth=0, double mu=0.) const
Computes the scaled variance of particle number fluctuations in the ideal gas. Computes the scaled va...
Class containing the particle list.
void GetCoefsIntegrateLegendre10(double a, double b, std::vector< double > *x, std::vector< double > *w)
constexpr double Pi()
Pi constant.
double BesselIexp(int n, double x)
Modified Bessel function I_n(x), divided by exponential factor.
The main namespace where all classes and functions of the Thermal-FIST library reside.
Name
Set of all conserved charges considered.
@ BaryonCharge
Baryon number.
@ StrangenessCharge
Strangeness.
@ ElectricCharge
Electric charge.
Struct containing a set of quantum numbers: Baryon number, electric charge, strangeness,...
Structure containing all thermal parameters of the model.
Contains some extra mathematical functions used in the code.