LALSimulation  5.4.0.1-fe68b98
LALSimNeutronStarEOSDynamicPolytrope.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2013 J. Lucaccioni, 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 dynamic polytrope 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 /* Calculates the energy density given the pressure using an n-piece dynamic polytrope. */
35 static double non_causal_Nparams(double p, double esec[], double psec[], double gsec[], size_t nsec){
36  double e;
37  int k;
38  // Find the polytrope section
39  for (k = 0; k <= (int)nsec - 2; ++k)
40  if (p < psec[k+1])
41  break;
42  // Eq. (5) of PRD 97, 123019 (2018)
43  e = (esec[k] - psec[k] / (gsec[k] - 1)) * pow(p / psec[k], 1 / gsec[k]) + p / (gsec[k] - 1);
44  return e;
45 }
46 
47 /* Calculates the energy density given the pressure for an n-piece causal dynamic polytrope. */
48 static double causal_Nparams(double p, double esec[], double psec[], double usec[], double vsec[], size_t nsec){
49  double e;
50  int k;
51  // Find the polytrope section
52  for (k = 0; k <= (int)nsec - 2; ++k)
53  if (p < psec[k+1])
54  break;
55  // Eq. (14) of PRD 97, 123019 (2018)
56  e = esec[k] + p - psec[k] + (psec[k] * usec[k] / (1 + vsec[k+1])) * (pow(p / psec[k], 1 + vsec[k+1]) - 1);
57  return e;
58 }
59 
60 /** @endcond */
61 
62 /**
63  * @brief Reads dynamic analytic eos parameters to make an eos.
64  * @details Reads an array of eos parameters to construct either the causal
65  * analytic eos or non-causal analytic polytrope generically outlined in PRD 97,
66  * 123019 (2018). The models are dynamic because the stitching pressures are
67  * also parameter choices.
68  * @param[in] parameters[] Array of dynamic analytic eos parameters.
69  * [param0, log10(p1), param1, log10(p2), ... , log10(pN), paramN], where
70  * pressure is in SI units, and the params are either gammas (adiabatic
71  * indexes) for the non-causal polytrope model or the vs (speed function
72  * exponents) for the causal analytic model.
73  * @param[in] nsec The number of sections (pressure sub-domains) to stitch to
74  * crust eos.
75  * @param[in] causal Option to use causal version (0=non-causal, 1=causal).
76  * @return A pointer to neutron star equation of state structure.
77  */
78 LALSimNeutronStarEOS *XLALSimNeutronStarEOSDynamicAnalytic(double parameters[], size_t nsec, int causal){
79  // Check that causal flag appropriately assigned
80  if (causal!=0 && causal!=1)
81  XLAL_ERROR_NULL(XLAL_EINVAL,"Did not specify which approach to take, Causal or Non-Causal");
82 
83  // Size is the number of polytrope pieces to stitch to low-density EOS
84  if (nsec<1)
85  XLAL_ERROR_NULL(XLAL_EINVAL,"Number of polytrope pieces should be at least 1\n");
86 
87  // Declares the max pressure(pmax). Units in geom.
88  // Chosen to match spectral decomposition and correspond to e0 and p0 for
89  // SLY EOS just below 0.5*rho_nuc. See Sec IID of PRD 98 063004 (2018) for
90  // more details. Note: Make adjustable in the future.
91  double pmax = 9.829054605e-8;
92  double p0 = 4.43784199e-13;
93 
94  // Pull out and convert pressure parameters
95  double psec[nsec];
96  psec[0]=p0;
97  for (int i=1; i < (int)nsec; i++)
98  // Odd indices, SI -> geom (so c=1)
99  psec[i] = pow(10,parameters[i*2-1])*LAL_G_C4_SI;
100 
101  if (psec[nsec-1]>pmax)
102  XLAL_ERROR_NULL(XLAL_EINVAL,"Highest p is set larger than %e, the limit at which EOS is generated\n",pmax);
103 
104  // Fill in arrays with SLy data. Units in geom.
105  // These values agree with LALSimNeutronStarEOS_SLY.dat
106  double SLYdat_p[] = {2.497300e-31, 1.592353e-30,
107  1.015332e-29, 6.474064e-29, 4.128057e-28,
108  2.632173e-27, 1.678353e-26, 1.070168e-25,
109  6.823712e-25, 4.351004e-24, 1.915235e-23,
110  8.060015e-23, 3.231442e-22, 4.345220e-22,
111  1.185661e-21, 3.166995e-21, 8.312020e-21,
112  2.151541e-20, 5.516008e-20, 7.219725e-20,
113  1.345952e-19, 2.502695e-19, 3.411564e-19,
114  4.160967e-19, 5.668037e-19, 1.050983e-18,
115  1.946632e-18, 3.604079e-18, 4.678197e-18,
116  6.363735e-18, 8.659043e-18, 1.177398e-17,
117  1.601262e-17, 2.068090e-17, 2.812536e-17,
118  3.823860e-17, 4.915329e-17, 6.683492e-17,
119  9.088690e-17, 1.198055e-16, 1.235236e-16,
120  1.679755e-16, 2.145757e-16, 2.389499e-16,
121  2.718344e-16, 3.695792e-16, 4.805438e-16,
122  6.228231e-16, 6.448839e-16, 6.519069e-16,
123  6.900794e-16, 7.517173e-16, 7.841887e-16,
124  8.122810e-16, 8.948228e-16, 1.780309e-15,
125  2.831705e-15, 4.352574e-15, 6.442724e-15,
126  9.210148e-15, 1.726355e-14, 2.961343e-14,
127  4.760077e-14, 7.280619e-14, 1.069739e-13,
128  1.786341e-13, 3.178976e-13, 4.169395e-13,
129  4.437842e-13, 8.192049e-13, 2.464440e-12,
130  5.749505e-12, 1.129311e-11, 1.962992e-11,
131  3.125683e-11, 4.664233e-11, 6.623341e-11,
132  9.045725e-11, 1.197311e-10, 1.544499e-10,
133  1.949854e-10, 2.417178e-10, 2.949858e-10,
134  3.551282e-10, 4.224506e-10, 4.972587e-10,
135  5.798254e-10, 6.704065e-10, 7.692419e-10,
136  8.765628e-10, 9.925676e-10, 1.117413e-09,
137  1.251265e-09, 1.394370e-09, 1.546730e-09,
138  1.708591e-09, 1.880037e-09, 2.061232e-09, 2.252177e-09};
139 
140  // Ensure p0 is in the crust eos range
141  size_t SLYdat_p_size = sizeof(SLYdat_p) / sizeof(*SLYdat_p);
142  if (psec[0] > SLYdat_p[SLYdat_p_size - 1])
143  XLAL_ERROR_NULL(XLAL_EINVAL,"p0 is set larger than %e, the limit of crust data",SLYdat_p[SLYdat_p_size - 1]);
144  if (psec[0] < SLYdat_p[0])
145  XLAL_ERROR_NULL(XLAL_EINVAL,"p0 is set smaller than %e, the lowest value of crust data",SLYdat_p[0]);
146 
147  double SLYdat_e[] = {9.768004e-24, 3.088914e-23,
148  9.768005e-23, 3.088915e-22, 9.768010e-22,
149  3.088918e-21, 9.768031e-21, 3.088931e-20,
150  9.768115e-20, 3.088985e-19, 7.759067e-19,
151  1.949099e-18, 4.896221e-18, 6.163579e-18,
152  1.229692e-17, 2.454210e-17, 4.898236e-17,
153  9.773109e-17, 1.950244e-16, 2.455315e-16,
154  3.892642e-16, 6.169263e-16, 7.768370e-16,
155  9.006424e-16, 1.192376e-15, 1.890371e-15,
156  3.094528e-15, 4.906359e-15, 5.964589e-15,
157  7.510611e-15, 9.797770e-15, 1.233538e-14,
158  1.553357e-14, 1.881882e-14, 2.462712e-14,
159  3.100969e-14, 3.743924e-14, 4.918149e-14,
160  6.194543e-14, 7.622245e-14, 8.111554e-14,
161  1.052007e-13, 1.264362e-13, 1.370769e-13,
162  1.557999e-13, 2.029004e-13, 2.471392e-13,
163  3.112816e-13, 3.195299e-13, 3.221410e-13,
164  3.362136e-13, 3.585373e-13, 3.701139e-13,
165  3.800336e-13, 4.248215e-13, 1.571192e-12,
166  2.360837e-12, 3.331525e-12, 4.497152e-12,
167  5.875556e-12, 9.359056e-12, 1.398990e-11,
168  2.000679e-11, 2.762451e-11, 3.691961e-11,
169  5.352249e-11, 7.810201e-11, 9.194762e-11,
170  9.546290e-11, 1.258593e-10, 1.895055e-10,
171  2.539315e-10, 3.194416e-10, 3.863255e-10,
172  4.548506e-10, 5.252990e-10, 5.979231e-10,
173  6.729756e-10, 7.507236e-10, 8.312713e-10,
174  9.150863e-10, 1.002169e-09, 1.092816e-09,
175  1.187250e-09, 1.285694e-09, 1.388296e-09,
176  1.495280e-09, 1.606794e-09, 1.723060e-09,
177  1.844228e-09, 1.970445e-09, 2.101934e-09,
178  2.238770e-09, 2.381175e-09, 2.529225e-09,
179  2.683140e-09, 2.842997e-09, 3.008942e-09, 3.181052e-09};
180 
181  // Insist that the size of SLYdat_p is the same as SLYdat_e
182  ((void)sizeof(char[1 - 2*!!(sizeof(SLYdat_p) != sizeof(SLYdat_e))]));
183 
184  // Check the ammount of SLy data that will be included
185  size_t limit;
186  // Already checked that p0 > smallest p of crust eos, so start limit at 1
187  for (limit = 1; limit < SLYdat_p_size; ++limit)
188  if (psec[0] < SLYdat_p[limit])
189  break;
190 
191  // 100 points is arbitrarily chosen to resolve high-density eos
192  size_t ndat = 100 + limit;
193 
194  // Declaring array and allocating memory space
195  double *edat;
196  double *pdat;
197 
198  pdat = XLALCalloc(ndat, sizeof(*pdat));
199  edat = XLALCalloc(ndat, sizeof(*edat));
200  if (pdat == NULL || edat == NULL) {
201  XLALFree(pdat);
202  XLALFree(edat);
204  }
205 
206  double logpmax = log(pmax);
207  double logp0 = log(psec[0]);
208  double dlogp = (logpmax-logp0)/(ndat-limit);
209 
210  // Add SLy data for crust
211  for (int i = 0; i < (int)limit; i++){
212  pdat[i] = SLYdat_p[i];
213  edat[i] = SLYdat_e[i];
214  }
215 
216  // Find energy density at p0
217  double b = SLYdat_e[limit-1];
218  double dedp = (SLYdat_e[limit]-SLYdat_e[limit-1])/(SLYdat_p[limit]-SLYdat_p[limit-1]);
219  double x = psec[0]-SLYdat_p[limit-1];
220  double e0 = (dedp*x) + b;
221 
222  // Find starting energy's of each section
223  double esec[nsec];
224  esec[0] = e0;
225 
226  if (causal == 1){
227  double vsec[nsec+1];
228  double usec[nsec];
229  // Solving Eq. (11) of PRD 97, 123019 (2018) for Y0
230  usec[0] = dedp-1;
231  // Solving Y(p0) = e^v0 for v0 = ln(Y0)
232  vsec[0] = log(usec[0]);
233  // Fill the rest of the v array
234  vsec[1] = parameters[0];
235  for (int i = 1; i < (int)nsec; i++)
236  // Even indices
237  vsec[i+1] = parameters[i*2];
238  for (int k=1; k < (int)nsec; ++k){
239  // Eq. (15) of PRD 97, 123019 (2018)
240  usec[k] = usec[k-1] * pow(psec[k] / psec[k-1],vsec[k]);
241  // Eq. (16) of PRD 97, 123019 (2018)
242  esec[k] = esec[k-1] + psec[k] - psec[k-1] + ( psec[k-1] * usec[k-1] / (1 + vsec[k])) * (pow(psec[k] / psec[k-1], 1 + vsec[k]) - 1);
243  }
244  // Compute polytrope data beyond the crust
245  for (int i = limit; i < (int)ndat; i++){
246  pdat[i] = exp(logp0 + (dlogp*(i-limit)));
247  edat[i] = causal_Nparams(pdat[i],esec,psec,usec,vsec,nsec);
248  }
249  }else{
250  double gsec[nsec];
251  gsec[0]=parameters[0];
252  for (int i = 1; i < (int)nsec; i++)
253  // Even indices
254  gsec[i] = parameters[i*2];
255  for (int k = 0; k < (int)nsec-1; ++k)
256  // Eq. (6) of PRD 97, 123019 (2018)
257  esec[k+1] = (esec[k] - psec[k] / (gsec[k] - 1)) * pow(psec[k+1] / psec[k], 1 / gsec[k]) + psec[k+1] / (gsec[k] - 1);
258  // Compute polytrope data beyond the crust
259  for (int i = limit; i < (int)ndat; i++){
260  pdat[i] = exp(logp0 + (dlogp*(i-limit)));
261  edat[i] = non_causal_Nparams(pdat[i],esec,psec,gsec,nsec);
262  }
263  }
264 
265  // Updating eos structure
266  LALSimNeutronStarEOS * eos;
267  double *nbdat = NULL;
268  double *mubdat = NULL;
269  double *muedat = NULL;
270  double *yedat = NULL;
271  double *cs2dat = NULL;
272  double *hdat = NULL;
273  size_t ncol = 2;
274  /* Updating eos structure */
275  eos = eos_alloc_tabular(nbdat, edat, pdat, mubdat, muedat, hdat, yedat, cs2dat, ndat, ncol);
276 
277 
278  XLALFree(edat);
279  XLALFree(pdat);
280 
281  return eos;
282 }
283 
284 /**
285  * @brief Reads 5 dynamic polytrope eos parameters to make an eos.
286  * @details Reads 5 dynamic polytrope eos parameters to construct a 3-piece
287  * dynamic polytrope eos, generically outlined in PRD 97, 123019 (2018), and
288  * stitched to a low-density SLy eos crust.
289  * @param[in] g0 The adiabatic index of the first polytrope.
290  * @param[in] log10p1_si The log10 of the first dividing pressure in SI units.
291  * @param[in] g1 The adiabatic index of the second polytrope.
292  * @param[in] log10p2_si The log10 of the second dividing pressure in SI units.
293  * @param[in] g2 The adiabatic index of the third polytrope.
294  * @return A pointer to neutron star equation of state structure.
295  */
296 LALSimNeutronStarEOS *XLALSimNeutronStarEOS3PieceDynamicPolytrope(double g0, double log10p1_si, double g1, double log10p2_si, double g2){
297  double params[]={g0,log10p1_si,g1,log10p2_si,g2};
298  LALSimNeutronStarEOS * eos;
299  // 3-piece (non-causal) dynamic polytrope
301  return eos;
302 }
303 
304 /**
305  * @brief Reads 5 causal analytic eos parameters to make an eos.
306  * @details Reads 5 causal analytic eos parameters to construct a 3-piece
307  * causal eos, generically outlined in PRD 97, 123019 (2018), and stitched to
308  * a low-density SLy eos crust.
309  * @param[in] v1 The first sound function exponent.
310  * @param[in] log10p1_si The log10 of the first dividing pressure in SI units.
311  * @param[in] v2 The second sound function exponent.
312  * @param[in] log10p2_si The log10 of the second dividing pressure in SI units.
313  * @param[in] v3 The third sound function exponent.
314  * @return A pointer to neutron star equation of state structure.
315  */
316 LALSimNeutronStarEOS *XLALSimNeutronStarEOS3PieceCausalAnalytic(double v1, double log10p1_si, double v2, double log10p2_si, double v3){
317  double params[]={v1,log10p1_si,v2,log10p2_si,v3};
318  LALSimNeutronStarEOS * eos;
319  // 3-piece causal analytic eos
321  return eos;
322 }
323 
324 /**
325  * @brief Check that EOS has enough points (>4) in M-R space to interpolate.
326  * As the TOV equations are integrated from pmin to pmax, masses are
327  * calculated. Once the mass turns over (i.e. m(p_i) > m(p_{i+1})), the
328  * integration is terminated. It is possible therefore to have less than 4
329  * points in M-R space. We demand, then, that in the interval [pmin,pmax],
330  * m(pmin) = m(p_0) < m(p_1) < m(p_2) < m(p_3).
331  * @details Reads 3-piece dynamic polytrope (non-causal) or analytic (causal)
332  * eos parameters and checks that the eos has at least 4 data points before
333  * turning over in M-R space, which abruptly terminates the eos.
334  * @param[in] p0 First model param, either g0 (non-causal) or v1 (causal).
335  * @param[in] log10p1_si The log10 of the first dividing pressure in SI units.
336  * @param[in] p1 Second model param, either g1 (non-causal) or v2 (causal).
337  * @param[in] log10p2_si The log10 of the second dividing pressure in SI units.
338  * @param[in] p2 Third model param, either g2 (non-causal) or v3 (causal).
339  * @param[in] causal Option to use causal version (0=non-causal, 1=causal).
340  * @return XLAL_SUCCESS or XLAL_FAILURE.
341  */
342 int XLALSimNeutronStarEOS3PDViableFamilyCheck(double p0, double log10p1_si, double p1, double log10p2_si, double p2, int causal){
343  // Check that causal flag appropriately assigned
344  if (causal!=0 && causal!=1)
345  XLAL_ERROR(XLAL_EINVAL,"Did not specify which approach to take, Causal or Non-Causal");
346  double pdat;
347  double mdat;
348  double mdat_prev;
349  double rdat;
350  double kdat;
351 
352  LALSimNeutronStarEOS *eos=NULL;
353  if (causal == 1)
354  eos = XLALSimNeutronStarEOS3PieceCausalAnalytic(p0, log10p1_si, p1, log10p2_si, p2);
355  else
356  eos = XLALSimNeutronStarEOS3PieceDynamicPolytrope(p0, log10p1_si, p1, log10p2_si, p2);
357 
358  // Initialize previous value for mdat comparison
359  mdat_prev = 0.0;
360 
361  // Ensure mass turnover does not happen too soon
362  const double logpmin = 75.5;
363  double logpmax = log(XLALSimNeutronStarEOSMaxPressure(eos));
364  double dlogp = (logpmax - logpmin) / 100.;
365  // Need at least four points
366  for (int i = 0; i < 4; ++i) {
367  pdat = exp(logpmin + i * dlogp);
368  XLALSimNeutronStarTOVODEIntegrate(&rdat, &mdat, &kdat, pdat, eos);
369  // Determine if maximum mass has been found
370  if (mdat <= mdat_prev){
371  // EOS has too few points to create family
372  // Clean up
374  return XLAL_FAILURE;
375  }
376  mdat_prev = mdat;
377  }
378 
380 
381  return XLAL_SUCCESS;
382 }
383 
384 /** @} */
385 /** @} */
const double g2
const double g0
const double g1
struct tagLALSimNeutronStarEOS LALSimNeutronStarEOS
Incomplete type for the neutron star Equation of State (EOS).
#define LAL_G_C4_SI
Factor to convert pressure in Pa to geometerized units of m^-2.
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)
int XLALSimNeutronStarEOS3PDViableFamilyCheck(double p0, double log10p1_si, double p1, double log10p2_si, double p2, int causal)
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.
LALSimNeutronStarEOS * XLALSimNeutronStarEOS3PieceCausalAnalytic(double v1, double log10p1_si, double v2, double log10p2_si, double v3)
Reads 5 causal analytic eos parameters to make an eos.
LALSimNeutronStarEOS * XLALSimNeutronStarEOSDynamicAnalytic(double parameters[], size_t nsec, int causal)
Reads dynamic analytic eos parameters to make an eos.
LALSimNeutronStarEOS * XLALSimNeutronStarEOS3PieceDynamicPolytrope(double g0, double log10p1_si, double g1, double log10p2_si, double g2)
Reads 5 dynamic polytrope eos parameters to make an eos.
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)
#define XLAL_ERROR_NULL(...)
#define XLAL_ERROR(...)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EINVAL
XLAL_FAILURE
list x
list p
Definition: burst.c:245