LALSimulation  5.4.0.1-fe68b98
LALSimNeutronStarEOSSpectralDecomposition.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2013 M. Carney, L. Wade
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with with program; see the file COPYING. If not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17  * MA 02110-1301 USA
18  */
19 /**
20  * @addtogroup LALSimNeutronStarEOS_c
21  * @{
22  */
23 /**
24  * @name Creation routines for spectral decomposition equations of state
25  * @{
26  */
27 
28 #include <lal/LALSimReadData.h>
29 #include <gsl/gsl_interp.h>
30 #include <lal/LALSimNeutronStar.h>
31 
32 /** @cond */
33 
34 /* Maps the abscissae from [-1,1] to [a,b] */
35 static void GLBoundConversion(double a, double b, double abscissae[], int nEval)
36 {
37  int i;
38 
39  // Converting to new evalutation points
40  for(i=0;i<nEval;i++)
41  {
42  abscissae[i]=((b-a)/2.0)*abscissae[i] + (a+b)/2.0;
43  }
44 }
45 
46 /* Resets 10 point array to standard abscissae */
47 static void resetAbscissae(double abscissae[])
48 {
49  abscissae[0] = -0.9739065285171717;
50  abscissae[1] = -0.8650633666889845;
51  abscissae[2] = -0.6794095682990244;
52  abscissae[3] = -0.4333953941292472;
53  abscissae[4] = -0.1488743389816312;
54  abscissae[5] = 0.1488743389816312;
55  abscissae[6] = 0.4333953941292472;
56  abscissae[7] = 0.6794095682990244;
57  abscissae[8] = 0.8650633666889845;
58  abscissae[9] = 0.9739065285171717;
59 }
60 
61 /* Spectral decomposition of eos's adiabatic index */
62 static double AdiabaticIndex(double gamma[], double x, int size)
63 {
64  double Gamma, logGamma = 0;
65  int i;
66  for(i=0;i<size;i++)
67  {
68  logGamma += gamma[i]*pow(x,(double) i);
69  }
70  Gamma = exp(logGamma);
71  return Gamma;
72 }
73 
74 /* Returns energy density given a pressure and spectral decomposition parameters */
75 static double eos_e_of_p_spectral_decomposition(double x, double gamma[], int size, double p0, double e0)
76 {
77  // Integration/Placeholder variables
78  int i;
79  int j;
80  int nEval = 10;
81  double Integral;
82  double IPrime;
83  double e, mu;
84 
85  // Declaring arrays needed for Gauss-Legendre abscissae and weights
86  double abscissae[nEval], abscissaePrime[nEval];
87  resetAbscissae(abscissae);
88  double weights[] = {
89  0.0666713443086881,
90  0.1494513491505806,
91  0.2190863625159820,
92  0.2692667193099963,
93  0.2955242247147529,
94  0.2955242247147529,
95  0.2692667193099963,
96  0.2190863625159820,
97  0.1494513491505806,
98  0.0666713443086881
99  };
100 
101  /* Calculation of \mu(x) */
102  /* Calculation based on integral in Eq. 8 of PRD 82 103011 (2010):
103 
104  \mu(x) = \exp[ - Integral(x) ]
105 
106  Intergral(x) = \int_{0}^{x} 1 / \Gamma(xp) dxp
107 
108  = (x/2) \int_{-1}^{1} 1 / \Gamma[ y(t) ] dt,
109 
110  where y(t) = (x/2) t + x/2.
111 
112  10-point Gaussian quadrature integration
113  */
114  Integral = 0.0;
115 
116  /* Shift abscissae, anticipating a change of integration limits */
117  GLBoundConversion(0.0,x,abscissae, nEval);
118  for(i=0;i<nEval;i++)
119  {
120  /* Integral for mu(x) calculation */
121  Integral += weights[i]*pow(AdiabaticIndex(gamma,abscissae[i],size),-1.0);
122  }
123 
124  Integral*=(x/2.0);
125  mu = exp(-Integral);
126  /* end \mu(x) calculation */
127 
128  /* Calculation of \epsilon(x) */
129  /* Calculation based on integral in Eq. 7 of PRD 82 103011 (2010):
130 
131  \epsilon(x) = \epsilon_0 / \mu(x) + p_0 * Integral / \mu(x)
132 
133  Intergral(x) = \int_{0}^{x} \mu(xp) \exp(xp) / \Gamma(xp) dxp
134 
135  = (x/2) \int_{-1}^{1} \mu[ y(t) ] \exp[ y(t) ] / \Gamma[ y(t) ] dt,
136 
137  where y(t) = (x/2) t + x/2.
138 
139  10-point Gaussian quadrature integration
140  */
141  Integral = 0.0;
142 
143  for(i=0;i<nEval;i++)
144  {
145  /* calculate \mu(xp) */
146  IPrime = 0.0;
147  resetAbscissae(abscissaePrime);
148  GLBoundConversion(0.0,abscissae[i],abscissaePrime, nEval);
149 
150  for(j=0;j<nEval;j++)
151  {
152  IPrime += weights[j]*pow(AdiabaticIndex(gamma,abscissaePrime[j],size),-1.0);
153  }
154 
155  IPrime *= (abscissae[i]/2.0);
156  IPrime = exp(-IPrime);
157  /* end mu(xp) calculation, and calculate integral in epsilon(x) */
158  Integral += weights[i]*(exp(abscissae[i])*IPrime/AdiabaticIndex(gamma,abscissae[i],size));
159  }
160 
161  Integral*=(x/2.0);
162 
163  e = e0/mu +(p0/mu)*Integral;
164  /* end epsilon(x) calculation */
165 
166  return e;
167 }
168 
169 /** @endcond */
170 
171 /**
172  * @brief Reads spectral decomposition eos parameters to make an eos.
173  * @details Reads an array of spectral decomposition eos parameters and the
174  * array length to construct an eos using a spectral decomposition of the
175  * adiabatic index. The specifics of this implementation are outlined in
176  * PRD 98 063004 (2018). Generic model presented in PRD 82 103011 (2010).
177  * @param[in] gamma[] Array of spectral decomposition eos parameters.
178  * @param[in] size The length of the gamma array.
179  * @return A pointer to neutron star equation of state structure.
180  */
182 {
183  LALSimNeutronStarEOS * eos;
184  size_t ndat_low = 69;
185  size_t ndat = ndat_low + 500;
186  size_t i;
187 
188  // Minimum pressure and energy density of core EOS geom
189  // Chosen to correspond to e0 and p0 for SLY EOS just below 0.5*rho_nuc.
190  // See Sec IID of PRD 98 063004 (2018) for more details.
191  // Note: Make adjustable in the future.
192  double e0 = 9.54629006e-11; // For reference: 1.1555e35 [cgs]
193  double p0 = 4.43784199e-13; // For reference: 5.3716e32 [cgs]
194 
195  double xmax = 12.3081;
196  double pmax = p0*exp(xmax); // For reference: 9.82905e-8 [geom], 1.18973e38 [cgs]
197 
198  // Declaring array and allocating memory space
199  double *edat;
200  double *pdat;
201  double xdat[ndat-ndat_low];
202 
203  pdat = XLALCalloc(ndat, sizeof(*pdat));
204  edat = XLALCalloc(ndat, sizeof(*edat));
205  if (pdat == NULL || edat == NULL) {
206  XLALFree(pdat);
207  XLALFree(edat);
209  }
210 
211  // Low density EOS values to be stitched (SLy, in geom)
212  // These values agree with LALSimNeutronStarEOS_SLY.dat
213  double pdat_low[]={
214  0.00000000e+00, 2.49730009e-31, 1.59235347e-30,
215  1.01533235e-29, 6.47406376e-29, 4.12805731e-28,
216  2.63217321e-27, 1.67835262e-26, 1.07016799e-25,
217  6.82371225e-25, 4.35100369e-24, 1.91523482e-23,
218  8.06001537e-23, 3.23144235e-22, 4.34521997e-22,
219  1.18566090e-21, 3.16699528e-21, 8.31201995e-21,
220  2.15154075e-20, 5.51600847e-20, 7.21972469e-20,
221  1.34595234e-19, 2.50269468e-19, 3.41156366e-19,
222  4.16096744e-19, 5.66803746e-19, 1.05098304e-18,
223  1.94663211e-18, 3.60407863e-18, 4.67819652e-18,
224  6.36373536e-18, 8.65904266e-18, 1.17739845e-17,
225  1.60126190e-17, 2.06809005e-17, 2.81253637e-17,
226  3.82385968e-17, 4.91532870e-17, 6.68349199e-17,
227  9.08868981e-17, 1.19805457e-16, 1.23523557e-16,
228  1.67975513e-16, 2.14575704e-16, 2.38949918e-16,
229  2.71834450e-16, 3.69579177e-16, 4.80543818e-16,
230  6.22823125e-16, 6.44883854e-16, 6.51906933e-16,
231  6.90079430e-16, 7.51717272e-16, 7.84188682e-16,
232  8.12280996e-16, 8.94822824e-16, 1.78030908e-15,
233  2.83170525e-15, 4.35257355e-15, 6.44272433e-15,
234  9.21014776e-15, 1.72635532e-14, 2.96134301e-14,
235  4.76007735e-14, 7.28061891e-14, 1.06973879e-13,
236  1.78634067e-13, 3.17897582e-13, 4.16939514e-13};
237 
238  double edat_low[]={
239  0.00000000e+00, 9.76800363e-24, 3.08891410e-23,
240  9.76800489e-23, 3.08891490e-22, 9.76801000e-22,
241  3.08891816e-21, 9.76803078e-21, 3.08893141e-20,
242  9.76811525e-20, 3.08898527e-19, 7.75906672e-19,
243  1.94909879e-18, 4.89622085e-18, 6.16357861e-18,
244  1.22969164e-17, 2.45420997e-17, 4.89823567e-17,
245  9.77310869e-17, 1.95024387e-16, 2.45531498e-16,
246  3.89264229e-16, 6.16926264e-16, 7.76837038e-16,
247  9.00642353e-16, 1.19237569e-15, 1.89037060e-15,
248  3.09452823e-15, 4.90635934e-15, 5.96458915e-15,
249  7.51061114e-15, 9.79776989e-15, 1.23353809e-14,
250  1.55335650e-14, 1.88188196e-14, 2.46271194e-14,
251  3.10096915e-14, 3.74392368e-14, 4.91814886e-14,
252  6.19454280e-14, 7.62224545e-14, 8.11155415e-14,
253  1.05200677e-13, 1.26436151e-13, 1.37076948e-13,
254  1.55799897e-13, 2.02900352e-13, 2.47139208e-13,
255  3.11281590e-13, 3.19529901e-13, 3.22140999e-13,
256  3.36213572e-13, 3.58537297e-13, 3.70113877e-13,
257  3.80033593e-13, 4.24821517e-13, 1.57119195e-12,
258  2.36083738e-12, 3.33152493e-12, 4.49715211e-12,
259  5.87555551e-12, 9.35905600e-12, 1.39898961e-11,
260  2.00067862e-11, 2.76245081e-11, 3.69196076e-11,
261  5.35224936e-11, 7.81020115e-11, 9.19476188e-11};
262 
263  // Populating first 69 points with low density EOS
264  for(i=0;i<ndat_low;i++)
265  {
266  pdat[i]=pdat_low[i];
267  edat[i]=edat_low[i];
268  }
269 
270  // Generating higher density portion of EOS with spectral decomposition
271  double logpmax = log(pmax);
272  double logp0 = log(p0);
273  double dlogp = (logpmax-logp0)/(ndat - ndat_low);
274 
275  // Calculating pressure table
276  for(i=0;i < ndat-ndat_low;i++)
277  {
278  pdat[i+ndat_low] = exp(logp0 + dlogp*(i));
279  }
280 
281  // Calculating xdat table
282  for(i = 0;i<ndat - ndat_low;i++) {
283  xdat[i] = log(pdat[i+ndat_low]/p0);
284  }
285  for(i = ndat_low;i < ndat;i++)
286  {
287  // Calculate energy density for each dimensionless pressure value
288  edat[i] = eos_e_of_p_spectral_decomposition(xdat[i-ndat_low], gamma, size, p0,e0);
289  }
290 
291  /* Updating eos structure */
292  double *nbdat = NULL;
293  double *mubdat = NULL;
294  double *muedat = NULL;
295  double *yedat = NULL;
296  double *cs2dat = NULL;
297  double *hdat = NULL;
298  size_t ncol = 2;
299  /* Updating eos structure */
300  eos = eos_alloc_tabular(nbdat, edat, pdat, mubdat, muedat, hdat, yedat, cs2dat, ndat, ncol);
301 
302 
303  if(snprintf(eos->name, sizeof(eos->name), "4-Param Spec Decomp (g0=%.4g, g1=%.4g, g2=%.4g, g3=%.4g)",
304  gamma[0], gamma[1], gamma[2], gamma[3]) >= (int) sizeof(eos->name))
305  XLAL_PRINT_WARNING("EOS name too long");
306 
307  XLALFree(edat);
308  XLALFree(pdat);
309  return eos;
310 }
311 
312 /**
313  * @brief Reads 4 spectral decomposition eos parameters to make an eos.
314  * @details Reads 4 spectral decomposition eos parameters to construct an eos
315  * using a spectral decomposition of the adiabatic index, outlined in
316  * PRD 82 103011 (2010).
317  * @param[in] SDgamma0,SDgamma1,SDgamma2,SDgamma3 The spectral decomposition
318  * eos parameters.
319  * @return A pointer to neutron star equation of state structure.
320  */
321 LALSimNeutronStarEOS *XLALSimNeutronStarEOS4ParameterSpectralDecomposition(double SDgamma0, double SDgamma1, double SDgamma2, double SDgamma3){
322  double gamma[] = {SDgamma0, SDgamma1, SDgamma2, SDgamma3};
323  LALSimNeutronStarEOS * eos;
325  return eos;
326 }
327 
328 /**
329  * @brief Check that EOS has adiabatic index in range (0.6,4.5)
330  * @details Reads 4 spectral decomposition eos parameters and checks that the
331  * adiabatic index of the eos is within a range (0.6,4.5), since the TOV solver
332  * fails for values outside that range.
333  * @param[in] g0,g1,g2,g3 The spectral decomposition eos parameters.
334  * @return XLAL_SUCCESS or XLAL_FAILURE.
335  */
336 int XLALSimNeutronStarEOS4ParamSDGammaCheck(double g0, double g1, double g2, double g3){
337  double gamma[]={g0,g1,g2,g3};
338  int i;
339  int ret = XLAL_SUCCESS;
340  double p0 = 4.43784199e-13;
341  double xmax = 12.3081;
342  double pmax = p0 * exp(xmax);
343  size_t ndat = 500;
344 
345  double *pdat;
346  double *adat;
347  double *xdat;
348 
349  pdat = XLALCalloc(ndat, sizeof(*pdat));
350  adat = XLALCalloc(ndat, sizeof(*adat));
351  xdat = XLALCalloc(ndat, sizeof(*xdat));
352  if (pdat == NULL || adat == NULL || xdat == NULL) {
353  XLALFree(xdat);
354  XLALFree(adat);
355  XLALFree(pdat);
357  }
358 
359 
360  // Generating higher density portion of EOS with spectral decomposition
361  double logpmax = log(pmax);
362  double logp0 = log(p0);
363  double dlogp = (logpmax-logp0)/ndat;
364  // Calculating pressure and adiabatic index table
365  for(i = 0;i < (int) ndat;i++)
366  {
367  pdat[i] = exp(logp0 + dlogp*i);
368  xdat[i] = log(pdat[i]/p0);
369  adat[i] = AdiabaticIndex(gamma, xdat[i], 4);
370  }
371 
372  // Make sure all values are within Adiabatic Prior range
373  for(i = 0;i<(int) ndat;i++) {
374  // FIXME: Should make range adjustable from the commandline
375  if(adat[i] < 0.6 || adat[i] > 4.5) {
376  ret = XLAL_FAILURE;
377  break;
378  }
379  }
380 
381  XLALFree(pdat);
382  XLALFree(xdat);
383  XLALFree(adat);
384 
385  return ret;
386 }
387 
388 /**
389  * @brief Check that EOS has enough points (>4) in M-R space to interpolate.
390  * As the TOV equations are integrated from pmin to pmax, masses are
391  * calculated. Once the mass turns over (i.e. m(p_i) > m(p_{i+1})), the
392  * integration is terminated. It is possible therefore to have less than 4
393  * points in M-R space. We demand, then, that in the interval [pmin,pmax],
394  * m(pmin) = m(p_0) < m(p_1) < m(p_2) < m(p_3).
395  * @details Reads 4 spectral decomposition eos parameters and checks that the
396  * eos has at least 4 data points before turning over in M-R space, which
397  * abruptly terminates the eos.
398  * @param[in] g0,g1,g2,g3 The spectral decomposition eos parameters.
399  * @return XLAL_SUCCESS or XLAL_FAILURE.
400  */
401 int XLALSimNeutronStarEOS4ParamSDViableFamilyCheck(double g0, double g1, double g2, double g3){
402  double pdat;
403  double mdat;
404  double mdat_prev;
405  double rdat;
406  double kdat;
407 
408  LALSimNeutronStarEOS *eos=NULL;
410 
411  // Initialize previous value for mdat comparison
412  mdat_prev = 0.0;
413  // Ensure mass turnover does not happen too soon
414  const double logpmin = 75.5;
415  double logpmax = log(XLALSimNeutronStarEOSMaxPressure(eos));
416  double dlogp = (logpmax - logpmin) / 100.;
417  // Need at least four points
418  for (int i = 0; i < 4; ++i) {
419  pdat = exp(logpmin + i * dlogp);
420  XLALSimNeutronStarTOVODEIntegrate(&rdat, &mdat, &kdat, pdat, eos);
421  // Determine if maximum mass has been found
422  if (mdat <= mdat_prev){
423  // EOS has too few points to create family
424  // Clean up
426  return XLAL_FAILURE;
427  }
428  mdat_prev = mdat;
429  }
430 
432 
433  return XLAL_SUCCESS;
434 }
435 
436 /** @} */
437 /** @} */
const double g3
const double g2
const double g0
const double g1
struct tagLALSimNeutronStarEOS LALSimNeutronStarEOS
Incomplete type for the neutron star Equation of State (EOS).
double i
Definition: bh_ringdown.c:118
double e
Definition: bh_ringdown.c:117
void * XLALCalloc(size_t m, size_t n)
void XLALFree(void *p)
LALSimNeutronStarEOS * XLALSimNeutronStarEOSSpectralDecomposition(double gamma[], int size)
Reads spectral decomposition eos parameters to make an eos.
LALSimNeutronStarEOS * XLALSimNeutronStarEOS4ParameterSpectralDecomposition(double SDgamma0, double SDgamma1, double SDgamma2, double SDgamma3)
Reads 4 spectral decomposition eos parameters to make an eos.
int XLALSimNeutronStarEOS4ParamSDGammaCheck(double g0, double g1, double g2, double g3)
Check that EOS has adiabatic index in range (0.6,4.5)
int XLALSimNeutronStarEOS4ParamSDViableFamilyCheck(double g0, double g1, double g2, double g3)
Check that EOS has enough points (>4) in M-R space to interpolate.
double XLALSimNeutronStarEOSMaxPressure(LALSimNeutronStarEOS *eos)
Returns the maximum pressure of the EOS in Pa.
void XLALDestroySimNeutronStarEOS(LALSimNeutronStarEOS *eos)
Frees the memory associated with a pointer to an EOS structure.
int XLALSimNeutronStarTOVODEIntegrate(double *radius, double *mass, double *love_number_k2, double central_pressure_si, LALSimNeutronStarEOS *eos)
static const INT4 a
#define XLAL_ERROR_NULL(...)
#define XLAL_ERROR(...)
#define XLAL_PRINT_WARNING(...)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_FAILURE
list x
list mu