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