Thermal-FIST 1.6
Package for hadron resonance gas model applications
Loading...
Searching...
No Matches
ThermalModelVDW.cpp
Go to the documentation of this file.
1/*
2 * Thermal-FIST package
3 *
4 * Copyright (c) 2016-2019 Volodymyr Vovchenko
5 *
6 * GNU General Public License (GPLv3 or later)
7 */
9
10#include <vector>
11#include <cmath>
12#include <cassert>
13#include <iostream>
14#include <ctime>
15#include <iomanip>
16#include <fstream>
17#include <sstream>
18
19#include "HRGBase/xMath.h"
21
22#ifdef USE_OPENMP
23#include <omp.h>
24#endif
25
26
27#include <Eigen/Dense>
28
29using namespace Eigen;
30
31using namespace std;
32
33namespace thermalfist {
34
37 {
38 m_chi.resize(6);
39 for(int i=0;i<6;++i) m_chi[i].resize(3);
40 m_chiarb.resize(6);
41 m_DensitiesId.resize(m_densities.size());
42 m_MuStar.resize(m_densities.size());
43 m_Virial.resize(m_densities.size(), vector<double>(m_densities.size(),0.));
47 m_Volume = params.V;
48 m_TAG = "ThermalModelVDW";
49
50 m_Ensemble = GCE;
51 m_InteractionModel = QvdW;
52 }
53
54
58
61 for(size_t i = 0; i < m_MuStar.size(); ++i)
62 m_MuStar[i] = m_Chem[i];
63 }
64
65 void ThermalModelVDW::SetChemicalPotentials(const vector<double>& chem)
66 {
68 for (size_t i = 0; i < m_MuStar.size(); ++i)
69 m_MuStar[i] = m_Chem[i];
70 }
71
72 void ThermalModelVDW::FillVirial(const vector<double> & ri) {
73 if (ri.size() != m_TPS->Particles().size()) {
74 std::cerr << "**WARNING** " << m_TAG << "::FillVirial(const vector<double> & ri): size of ri does not match number of hadrons in the list" << std::endl;
75 return;
76 }
77 m_Virial.resize(m_TPS->Particles().size());
78 for (int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
79 m_Virial[i].resize(m_TPS->Particles().size());
80 for (int j = 0; j < m_TPS->ComponentsNumber(); ++j)
81 m_Virial[i][j] = CuteHRGHelper::brr(ri[i], ri[j]);
82 }
83
84 // Correct R1=R2 and R2=0
85 vector< vector<double> > fVirialTmp = m_Virial;
86 for(int i=0;i<m_TPS->ComponentsNumber();++i)
87 for(int j=0;j<m_TPS->ComponentsNumber();++j) {
88 if (i==j) m_Virial[i][j] = fVirialTmp[i][j];
89 else if ((fVirialTmp[i][i] + fVirialTmp[j][j]) > 0.0) m_Virial[i][j] = 2. * fVirialTmp[i][j] * fVirialTmp[i][i] / (fVirialTmp[i][i] + fVirialTmp[j][j]);
90 }
91
92 m_VirialdT = vector< vector<double> >(m_TPS->Particles().size(), vector<double>(m_TPS->Particles().size(),0.));
93 m_AttrdT = vector< vector<double> >(m_TPS->Particles().size(), vector<double>(m_TPS->Particles().size(), 0.));
94
96 }
97
98 void ThermalModelVDW::FillVirialEV(const vector< vector<double> >& bij)
99 {
100 if (bij.size() != m_TPS->Particles().size()) {
101 std::cerr << "**WARNING** " << m_TAG << "::FillVirialEV(const vector<double> & bij): size of bij does not match number of hadrons in the list" << std::endl;
102 return;
103 }
104 m_Virial = bij;
105
107 }
108
109 void ThermalModelVDW::FillAttraction(const vector<vector<double> >& aij)
110 {
111 if (aij.size() != m_TPS->Particles().size()) {
112 std::cerr << "**WARNING** " << m_TAG << "::FillAttraction(const vector<double> & aij): size of aij does not match number of hadrons in the list" << std::endl;
113 return;
114 }
115 m_Attr = aij;
116
118 }
119
120 void ThermalModelVDW::ReadInteractionParameters(const string & filename)
121 {
122 m_Virial = vector< vector<double> >(m_TPS->Particles().size(), vector<double>(m_TPS->Particles().size(), 0.));
123 m_Attr = vector< vector<double> >(m_TPS->Particles().size(), vector<double>(m_TPS->Particles().size(), 0.));
124
125 ifstream fin(filename.c_str());
126 char cc[2000];
127 while (!fin.eof()) {
128 fin.getline(cc, 2000);
129 string tmp = string(cc);
130 vector<string> elems = CuteHRGHelper::split(tmp, '#');
131 if (elems.size() < 1)
132 continue;
133 istringstream iss(elems[0]);
134 long long pdgid1, pdgid2;
135 double b, a;
136 if (iss >> pdgid1 >> pdgid2 >> b) {
137 if (!(iss >> a))
138 a = 0.;
139 int ind1 = m_TPS->PdgToId(pdgid1);
140 int ind2 = m_TPS->PdgToId(pdgid2);
141 if (ind1 != -1 && ind2 != -1) {
142 m_Virial[ind1][ind2] = b;
143 m_Attr[ind1][ind2] = a;
144 }
145 }
146 }
147 fin.close();
148
150 }
151
153 {
154 ofstream fout(filename.c_str());
155 fout << "# List of the van dar Waals interaction parameters to be used in the QvdW-HRG model"
156 << std::endl;
157 fout << "# Only particle pairs with a non-zero QvdW interaction are listed here"
158 << std::endl;
159 /*fout << "#" << std::setw(14) << "pdg_i"
160 << std::setw(15) << "pdg_j"
161 << std::setw(15) << "b_{ij}[fm^3]"
162 << std::setw(20) << "a_{ij}[GeV*fm^3]"
163 << std::endl;*/
164 fout << "#" << " " << "pdg_i"
165 << " " << "pdg_j"
166 << " " << "b_{ij}[fm^3]"
167 << " " << "a_{ij}[GeV*fm^3]"
168 << std::endl;
169 for (int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
170 for (int j = 0; j < m_TPS->ComponentsNumber(); ++j) {
171 if (m_Virial[i][j] != 0. || m_Attr[i][j] != 0.) {
172 //fout << setw(15) << m_TPS->Particle(i).PdgId();
173 //fout << setw(15) << m_TPS->Particle(j).PdgId();
174 //fout << setw(15) << m_Virial[i][j];
175 //fout << setw(20) << m_Attr[i][j];
176 //fout << endl;
177 fout << " " << m_TPS->Particle(i).PdgId();
178 fout << " " << m_TPS->Particle(j).PdgId();
179 fout << " " << m_Virial[i][j];
180 fout << " " << m_Attr[i][j];
181 fout << endl;
182 }
183 }
184 }
185 fout.close();
186 }
187
190 m_Virial = vector< vector<double> >(m_TPS->Particles().size(), vector<double>(m_TPS->Particles().size(), 0.));
191 m_Attr = vector< vector<double> >(m_TPS->Particles().size(), vector<double>(m_TPS->Particles().size(), 0.));
192 m_VirialdT = vector< vector<double> >(m_TPS->Particles().size(), vector<double>(m_TPS->Particles().size(), 0.));
193 m_AttrdT = vector< vector<double> >(m_TPS->Particles().size(), vector<double>(m_TPS->Particles().size(), 0.));
195 }
196
197 std::vector<double> ThermalModelVDW::ComputeNp(const std::vector<double>& dmustar)
198 {
199 vector<double> ns(m_densities.size(), 0.);
200 for (size_t i = 0; i < m_densities.size(); ++i)
201 ns[i] = m_TPS->Particles()[i].Density(m_Parameters, IdealGasFunctions::ParticleDensity, m_UseWidth, m_Chem[i] + dmustar[m_MapTodMuStar[i]]);
202
203 return ComputeNp(dmustar, ns);
204 }
205
206 std::vector<double> ThermalModelVDW::ComputeNp(const std::vector<double>& /*dmustar*/, const std::vector<double>& ns)
207 {
208 int NN = m_densities.size();
209 int NNdmu = m_MapFromdMuStar.size();
210
211 MatrixXd densMatrix(NNdmu, NNdmu);
212 VectorXd solVector(NNdmu), xVector(NNdmu);
213
214 for (int i = 0; i < NNdmu; ++i) {
215 for (int j = 0; j < NNdmu; ++j) {
216 densMatrix(i, j) = 0.;
217 if (i == j)
218 densMatrix(i, j) += 1.;
219
220 for (size_t m = 0; m < m_dMuStarIndices[i].size(); ++m) {
221 densMatrix(i, j) += m_Virial[m_MapFromdMuStar[j]][m_dMuStarIndices[i][m]] * ns[m_dMuStarIndices[i][m]];
222 }
223 }
224 }
225
226 PartialPivLU<MatrixXd> decomp(densMatrix);
227
228 for (int kp = 0; kp < NNdmu; ++kp) {
229 xVector[kp] = 0.;
230 for (size_t m = 0; m < m_dMuStarIndices[kp].size(); ++m) {
231 xVector[kp] += ns[m_dMuStarIndices[kp][m]];
232 }
233 }
234
235
236 solVector = decomp.solve(xVector);
237
238 vector<double> ntildek(NNdmu, 0.);
239 for (int i = 0; i < NNdmu; ++i)
240 ntildek[i] = solVector[i];
241
242 vector<double> np(m_densities.size(), 0.);
243 for (int i = 0; i < NN; ++i) {
244 np[i] = 0.;
245 for (int k = 0; k < NNdmu; ++k) {
246 np[i] += m_Virial[m_MapFromdMuStar[k]][i] * solVector[k];
247 }
248 np[i] = (1. - np[i]) * ns[i];
249 }
250
251 return np;
252 }
253
255 {
256 map< vector<double>, int> MapVDW;
257
258 int NN = m_densities.size();
259
260 m_MapTodMuStar.resize(NN);
261 m_MapFromdMuStar.clear();
262 MapVDW.clear();
263 m_dMuStarIndices.clear();
264
265 int tind = 0;
266 for (int i = 0; i < NN; ++i) {
267 vector<double> VDWParam(0);
268 for (int j = 0; j < NN; ++j) {
269 VDWParam.push_back(m_Virial[i][j]);
270 }
271 for (int j = 0; j < NN; ++j) {
272 VDWParam.push_back(m_Attr[i][j] + m_Attr[j][i]);
273 }
274
275 if (MapVDW.count(VDWParam) == 0) {
276 MapVDW[VDWParam] = tind;
277 m_MapTodMuStar[i] = tind;
278 m_MapFromdMuStar.push_back(i);
279 m_dMuStarIndices.push_back(vector<int>(1, i));
280 tind++;
281 }
282 else {
283 m_MapTodMuStar[i] = MapVDW[VDWParam];
284 m_dMuStarIndices[MapVDW[VDWParam]].push_back(i);
285 }
286 }
287
289 }
290
291 vector<double> ThermalModelVDW::SearchSingleSolution(const vector<double>& muStarInit)
292 {
293 int NN = m_densities.size();
294 int NNdmu = m_MapFromdMuStar.size();
295
296 vector<double> dmuscur(NNdmu, 0.);
297 for (int i = 0; i < NNdmu; ++i)
298 dmuscur[i] = muStarInit[m_MapFromdMuStar[i]] - m_Chem[m_MapFromdMuStar[i]];
299
300 BroydenEquationsVDW eqs(this);
301 BroydenJacobianVDW jac(this);
302 Broyden broydn(&eqs, &jac);
303 BroydenSolutionCriteriumVDW crit(this);
304
305 dmuscur = broydn.Solve(dmuscur, &crit);
306
307 if (broydn.Iterations() == broydn.MaxIterations())
309 else m_LastBroydenSuccessFlag = true;
310
311 m_MaxDiff = broydn.MaxDifference();
312
313 vector<double> ret(NN);
314 for (int i = 0; i < NN; ++i)
315 ret[i] = m_Chem[i] + dmuscur[m_MapTodMuStar[i]];
316
317 return ret;
318 }
319
321 vector<double> csol(m_densities.size(), 0.);
322 double Psol = 0.;
323 bool solved = false;
324 double muBmin = m_Parameters.muB - 0.5 * xMath::mnucleon();
325 double muBmax = m_Parameters.muB + 0.5 * xMath::mnucleon();
326 double dmu = (muBmax - muBmin) / iters;
327 vector<double> curmust(m_densities.size(), 0.);
328 double maxdif = 0.;
329 for(int isol = 0; isol < iters; ++isol) {
330 double tmu = muBmin + (0.5 + isol) * dmu;
331 for(size_t j = 0; j < curmust.size(); ++j) {
332 if (m_Parameters.muB != 0.0)
333 curmust[j] = m_Chem[j] + (tmu - m_Parameters.muB) * m_Chem[j] / m_Parameters.muB;
334 else
335 curmust[j] = tmu;
336 if (m_TPS->Particles()[j].Statistics()==-1 && curmust[j] > m_TPS->Particles()[j].Mass())
337 curmust[j] = 0.98 * m_TPS->Particles()[j].Mass();
338 }
339
340 vector<double> sol = SearchSingleSolution(curmust);
341
342 bool fl = true;
343 for(size_t i = 0; i < sol.size(); ++i)
344 if (sol[i] != sol[i]) fl = false;
346 if (!fl) continue;
347
348 for(int i = 0; i < m_TPS->ComponentsNumber(); ++i)
349 m_DensitiesId[i] = m_TPS->Particles()[i].Density(m_Parameters, IdealGasFunctions::ParticleDensity, m_UseWidth, sol[i]);
350
351 int NN = m_densities.size();
352
353 MatrixXd densMatrix(NN, NN);
354 VectorXd solVector(NN), xVector(NN);
355
356 for(int i=0;i<NN;++i)
357 for(int j=0;j<NN;++j) {
358 densMatrix(i,j) = m_Virial[j][i] * m_DensitiesId[i];
359 if (i==j) densMatrix(i,j) += 1.;
360 }
361
362 PartialPivLU<MatrixXd> decomp(densMatrix);
363
364 for(int i=0;i<NN;++i)
365 xVector[i] = m_DensitiesId[i];
366 solVector = decomp.solve(xVector);
367 for(int i=0;i<NN;++i)
368 m_densities[i] = solVector[i];
369
370 double tP = 0.;
371 for(size_t i=0;i<m_densities.size();++i)
372 tP += m_TPS->Particles()[i].Density(m_Parameters, IdealGasFunctions::Pressure, m_UseWidth, sol[i]);
373 for(size_t i=0;i<m_densities.size();++i)
374 for(size_t j=0;j<m_densities.size();++j)
375 tP += -m_Attr[i][j] * m_densities[i] * m_densities[j];
376
377 if (!solved || tP > Psol) {
378 solved = true;
379 Psol = tP;
380 csol = sol;
381 maxdif = m_MaxDiff;
382 }
383 }
385 m_MaxDiff = maxdif;
386 return csol;
387 }
388
391
392 vector<double> muStarInit = m_MuStar;
393
394 for(size_t i=0;i<muStarInit.size();++i) {
395 if (m_TPS->Particles()[i].Statistics()==-1 && muStarInit[i] > m_TPS->Particles()[i].Mass())
396 muStarInit[i] = 0.98 * m_TPS->Particles()[i].Mass();
397 }
398 m_MuStar = SearchSingleSolution(muStarInit);
399
400 // If single solution failed, try alternative initial conditions
403 }
404 }
405 else {
407 }
408 }
409
410 vector<double> ThermalModelVDW::SearchFirstSolution(int iters) {
411 // Try different initial conditions and return the first successful solution
412 double muBmin = m_Parameters.muB - 0.5 * xMath::mnucleon();
413 double muBmax = m_Parameters.muB + 0.5 * xMath::mnucleon();
414 double dmu = (muBmax - muBmin) / iters;
415 vector<double> curmust(m_densities.size(), 0.);
416
417 for (int isol = 0; isol < iters; ++isol) {
418 double tmu = muBmin + (0.5 + isol) * dmu;
419 for (size_t j = 0; j < curmust.size(); ++j) {
420 if (m_Parameters.muB != 0.0)
421 curmust[j] = m_Chem[j] + (tmu - m_Parameters.muB) * m_Chem[j] / m_Parameters.muB;
422 else
423 curmust[j] = tmu;
424 if (m_TPS->Particles()[j].Statistics() == -1 && curmust[j] > m_TPS->Particles()[j].Mass())
425 curmust[j] = 0.98 * m_TPS->Particles()[j].Mass();
426 }
427
428 vector<double> sol = SearchSingleSolution(curmust);
429
430 // Check if solution is valid (no NaN and Broyden succeeded)
431 bool valid = m_LastBroydenSuccessFlag;
432 for (size_t i = 0; i < sol.size() && valid; ++i)
433 if (sol[i] != sol[i]) // NaN check
434 valid = false;
435
436 if (valid) {
437 return sol; // Return first valid solution found
438 }
439 }
440
441 // No valid solution found
443 return m_MuStar; // Return current (possibly invalid) values
444 }
445
447 CalculatePrimordialDensitiesNew();
449 }
450
451 void ThermalModelVDW::CalculatePrimordialDensitiesOld() {
452 m_FluctuationsCalculated = false;
453
456
457 int NN = m_densities.size();
458
459 //map< vector<double>, int> m_MapVDW;
460 //{
461 // m_MapTodMuStar.resize(NN);
462 // m_MapFromdMuStar.clear();
463 // m_MapVDW.clear();
464 // m_dMuStarIndices.clear();
465
466 // int tind = 0;
467 // for (int i = 0; i < NN; ++i) {
468 // vector<double> VDWParam(0);
469 // for (int j = 0; j < NN; ++j) {
470 // VDWParam.push_back(m_Virial[i][j]);
471 // }
472 // for (int j = 0; j < NN; ++j) {
473 // VDWParam.push_back(m_Attr[i][j] + m_Attr[j][i]);
474 // }
475
476 // if (m_MapVDW.count(VDWParam) == 0) {
477 // m_MapVDW[VDWParam] = tind;
478 // m_MapTodMuStar[i] = tind;
479 // m_MapFromdMuStar.push_back(i);
480 // m_dMuStarIndices.push_back(vector<int>(1, i));
481 // tind++;
482 // }
483 // else {
484 // m_MapTodMuStar[i] = m_MapVDW[VDWParam];
485 // m_dMuStarIndices[m_MapVDW[VDWParam]].push_back(i);
486 // }
487 // }
488
489 // printf("Optimization: %d --> %d\n", NN, static_cast<int>(m_MapFromdMuStar.size()));
490 //}
491
492 clock_t tbeg = clock();
493
494 {
495
496 vector<double> muStarInit = m_MuStar;
497
498 for (size_t i = 0; i<muStarInit.size(); ++i) {
499 if (m_TPS->Particles()[i].Statistics() == -1 && muStarInit[i] > m_TPS->Particles()[i].Mass())
500 muStarInit[i] = 0.98 * m_TPS->Particles()[i].Mass();
501 }
502
503
504 m_MuStar = SearchSingleSolution(muStarInit);
505 }
506
507
508 printf("Solution time = %lf ms\n", (clock() - tbeg) / (double)(CLOCKS_PER_SEC) * 1.e3);
509
510 tbeg = clock();
511
512 for(int i=0;i<m_TPS->ComponentsNumber();++i)
513 m_DensitiesId[i] = m_TPS->Particles()[i].Density(m_Parameters, IdealGasFunctions::ParticleDensity, m_UseWidth, m_MuStar[i]);
514
515 MatrixXd densMatrix(NN, NN);
516 VectorXd solVector(NN), xVector(NN);
517
518 for(int i=0;i<NN;++i)
519 for(int j=0;j<NN;++j) {
520 densMatrix(i,j) = m_Virial[j][i] * m_DensitiesId[i];
521 if (i==j) densMatrix(i,j) += 1.;
522 }
523
524 PartialPivLU<MatrixXd> decomp(densMatrix);
525
526 for(int i=0;i<NN;++i) xVector[i] = m_DensitiesId[i];
527 solVector = decomp.solve(xVector);
528 for(int i=0;i<NN;++i) m_densities[i] = solVector[i];
529
530 // TODO: Scalar density properly
531 for(int i=0;i<NN;++i) xVector[i] = m_TPS->Particles()[i].Density(m_Parameters, IdealGasFunctions::ScalarDensity, m_UseWidth, m_MuStar[i]);
532 solVector = decomp.solve(xVector);
533 m_scaldens.resize(m_densities.size());
534 for(int i=0;i<NN;++i) m_scaldens[i] = solVector[i];
535
536
537 tbeg = clock();
538
539 m_Calculated = true;
540 }
541
542 void ThermalModelVDW::CalculatePrimordialDensitiesNew() {
543 m_FluctuationsCalculated = false;
544
547
548 int NN = m_densities.size();
549
550 clock_t tbeg = clock();
551
553
554 tbeg = clock();
555
556 for (int i = 0; i < m_TPS->ComponentsNumber(); ++i)
557 m_DensitiesId[i] = m_TPS->Particles()[i].Density(m_Parameters, IdealGasFunctions::ParticleDensity, m_UseWidth, m_MuStar[i]);
558
559
560 int NNdmu = m_MapFromdMuStar.size();
561
562 MatrixXd densMatrix(NNdmu, NNdmu);
563 VectorXd solVector(NNdmu), xVector(NNdmu);
564
565 for (int i = 0; i < NNdmu; ++i) {
566 for (int j = 0; j < NNdmu; ++j) {
567 densMatrix(i, j) = 0.;
568 if (i == j)
569 densMatrix(i, j) += 1.;
570
571 for (size_t m = 0; m < m_dMuStarIndices[i].size(); ++m) {
572 densMatrix(i, j) += m_Virial[m_MapFromdMuStar[j]][m_dMuStarIndices[i][m]] * m_DensitiesId[m_dMuStarIndices[i][m]];
573 }
574 }
575 }
576
577 PartialPivLU<MatrixXd> decomp(densMatrix);
578
579 for (int kp = 0; kp < NNdmu; ++kp) {
580 xVector[kp] = 0.;
581 for (size_t m = 0; m < m_dMuStarIndices[kp].size(); ++m) {
582 xVector[kp] += m_DensitiesId[m_dMuStarIndices[kp][m]];
583 }
584 }
585
586 solVector = decomp.solve(xVector);
587
588 vector<double> ntildek(NNdmu, 0.);
589 for (int i = 0; i < NNdmu; ++i)
590 ntildek[i] = solVector[i];
591
592 //vector<double> np(m_densities.size(), 0.);
593 for (int i = 0; i < NN; ++i) {
594 m_densities[i] = 0.;
595 for (int k = 0; k < NNdmu; ++k) {
596 m_densities[i] += m_Virial[m_MapFromdMuStar[k]][i] * solVector[k];
597 }
598 m_densities[i] = (1. - m_densities[i]) * m_DensitiesId[i];
599 }
600
601 // TODO: Scalar density properly
602 m_scaldens = m_densities;
603
604 m_Calculated = true;
605 }
606
607 vector<double> ThermalModelVDW::CalculateChargeFluctuations(const vector<double> &chgs, int order, bool dimensionfull) {
608 vector<double> ret(order + 1, 0.);
609
610 // chi1
611 for(size_t i=0;i<m_densities.size();++i)
612 ret[0] += chgs[i] * m_densities[i];
613
614 if (!dimensionfull)
615 ret[0] /= pow(m_Parameters.T * xMath::GeVtoifm(), 3);
616 else
617 ret[0] /= pow(xMath::GeVtoifm(), 3);
618
619 if (order<2) return ret;
620 // Preparing matrix for system of linear equations
621 int NN = m_densities.size();
622 MatrixXd densMatrix(2*NN, 2*NN);
623 VectorXd solVector(2*NN), xVector(2*NN);
624
625 vector<double> chi2id(m_densities.size());
626 for(int i=0;i<NN;++i)
627 // chi2id[i] = m_TPS->Particles()[i].chi(2, m_Parameters, m_UseWidth, m_MuStar[i]);
628 chi2id[i] = m_TPS->Particles()[i].chiDimensionfull(2, m_Parameters, m_UseWidth, m_MuStar[i]);
629
630 for(int i=0;i<NN;++i)
631 for(int j=0;j<NN;++j) {
632 densMatrix(i,j) = m_Virial[j][i] * m_DensitiesId[i];
633 if (i==j) densMatrix(i,j) += 1.;
634 }
635
636 for(int i=0;i<NN;++i)
637 for(int j=0;j<NN;++j)
638 densMatrix(i,NN+j) = 0.;
639
640 for(int i=0;i<NN;++i) {
641 densMatrix(i,NN+i) = 0.;
642 for(int k=0;k<NN;++k) {
643 densMatrix(i,NN+i) += m_Virial[k][i] * m_densities[k];
644 }
645 densMatrix(i,NN+i) = (densMatrix(i,NN+i) - 1.) * chi2id[i] * pow(xMath::GeVtoifm(), 3);
646 }
647
648 for(int i=0;i<NN;++i)
649 for(int j=0;j<NN;++j) {
650 densMatrix(NN+i,j) = -(m_Attr[i][j] + m_Attr[j][i]);
651 }
652
653 for(int i=0;i<NN;++i)
654 for(int j=0;j<NN;++j) {
655 densMatrix(NN+i,NN+j) = m_Virial[i][j] * m_DensitiesId[j];
656 if (i==j) densMatrix(NN+i,NN+j) += 1.;
657 }
658
659
660 PartialPivLU<MatrixXd> decomp(densMatrix);
661
662 // chi2
663 vector<double> dni(NN, 0.), dmus(NN, 0.);
664
665 for(int i=0;i<NN;++i) {
666 xVector[i] = 0.;
667 xVector[NN+i] = chgs[i];
668 }
669
670 solVector = decomp.solve(xVector);
671
672 for(int i=0;i<NN;++i) {
673 dni[i] = solVector[i];
674 dmus[i] = solVector[NN+i];
675 }
676
677 for(int i=0;i<NN;++i)
678 ret[1] += chgs[i] * dni[i];
679
680 if (!dimensionfull)
681 ret[1] /= pow(m_Parameters.T, 2) * pow(xMath::GeVtoifm(), 3);
682 else
683 ret[1] /= pow(xMath::GeVtoifm(), 3);
684
685 if (order<3) return ret;
686
687 // chi3
688 vector<double> d2ni(NN, 0.), d2mus(NN, 0.);
689
690 vector<double> chi3id(m_densities.size());
691 for(int i=0;i<NN;++i)
692 // chi3id[i] = m_TPS->Particles()[i].chi(3, m_Parameters, m_UseWidth, m_MuStar[i]);
693 chi3id[i] = m_TPS->Particles()[i].chiDimensionfull(3, m_Parameters, m_UseWidth, m_MuStar[i]);
694
695 for(int i=0;i<NN;++i) {
696 xVector[i] = 0.;
697
698 double tmp = 0.;
699 for(int j=0;j<NN;++j) tmp += m_Virial[j][i] * dni[j];
700 tmp = -2. * tmp * chi2id[i] * pow(xMath::GeVtoifm(), 3) * dmus[i];
701 xVector[i] += tmp;
702
703 tmp = 0.;
704 for(int j=0;j<NN;++j) tmp += m_Virial[j][i] * m_densities[j];
705 tmp = -(tmp - 1.) * chi3id[i] * pow(xMath::GeVtoifm(), 3) * dmus[i] * dmus[i];
706 xVector[i] += tmp;
707 }
708 for(int i=0;i<NN;++i) {
709 xVector[NN+i] = 0.;
710
711 double tmp = 0.;
712 for(int j=0;j<NN;++j) tmp += -m_Virial[i][j] * dmus[j] * chi2id[j] * pow(xMath::GeVtoifm(), 3) * dmus[j];
713
714 xVector[NN+i] = tmp;
715 }
716
717 solVector = decomp.solve(xVector);
718
719 for(int i=0;i<NN;++i) {
720 d2ni[i] = solVector[i];
721 d2mus[i] = solVector[NN+i];
722 }
723
724 for(int i=0;i<NN;++i)
725 ret[2] += chgs[i] * d2ni[i];
726
727 if (!dimensionfull)
728 ret[2] /= m_Parameters.T * pow(xMath::GeVtoifm(), 3);
729 else
730 ret[2] /= pow(xMath::GeVtoifm(), 3);
731
732
733 if (order<4) return ret;
734
735 // chi4
736 vector<double> d3ni(NN, 0.), d3mus(NN, 0.);
737
738 vector<double> chi4id(m_densities.size());
739 for (int i = 0; i < NN; ++i)
740 // chi4id[i] = m_TPS->Particles()[i].chi(4, m_Parameters, m_UseWidth, m_MuStar[i]);
741 chi4id[i] = m_TPS->Particles()[i].chiDimensionfull(4, m_Parameters, m_UseWidth, m_MuStar[i]);
742
743 vector<double> dnis(NN, 0.);
744 for(int i=0;i<NN;++i) {
745 dnis[i] = chi2id[i] * pow(xMath::GeVtoifm(), 3) * dmus[i];
746 }
747
748 vector<double> d2nis(NN, 0.);
749 for(int i=0;i<NN;++i) {
750 d2nis[i] = chi3id[i] * pow(xMath::GeVtoifm(), 3) * dmus[i] * dmus[i] +
751 chi2id[i] * pow(xMath::GeVtoifm(), 3) * d2mus[i];
752 }
753
754 for(int i=0;i<NN;++i) {
755 xVector[i] = 0.;
756
757 double tmp = 0.;
758 for(int j=0;j<NN;++j) tmp += m_Virial[j][i] * dni[j];
759 tmp = -3. * tmp * d2nis[i];
760 xVector[i] += tmp;
761
762 tmp = 0.;
763 for(int j=0;j<NN;++j) tmp += m_Virial[j][i] * d2ni[j];
764 tmp = -3. * tmp * dnis[i];
765 xVector[i] += tmp;
766
767 double tmps = 0.;
768 for(int j=0;j<NN;++j) tmps += m_Virial[j][i] * m_densities[j];
769
770 tmp = -(tmps - 1.) * chi3id[i] * pow(xMath::GeVtoifm(), 3) * d2mus[i] * 3. * dmus[i];
771 xVector[i] += tmp;
772
773 tmp = -(tmps - 1.) * chi4id[i] * pow(xMath::GeVtoifm(), 3) * dmus[i] * dmus[i] * dmus[i];
774 xVector[i] += tmp;
775 }
776 for(int i=0;i<NN;++i) {
777 xVector[NN+i] = 0.;
778
779 double tmp = 0.;
780 for(int j=0;j<NN;++j) tmp += -2. * m_Virial[i][j] * d2mus[j] * dnis[j];
781 xVector[NN+i] += tmp;
782
783 tmp = 0.;
784 for(int j=0;j<NN;++j) tmp += -m_Virial[i][j] * dmus[j] * d2nis[j];
785 xVector[NN+i] += tmp;
786 }
787
788 solVector = decomp.solve(xVector);
789
790 for(int i=0;i<NN;++i) {
791 d3ni[i] = solVector[i];
792 d3mus[i] = solVector[NN+i];
793 }
794
795 for(int i=0;i<NN;++i)
796 ret[3] += chgs[i] * d3ni[i];
797
798 ret[3] /= pow(xMath::GeVtoifm(), 3); // same for dimensionfull and dimensionless
799
800 return ret;
801 }
802
803 // TODO include correlations
804 vector< vector<double> > ThermalModelVDW::CalculateFluctuations(int order) {
805 if (order<1) return m_chi;
806
807 vector<double> chgs(m_densities.size());
808 vector<double> chis;
809
810 // Baryon charge
811 for(size_t i=0;i<chgs.size();++i)
812 chgs[i] = m_TPS->Particles()[i].BaryonCharge();
813 chis = CalculateChargeFluctuations(chgs, order);
814 for(int i=0;i<order;++i) m_chi[i][0] = chis[i];
815
816 // Electric charge
817 for(size_t i=0;i<chgs.size();++i)
818 chgs[i] = m_TPS->Particles()[i].ElectricCharge();
819 chis = CalculateChargeFluctuations(chgs, order);
820 for(int i=0;i<order;++i) m_chi[i][1] = chis[i];
821
822 // Strangeness charge
823 for(size_t i=0;i<chgs.size();++i)
824 chgs[i] = m_TPS->Particles()[i].Strangeness();
825 chis = CalculateChargeFluctuations(chgs, order);
826 for(int i=0;i<order;++i) m_chi[i][2] = chis[i];
827
828 // Arbitrary charge
829 for(size_t i=0;i<chgs.size();++i)
830 chgs[i] = m_TPS->Particles()[i].ArbitraryCharge();
831 chis = CalculateChargeFluctuations(chgs, order);
832 for(int i=0;i<order;++i) m_chiarb[i] = chis[i];
833
834 return m_chi;
835 }
836
838 {
839 int NN = m_densities.size();
840
841 m_PrimCorrel.resize(NN);
842 for (int i = 0; i < NN; ++i)
843 m_PrimCorrel[i].resize(NN);
844 m_dmusdmu = m_PrimCorrel;
845 m_TotalCorrel = m_PrimCorrel;
846
847 MatrixXd densMatrix(2 * NN, 2 * NN);
848 VectorXd solVector(2 * NN), xVector(2 * NN);
849
850 vector<double> chi2id(m_densities.size());
851 for (int i = 0; i<NN; ++i)
852 //chi2id[i] = m_TPS->Particles()[i].chi(2, m_Parameters, m_UseWidth, m_MuStar[i]);
853 chi2id[i] = m_TPS->Particles()[i].chiDimensionfull(2, m_Parameters, m_UseWidth, m_MuStar[i]);
854
855 for (int i = 0; i<NN; ++i)
856 for (int j = 0; j<NN; ++j) {
857 densMatrix(i, j) = m_Virial[j][i] * m_DensitiesId[i];
858 if (i == j) densMatrix(i, j) += 1.;
859 }
860
861 for (int i = 0; i<NN; ++i)
862 for (int j = 0; j<NN; ++j)
863 densMatrix(i, NN + j) = 0.;
864
865 for (int i = 0; i<NN; ++i) {
866 densMatrix(i, NN + i) = 0.;
867 for (int k = 0; k<NN; ++k) {
868 densMatrix(i, NN + i) += m_Virial[k][i] * m_densities[k];
869 }
870 //densMatrix(i, NN + i) = (densMatrix(i, NN + i) - 1.) * chi2id[i] * pow(xMath::GeVtoifm(), 3) * m_Parameters.T * m_Parameters.T;
871 densMatrix(i, NN + i) = (densMatrix(i, NN + i) - 1.) * chi2id[i] * pow(xMath::GeVtoifm(), 3);
872 }
873
874 for (int i = 0; i<NN; ++i)
875 for (int j = 0; j<NN; ++j) {
876 densMatrix(NN + i, j) = -(m_Attr[i][j] + m_Attr[j][i]);
877 }
878
879 for (int i = 0; i<NN; ++i)
880 for (int j = 0; j<NN; ++j) {
881 densMatrix(NN + i, NN + j) = m_Virial[i][j] * m_DensitiesId[j];
882 if (i == j) densMatrix(NN + i, NN + j) += 1.;
883 }
884
885 PartialPivLU<MatrixXd> decomp(densMatrix);
886
887 for (int k = 0; k < NN; ++k) {
888 vector<double> dni(NN, 0.), dmus(NN, 0.);
889
890 for (int i = 0; i < NN; ++i) {
891 xVector[i] = 0.;
892 xVector[NN + i] = static_cast<int>(i == k);
893 }
894
895 solVector = decomp.solve(xVector);
896
897 for (int i = 0; i < NN; ++i) {
898 dni[i] = solVector[i];
899 dmus[i] = solVector[NN + i];
900 m_dmusdmu[i][k] = dmus[i];
901 }
902
903 for (int j = 0; j < NN; ++j) {
904 m_PrimCorrel[j][k] = dni[j];
905 }
906 }
907
908 for (int i = 0; i < NN; ++i) {
909 m_wprim[i] = m_PrimCorrel[i][i];
910 if (m_densities[i] > 0.) m_wprim[i] *= m_Parameters.T / m_densities[i];
911 else m_wprim[i] = 1.;
912 if (m_wprim[i] != m_wprim[i]) m_wprim[i] = 1.;
913 }
914
915 m_TwoParticleCorrelationsCalculated = true;
916 }
917
919 {
925
926 for (size_t i = 0; i < m_wprim.size(); ++i) {
927 m_skewprim[i] = 1.;
928 m_kurtprim[i] = 1.;
929 m_skewtot[i] = 1.;
930 m_kurttot[i] = 1.;
931 }
932
933 m_FluctuationsCalculated = true;
934
935 if (IsTemperatureDerivativesCalculated()) {
936 m_TemperatureDerivativesCalculated = false;
938 }
939 }
940
942 if (!IsTemperatureDerivativesCalculated())
944
945 // Compute dE/dT
946 double ret = 0.;
947
948 for (int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
949 const ThermalParticle &part = m_TPS->Particles()[i];
950 double fi = 1., dvi = 0.;
951 // Term 1
952 for (int k = 0; k < m_TPS->ComponentsNumber(); ++k) {
953 double dfik = -m_Virial[k][i];
954 ret += dfik * m_dndT[k] * part.Density(m_Parameters, IdealGasFunctions::EnergyDensity, m_UseWidth, m_MuStar[i]);
955 fi -= m_Virial[k][i] * m_densities[k];
956 dvi += -(m_Attr[k][i] + m_Attr[i][k]) * m_densities[k];
957 }
958
959 // Term 2
960 ret += fi * part.Density(m_Parameters, IdealGasFunctions::dedT, m_UseWidth, m_MuStar[i]);
961
962 // Term 3
963 ret += fi * part.Density(m_Parameters, IdealGasFunctions::dedmu, m_UseWidth, m_MuStar[i]) * m_dmusdT[i];
964
965 // Term 4
966 ret += dvi * m_dndT[i];
967 }
968
969 return ret;
970 }
971
973 if (!IsTemperatureDerivativesCalculated())
975
976 // Compute ds/dT
977 double ret = 0.;
978
979 for (int i = 0; i < m_TPS->ComponentsNumber(); ++i) {
980 const ThermalParticle &part = m_TPS->Particles()[i];
981 double fi = 1.;
982 // Term 1
983 for (int k = 0; k < m_TPS->ComponentsNumber(); ++k) {
984 double dfik = -m_Virial[k][i];
985 ret += dfik * m_dndT[k] * part.Density(m_Parameters, IdealGasFunctions::EntropyDensity, m_UseWidth, m_MuStar[i]);
986 fi -= m_Virial[k][i] * m_densities[k];
987 }
988
989 // Term 2
990 ret += fi * part.Density(m_Parameters, IdealGasFunctions::dsdT, m_UseWidth, m_MuStar[i]);
991
992 // Term 3: ds/dmu = dn/dT (Maxwell relation)
993 ret += fi * part.Density(m_Parameters, IdealGasFunctions::dndT, m_UseWidth, m_MuStar[i]) * m_dmusdT[i];
994 }
995
996 return ret;
997 }
998
1000 if (!IsCalculated())
1002
1003 int N = m_TPS->ComponentsNumber();
1004 m_dndT = vector<double>(N, 0.);
1005 m_dmusdT = vector<double>(N, 0.);
1006 m_PrimChi2sdT = vector<vector<double>>(N, vector<double>(N, 0.));
1007
1008 double T = m_Parameters.T;
1009
1010 vector<double> nids(N, 0.), dniddTs(N, 0.), chi2ids(N, 0.), dchi2idsdT(N, 0.), chi3ids(N, 0.);
1011 for (int i = 0; i < N; ++i) {
1012 nids[i] = m_TPS->Particles()[i].Density(m_Parameters, IdealGasFunctions::ParticleDensity, m_UseWidth, m_MuStar[i]);
1013 dniddTs[i] = m_TPS->Particles()[i].Density(m_Parameters, IdealGasFunctions::dndT, m_UseWidth, m_MuStar[i]);
1014 chi2ids[i] = m_TPS->Particles()[i].chiDimensionfull(2, m_Parameters, m_UseWidth, m_MuStar[i]) * xMath::GeVtoifm3();
1015 // dchi2idsdT = d(dn^id/dmu*)/dT = T^2 * dchi2/dT + 2 * chi2ids / T
1016 // The two terms individually diverge as 1/T but their sum is O(T).
1017 // At T=0 the result is exactly zero (Sommerfeld: dn/dmu = const + O(T^2)).
1018 if (T > 0.)
1019 dchi2idsdT[i] = (T * T * m_TPS->Particles()[i].Density(m_Parameters, IdealGasFunctions::dchi2dT, m_UseWidth, m_MuStar[i]) * xMath::GeVtoifm3() + 2. * chi2ids[i] / T);
1020 else
1021 dchi2idsdT[i] = 0.;
1022 chi3ids[i] = m_TPS->Particles()[i].chiDimensionfull(3, m_Parameters, m_UseWidth, m_MuStar[i]) * xMath::GeVtoifm3();
1023 }
1024
1025 int NN = m_densities.size();
1026
1027 MatrixXd densMatrix(2 * NN, 2 * NN);
1028 VectorXd solVector(2 * NN), xVector(2 * NN);
1029
1030 //vector<double> chi2id(m_densities.size());
1031
1032 for (int i = 0; i<NN; ++i)
1033 for (int j = 0; j<NN; ++j) {
1034 densMatrix(i, j) = m_Virial[j][i] * m_DensitiesId[i];
1035 if (i == j) densMatrix(i, j) += 1.;
1036 }
1037
1038 for (int i = 0; i<NN; ++i)
1039 for (int j = 0; j<NN; ++j)
1040 densMatrix(i, NN + j) = 0.;
1041
1042 for (int i = 0; i<NN; ++i) {
1043 densMatrix(i, NN + i) = 0.;
1044 for (int k = 0; k<NN; ++k) {
1045 densMatrix(i, NN + i) += m_Virial[k][i] * m_densities[k];
1046 }
1047 densMatrix(i, NN + i) = (densMatrix(i, NN + i) - 1.) * chi2ids[i];
1048 }
1049
1050 for (int i = 0; i<NN; ++i)
1051 for (int j = 0; j<NN; ++j) {
1052 densMatrix(NN + i, j) = -(m_Attr[i][j] + m_Attr[j][i]);
1053 }
1054
1055 for (int i = 0; i<NN; ++i)
1056 for (int j = 0; j<NN; ++j) {
1057 densMatrix(NN + i, NN + j) = m_Virial[i][j] * m_DensitiesId[j];
1058 if (i == j) densMatrix(NN + i, NN + j) += 1.;
1059 }
1060
1061 PartialPivLU<MatrixXd> decomp(densMatrix);
1062
1063 for(int i=0;i<NN;++i) {
1064 double fi = 1.;
1065 for(int k=0;k<NN;++k) {
1066 fi -= m_Virial[k][i] * m_densities[k];
1067 }
1068 xVector[i] = fi * dniddTs[i];
1069 xVector[NN + i] = 0.;
1070 for(int j = 0; j < NN; ++j) {
1071 xVector[NN + i] += -m_Virial[i][j] * m_TPS->Particles()[j].Density(m_Parameters, IdealGasFunctions::EntropyDensity, m_UseWidth, m_MuStar[j]);
1072 }
1073 }
1074
1075 solVector = decomp.solve(xVector);
1076
1077 for(int i=0;i<NN;++i) {
1078 m_dndT[i] = solVector[i];
1079 m_dmusdT[i] = solVector[NN+i];
1080 }
1081
1082
1083 // dchi2's
1084 if (IsSusceptibilitiesCalculated()) {
1085
1086 // TODO: Faster implementation
1087 // int NNdmu = m_MapFromdMuStar.size();
1088 // vector<vector<double>> dfij = vector<vector<double>>(NNdmu, vector<double>(NNdmu, 0.));
1089 // vector<double> fi = vector<double>(NNdmu, 0.);
1090 // vector<double> tsum1 = vector<double>(NNdmu, 0.);
1091 // vector<double> tsumdndT = vector<double>(NNdmu, 0.);
1092
1093 // for (int j = 0; j < NN; ++j) {
1094 // for (int i = 0; i < NN; ++i) {
1095 // dfij[m_MapTodMuStar[i]][m_MapTodMuStar[j]] += m_Virial[j][i];
1096 // fi[m_MapTodMuStar[i]] += m_Virial[j][i] * m_densities[j];
1097 // }
1098 // tsum1[m_MapTodMuStar[j]] += (dniddTs[j] + chi2ids[j] * m_dmusdT[j]);
1099 // tsumdndT[m_MapTodMuStar[j]] += m_dndT[j];
1100 // }
1101
1102 for (int j = 0; j < NN; ++j) {
1103 // vector<double> PrimCorrelkjsum = vector<double>(NNdmu, 0.);
1104 // for(int k = 0; k < NN; ++k) {
1105 // PrimCorrelkjsum[m_MapTodMuStar[k]] += m_PrimCorrel[k][j];
1106 // }
1107 for (int i = 0; i < NN; ++i) {
1108
1109 // Faster calculation, to be checked
1110 // // a1
1111 // double a1 = 0.;
1112 // for (int k = 0; k < NNdmu; ++k) {
1113 // a1 += PrimCorrelkjsum[m_MapFromdMuStar[k]] * dfij[k][m_MapTodMuStar[i]] * (dniddTs[i] + chi2ids[i] * m_dmusdT[i]);
1114 // a1 += m_dmusdmu[i][j] * dfij[m_MapTodMuStar[i]][k] * tsumdndT[k] * chi2ids[i];
1115 // }
1116 // a1 += m_dmusdmu[i][j] * fi[m_MapTodMuStar[i]] * (dchi2idsdT[i] + chi3ids[i] * m_dmusdT[i]);
1117 // xVector[i] = a1;
1118
1119 // // a2
1120 // double a2 = 0.;
1121 // for (int k = 0; k < NNdmu; ++k) {
1122 // a2 += m_dmusdmu[m_MapFromdMuStar[k]][j] * (-m_Virial[i][m_MapFromdMuStar[k]]) * tsum1[k]; // To be checked
1123 // }
1124 // xVector[i + NN] = a2;
1125
1126 double fi = 1.;
1127 vector<double> dfik = vector<double>(NN, 0.);
1128 //vector<vector<double>> d2fikl = vector<vector<double>>(NN, vector<double>(NN, 0.));
1129 for (int k = 0; k < NN; ++k) {
1130 dfik[k] = -m_Virial[k][i];
1131 fi -= m_Virial[k][i] * m_densities[k];
1132 }
1133
1134 // a1
1135 double a1 = 0.;
1136 for (int k = 0; k < NN; ++k) {
1137 a1 += m_PrimCorrel[k][j] * dfik[k] * (dniddTs[i] + chi2ids[i] * m_dmusdT[i]);
1138 a1 += m_dmusdmu[i][j] * dfik[k] * m_dndT[k] * chi2ids[i];
1139 }
1140 a1 += m_dmusdmu[i][j] * fi * (dchi2idsdT[i] + chi3ids[i] * m_dmusdT[i]);
1141 xVector[i] = a1;
1142
1143 // a2
1144 double a2 = 0.;
1145 for (int k = 0; k < NN; ++k) {
1146 a2 += m_dmusdmu[k][j] * (-m_Virial[i][k]) * (dniddTs[k] + chi2ids[k] * m_dmusdT[k]);
1147 }
1148 xVector[i + NN] = a2;
1149 }
1150
1151 solVector = decomp.solve(xVector);
1152
1153 for (int i = 0; i < NN; ++i) {
1154 // dchi2/dT = dchi2til/dT / T^2 - 2 * chi2til / T^3
1155 // Both terms diverge as T -> 0; guard against division by zero.
1156 if (T > 0.)
1157 m_PrimChi2sdT[i][j] = solVector[i] / (xMath::GeVtoifm3() * T * T) - 2. * m_PrimCorrel[i][j] / T / T / T / xMath::GeVtoifm3();
1158 else
1159 m_PrimChi2sdT[i][j] = 0.;
1160 }
1161 }
1162
1163 m_TemperatureDerivativesCalculated = true;
1165 }
1166
1167 m_TemperatureDerivativesCalculated = true;
1168 }
1169
1170
1171
1173 if (!m_Calculated) CalculateDensities();
1174 double ret = 0.;
1175 for(size_t i=0;i<m_densities.size();++i)
1176 if (m_densities[i]>0.)
1177 ret += m_densities[i] / m_DensitiesId[i] * m_TPS->Particles()[i].Density(m_Parameters, IdealGasFunctions::EnergyDensity, m_UseWidth, m_MuStar[i]);
1178 for(size_t i=0;i<m_densities.size();++i)
1179 for(size_t j=0;j<m_densities.size();++j)
1180 ret += -m_Attr[i][j] * m_densities[i] * m_densities[j];
1181
1183 for (size_t i = 0; i < m_densities.size(); ++i) {
1184 double tPid = m_TPS->Particles()[i].Density(m_Parameters, IdealGasFunctions::Pressure, m_UseWidth, m_MuStar[i]);
1185 for (size_t j = 0; j < m_densities.size(); ++j) {
1186 ret += -tPid * m_densities[j] * m_Parameters.T * m_VirialdT[j][i];
1187 ret += m_Parameters.T * m_AttrdT[i][j] * m_densities[i] * m_densities[j];
1188 }
1189 }
1190 }
1191
1192 return ret;
1193 }
1194
1196 if (!m_Calculated) CalculateDensities();
1197 double ret = 0.;
1198 for(size_t i=0;i<m_densities.size();++i)
1199 if (m_densities[i]>0.)
1200 ret += m_densities[i] / m_DensitiesId[i] * m_TPS->Particles()[i].Density(m_Parameters, IdealGasFunctions::EntropyDensity, m_UseWidth, m_MuStar[i]);
1201
1203 for (size_t i = 0; i < m_densities.size(); ++i) {
1204 double tPid = m_TPS->Particles()[i].Density(m_Parameters, IdealGasFunctions::Pressure, m_UseWidth, m_MuStar[i]);
1205 for (size_t j = 0; j < m_densities.size(); ++j) {
1206 ret += -tPid * m_densities[j] * m_VirialdT[j][i];
1207 ret += m_AttrdT[i][j] * m_densities[i] * m_densities[j];
1208 }
1209 }
1210 }
1211
1212 return ret;
1213 }
1214
1216 if (!m_Calculated) CalculateDensities();
1217 double ret = 0.;
1218 for(size_t i=0;i<m_densities.size();++i)
1219 ret += m_TPS->Particles()[i].Density(m_Parameters, IdealGasFunctions::Pressure, m_UseWidth, m_MuStar[i]);
1220 for(size_t i=0;i<m_densities.size();++i)
1221 for(size_t j=0;j<m_densities.size();++j)
1222 ret += -m_Attr[i][j] * m_densities[i] * m_densities[j];
1223 return ret;
1224 }
1225
1226
1228 if (!m_Calculated) CalculateDensities();
1229
1230 return m_scaldens[part];
1231 }
1232
1233 double ThermalModelVDW::MuShift(int id) const
1234 {
1235 if (id >= 0. && id < static_cast<int>(m_Virial.size()))
1236 return m_MuStar[id] - m_Chem[id];
1237 else
1238 return 0.0;
1239 }
1240
1241 double ThermalModelVDW::VirialCoefficient(int i, int j) const
1242 {
1243 if (i<0 || i >= static_cast<int>(m_Virial.size()) || j < 0 || j >= static_cast<int>(m_Virial.size()))
1244 return 0.;
1245 return m_Virial[i][j];
1246 }
1247
1249 {
1250 if (i<0 || i >= static_cast<int>(m_Attr.size()) || j < 0 || j >= static_cast<int>(m_Attr.size()))
1251 return 0.;
1252 return m_Attr[i][j];
1253 }
1254
1255 double ThermalModelVDW::VirialCoefficientdT(int i, int j) const
1256 {
1257 if (i<0 || i >= static_cast<int>(m_VirialdT.size()) || j < 0 || j >= static_cast<int>(m_VirialdT.size()))
1258 return 0.;
1259 return m_VirialdT[i][j];
1260 }
1261
1263 {
1264 if (i<0 || i >= static_cast<int>(m_AttrdT.size()) || j < 0 || j >= static_cast<int>(m_AttrdT.size()))
1265 return 0.;
1266 return m_AttrdT[i][j];
1267 }
1268
1269 std::vector<double> ThermalModelVDW::BroydenEquationsVDW::Equations(const std::vector<double>& x)
1270 {
1271 int NN = m_THM->Densities().size();
1272 vector<double> Ps(NN, 0.);
1273 for (int i = 0; i < NN; ++i) {
1274 Ps[i] = m_THM->TPS()->Particles()[i].Density(m_THM->Parameters(),
1276 m_THM->UseWidth(),
1277 m_THM->ChemicalPotential(i) + x[m_THM->m_MapTodMuStar[i]]
1278 );
1279 }
1280
1281 vector<double> ns(NN, 0.);
1282 for (int i = 0; i < NN; ++i) {
1283 ns[i] = m_THM->TPS()->Particles()[i].Density(m_THM->Parameters(),
1285 m_THM->UseWidth(),
1286 m_THM->ChemicalPotential(i) + x[m_THM->m_MapTodMuStar[i]]
1287 );
1288 }
1289
1290 vector<double> np = m_THM->ComputeNp(x, ns);
1291
1292
1293 vector<double> ret(m_N, 0.);
1294 for (size_t i = 0; i < ret.size(); ++i) {
1295 ret[i] = x[i];
1296 for (int j = 0; j < NN; ++j)
1297 ret[i] += m_THM->VirialCoefficient(m_THM->m_MapFromdMuStar[i], j) * Ps[j]
1298 - (m_THM->AttractionCoefficient(m_THM->m_MapFromdMuStar[i], j)
1299 + m_THM->AttractionCoefficient(j, m_THM->m_MapFromdMuStar[i])) * np[j];
1300 }
1301 return ret;
1302 }
1303
1304 std::vector<double> ThermalModelVDW::BroydenJacobianVDW::Jacobian(const std::vector<double>& x)
1305 {
1306 int NN = m_THM->m_densities.size();
1307 int NNdmu = m_THM->m_MapFromdMuStar.size();
1308
1309 bool attrfl = false;
1310 for (int i = 0; i < NN; ++i) {
1311 for (int j = 0; j < NN; ++j) {
1312 if (m_THM->AttractionCoefficient(i, j) != 0.0) {
1313 attrfl = true;
1314 break;
1315 }
1316 }
1317 if (attrfl) break;
1318 }
1319
1320 MatrixXd densMatrix(NNdmu, NNdmu);
1321 VectorXd solVector(NNdmu), xVector(NNdmu);
1322
1323 std::vector<double> ret(NNdmu*NNdmu, 0.);
1324 {
1325 vector<double> Ps(NN, 0.);
1326 for (int i = 0; i<NN; ++i)
1327 Ps[i] = m_THM->TPS()->Particles()[i].Density(m_THM->Parameters(),
1329 m_THM->UseWidth(),
1330 m_THM->ChemicalPotential(i) + x[m_THM->m_MapTodMuStar[i]]
1331 );
1332
1333 vector<double> ns(NN, 0.);
1334 for (int i = 0; i<NN; ++i)
1335 ns[i] = m_THM->TPS()->Particles()[i].Density(m_THM->Parameters(),
1337 m_THM->UseWidth(),
1338 m_THM->ChemicalPotential(i) + x[m_THM->m_MapTodMuStar[i]]
1339 );
1340
1341 vector<double> chi2s(NN, 0.);
1342 for (int i = 0; i<NN; ++i)
1343 chi2s[i] = m_THM->TPS()->Particles()[i].chiDimensionfull(2, m_THM->Parameters(),
1344 m_THM->UseWidth(),
1345 m_THM->ChemicalPotential(i) + x[m_THM->m_MapTodMuStar[i]]
1346 );
1347
1348 for (int i = 0; i < NNdmu; ++i) {
1349 for (int j = 0; j < NNdmu; ++j) {
1350 densMatrix(i, j) = 0.;
1351 if (i == j)
1352 densMatrix(i, j) += 1.;
1353
1354 for (size_t m = 0; m < m_THM->m_dMuStarIndices[i].size(); ++m) {
1355 densMatrix(i, j) += m_THM->m_Virial[m_THM->m_MapFromdMuStar[j]][m_THM->m_dMuStarIndices[i][m]] * ns[m_THM->m_dMuStarIndices[i][m]];
1356 }
1357 }
1358 }
1359
1360 PartialPivLU<MatrixXd> decomp(densMatrix);
1361
1362
1363 for (int kp = 0; kp < NNdmu; ++kp) {
1364 xVector[kp] = 0.;
1365 for (size_t m = 0; m < m_THM->m_dMuStarIndices[kp].size(); ++m) {
1366 xVector[kp] += ns[m_THM->m_dMuStarIndices[kp][m]];
1367 }
1368 }
1369
1370
1371 solVector = decomp.solve(xVector);
1372
1373 vector<double> ntildek(NNdmu, 0.);
1374 for (int i = 0; i < NNdmu; ++i)
1375 ntildek[i] = solVector[i];
1376
1377 vector<double> np(NN, 0.);
1378 for (int i = 0; i < NN; ++i) {
1379 np[i] = 0.;
1380 for (int k = 0; k < NNdmu; ++k) {
1381 np[i] += m_THM->m_Virial[m_THM->m_MapFromdMuStar[k]][i] * solVector[k];
1382 }
1383 np[i] = (1. - np[i]) * ns[i];
1384 }
1385
1386 for (int kp = 0; kp < NNdmu; ++kp) {
1387
1388 if (attrfl) {
1389 for (int l = 0; l < NNdmu; ++l) {
1390 xVector[l] = 0.;
1391 for (size_t m = 0; m < m_THM->m_dMuStarIndices[l].size(); ++m) {
1392 int ti = m_THM->m_dMuStarIndices[l][m];
1393 if (m_THM->m_MapTodMuStar[ti] != kp)
1394 continue;
1395
1396 double tmps = 1.;
1397 if (ns[ti] != 0.)
1398 tmps = np[ti] / ns[ti];
1399 xVector[l] += chi2s[ti] * pow(xMath::GeVtoifm(), 3) * tmps;
1400 }
1401 }
1402
1403 solVector = decomp.solve(xVector);
1404 for (int i = 0; i < NNdmu; ++i)
1405 if (solVector[i] > 1.) solVector[i] = 1.; // Stabilizer
1406 }
1407
1408 vector<double> dnjdmukp(NN, 0.);
1409 if (attrfl) {
1410 for (int j = 0; j < NN; ++j) {
1411 for (int kk = 0; kk < NNdmu; ++kk) {
1412 dnjdmukp[j] += -m_THM->m_Virial[m_THM->m_MapFromdMuStar[kk]][j] * solVector[kk] * ns[j];
1413 }
1414
1415 if (m_THM->m_MapTodMuStar[j] == kp) {
1416 double tmps = 1.;
1417 if (ns[j] != 0.)
1418 tmps = np[j] / ns[j];
1419 dnjdmukp[j] += tmps * chi2s[j] * pow(xMath::GeVtoifm(), 3);
1420 }
1421 }
1422 }
1423
1424
1425 for (int k = 0; k < NNdmu; ++k) {
1426 if (k == kp)
1427 ret[k*NNdmu + kp] += 1.;
1428 for (size_t m = 0; m < m_THM->m_dMuStarIndices[kp].size(); ++m) {
1429 int tj = m_THM->m_dMuStarIndices[kp][m];
1430 ret[k*NNdmu + kp] += m_THM->m_Virial[m_THM->m_MapFromdMuStar[k]][tj] * ns[tj];
1431 }
1432
1433 if (attrfl) {
1434 for (int j = 0; j < NN; ++j) {
1435 ret[k*NNdmu + kp] += -(m_THM->m_Attr[m_THM->m_MapFromdMuStar[k]][j] + m_THM->m_Attr[j][m_THM->m_MapFromdMuStar[k]]) * dnjdmukp[j];
1436 }
1437 }
1438 }
1439
1440 }
1441 }
1442
1443 return ret;
1444 }
1445
1446 bool ThermalModelVDW::BroydenSolutionCriteriumVDW::IsSolved(const std::vector<double>& x, const std::vector<double>& f, const std::vector<double>& xdelta) const
1447 {
1448 if (xdelta.size() == x.size()) {
1449 double maxdiff = 0.;
1450 for (size_t i = 0; i < xdelta.size(); ++i) {
1451 maxdiff = std::max(maxdiff, fabs(xdelta[i]));
1452 maxdiff = std::max(maxdiff, fabs(f[i]));
1453 }
1454 return (maxdiff < m_MaximumError);
1455 }
1456 else {
1458 }
1459 }
1460
1461 void SetVDWHRGInteractionParameters(ThermalModelBase *model, double a, double b)
1462 {
1463 auto vdWa = GetBaryonBaryonInteractionMatrix(model->TPS(), a);
1464 auto vdWb = GetBaryonBaryonInteractionMatrix(model->TPS(), b);
1465 // Iterate over all hadron pairs
1466 for (int i1 = 0; i1 < model->TPS()->Particles().size(); ++i1) {
1467 for (int i2 = 0; i2 < model->TPS()->Particles().size(); ++i2) {
1468 model->SetAttraction(i1, i2, vdWa[i1][i2]);
1469 model->SetVirial(i1, i2, vdWb[i1][i2]);
1470 }
1471 }
1472 }
1473
1474} // namespace thermalfist
Contains some functions to deal with excluded volumes.
map< string, double > params
virtual bool IsSolved(const std::vector< double > &x, const std::vector< double > &f, const std::vector< double > &xdelta=std::vector< double >()) const
Definition Broyden.cpp:216
int m_N
The number of equations.
Definition Broyden.h:66
Class implementing the Broyden method to solve a system of non-linear equations.
Definition Broyden.h:132
double MaxDifference() const
Definition Broyden.h:239
virtual std::vector< double > Solve(const std::vector< double > &x0, BroydenSolutionCriterium *solcrit=NULL, int max_iterations=MAX_ITERS)
Definition Broyden.cpp:83
int Iterations() const
Definition Broyden.h:229
int MaxIterations() const
Definition Broyden.h:234
Abstract base class for an HRG model implementation.
virtual void CalculateSusceptibilityMatrix()
Calculates the conserved charges susceptibility matrix.
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...
virtual void SetVirial(int, int, double)
Set the excluded volume coefficient .
virtual void FillChemicalPotentials()
Sets the chemical potentials of all particles.
@ QvdW
Quantum van der Waals model.
virtual void SetChemicalPotentials(const std::vector< double > &chem=std::vector< double >(0))
Sets the chemical potentials of all particles.
double ChemicalPotential(int i) const
Chemical potential of particle species i.
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 &params=ThermalModelParameters())
Construct a new ThermalModelBase object.
bool UseWidth() const
Whether finite resonance widths are considered.
virtual void CalculateDensities()
Calculates the primordial and total (after decays) densities of all species.
virtual void SetAttraction(int, int, double)
Set the vdW mean field attraction coefficient .
const ThermalModelParameters & Parameters() const
@ GCE
Grand canonical ensemble.
virtual void CalculateTwoParticleFluctuationsDecays()
Computes particle number correlations and fluctuations for all final-state particles which are marked...
virtual void SetChemicalPotentials(const std::vector< double > &chem=std::vector< double >(0))
Sets the chemical potentials of all particles.
std::vector< double > m_chiarb
virtual double CalculateEnergyDensityDerivativeT()
virtual void WriteInteractionParameters(const std::string &filename)
Write the QvdW interaction parameters to a file.
double VirialCoefficientdT(int i, int j) const
The temperature derivative of the eigenvolume parameter .
virtual void ChangeTPS(ThermalParticleSystem *TPS)
Change the particle list.
bool m_VDWComponentMapCalculated
Whether the mapping to components with the same VDW parameters has been calculated.
virtual std::vector< double > SearchSingleSolution(const std::vector< double > &muStarInit)
Uses the Broyden method with a provided initial guess to determine the shifted chemical potentials by...
virtual double MuShift(int id) const
The shift in the chemical potential of particle species i due to the QvdW interactions.
std::vector< double > m_DensitiesId
Vector of ideal gas densities with shifted chemical potentials.
virtual void ReadInteractionParameters(const std::string &filename)
Reads the QvdW interaction parameters from a file.
void FillVirialEV(const std::vector< std::vector< double > > &bij=std::vector< std::vector< double > >(0))
Same as FillVirial() but uses the matrix of excluded-volume coefficients as input instead of radii.
double AttractionCoefficient(int i, int j) const
QvdW mean field attraction coefficient .
std::vector< int > m_MapTodMuStar
void CalculateVDWComponentsMap()
Partitions particles species into sets that have identical VDW parameters.
virtual std::vector< double > CalculateChargeFluctuations(const std::vector< double > &chgs, int order=4, bool dimensionfull=false)
Calculates fluctuations (diagonal susceptibilities) of an arbitrary "conserved" charge.
void FillChemicalPotentials()
Sets the chemical potentials of all particles.
std::vector< std::vector< double > > m_AttrdT
void CalculateTwoParticleCorrelations()
Computes the fluctuations and correlations of the primordial particle numbers.
std::vector< double > ComputeNp(const std::vector< double > &dmustar)
std::vector< double > SearchFirstSolution(int iters=50)
Try different initial guesses and return the first valid solution found.
virtual void FillAttraction(const std::vector< std::vector< double > > &aij=std::vector< std::vector< double > >(0))
double AttractionCoefficientdT(int i, int j) const
The temperature derivative of the QvdW attraction parameter .
std::vector< std::vector< int > > m_dMuStarIndices
virtual ~ThermalModelVDW(void)
Destroy the ThermalModelVDW object.
virtual void CalculateTemperatureDerivatives()
Computes the temperature derivatives of densities, shifted chemical potentials, and primordial hadron...
std::vector< int > m_MapFromdMuStar
std::vector< std::vector< double > > m_Virial
std::vector< double > m_MuStar
Vector of the shifted chemical potentials.
void CalculateFluctuations()
Computes the fluctuation observables.
virtual double ParticleScalarDensity(int part)
std::vector< double > m_scaldens
Vector of scalar densities. Not used.
virtual void CalculatePrimordialDensities()
Calculates the primordial densities of all species.
std::vector< std::vector< double > > m_chi
std::vector< std::vector< double > > m_VirialdT
bool m_SearchMultipleSolutions
Whether multiple solutions are considered.
ThermalModelVDW(ThermalParticleSystem *TPS_, const ThermalModelParameters &params=ThermalModelParameters())
Construct a new ThermalModelVDW object.
bool m_LastBroydenSuccessFlag
Whether Broyden's method was successfull.
double VirialCoefficient(int i, int j) const
Excluded volume coefficient .
virtual void FillVirial(const std::vector< double > &ri=std::vector< double >(0))
Fills the excluded volume coefficients based on the provided radii parameters for all species.
std::vector< std::vector< double > > m_Attr
Matrix of the attractive QvdW coefficients .
std::vector< double > SearchMultipleSolutions(int iters=300)
Uses the Broyden method with different initial guesses to look for different possible solutions of th...
virtual double CalculateEntropyDensityDerivativeT()
Class containing all information about a particle specie.
double Density(const ThermalModelParameters &params, IdealGasFunctions::Quantity type=IdealGasFunctions::ParticleDensity, bool useWidth=0, double mu=0.) const
Computes a specified ideal gas thermodynamic function.
Class containing the particle list.
std::vector< std::string > split(const std::string &s, char delim)
double brr(double r1, double r2)
Computes the symmetric 2nd virial coefficient of the classical hard spheres equation of state from t...
constexpr double GeVtoifm()
A constant to transform GeV into fm .
Definition xMath.h:25
constexpr double GeVtoifm3()
A constant to transform GeV into fm .
Definition xMath.h:31
constexpr double mnucleon()
Nucleon's mass. Value as in UrQMD.
Definition xMath.h:34
The main namespace where all classes and functions of the Thermal-FIST library reside.
Definition CosmicEoS.h:9
std::vector< std::vector< double > > GetBaryonBaryonInteractionMatrix(const ThermalParticleSystem *TPS, double param)
Returns the matrix of attraction and repulsion parameters for baryon-baryon and antibaryon-antibaryon...
void SetVDWHRGInteractionParameters(ThermalModelBase *model, double a, double b)
Sets vdW interactions for baryon-baryon and antibaryon-antibaryon pairs as in https://arxiv....
Structure containing all thermal parameters of the model.
Contains some extra mathematical functions used in the code.