Thermal-FIST  1.3
Package for hadron resonance gas model applications
ThermalModelPCE.cpp
Go to the documentation of this file.
2 
3 #include <iostream>
4 
5 using namespace std;
6 
7 #include <Eigen/Dense>
8 
9 using namespace Eigen;
10 
11 namespace thermalfist {
12 
13 
14 
15  ThermalModelPCE::ThermalModelPCE(ThermalModelBase * THMbase, bool FreezeLonglived, double LonglivedResoWidthCut) :
16  m_model(THMbase),
17  m_UseSahaForNuclei(true),
18  m_FreezeLonglivedResonances(FreezeLonglived),
19  m_ResoWidthCut(LonglivedResoWidthCut),
20  m_ChemicalFreezeoutSet(false),
21  m_StabilityFlagsSet(false),
22  m_IsCalculated(false)
23  {
25  }
26 
27  void ThermalModelPCE::SetStabilityFlags(const std::vector<int>& StabilityFlags)
28  {
29  // A helper ThermalParticleSystem instance to compute the PCE effective charges for all particles
31 
32  // Set the nucleon content of the known light nuclei as "decay" products
33  PrepareNucleiForPCE(&TPShelper);
34 
36 
38  for (int i = 0; i < TPShelper.Particles().size(); ++i) {
39  TPShelper.Particle(i).SetStable(m_StabilityFlags[i] != 0);
40  if (m_StabilityFlags[i] != 0)
42  }
43 
44  TPShelper.FillResonanceDecays();
45 
46  m_StableMapTo = std::vector<int>(0);
47  m_EffectiveCharges = std::vector< std::vector<double> >(m_StabilityFlags.size(), std::vector<double>(m_StableComponentsNumber, 0.));
48  int stab_index = 0;
49  for (int i = 0; i < TPShelper.Particles().size(); ++i) {
50  const ThermalParticle& part = TPShelper.Particles()[i];
51  if (part.IsStable()) {
52  if (stab_index >= m_EffectiveCharges[0].size()) {
53  printf("**ERROR** ThermalModelPCE::SetStabilityFlags: Wrong number of stable components!\n");
54  exit(1);
55  }
56  m_EffectiveCharges[i][stab_index] = 1.;
58  for (int j = 0; j < decayContributions.size(); ++j) {
59  const pair<double,int> Contrs = decayContributions[j];
60  m_EffectiveCharges[Contrs.second][stab_index] = Contrs.first;
61  }
62  m_StableMapTo.push_back(i);
63  stab_index++;
64  }
65  }
66 
68 
69  m_StabilityFlagsSet = true;
70  m_ChemicalFreezeoutSet = false;
71  m_IsCalculated = false;
72  }
73 
74  void ThermalModelPCE::SetChemicalFreezeout(const ThermalModelParameters & params, const std::vector<double>& ChemInit)
75  {
76  if (!m_StabilityFlagsSet) {
78  }
79 
80  m_ParametersInit = params;
81 
83  if (ChemInit.size() == m_model->ComponentsNumber()) {
84  m_model->SetChemicalPotentials(ChemInit);
85  m_ChemInit = ChemInit;
86  }
87  else {
90  }
91  //m_model->CalculateDensities();
93 
94  //m_DensitiesInit = m_model->TotalDensities();
95 
96  m_StableDensitiesInit = std::vector<double>(m_StableComponentsNumber, 0.);
97  for (int is = 0; is < m_StableDensitiesInit.size(); ++is) {
98  double totdens = 0.;
99  for (int i = 0; i < m_EffectiveCharges.size(); ++i) {
100  totdens += m_EffectiveCharges[i][is] * m_model->Densities()[i];
101  }
102  m_StableDensitiesInit[is] = totdens;
103  }
104 
105 
107 
109 
112 
113  m_ChemicalFreezeoutSet = true;
114  m_IsCalculated = false;
115  }
116 
117  void ThermalModelPCE::CalculatePCE(double param, PCEMode mode)
118  {
119  if (!m_ChemicalFreezeoutSet) {
120  printf("**ERROR** ThermalModelPCE::CalculatePCE:"
121  "Tried to make a PCE calculation without setting the chemical freze-out!"
122  "Call ThermalModelPCE::SetChemicalFreezeout() first.\n");
123  exit(1);
124  }
125 
126  if (!m_StabilityFlagsSet) {
128  }
129 
130  double T = param;
131  if (mode == 1) {
132  // Initial guess for the new temperature
133  T = m_ParametersCurrent.T * pow(m_ParametersCurrent.V / param, 1. / 3.);
134  m_ParametersCurrent.V = param;
135  }
136  else {
137  // Initial guess for the new volume
139  }
140 
141 
142 
143  BroydenEquationsPCE eqs(this, mode);
144  Broyden broydn(&eqs);
145 
146  std::vector<double> PCEParams(m_StableComponentsNumber, 0.);
147  int stab_index = 0;
148  for (int i = 0; i < m_StabilityFlags.size(); ++i) {
149  if (m_StabilityFlags[i]) {
150  if (stab_index >= m_EffectiveCharges[0].size()) {
151  printf("**ERROR** ThermalModelPCE::CalculatePCE: Wrong number of stable components!\n");
152  exit(1);
153  }
154 
155  //PCEParams[stab_index] = m_ChemCurrent[i];
156  // Improved initial guesses for the PCE chemical potentials
157  PCEParams[stab_index] = m_ChemCurrent[i] * T / m_ParametersCurrent.T + ThermalModel()->TPS()->Particle(i).Mass() * (1. - T / m_ParametersCurrent.T);
158  stab_index++;
159  }
160  }
161 
163 
164  if (mode == 0)
165  PCEParams.push_back(m_ParametersCurrent.V);
166  else
167  PCEParams.push_back(m_ParametersCurrent.T);
168 
169  PCEParams = broydn.Solve(PCEParams);
170 
172  if (mode == 0)
173  m_ParametersCurrent.V = PCEParams[PCEParams.size() - 1];
174  else
175  m_ParametersCurrent.T = PCEParams[PCEParams.size() - 1];
176 
178 
179  m_IsCalculated = true;
180  }
181 
183  {
184  ThermalParticleSystem &parts = *TPS;
185  vector<long long> nuclpdgs;
186  vector<string> nuclnames;
187  vector< vector<long long> > nuclcontent;
188 
189  nuclpdgs.push_back(1000010020);
190  nuclnames.push_back("d");
191  nuclcontent.push_back(vector<long long>());
192  nuclcontent[nuclcontent.size() - 1].push_back(2212);
193  nuclcontent[nuclcontent.size() - 1].push_back(2112);
194 
195  nuclpdgs.push_back(1000020030);
196  nuclnames.push_back("He3");
197  nuclcontent.push_back(vector<long long>());
198  nuclcontent[nuclcontent.size() - 1].push_back(2212);
199  nuclcontent[nuclcontent.size() - 1].push_back(2212);
200  nuclcontent[nuclcontent.size() - 1].push_back(2112);
201 
202  nuclpdgs.push_back(1010010030);
203  nuclnames.push_back("H3La");
204  nuclcontent.push_back(vector<long long>());
205  nuclcontent[nuclcontent.size() - 1].push_back(2212);
206  nuclcontent[nuclcontent.size() - 1].push_back(2112);
207  nuclcontent[nuclcontent.size() - 1].push_back(3122);
208 
209  nuclpdgs.push_back(1000020040);
210  nuclnames.push_back("He4");
211  nuclcontent.push_back(vector<long long>());
212  nuclcontent[nuclcontent.size() - 1].push_back(2212);
213  nuclcontent[nuclcontent.size() - 1].push_back(2112);
214  nuclcontent[nuclcontent.size() - 1].push_back(2212);
215  nuclcontent[nuclcontent.size() - 1].push_back(2112);
216 
217  nuclpdgs.push_back(1010000020);
218  nuclnames.push_back("LambdaNeutron");
219  nuclcontent.push_back(vector<long long>());
220  nuclcontent[nuclcontent.size() - 1].push_back(2112);
221  nuclcontent[nuclcontent.size() - 1].push_back(3122);
222 
223  nuclpdgs.push_back(1010010020);
224  nuclnames.push_back("LambdaProton");
225  nuclcontent.push_back(vector<long long>());
226  nuclcontent[nuclcontent.size() - 1].push_back(2212);
227  nuclcontent[nuclcontent.size() - 1].push_back(3122);
228 
229  nuclpdgs.push_back(1020000020);
230  nuclnames.push_back("DiLambda");
231  nuclcontent.push_back(vector<long long>());
232  nuclcontent[nuclcontent.size() - 1].push_back(3122);
233  nuclcontent[nuclcontent.size() - 1].push_back(3122);
234 
235  nuclpdgs.push_back(1000010030);
236  nuclnames.push_back("Triton");
237  nuclcontent.push_back(vector<long long>());
238  nuclcontent[nuclcontent.size() - 1].push_back(2212);
239  nuclcontent[nuclcontent.size() - 1].push_back(2112);
240  nuclcontent[nuclcontent.size() - 1].push_back(2112);
241 
242  nuclpdgs.push_back(1010020040);
243  nuclnames.push_back("He4La");
244  nuclcontent.push_back(vector<long long>());
245  nuclcontent[nuclcontent.size() - 1].push_back(2212);
246  nuclcontent[nuclcontent.size() - 1].push_back(2112);
247  nuclcontent[nuclcontent.size() - 1].push_back(2212);
248  nuclcontent[nuclcontent.size() - 1].push_back(3122);
249 
250  nuclpdgs.push_back(1010010040);
251  nuclnames.push_back("H4La");
252  nuclcontent.push_back(vector<long long>());
253  nuclcontent[nuclcontent.size() - 1].push_back(2212);
254  nuclcontent[nuclcontent.size() - 1].push_back(2112);
255  nuclcontent[nuclcontent.size() - 1].push_back(2112);
256  nuclcontent[nuclcontent.size() - 1].push_back(3122);
257 
258  nuclpdgs.push_back(1010020050);
259  nuclnames.push_back("He5La");
260  nuclcontent.push_back(vector<long long>());
261  nuclcontent[nuclcontent.size() - 1].push_back(2212);
262  nuclcontent[nuclcontent.size() - 1].push_back(2112);
263  nuclcontent[nuclcontent.size() - 1].push_back(2212);
264  nuclcontent[nuclcontent.size() - 1].push_back(2112);
265  nuclcontent[nuclcontent.size() - 1].push_back(3122);
266 
267  nuclpdgs.push_back(1020010020);
268  nuclnames.push_back("XiProton");
269  nuclcontent.push_back(vector<long long>());
270  nuclcontent[nuclcontent.size() - 1].push_back(3322);
271  nuclcontent[nuclcontent.size() - 1].push_back(2212);
272 
273  nuclpdgs.push_back(1030000020);
274  nuclnames.push_back("OmegaProton");
275  nuclcontent.push_back(vector<long long>());
276  nuclcontent[nuclcontent.size() - 1].push_back(3334);
277  nuclcontent[nuclcontent.size() - 1].push_back(2212);
278 
279  nuclpdgs.push_back(1040000020);
280  nuclnames.push_back("DiXi0");
281  nuclcontent.push_back(vector<long long>());
282  nuclcontent[nuclcontent.size() - 1].push_back(3322);
283  nuclcontent[nuclcontent.size() - 1].push_back(3322);
284 
285  // Fill "decays" of light nuclei
286  for (int i = 0; i < parts.Particles().size(); ++i) {
287  ThermalParticle &part = parts.Particle(i);
288 
289  for (int j = 0; j < nuclpdgs.size(); ++j) {
290  if (part.PdgId() == nuclpdgs[j] || part.PdgId() == -nuclpdgs[j]) {
291  part.Decays().resize(0);
292  long long sign = 1;
293  if (part.PdgId() < 0)
294  sign = -1;
295  std::vector<long long> daughters;
296  for (int k = 0; k < nuclcontent[j].size(); ++k) {
297  daughters.push_back(sign * nuclcontent[j][k]);
298  }
299  part.Decays().push_back(ParticleDecayChannel(1., daughters));
300  }
301  }
302  }
303  }
304 
305  vector<int> ThermalModelPCE::ComputePCEStabilityFlags(const ThermalParticleSystem* TPS, bool SahaEquationForNuclei, bool FreezeLongLived, double WidthCut)
306  {
307 
308  // By default strongly decaying resonances and all nuclei are considered not to be frozen
309  vector<int> stability_flags(0);
310  for (int i = 0; i < TPS->Particles().size(); ++i) {
311  const ThermalParticle& part = TPS->Particles()[i];
312 
313  int frozen = 0;
314 
315  // Yields of hadrons not decaying strongly are frozen, except light nuclei
316  frozen = static_cast<int> (part.DecayType() != ParticleDecayType::Strong);
317  if (SahaEquationForNuclei && abs(part.BaryonCharge()) > 1)
318  frozen = 0;
319 
320  // Yields of long-lived resonances might also be frozen
321  if (FreezeLongLived && part.DecayType() == ParticleDecayType::Strong && part.ResonanceWidth() < WidthCut && abs(part.BaryonCharge()) <= 1)
322  frozen = 1;
323 
324  // The special case of K0. Instead of K0S and K0L work directly with (anti-)K0
325  if (part.PdgId() == 310 || part.PdgId() == 130)
326  frozen = 0;
327  if (part.PdgId() == 311 || part.PdgId() == -311)
328  frozen = 1;
329 
330  stability_flags.push_back(frozen);
331  }
332  return stability_flags;
333  }
334 
336  {
337  for (int ipart = 0; ipart < m_EffectiveCharges.size(); ++ipart) {
338  ThermalParticle& part = m_model->TPS()->Particle(ipart);
339  if (part.ZeroWidthEnforced() || part.Statistics() != -1)
340  continue;
341 
342  double totmu = 0.;
343  for (int ifeed = 0; ifeed < m_EffectiveCharges[ipart].size(); ++ifeed) {
344  totmu += m_EffectiveCharges[ipart][ifeed] * m_model->TPS()->Particle(m_StableMapTo[ifeed]).Mass();
345  }
346 
347  if (totmu > part.DecayThresholdMassDynamical()) {
348  cout << "Changing threshold mass for " << part.Name() << " from " << part.DecayThresholdMassDynamical() << " to " << totmu << "\n";
349  part.SetDecayThresholdMassDynamical(totmu);
351  }
352  }
353 
354  m_model->TPS()->ProcessDecays();
355  }
356 
357  std::vector<double> ThermalModelPCE::BroydenEquationsPCE::Equations(const std::vector<double>& x)
358  {
359  std::vector<double> ret(x.size(), 0.);
360 
361  std::vector<double> Chem(m_THM->ThermalModel()->Densities().size(), 0.);
362  for (int i = 0; i < m_THM->m_EffectiveCharges.size(); ++i) {
363  for (int is = 0; is < m_THM->m_EffectiveCharges[i].size(); ++is) {
364  Chem[i] += m_THM->m_EffectiveCharges[i][is] * x[is];
365  }
366  }
367 
368  ThermalModelBase *model = m_THM->ThermalModel();
369 
370  model->SetChemicalPotentials(Chem);
371  if (m_Mode == 0) {
372  const double& Vtmp = x[x.size() - 1];
373  m_THM->m_ParametersCurrent.V = Vtmp;
374  }
375  else {
376  const double& Ttmp = x[x.size() - 1];
377  m_THM->m_ParametersCurrent.T = Ttmp;
378  }
379  double V = m_THM->m_ParametersCurrent.V;
380  model->SetParameters(m_THM->m_ParametersCurrent);
381  //model->CalculateDensities();
383 
384  for (int is = 0; is < m_THM->m_StableComponentsNumber; ++is) {
385  double totdens = 0.;
386  for (int i = 0; i < m_THM->m_EffectiveCharges.size(); ++i) {
387  totdens += m_THM->m_EffectiveCharges[i][is] * model->Densities()[i];
388  }
389 
390  //ret[is] = totdens * V - m_THM->m_StableDensitiesInit[is] * m_THM->m_ParametersInit.V;
391  ret[is] = (totdens * V) / (m_THM->m_StableDensitiesInit[is] * m_THM->m_ParametersInit.V) - 1.;
392  }
393 
394  ret[ret.size() - 1] = (model->CalculateEntropyDensity() * V) / (m_THM->m_EntropyDensityInit * m_THM->m_ParametersInit.V) - 1.;
395 
396  return ret;
397  }
398 
399 } // namespace thermalfist
400 
Abstract base class for an HRG model implementation.
Structure containing information about a single decay channel of a particle.
Definition: ParticleDecay.h:73
const std::vector< double > & Densities() const
Class implementing the Broyden method to solve a system of non-linear equations.
Definition: Broyden.h:131
std::vector< double > m_ChemCurrent
double EntropyDensity()
Entropy density (fm )
const ThermalParticle & Particle(int id) const
ThermalParticle object corresponding to particle species with a provided 0-based index.
void SetChemicalFreezeout(const ThermalModelParameters &params, const std::vector< double > &ChemInit=std::vector< double >(0))
Sets the chemical freeze-out conditions to be used as an initial condition for PCE calculations...
std::vector< double > Equations(const std::vector< double > &x)
ThermalModelBase * ThermalModel() const
Pointer to the HRG model used in calculations.
virtual void SetStabilityFlags(const std::vector< int > &StabilityFlags)
Manually set the PCE stability flags for all species.
long long PdgId() const
Particle&#39;s Particle Data Group (PDG) ID number.
Class containing the particle list.
bool FreezeLonglivedResonances() const
double HadronDensity()
Total number density of all particle (fm )
virtual void CalculatePrimordialDensities()=0
Calculates the primordial densities of all species.
std::vector< int > m_StabilityFlags
const std::vector< double > & ChemicalPotentials() const
A vector of chemical potentials of all particles.
virtual void SetParameters(const ThermalModelParameters &params)
The thermal parameters.
double ResonanceWidth() const
Particle&#39;s width at the pole mass (GeV)
std::vector< double > m_ChemInit
Structure containing all thermal parameters of the model.
virtual void CalculatePCE(double param, PCEMode mode=AtFixedTemperature)
Solves the equations of partial chemical equilibrium at a fixed temperature or a fixed volume...
std::vector< double > m_StableDensitiesInit
void FillCoefficientsDynamical()
Fills coefficients for mass integration in the eBW scheme.
bool m_IsCalculated
Whether PCE has been calculated.
virtual void FillChemicalPotentials()
Sets the chemical potentials of all particles.
int BaryonCharge() const
Particle&#39;s baryon number.
Class containing all information about a particle specie.
std::vector< SingleDecayContribution > DecayContributionsToParticle
A vector of SingleDecayContribution where each element corresponds to a certain resonance species...
bool m_ChemicalFreezeoutSet
Whether the chemical freeze-out "initial" condition has been set.
static void PrepareNucleiForPCE(ThermalParticleSystem *TPS)
Fills the "decay" products of light nuclei in accordance with their baryon content.
virtual std::vector< double > Solve(const std::vector< double > &x0, BroydenSolutionCriterium *solcrit=NULL, int max_iterations=MAX_ITERS)
Definition: Broyden.cpp:77
double DecayThresholdMassDynamical() const
const std::string & Name() const
Particle&#39;s name.
std::vector< int > m_StableMapTo
const std::vector< ThermalParticle > & Particles() const
Returns the vector of all particle species.
ThermalModelParameters m_ParametersCurrent
The current PCE thermal paratmeres and chemical potentials.
std::vector< std::vector< double > > m_EffectiveCharges
void SetStable(bool stable=true)
Sets particle stability flag.
virtual double CalculateEntropyDensity()=0
void UsePartialChemicalEquilibrium(bool usePCE)
Sets whether partial chemical equilibrium with additional chemical potentials is used.
double Mass() const
Particle&#39;s mass [GeV].
ThermalModelParameters m_ParametersInit
Parameters at the chemical freeze-out.
bool m_StabilityFlagsSet
PCE configuration, list of stable species etc.
bool ZeroWidthEnforced() const
Whether zero-width approximation is enforced for this particle species.
void FillResonanceDecays()
Computes the decay contributions of decaying resonances to all particle yields.
bool IsStable() const
Return particle stability flag.
virtual void CalculateFeeddown()
Calculates the total densities which include feeddown contributions.
const std::vector< DecayContributionsToAllParticles > & DecayContributionsByFeeddown() const
double LonglivedResonanceWidthCut() const
ParticleDecayType::DecayType DecayType() const
Decay type of the particle.
void ProcessDecays()
Computes the decay contributions of decaying resonances to all particle yields.
PCEMode
Whether partial chemical equilibrium should be calculated at a fixed value of the temperature or a fi...
void ApplyFixForBoseCondensation()
Modifies the decay threshold masses of bosonic resonances such that the Bose-Condesation does not occ...
const ParticleDecaysVector & Decays() const
A vector of particle&#39;s decays.
const std::vector< int > & StabilityFlags() const
The main namespace where all classes and functions of the Thermal-FIST library reside.
virtual void SetChemicalPotentials(const std::vector< double > &chem=std::vector< double >(0))
Sets the chemical potentials of all particles.
Feeddown from all particles marked as unstable.
Definition: ParticleDecay.h:37
void SetDecayThresholdMassDynamical(double threshold)
Set the threshold mass manually for use in the eBW scheme.
int ComponentsNumber() const
Number of different particle species in the list.
ThermalParticleSystem * TPS()
static std::vector< int > ComputePCEStabilityFlags(const ThermalParticleSystem *TPS, bool SahaEquationForNuclei=true, bool FreezeLongLived=false, double WidthCut=0.015)
Computes the PCE stability flags based on the provided particle list and a number of parameters...
int Statistics() const
Particle&#39;s statistics.