LORENE
eos_compose_fit_build.C
1/*
2 * Methods of class Eos_compose_fit building.
3 *
4 * (see file eos_compose_fit.h for documentation).
5 *
6 */
7
8/*
9 * Copyright (c) 2022 Jerome Novak
10 *
11 * This file is part of LORENE.
12 *
13 * LORENE is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * LORENE is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with LORENE; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 *
27 */
28
29
30
31
32/*
33 * $Id: eos_compose_fit_build.C,v 1.6 2023/07/12 15:39:30 j_novak Exp $
34 * $Log: eos_compose_fit_build.C,v $
35 * Revision 1.6 2023/07/12 15:39:30 j_novak
36 * Reversed order of matching the EoS fit: it now starts from the crust (polytrope) and adjusts the kappa of this crust so as to have the right pressure at the highest density in the original table.
37 *
38 * Revision 1.4 2023/03/17 16:10:46 j_novak
39 * Better computation of gamma_low, to avoid jumps in sound speed.
40 *
41 * Revision 1.3 2023/01/27 16:10:35 j_novak
42 * A polytrope (class Eos_poly) is used for low and high enthalpies.
43 *
44 * Revision 1.2 2022/07/21 12:34:18 j_novak
45 * Corrected units
46 *
47 * Revision 1.1 2022/04/15 13:39:24 j_novak
48 * New class Eos_compose_fit to generate fitted EoSs from CompOSE tables.
49 *
50 *
51 * $Header: /cvsroot/Lorene/C++/Source/Eos/eos_compose_fit_build.C,v 1.6 2023/07/12 15:39:30 j_novak Exp $
52 *
53 */
54
55// Headers Lorene
56#include "eos_compose_fit.h"
57#include "scalar.h"
58#include "utilitaires.h"
59#include "unites.h"
60#include "graphique.h"
61
62namespace Lorene {
63 void Eos_compose_fit::read_compose_data(int& nbp, Tbl*& logh_read,
64 Tbl*& logp_read, Tbl*& loge_read,
65 Tbl*& lognb_read, Tbl*& gam1_read) {
66 // Files containing data and a test
67 //---------------------------------
68
69 string file_nb = tablename + "eos.nb" ;
70 string file_thermo = tablename + "eos.thermo" ;
71
72 cout << "opening " << file_nb << " and " << file_thermo << " ... " << flush ;
73 ifstream in_nb(file_nb.data()) ;
74 if (!in_nb) {
75 cerr << "Eos_compose_fit::read_compose_data:" << endl ;
76 cerr << "Problem in opening the EOS file!" << endl ;
77 cerr << "While trying to open " << file_nb << endl ;
78 cerr << "Aborting..." << endl ;
79 abort() ;
80 }
81
82 // obtaining the size of the tables for memory allocation
83 //-------------------------------------------------------
84
85 int index1, index2 ;
86 in_nb >> index1 >> index2 ;
87 nbp = index2 - index1 + 1 ;
88 assert(nbp > 0) ;
89
90 Tbl press(nbp) ; press.set_etat_qcq() ;
91 Tbl nb(nbp) ; nb.set_etat_qcq() ;
92 Tbl ener(nbp) ; ener.set_etat_qcq() ;
93
94 if (logh_read != nullptr) delete logh_read ;
95 logh_read = new Tbl(nbp) ;
96 logh_read->set_etat_qcq() ;
97 if (logp_read != nullptr) delete logp_read ;
98 logp_read = new Tbl(nbp) ;
99 logp_read->set_etat_qcq() ;
100 if (loge_read != nullptr) delete loge_read ;
101 loge_read = new Tbl(nbp) ;
102 loge_read->set_etat_qcq() ;
103 if (lognb_read != nullptr) delete lognb_read ;
104 lognb_read = new Tbl(nbp) ;
105 lognb_read->set_etat_qcq() ;
106 if (gam1_read != nullptr) delete gam1_read ;
107 gam1_read = new Tbl(nbp) ;
108 gam1_read->set_etat_qcq() ;
109
110 // Variables and conversion
111 //-------------------------
112 double nb_fm3, rho_cgs, p_cgs, p_over_nb_comp, eps_comp ;
113 double dummy_x ;
114 int dummy_n ;
115
116 //# Dealing with units could be optimized...
117 double rhonuc_cgs = Unites::rhonuc_si * 1e-3 ;
118 double c2_cgs = Unites::c_si * Unites::c_si * 1e4 ;
119 double m_neutron_MeV, m_proton_MeV ;
120
121 ifstream in_p_rho (file_thermo.data()) ;
122 if (!in_p_rho) {
123 cerr << "Reading CompOSE data: " << endl ;
124 cerr << "Problem in opening the EOS file!" << endl ;
125 cerr << "While trying to open " << file_thermo << endl ;
126 cerr << "Aborting..." << endl ;
127 abort() ;
128 }
129 in_p_rho >> m_neutron_MeV >> m_proton_MeV ; //Neutron and proton masses
130 in_p_rho.ignore(1000, '\n') ;
131
132 // Conversion from MeV/fm^3 to cgs
133 double p_convert = Unites::mev_si * 1.e45 * 10. ;
134 // From meV/fm^3 to g/cm^3
135 double eps_convert = Unites::mev_si * 1.e42 / (Unites::c_si*Unites::c_si) ;
136
137 cout << " done. " << endl ;
138 cout << "Reading the table ... " << flush ;
139
140 //--------------------------------------
141 // Main loop reading the CompOSE tables
142 //--------------------------------------
143 for (int i=0; i<nbp; i++) {
144 in_nb >> nb_fm3 ;
145 in_p_rho >> dummy_n >> dummy_n >> dummy_n >> p_over_nb_comp ;
146 in_p_rho >> dummy_x >> dummy_x >> dummy_x >> dummy_x >> dummy_x
147 >> eps_comp ;
148 in_p_rho.ignore(1000, '\n') ;
149 p_cgs = p_over_nb_comp * nb_fm3 * p_convert ;
150 rho_cgs = ( eps_comp + 1. ) * m_neutron_MeV * nb_fm3 * eps_convert ;
151
152 if ( (nb_fm3 < 0) || (rho_cgs < 0) || (p_cgs < 0) ){
153 cerr << "Eos_compose_fit::read_compose_data: " << endl ;
154 cerr << "Negative value in table!" << endl ;
155 cerr << "nb = " << nb_fm3 << ", rho = " << rho_cgs <<
156 ", p = " << p_cgs << endl ;
157 cerr << "Aborting..." << endl ;
158 abort() ;
159 }
160
161 press.set(i) = p_cgs / c2_cgs ;
162 nb.set(i) = nb_fm3 ;
163 ener.set(i) = rho_cgs ;
164
165 // log-quantities in cgs units
166 logp_read->set(i) = log( press(i) / rhonuc_cgs ) ;
167 loge_read->set(i) = log( ener(i) / rhonuc_cgs ) ;
168 lognb_read->set(i) = log( 10.* nb(i) ) ;
169 }
170 nb_max = nb(nbp-1) ;
171 cout << " done." << endl ;
172 // -----------------------------------------
173 // End of the reading of the CompOSE tables
174 // -----------------------------------------
175
176 cout << "Computation of derived quantities and file outputs.. " << flush ;
177
178 // Computation of various derived quantities
179 //-------------------------------------------
180
181 // log-enthallpy, with a shift ensuring h=10^{-14} for the lowest density
182 double ww = 0. ;
183 for (int i=0; i<nbp; i++) {
184 double h = log( (ener(i) + press(i)) / (10 * nb(i) * rhonuc_cgs) ) ;
185
186 if (i==0) { ww = h ; }
187 h = h - ww + 1.e-14 ;
188
189 logh_read->set(i) = log( h ) ;
190 }
191
192 // d log(p) / d log(n) -> adiabatic index \Gamma_1
193 compute_derivative((*lognb_read), (*logp_read), (*gam1_read) ) ;
194
195 cout << "done" << endl ;
196
197 } // End (read_compose_data)
198
199
200 void Eos_compose_fit::adiabatic_index_fit(int i_min, int i_mid, const Tbl&
201 logh_read, const Tbl& logp_read,
202 const Tbl&, const Tbl&
203 lognb_read, const Tbl& gam1_read) {
204
205 int nbp = logh_read.get_dim(0) ;
206 double nb0_max = exp(lognb_read(nbp-1)) ;
207
208 assert((mp != nullptr) && (mg != nullptr)) ;
209 const Map_af& mpd = *mp ;
210 int nz = mg->get_nzone() ;
211 assert(nz == 2) ;
212 int nr = mg->get_nr(0) ;
213#ifndef NDEBUG
214 for (int l=1; l<nz; l++)
215 assert(mg->get_nr(l) == nr) ;
216#endif
217 const Coord& xx = mpd.r ; // xx = log(h) = log(log(e+p/m_B n_B))
218 double x_max = (+xx)(nz-1, 0, 0, nr-1) ;
219 double x_mid = (+xx)(1, 0, 0, 0) ;
220 double x_min = (+xx)(0, 0, 0, 0) ;
221
222 if (log_p != nullptr) delete log_p ;
223 if (log_e != nullptr) delete log_e ;
224 if (log_nb != nullptr) delete log_nb ;
225 if (log_cs2 != nullptr) delete log_cs2 ;
226
227 int np_gam = 0 ;
228 double mean_gam = 0. ;
229 for (int i=0; i<i_min; i++) {
230 mean_gam += gam1_read(i) ;
231 np_gam++ ;
232 }
233
234 Scalar expexpx(mpd) ; // e^(e^x) , or simply (e+p)/(m_B n_B)
235 expexpx = exp(exp(xx)) ;
236 expexpx.std_spectral_base() ;
237 Scalar expx(mpd) ; // e^x or simply h = log((e+p)/(m_B n_B))
238 expx = exp(xx) ;
239 expx.std_spectral_base() ;
240
241 mean_gam /= double(np_gam) ;
242 cout << "Mean Gamma_1 = " << mean_gam << endl ;
243
244 // Fitting of the adiabatic index \Gamma_1
245 Scalar gam1_spec(mpd) ;
246 gam1_spec = mean_gam ;
247 gam1_spec.std_spectral_base() ;
248
249 // High density part : polynomial fit (polynomial regression)
250 //--------------------------------------------------------------
251 int ndata = nbp - i_mid ;
252 Tbl xdata(ndata) ; xdata.set_etat_qcq() ;
253 Tbl ydata(ndata) ; ydata.set_etat_qcq() ;
254 for (int i=i_mid; i<nbp; i++) {
255 xdata.set(i-i_mid) = 2.*(logh_read(i) - x_mid)
256 / (x_max - x_mid) - 1. ;
257 ydata.set(i-i_mid) = gam1_read(i) ;
258 }
259
260 Tbl tcoefs = poly_regression(xdata, ydata, n_coefs) ;
261
262 // Putting coefficients to the 'Scalar' object
263 gam1_spec.set_spectral_va().coef() ;
264 for (int i=0; i<=n_coefs; i++) {
265 (*gam1_spec.set_spectral_va().c_cf).set(1, 0, 0, i) = tcoefs(i) ;
266 }
267
268 // Not nice, but only simple way to update values on grid points
269 if (gam1_spec.set_spectral_va().c != nullptr) {
270 delete gam1_spec.set_spectral_va().c ;
271 gam1_spec.set_spectral_va().c = nullptr ;
272 }
273 gam1_spec.set_spectral_va().coef_i() ;
274
275 // Intermediate part : linear interpolation
276 //------------------------------------------
277 Scalar interm(mpd) ;
278 // Linear formula
279 interm = mean_gam
280 + (gam1_spec.val_grid_point(1, 0, 0, 0) - mean_gam)
281 * (xx - x_min) / (x_mid - x_min) ;
282
283 gam1_spec.set_domain(0) = interm.domain(0) ;
284
285 // Low density part : polytrope, \Gamma_1 = const.
286 //-------------------------------------------------
287
288 Scalar YYY(mpd) ;
289 // Determining kappa_low
290 double p_min = exp(logp_read(i_min)) ;
291 double ccc = (mean_gam - 1.) / mean_gam ;
292 double kappa_low0 = pow(ccc*expm1(exp(x_min)), mean_gam)
293 / pow(p_min, mean_gam*ccc) ;
294 double kappa_low1 = 0.1*kappa_low0 ;
295 double logp_max0 = integrate_equations(kappa_low0, mean_gam, gam1_spec, expx,
296 expexpx, YYY) ;
297 double logp_max = logp_read(nbp-1) ;
298
299 // 'kappa_low' is determined to get the correct pressure at the higher end
300 //-------------------------------------------------------------------------
301 while(fabs(logp_max0 - logp_max)/logp_max > 1.e-3) {
302 double logp_max1 = integrate_equations(kappa_low1, mean_gam, gam1_spec, expx,
303 expexpx, YYY) ;
304 double kappa_low_new
305 = (kappa_low0*(logp_max1 -logp_max)- kappa_low1*(logp_max0 - logp_max))
306 / (logp_max1 - logp_max0) ;
307 cout << "Kappa(new) = " << kappa_low_new << ", logp = " << logp_max1 << endl ;
308 if (kappa_low_new < 0.) kappa_low_new = 0.01*kappa_low0 ;
309 kappa_low0 = kappa_low1 ;
310 logp_max0 = logp_max1 ;
311 kappa_low1 = kappa_low_new ;
312 }
313
314 //des_profile(YYY, x_min, x_max, 0, 0) ;
315
316 // sound speed : log(cs^2) = log(Y*\Gamma_1)
317 log_cs2 = new Scalar(log(YYY*gam1_spec)) ;
318 log_cs2->std_spectral_base();
319
320 // Pressure
321 Scalar spec_press = exp((*log_p)) ;
322 spec_press.std_spectral_base( );
323
324 // Energy density
325 Scalar spec_ener = spec_press*(1./YYY - 1.) ; spec_ener.std_spectral_base() ;
326 log_e = new Scalar(log(spec_ener)) ;
327 log_e->std_spectral_base() ;
328
329 // Baryon density
330 Scalar spec_nbar = spec_press / (YYY * expexpx) ;
331 cout << "Relative difference in baryon density at the last point" << endl ;
332 cout << "(fitted computed / original tabulated) : "
333 << fabs(1. - spec_nbar.val_grid_point(nz-1, 0, 0, nr-1) / nb0_max)
334 << endl ;
335 log_nb = new Scalar(log(spec_nbar)) ;
336 log_nb->std_spectral_base() ; // log_nb_spec = log(n_B)
337
338 log_p->set_spectral_va().coef_i() ;
339 log_e->set_spectral_va().coef_i() ;
340 log_nb->set_spectral_va().coef_i() ;
341 spec_nbar.set_spectral_va().coef_i() ;
342 log_cs2->set_spectral_va().coef_i() ;
343
344 // Matching to the high-density part polytrope
345 //--------------------------------------------
346
347 double gam_high = gam1_spec.val_grid_point(1, 0, 0, nr-1) ;
348 double kappa_high = spec_press.val_grid_point(1, 0, 0, nr-1)
349 / pow(spec_nbar.val_grid_point(1, 0, 0, nr-1), gam_high) ;
350
351 double mu_high = (spec_ener.val_grid_point(1, 0, 0, nr-1)
352 - kappa_high/(gam_high - 1.)
353 * pow(spec_nbar.val_grid_point(1, 0, 0, nr-1), gam_high))
354 / spec_nbar.val_grid_point(1, 0, 0, nr-1);
355
356 if (p_eos_high != nullptr) delete p_eos_high ;
357 p_eos_high = new Eos_poly(gam_high, kappa_high, mu_high, mu_high) ;
358
359 cout << "... done (analytic representation)" << endl ;
360
361 } // End (adiabatic_index_fit)
362
364 (double kappa_low, double mean_gam, const Scalar& gam1_spec,
365 const Scalar& expx, const Scalar& expexpx, Scalar& YYY) {
366
367 // Enthalpy at lower end of the grid
368 double ent_min = expx.val_grid_point(0, 0, 0, 0) ;
369
370 // The low-density part is defined through an "Eos_poly" object
371 if (p_eos_low != nullptr) delete p_eos_low ;
372 p_eos_low = new Eos_poly(mean_gam, kappa_low) ;
373
374 // pressure & energy from th epolytropic EoS
375 double p_min = p_eos_low->press_ent_p(ent_min) ;
376 double e_min = p_eos_low->ener_ent_p(ent_min) ;
377
378 // Solution of the differential equations to compute pressure, energy, etc
379 //--------------------------------------------------------------------------
380 // rhs: f = (\Gamma_1 - 1.)/\Gamma_1 * e^x * e^(e^x)
381 Scalar fff = ((gam1_spec-1.)/gam1_spec)*expx*expexpx ;
382 fff.std_spectral_base() ;
383
384 // First integration
385 //-------------------
386 // F = primitive(f)
387 Scalar FFF = fff.primr() ;
388 FFF.std_spectral_base() ;
389 // Integration constant
390 double Y_min = p_min / (e_min + p_min) ;
391 double A_min = expexpx.val_grid_point(0, 0, 0, 0)*Y_min
392 - FFF.val_grid_point(0, 0, 0, 0) ;
393
394 // Y is solution of Y' + Y e^x = f
395 YYY = (A_min + FFF)/expexpx ;
396
397 // Second integration
398 //--------------------
399 // \Pi' = e^x / Y
400 Scalar Pidot = expx / YYY ;
401 if (log_p != nullptr) delete log_p ;
402 log_p = new Scalar(Pidot.primr()) ; // log_p_spec = log(p)
403 // Integration constant
404 double lnp0 = log(p_min) - log_p->val_grid_point(0, 0, 0, 0) ;
405 (*log_p) = (*log_p) + lnp0 ;
406
407 // returning the log of pressure at the higher end of the grid
408 return log_p->val_grid_point(1, 0, 0, mg->get_nr(1)-1) ;
409 }
410
411}
Active physical coordinates and mapping derivatives.
Definition coord.h:90
const Eos_poly * p_eos_low
Pointer on a polytropic EoS for the description of low densities (nb<nb_min).
const Map_af * mp
Mapping in .
void read_compose_data(int &nbp, Tbl *&logh, Tbl *&logp, Tbl *&loge, Tbl *&lognb, Tbl *&gam1)
Reads Compose data and stores the values of thermodynamic quantities.
const Mg3d * mg
Multi-grid defining the number of domains and spectral coefficients.
double integrate_equations(double kappa, double mean_gam, const Scalar &gamma1, const Scalar &log_ent, const Scalar &ent, Scalar &YYY)
Integrates the differential system giving all thermo quantities from the adiabatic index.
Scalar * log_nb
Table of .
Scalar * log_e
Table of .
void adiabatic_index_fit(int i_min, int i_max, const Tbl &logh_read, const Tbl &logp_read, const Tbl &loge_read, const Tbl &lognb_read, const Tbl &gam1_read)
From the read values, makes the fit on the adiabatic index and deduces the other quantities from ther...
string tablename
Name of the file containing the tabulated data.
const Eos_poly * p_eos_high
Pointer on a polytropic EoS for the description of high densities (nb>nb_max).
double nb_max
Higher bound on the density, above which the EoS is assumed to be a polytrope.
Scalar * log_p
Table of .
int n_coefs
Number of coeficients for polynomial regression.
Scalar * log_cs2
Table of .
Polytropic equation of state (relativistic case).
Definition eos.h:809
Affine radial mapping.
Definition map.h:2042
Tensor field of valence 0 (or component of a tensorial field).
Definition scalar.h:393
virtual void std_spectral_base()
Sets the spectral bases of the Valeur va to the standard ones for a scalar field.
Definition scalar.C:790
double val_grid_point(int l, int k, int j, int i) const
Returns the value of the field at a specified grid point.
Definition scalar.h:643
Tbl & set_domain(int l)
Read/write of the value in a given domain.
Definition scalar.h:621
Valeur & set_spectral_va()
Returns va (read/write version).
Definition scalar.h:610
const Tbl & domain(int l) const
Read-only of the value in a given domain.
Definition scalar.h:631
Scalar primr(bool null_infty=true) const
Computes the radial primitive which vanishes for .
Basic array class.
Definition tbl.h:161
void set_etat_qcq()
Sets the logical state to ETATQCQ (ordinary state).
Definition tbl.C:364
double & set(int i)
Read/write of a particular element (index i) (1D case).
Definition tbl.h:281
int get_dim(int i) const
Gives the i-th dimension (ie dim.dim[i]).
Definition tbl.h:403
Mtbl * c
Values of the function at the points of the multi-grid.
Definition valeur.h:309
void coef_i() const
Computes the physical value of *this.
void coef() const
Computes the coeffcients of *this.
Cmp exp(const Cmp &)
Exponential.
Definition cmp_math.C:273
Cmp pow(const Cmp &, int)
Power .
Definition cmp_math.C:351
Cmp log(const Cmp &)
Neperian logarithm.
Definition cmp_math.C:299
Tbl poly_regression(const Tbl &, const Tbl &, int)
Polynomial regression, giving Chebyshev coefficients.
void compute_derivative(const Tbl &xx, const Tbl &ff, Tbl &dfdx)
Derives a function defined on an unequally-spaced grid, approximating it by piecewise parabolae.
Definition misc.C:64
Lorene prototypes.
Definition app_hor.h:67