LALSimulation  5.4.0.1-fe68b98
LALSimIMRSEOBNRv2ROMEffectiveSpin.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Michael Puerrer, John Veitch
3  * Reduced Order Model for SEOBNR
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with with program; see the file COPYING. If not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18  * MA 02110-1301 USA
19  */
20 
21 #ifdef __GNUC__
22 #define UNUSED __attribute__ ((unused))
23 #else
24 #define UNUSED
25 #endif
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <math.h>
30 #include <complex.h>
31 #include <time.h>
32 #include <stdbool.h>
33 #include <alloca.h>
34 #include <string.h>
35 #include <libgen.h>
36 
37 #include <gsl/gsl_errno.h>
38 #include <gsl/gsl_bspline.h>
39 #include <gsl/gsl_blas.h>
40 #include <gsl/gsl_min.h>
41 #include <gsl/gsl_spline.h>
42 #include <lal/Units.h>
43 #include <lal/SeqFactories.h>
44 #include <lal/LALConstants.h>
45 #include <lal/XLALError.h>
46 #include <lal/FrequencySeries.h>
47 #include <lal/Date.h>
48 #include <lal/StringInput.h>
49 #include <lal/Sequence.h>
50 #include <lal/LALStdio.h>
51 #include <lal/FileIO.h>
52 
53 #include <lal/LALSimInspiral.h>
54 #include <lal/LALSimIMR.h>
56 
57 #include <lal/LALConfig.h>
58 #ifdef LAL_PTHREAD_LOCK
59 #include <pthread.h>
60 #endif
61 
62 
63 /********* Input data for spline basis points **************/
64 #define nk_amp 200 // number of SVD-modes == number of basis functions for amplitude
65 #define nk_phi 250 // number of SVD-modes == number of basis functions for phase
66 
67 // Check whether we actually need the full precison
68 static const double gA[] = {0.0001,0.00010412,0.000108409744,0.00011287622545279999,0.00011752672594145534, 0.00012236882705024332,
69  0.00012741042272471334,0.00013265973214097152,0.00013812531310517954,0.00014381607600511294,0.0001497412983365236,
70  0.00015591063982798835,0.00016233415818890147,0.0001690223255062842,0.00017598604531714312,0.0001832366703842094,
71  0.00019078602120403885,0.00019864640527764526,0.00020683063717508426,0.00021535205942669773,0.00022422456427507767,
72  0.00023346261632321087,0.00024308127611572715,0.0002530962246916951,0.00026352378914899294,0.00027438096926193147,
73  0.00028568546519552304,0.00029745570636157857,0.0003097108814636756,0.000322470969779979,0.0003357567737349142,
74  0.00034958995281279267,0.00036399305886867974,0.00037898957289406936,0.000394603943297305,0.000410861625761154,
75  0.00042778912474251355,0.0004454140366819051,0.0004637650949931996,0.0004828722169069194,0.0005027665522434845,
76  0.0005234805341959161,0.0005450479322047879,0.0005675039070116251,0.000590885067980504,0.0006152295327813008,
77  0.0006405769895318904,0.0006669687615006042,0.0006944478744744291,0.0007230591269027756,0.00075284916293117,
78  0.0007838665484439342,0.0008161618502398242,0.000849787718469705,0.0008847989724706569,0.0009212526901364479,
79  0.0009592083009700695,0.0009987276829700365,0.001039875263508402,0.0010827181243649481,0.001127326111088784,
80  0.0011737719468656418,0.0012221313510765062,0.0012724831627408582,0.0013249094690457816,0.0013794957391704678,
81  0.001436330963624291,0.0014955077993256119,0.001557122720657827,0.0016212761767489296,0.0016880727552309855,
82  0.0017576213527465022,0.0018300353524796581,0.00190543280900182,0.001983936640732695,0.002065674830330882,
83  0.0021507806333405143,0.0022393927954341437,0.0023316557786060305,0.002427719996684599,0.0025277420605480045,
84  0.002631885033442582,0.0027403186968204163,0.0028532198271294176,0.0029707724840071495,0.003093168310348244,
85  0.0032206068447345917,0.003353295846737657,0.0034914516356232485,0.0036352994430109264,0.0037850737800629764,
86  0.003941018819801571,0.0041033887951773965,0.004272448413538705,0.0044484732881765,0.004631750387649371,0.004822578503620526,
87  0.005021268737969691,0.0052281450099740424,0.005443544584384973,0.005667818621261634,0.005901332748457613,
88  0.0061444676576940666,0.006397619725191062,0.006661201657868934,0.006935643166173134,0.007221391664619468,0.00751891300120179,
89  0.007828692216851304,0.008151234336185578,0.008487065190836423,0.008836732276698884,0.009200805646498878,0.009579878839134632,
90  0.009974569847306979,0.010385522125016027,0.010813405636566686,0.011258917948793233,0.011722785368283514,0.012205764125456795,
91  0.012708641607425615,0.01323223764165155,0.013777405832487594,0.014345034952786082,0.014936050392840869,0.015551415669025912,
92  0.01619213399458978,0.01685924991516688,0.017553851011671756,0.018277069673352634,0.019030084943894764,0.019814124443583228,
93  0.020630466370658858,0.021480441585130003,0.02236543577843736,0.023286891732508978,0.024246311671888347,0.025245259712770148,
94  0.026285364412936277,0.02736832142674925,0.02849589626953132,0.029669927195836013,0.030892328196304455,0.0321650921179922,
95  0.03349029391325348,0.03487009402247952,0.036306741896205676,0.03780257966232935,0.03936004594441732,0.04098167983732731,
96  0.0426701250466252,0.04442813419854616,0.04625857332752626,0.04816442654862034,0.0501488009224235,0.052214931520427346,
97  0.05436618669906895,0.056606073591070595,0.05893824382302271,0.06136649946853124,0.06389479924663473,0.06652726497559608,
98  0.06926818829259064,0.07212203765024537,0.07509346560143548,0.07818731638421463,0.08140863381924426,0.08476266953259713,
99  0.08825489151734013,0.09189099304785454,0.09567690196142616,0.09961879032223692,0.10372308448351308,0.10799647556423382,
100  0.11244593035748025,0.11707870268820844,0.12190234523896262,0.12692472186280787,0.13215402040355556,0.13759876604418206,
101  0.14326783520520237,0.1491704700156567,0.15531629338030176,0.1617153246675702,0.16837799604387407,0.1753151694808817,
102  0.182538154463494,0.19005872642738997,0.19788914595619844,0.20604217876959383,0.2145311165349011,0.223369798536139,
103  0.23257263423582794,0.24215462676634406,0.25213139738911744,0.26251921096154907,0.2733350024531649,0.2845964045542353,
104  0.2963217764218698,0.3};
105 
106 static const double gPhi[] = {0.0001,0.0001011603972084032,0.00010233878267233898,0.00010353550576343408,0.00010475092401703343,0.00010598540335537165,
107  0.00010723931831773738,0.0001085130522978776,0.00010980699778889891,0.00011112155663593303,0.00011245714029684425,
108  0.00011381417011126748,0.00011519307757827774,0.00011659430464300309,0.00011801830399250643,0.00011946553936127435,
109  0.00012093648584666495,0.00012243163023468122,0.0001239514713364512,0.00012549652033581237,0.00012706730114841344,
110  0.00012866435079276461,0.0001302882197736849,0.00013193947247861382,0.0001336186875872749,0.00013532645849519842,
111  0.00013706339375163268,0.00013883011751239573,0.00014062727000824248,0.00014245550802934775,0.00014431550542653068,
112  0.00014620795362987388,0.00014813356218541844,0.00015009305931064617,0.0001520871924694914,0.00015411672896765733,
113  0.00015618245656904637,0.00015828518413414986,0.00016042574228128018,0.00016260498407156794,0.00016482378571868855,
114  0.00016708304732432604,0.00016938369364042784,0.0001717266748593521,0.00017411296743306026,0.00017654357492255984,
115  0.000179019528878859,0.0001815418897567524,0.00018411174786282027,0.0001867302243390864,0.0001893984721838501,
116  0.0001921176773112781,0.00019488905965141826,0.00019771387429237596,0.00020059341266647862,0.00020352900378234071,
117  0.0002065220155048353,0.0002095738558850754,0.0002126859745426121,0.00021585986410216392,0.00021909706168730754,
118  0.0002223991504736801,0.00022576776130437057,0.0002292045743703129,0.00023271132095863427,0.00023628978527206272,
119  0.00023994180632265591,0.00024366927990327993,0.0002474741606404437,0.00025135846413228087,0.00025532426917566865,
120  0.000259373720086681,0.00026350902911879455,0.00026773247898349915,0.0002720464254782114,0.00027645330022665123,
121  0.0002809556135371191,0.0002855559573844033,0.00029025700852135906,0.00029506153172652994,0.00029997238319453087,
122  0.00030499251407628374,0.00031012497417658787,0.0003153729158169264,0.0003207395978718508,0.0003262283899877574,
123  0.00033184277699336776,0.0003375863635117564,0.0003434628787843332,0.000349476181717788,0.0003556302661656416,
124  0.00036192926645672906,0.00036837746318366013,0.0003749792892650752,0.00038173933629633125,0.00038866236120412836,
125  0.0003957532932215169,0.00040301724120071894,0.00041045950128225665,0.0004180855649400099,0.0004259011274230334,
126  0.00043391209661625043,0.0004421246023435188,0.0004505450061380353,0.0004591799115066175,0.00046803617471608764,
127  0.0004771209161317804,0.0004864415321401282,0.0004960057076893408,0.0005058214294844088,0.0005158969998750328,
128  0.0005262410514776242,0.0005368625625752512,0.0005477708733423325,0.0005589757029440297,0.000570487167563663,
129  0.0005823157994151132,0.0005944725668010725,0.0006069688952822128,0.0006198166900268609,0.0006330283594156419,
130  0.0006466168399807966,0.0006605956227655398,0.0006749787811949231,0.0006897810005562521,0.0007050176091942138,
131  0.0007207046115335476,0.0007368587230503925,0.0007534974073224147,0.0007706389152975295,0.0007883023269315418,
132  0.0008065075953564147,0.0008252755937532143,0.0008446281651171619,0.0008645881751167426,0.0008851795682645893,
133  0.0009064274276349821,0.0009283580383814316,0.0009509989553280604,0.0009743790749305488,0.0009985287119264209,
134  0.001023479681020617,0.0010492653839808423,0.0010759209025483307,0.0011034830976036844,0.0011319907150646252,
135  0.001161484499033161,0.0011920073127541697,0.001223604267996143,0.0012563228635182632,0.001290213133346581,
136  0.0013253278056463969,0.0013617224730486212,0.0013994557753655948,0.0014385895957173568,0.0014791892711835141,
137  0.0015213238191996614,0.0015650661810317963,0.0016104934837885981,0.001657687322571147,0.0017067340645141838,
138  0.0017577251766440938,0.0018107575796683735,0.0018659340300216179,0.0019233635327265298,0.0019831617878879122,
139  0.0020454516739262497,0.002110363770978921,0.002178036928255416,0.0022486188795328055,0.0023222669114244575,
140  0.0023991485895546133,0.002479442548330867,0.0025633393506336675,0.0026510424244457313,0.002742769084235,
141  0.0028387516457943815,0.0029392386442435347,0.0030444961660280956,0.003154809307027991,0.0032704837703296783,
142  0.0033918476188513494,0.0035192531998631655,0.00365307926054877,0.0037937332761471616,0.003941654014939118,
143  0.00409731436745065,0.0042612244707968,0.004433935163151941,0.0046160418079890615,0.004808188533075856,0.0050110729353623155,
144  0.005225451309975515,0.0054521444697090025,0.0056920442308420974,0.005946120652068382,0.006215430126014334,
145  0.006501124437600008,0.00680446092070622,0.007126813864712588,0.007469687345993064,0.007834729687044038,0.00822374977835156,
146  0.00863873553631827,0.00908187481570728,0.009555579148505829,0.01006251074455828,0.0106056132648355,0.011188146968337661,
147  0.011813728941498652,0.012486379248439126,0.013210573996293905,0.013991306498080315,0.014834157943620526,0.015745379266211335,
148  0.016731986230784316,0.017801870183039872,0.018963927407269193,0.02022821066724284,0.021606107280277058,0.023110549038761655,
149  0.024756260496891908,0.02656005364907936,0.028541178926603447,0.030721744843400595,0.03312722167935155,0.03578704849750366,
150  0.03873536781388351,0.04201191872880512,0.045663127765211343,0.049743447693639815,0.05431700914731336,0.05945966907716407,
151  0.06526156578101447,0.07183032477168075,0.07929510653451066,0.08781175113621649,0.0975693627088662,0.10879879928126432,0.115,
152  0.12178370533810129,0.13,0.1368749683040054,0.145,0.15450982970874225,0.17523738873197545,0.19975298003522046,
153  0.22894501461505934,0.26395954156353574,0.3};
154 
155 #ifdef LAL_PTHREAD_LOCK
156 static pthread_once_t SEOBNRv2ROMEffectiveSpin_is_initialized = PTHREAD_ONCE_INIT;
157 #endif
158 
159 /*************** type definitions ******************/
160 
161 typedef struct tagSEOBNRROMdata_coeff
162 {
163  gsl_vector* c_amp;
164  gsl_vector* c_phi;
166 
167 struct tagSEOBNRROMdata
168 {
169  UINT4 setup;
170  gsl_vector* cvec_amp;
171  gsl_vector* cvec_phi;
172  gsl_matrix *Bamp;
173  gsl_matrix *Bphi;
174  gsl_vector* cvec_amp_pre;
175 };
176 typedef struct tagSEOBNRROMdata SEOBNRROMdata;
177 
178 static SEOBNRROMdata __lalsim_SEOBNRv2ROMSS_data;
179 
180 typedef struct tagSplineData
181 {
182  gsl_bspline_workspace *bwx;
183  gsl_bspline_workspace *bwy;
184  int ncx, ncy;
185 } SplineData;
186 
187 /**************** Internal functions **********************/
188 
189 static void SEOBNRv2ROMEffectiveSpin_Init_LALDATA(void);
190 static int SEOBNRv2ROMEffectiveSpin_Init(const char dir[]);
191 static bool SEOBNRv2ROMEffectiveSpin_IsSetup(void);
192 
193 static int SEOBNRROMdata_Init(SEOBNRROMdata *romdata, const char dir[]);
194 static void SEOBNRROMdata_Cleanup(SEOBNRROMdata *romdata);
195 
196 static void SEOBNRROMdata_coeff_Init(SEOBNRROMdata_coeff **romdatacoeff);
197 static void SEOBNRROMdata_coeff_Cleanup(SEOBNRROMdata_coeff *romdatacoeff);
198 
199 static size_t NextPow2(const size_t n);
200 static void SplineData_Destroy(SplineData *splinedata);
201 static void SplineData_Init(SplineData **splinedata);
202 
203 static int read_vector(const char dir[], const char fname[], gsl_vector *v);
204 static int read_matrix(const char dir[], const char fname[], gsl_matrix *m);
205 
206 static int load_data(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *cvec_amp_pre);
207 
208 static int TP_Spline_interpolation_2d(
209  REAL8 q, // Input: q-value for which projection coefficients should be evaluated
210  REAL8 chi, // Input: chi-value for which projection coefficients should be evaluated
211  gsl_vector *cvec_amp, // Input: data for spline coefficients for amplitude
212  gsl_vector *cvec_phi, // Input: data for spline coefficients for phase
213  gsl_vector *cvec_amp_pre, // Input: data for spline coefficients for amplitude prefactor
214  gsl_vector *c_amp, // Output: interpolated projection coefficients for amplitude
215  gsl_vector *c_phi, // Output: interpolated projection coefficients for phase
216  REAL8 *amp_pre // Output: interpolated amplitude prefactor
217 );
218 
219 
220 /**
221  * Core function for computing the ROM waveform.
222  * Interpolate projection coefficient data and evaluate coefficients at desired (q, chi).
223  * Construct 1D splines for amplitude and phase.
224  * Compute strain waveform from amplitude and phase.
225 */
227  COMPLEX16FrequencySeries **hptilde,
228  COMPLEX16FrequencySeries **hctilde,
229  double phiRef,
230  double fRef,
231  double distance,
232  double inclination,
233  double Mtot_sec,
234  double eta,
235  double chi,
236  const REAL8Sequence *freqs, /* Frequency points at which to evaluate the waveform (Hz) */
237  double deltaF
238  /* If deltaF > 0, the frequency points given in freqs are uniformly spaced with
239  * spacing deltaF. Otherwise, the frequency points are spaced non-uniformly.
240  * Then we will use deltaF = 0 to create the frequency series we return. */
241 );
242 
243 // Auxiliary function to perform setup of phase spline for t(f) and f(t) functions
245  gsl_spline **spline_phi, // phase spline
246  gsl_interp_accel **acc_phi, // phase spline accelerator
247  REAL8 *Mf_final, // ringdown frequency in Mf
248  REAL8 *Mtot_sec, // total mass in seconds
249  REAL8 m1SI, // Mass of companion 1 (kg)
250  REAL8 m2SI, // Mass of companion 2 (kg)
251  REAL8 chi // Effective aligned spin
252 );
253 
255  gsl_vector *v,
256  REAL8 eta,
257  REAL8 chi1,
258  REAL8 chi2,
259  int ncy,
260  int ncz,
261  gsl_bspline_workspace *bwx,
262  gsl_bspline_workspace *bwy,
263  gsl_bspline_workspace *bwz
264 );
265 
266 /********************* Definitions begin here ********************/
267 
268 /** Setup SEOBNRv2ROMEffectiveSpin model using data files installed in dir
269  */
270 static int SEOBNRv2ROMEffectiveSpin_Init(const char dir[]) {
272  XLAL_ERROR(XLAL_EFAILED, "Error: SEOBNRROMdata was already set up!");
273 
275 
276  if(__lalsim_SEOBNRv2ROMSS_data.setup) {
277  return(XLAL_SUCCESS);
278  }
279  else {
280  return(XLAL_EFAILED);
281  }
282 }
283 
284 /** Helper function to check if the SEOBNRv2ROMEffectiveSpin model has been initialised */
287  return true;
288  else
289  return false;
290 }
291 
292 // Read binary ROM data for basis functions and coefficients
293 static int load_data(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *cvec_amp_pre) {
294  // Load binary data for amplitude and phase spline coefficients as computed in Mathematica
295  int ret = XLAL_SUCCESS;
296  ret |= read_vector(dir, "SEOBNRv2ROM_SS_Amp_ciall.dat", cvec_amp);
297  ret |= read_vector(dir, "SEOBNRv2ROM_SS_Phase_ciall.dat", cvec_phi);
298  ret |= read_matrix(dir, "SEOBNRv2ROM_SS_Bamp_bin.dat", Bamp);
299  ret |= read_matrix(dir, "SEOBNRv2ROM_SS_Bphase_bin.dat", Bphi);
300  ret |= read_vector(dir, "SEOBNRv2ROM_SS_AmpPrefac_ci.dat", cvec_amp_pre);
301  return(ret);
302 }
303 
304 static void SplineData_Init( SplineData **splinedata )
305 {
306  if(!splinedata) exit(1);
307  if(*splinedata) SplineData_Destroy(*splinedata);
308 
309  (*splinedata)=XLALCalloc(1,sizeof(SplineData));
310 
311  const int ncx = 50; // points in eta + 2
312  const int ncy = 50; // points in chi + 2
313  (*splinedata)->ncx = ncx;
314  (*splinedata)->ncy = ncy;
315 
316  // Set up B-spline basis for desired knots
317  double etavec[] = {0.01, 0.011, 0.012, 0.013, 0.014, 0.015, 0.016, 0.017, 0.018, 0.019, \
318  0.02, 0.0225, 0.025, 0.0275, 0.03, 0.035, 0.04, 0.045, 0.05, 0.055, \
319  0.06, 0.065, 0.07, 0.075, 0.08, 0.09, 0.1, 0.11, 0.12, 0.13, 0.14, \
320  0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.245, \
321  0.247, 0.248, 0.2495, 0.2498, 0.2499, 0.25};
322 
323  double chivec[] = {-1., -0.9, -0.8, -0.67115, -0.5423, -0.430639, -0.318978, -0.234489, \
324  -0.15, -0.075, 0., 0.130167, 0.260333, 0.34325, 0.426167, 0.514612, \
325  0.603056, 0.647278, 0.6915, 0.723561, 0.755622, 0.782156, 0.808689, \
326  0.829695, 0.8507, 0.861756, 0.872811, 0.888289, 0.903767, 0.904873, \
327  0.905978, 0.911506, 0.917033, 0.922561, 0.928089, 0.931406, 0.934722, \
328  0.935828, 0.936933, 0.942461, 0.947989, 0.955728, 0.963467, 0.9701, \
329  0.976733, 0.983367, 0.987, 0.99};
330 
331  const size_t nbreak_x = ncx-2; // must have nbreak = n -2 for cubic splines
332  const size_t nbreak_y = ncy-2; // must have nbreak = n -2 for cubic splines
333 
334  // allocate a cubic bspline workspace (k = 4)
335  gsl_bspline_workspace *bwx = gsl_bspline_alloc(4, nbreak_x);
336  gsl_bspline_workspace *bwy = gsl_bspline_alloc(4, nbreak_y);
337 
338  // set breakpoints (and thus knots by hand)
339  gsl_vector *breakpts_x = gsl_vector_alloc(nbreak_x);
340  gsl_vector *breakpts_y = gsl_vector_alloc(nbreak_y);
341  for (UINT4 i=0; i<nbreak_x; i++)
342  gsl_vector_set(breakpts_x, i, etavec[i]);
343  for (UINT4 j=0; j<nbreak_y; j++)
344  gsl_vector_set(breakpts_y, j, chivec[j]);
345 
346  gsl_bspline_knots(breakpts_x, bwx);
347  gsl_bspline_knots(breakpts_y, bwy);
348 
349  gsl_vector_free(breakpts_x);
350  gsl_vector_free(breakpts_y);
351 
352  (*splinedata)->bwx=bwx;
353  (*splinedata)->bwy=bwy;
354 }
355 
356 static void SplineData_Destroy(SplineData *splinedata)
357 {
358  if(!splinedata) return;
359  if(splinedata->bwx) gsl_bspline_free(splinedata->bwx);
360  if(splinedata->bwy) gsl_bspline_free(splinedata->bwy);
361  XLALFree(splinedata);
362 }
363 
364 // Interpolate projection coefficients for amplitude and phase over the parameter space (q, chi).
365 // The multi-dimensional interpolation is carried out via a tensor product decomposition.
367  REAL8 eta, // Input: eta-value for which projection coefficients should be evaluated
368  REAL8 chi, // Input: chi-value for which projection coefficients should be evaluated
369  gsl_vector *cvec_amp, // Input: data for spline coefficients for amplitude
370  gsl_vector *cvec_phi, // Input: data for spline coefficients for phase
371  gsl_vector *cvec_amp_pre, // Input: data for spline coefficients for amplitude prefactor
372  gsl_vector *c_amp, // Output: interpolated projection coefficients for amplitude
373  gsl_vector *c_phi, // Output: interpolated projection coefficients for phase
374  REAL8 *amp_pre // Output: interpolated amplitude prefactor
375 ) {
376 
377  SplineData *splinedata=NULL;
378  SplineData_Init(&splinedata);
379  gsl_bspline_workspace *bwx=splinedata->bwx;
380  gsl_bspline_workspace *bwy=splinedata->bwy;
381 
382  int ncx = splinedata->ncx; // points in eta
383  int ncy = splinedata->ncy; // points in chi
384  int N = ncx*ncy; // size of the data matrix for one SVD-mode
385 
386  // Evaluate the TP spline for all SVD modes - amplitude
387  for (int k=0; k<nk_amp; k++) { // For each SVD mode
388  gsl_vector v = gsl_vector_subvector(cvec_amp, k*N, N).vector; // Pick out the coefficient matrix corresponding to the k-th SVD mode.
389  REAL8 csum = Interpolate_Coefficent_Matrix(&v, eta, chi, ncx, ncy, bwx, bwy);
390  gsl_vector_set(c_amp, k, csum);
391  }
392 
393  // Evaluate the TP spline for all SVD modes - phase
394  for (int k=0; k<nk_phi; k++) { // For each SVD mode
395  gsl_vector v = gsl_vector_subvector(cvec_phi, k*N, N).vector; // Pick out the coefficient matrix corresponding to the k-th SVD mode.
396  REAL8 csum = Interpolate_Coefficent_Matrix(&v, eta, chi, ncx, ncy, bwx, bwy);
397  gsl_vector_set(c_phi, k, csum);
398  }
399 
400  // Evaluate the TP spline for the amplitude prefactor
401  *amp_pre = Interpolate_Coefficent_Matrix(cvec_amp_pre, eta, chi, ncx, ncy, bwx, bwy);
402 
403  SplineData_Destroy(splinedata);
404 
405  return(0);
406 }
407 
408 /* Set up a new ROM model, using data contained in dir */
409 static int SEOBNRROMdata_Init(SEOBNRROMdata *romdata, const char dir[]) {
410  // set up ROM
411  int ncx = 50; // points in eta + 2
412  int ncy = 50; // points in chi + 2
413  int N = ncx*ncy; // size of the data matrix for one SVD-mode
414 
415  int ret = XLAL_FAILURE;
416 
417  /* Create storage for structures */
418  if(romdata->setup)
419  {
420  XLAL_PRINT_WARNING("WARNING: You tried to setup the SEOBNRv2ROMEffectiveSpin model that was already initialised. Ignoring");
421  return (XLAL_FAILURE);
422  }
423 
424  (romdata)->cvec_amp = gsl_vector_alloc(N*nk_amp);
425  (romdata)->cvec_phi = gsl_vector_alloc(N*nk_phi);
426  (romdata)->Bamp = gsl_matrix_alloc(nk_amp, nk_amp);
427  (romdata)->Bphi = gsl_matrix_alloc(nk_phi, nk_phi);
428  (romdata)->cvec_amp_pre = gsl_vector_alloc(N);
429  ret=load_data(dir, (romdata)->cvec_amp, (romdata)->cvec_phi, (romdata)->Bamp, (romdata)->Bphi, (romdata)->cvec_amp_pre);
430 
431  if(XLAL_SUCCESS==ret) romdata->setup=1;
432  else SEOBNRROMdata_Cleanup(romdata);
433 
434  return (ret);
435 }
436 
437 
438 /* Deallocate contents of the given SEOBNRROMdata structure */
439 static void SEOBNRROMdata_Cleanup(SEOBNRROMdata *romdata) {
440  if(romdata->cvec_amp) gsl_vector_free(romdata->cvec_amp);
441  if(romdata->cvec_phi) gsl_vector_free(romdata->cvec_phi);
442  if(romdata->Bamp) gsl_matrix_free(romdata->Bamp);
443  if(romdata->Bphi) gsl_matrix_free(romdata->Bphi);
444  if(romdata->cvec_amp_pre) gsl_vector_free(romdata->cvec_amp_pre);
445  romdata->setup=0;
446 }
447 
448 /* Structure for internal use */
449 static void SEOBNRROMdata_coeff_Init(SEOBNRROMdata_coeff **romdatacoeff) {
450 
451  if(!romdatacoeff) exit(1);
452  /* Create storage for structures */
453  if(!*romdatacoeff) *romdatacoeff=XLALCalloc(1,sizeof(SEOBNRROMdata_coeff));
454  else
455  {
456  SEOBNRROMdata_coeff_Cleanup(*romdatacoeff);
457  }
458 
459  (*romdatacoeff)->c_amp = gsl_vector_alloc(nk_amp);
460  (*romdatacoeff)->c_phi = gsl_vector_alloc(nk_phi);
461 }
462 
463 /* Deallocate contents of the given SEOBNRROMdata_coeff structure */
465  if(romdatacoeff->c_amp) gsl_vector_free(romdatacoeff->c_amp);
466  if(romdatacoeff->c_phi) gsl_vector_free(romdatacoeff->c_phi);
467  XLALFree(romdatacoeff);
468 }
469 
470 /* Return the closest higher power of 2 */
471 static size_t NextPow2(const size_t n) {
472  return 1 << (size_t) ceil(log2(n));
473 }
474 
475 /**
476  * Core function for computing the ROM waveform.
477  * Interpolate projection coefficient data and evaluate coefficients at desired (q, chi).
478  * Construct 1D splines for amplitude and phase.
479  * Compute strain waveform from amplitude and phase.
480 */
482  COMPLEX16FrequencySeries **hptilde,
483  COMPLEX16FrequencySeries **hctilde,
484  double phiRef,
485  double fRef,
486  double distance,
487  double inclination,
488  double Mtot_sec,
489  double eta,
490  double chi,
491  const REAL8Sequence *freqs_in, /* Frequency points at which to evaluate the waveform (Hz) */
492  double deltaF
493  /* If deltaF > 0, the frequency points given in freqs are uniformly spaced with
494  * spacing deltaF. Otherwise, the frequency points are spaced non-uniformly.
495  * Then we will use deltaF = 0 to create the frequency series we return. */
496 )
497 {
498  /* Check output arrays */
499  if(!hptilde || !hctilde)
501  SEOBNRROMdata *romdata=&__lalsim_SEOBNRv2ROMSS_data;
502  if(*hptilde || *hctilde)
503  XLAL_ERROR(XLAL_EFAULT, "(*hptilde) and (*hctilde) are supposed to be NULL, but got %p and %p",(*hptilde),(*hctilde));
504  int retcode=0;
505 
506  // 'Nudge' parameter values to allowed boundary values if close by
507  if (eta > 0.25) nudge(&eta, 0.25, 1e-6);
508  if (eta < 0.01) nudge(&eta, 0.01, 1e-6);
509  if (chi < -1.0) nudge(&chi, -1.0, 1e-6);
510  if (chi > 0.99) nudge(&chi, 0.99, 1e-6);
511 
512  if (chi < -1.0 || chi > 0.99)
513  XLAL_ERROR(XLAL_EDOM, "XLAL Error - %s: chi (%f) smaller than -1 or larger than 0.99!\nSEOBNRv2ROMEffectiveSpin is only available for spins in the range -1 <= a/M <= 0.99.\n", __func__,chi);
514 
515  if (eta < 0.01 || eta > 0.25)
516  XLAL_ERROR(XLAL_EDOM, "XLAL Error - %s: eta (%f) smaller than 0.01 or unphysical!\nSEOBNRv2ROMEffectiveSpin is only available for eta in the range 0.01 <= eta <= 0.25.\n", __func__,eta);
517 
518  /* Find frequency bounds */
519  if (!freqs_in) XLAL_ERROR(XLAL_EFAULT);
520  double fLow = freqs_in->data[0];
521  double fHigh = freqs_in->data[freqs_in->length - 1];
522 
523  if(fRef==0.0)
524  fRef=fLow;
525 
526  /* Convert to geometric units for frequency */
527  double Mf_ROM_min = fmax(gA[0], gPhi[0]); // lowest allowed geometric frequency for ROM
528  double Mf_ROM_max = fmin(gA[nk_amp-1], gPhi[nk_phi-1]); // highest allowed geometric frequency for ROM
529  double fLow_geom = fLow * Mtot_sec;
530  double fHigh_geom = fHigh * Mtot_sec;
531  double fRef_geom = fRef * Mtot_sec;
532  double deltaF_geom = deltaF * Mtot_sec;
533 
534  // Enforce allowed geometric frequency range
535  if (fLow_geom < Mf_ROM_min)
536  XLAL_ERROR(XLAL_EDOM, "Starting frequency Mflow=%g is smaller than lowest frequency in ROM Mf=%g.\n", fLow_geom, Mf_ROM_min);
537  if (fHigh_geom == 0)
538  fHigh_geom = Mf_ROM_max;
539  else if (fHigh_geom > Mf_ROM_max) {
540  XLALPrintWarning("Maximal frequency Mf_high=%g is greater than highest ROM frequency Mf_ROM_Max=%g. Using Mf_high=Mf_ROM_Max.", fHigh_geom, Mf_ROM_max);
541  fHigh_geom = Mf_ROM_max;
542  }
543  else if (fHigh_geom < Mf_ROM_min)
544  XLAL_ERROR(XLAL_EDOM, "End frequency %g is smaller than starting frequency %g!\n", fHigh_geom, fLow_geom);
545  if (fRef_geom > Mf_ROM_max) {
546  XLALPrintWarning("Reference frequency Mf_ref=%g is greater than maximal frequency in ROM Mf=%g. Starting at maximal frequency in ROM.\n", fRef_geom, Mf_ROM_max);
547  fRef_geom = Mf_ROM_max; // If fref > fhigh we reset fref to default value of cutoff frequency.
548  }
549  if (fRef_geom < Mf_ROM_min) {
550  XLAL_PRINT_WARNING("Reference frequency Mf_ref=%g is smaller than lowest frequency in ROM Mf=%g. Starting at lowest frequency in ROM.\n", fLow_geom, Mf_ROM_min);
551  fRef_geom = Mf_ROM_min;
552  }
553 
554  /* Internal storage for w.f. coefficiencts */
555  SEOBNRROMdata_coeff *romdata_coeff=NULL;
556  SEOBNRROMdata_coeff_Init(&romdata_coeff);
557  REAL8 amp_pre;
558 
559  /* Interpolate projection coefficients and evaluate them at (eta,chi) */
561  eta, // Input: eta-value for which projection coefficients should be evaluated
562  chi, // Input: chi-value for which projection coefficients should be evaluated
563  romdata->cvec_amp, // Input: data for spline coefficients for amplitude
564  romdata->cvec_phi, // Input: data for spline coefficients for phase
565  romdata->cvec_amp_pre, // Input: data for spline coefficients for amplitude prefactor
566  romdata_coeff->c_amp, // Output: interpolated projection coefficients for amplitude
567  romdata_coeff->c_phi, // Output: interpolated projection coefficients for phase
568  &amp_pre // Output: interpolated amplitude prefactor
569  );
570 
571  if(retcode!=0) {
572  SEOBNRROMdata_coeff_Cleanup(romdata_coeff);
573  XLAL_ERROR(retcode, "Parameter-space interpolation failed.");
574  }
575 
576  // Compute function values of amplitude an phase on sparse frequency points by evaluating matrix vector products
577  // amp_pts = B_A^T . c_A
578  // phi_pts = B_phi^T . c_phi
579  gsl_vector* amp_f = gsl_vector_alloc(nk_amp);
580  gsl_vector* phi_f = gsl_vector_alloc(nk_phi);
581  gsl_blas_dgemv(CblasTrans, 1.0, romdata->Bamp, romdata_coeff->c_amp, 0.0, amp_f);
582  gsl_blas_dgemv(CblasTrans, 1.0, romdata->Bphi, romdata_coeff->c_phi, 0.0, phi_f);
583 
584  // Setup 1d splines in frequency
585  gsl_interp_accel *acc_amp = gsl_interp_accel_alloc();
586  gsl_spline *spline_amp = gsl_spline_alloc(gsl_interp_cspline, nk_amp);
587  gsl_spline_init(spline_amp, gA, gsl_vector_const_ptr(amp_f,0), nk_amp);
588 
589  gsl_interp_accel *acc_phi = gsl_interp_accel_alloc();
590  gsl_spline *spline_phi = gsl_spline_alloc(gsl_interp_cspline, nk_phi);
591  gsl_spline_init(spline_phi, gPhi, gsl_vector_const_ptr(phi_f,0), nk_phi);
592 
593  size_t npts = 0;
594  LIGOTimeGPS tC = {0, 0};
595  UINT4 offset = 0; // Index shift between freqs and the frequency series
596  REAL8Sequence *freqs = NULL;
597  if (deltaF > 0) { // freqs contains uniform frequency grid with spacing deltaF; we start at frequency 0
598  /* Set up output array with size closest power of 2 */
599  npts = NextPow2(fHigh_geom / deltaF_geom) + 1;
600  if (fHigh_geom < fHigh * Mtot_sec) /* Resize waveform if user wants f_max larger than cutoff frequency */
601  npts = NextPow2(fHigh * Mtot_sec / deltaF_geom) + 1;
602 
603  XLALGPSAdd(&tC, -1. / deltaF); /* coalesce at t=0 */
604  *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, npts);
605  *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, npts);
606 
607  // Recreate freqs using only the lower and upper bounds
608  // Use fLow, fHigh and deltaF rather than geometric frequencies for numerical accuracy
609  double fHigh_temp = fHigh_geom / Mtot_sec;
610  UINT4 iStart = (UINT4) ceil(fLow / deltaF);
611  UINT4 iStop = (UINT4) ceil(fHigh_temp / deltaF);
612  freqs = XLALCreateREAL8Sequence(iStop - iStart);
613  if (!freqs) {
614  XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
615  }
616  for (UINT4 i=iStart; i<iStop; i++)
617  freqs->data[i-iStart] = i*deltaF_geom;
618 
619  offset = iStart;
620  } else { // freqs contains frequencies with non-uniform spacing; we start at lowest given frequency
621  npts = freqs_in->length;
622  *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &tC, fLow, 0, &lalStrainUnit, npts);
623  *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &tC, fLow, 0, &lalStrainUnit, npts);
624  offset = 0;
625 
626  freqs = XLALCreateREAL8Sequence(freqs_in->length);
627  if (!freqs) {
628  XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
629  }
630  for (UINT4 i=0; i<freqs_in->length; i++)
631  freqs->data[i] = freqs_in->data[i] * Mtot_sec;
632  }
633 
634  if (!(*hptilde) || !(*hctilde)) {
636  gsl_spline_free(spline_amp);
637  gsl_spline_free(spline_phi);
638  gsl_interp_accel_free(acc_amp);
639  gsl_interp_accel_free(acc_phi);
640  gsl_vector_free(amp_f);
641  gsl_vector_free(phi_f);
642  SEOBNRROMdata_coeff_Cleanup(romdata_coeff);
643  XLAL_ERROR(XLAL_EFUNC, "Waveform allocation failed.");
644  }
645  memset((*hptilde)->data->data, 0, npts * sizeof(COMPLEX16));
646  memset((*hctilde)->data->data, 0, npts * sizeof(COMPLEX16));
647 
648  XLALUnitMultiply(&(*hptilde)->sampleUnits, &(*hptilde)->sampleUnits, &lalSecondUnit);
649  XLALUnitMultiply(&(*hctilde)->sampleUnits, &(*hctilde)->sampleUnits, &lalSecondUnit);
650 
651  COMPLEX16 *pdata=(*hptilde)->data->data;
652  COMPLEX16 *cdata=(*hctilde)->data->data;
653 
654  REAL8 cosi = cos(inclination);
655  REAL8 pcoef = 0.5*(1.0 + cosi*cosi);
656  REAL8 ccoef = cosi;
657 
658  REAL8 s = 1.0/2.0; // Scale polarization amplitude so that strain agrees with FFT of SEOBNRv2
659  double Mtot = Mtot_sec / LAL_MTSUN_SI;
660  double amp0 = Mtot * amp_pre * Mtot_sec * LAL_MRSUN_SI / (distance); // Correct overall amplitude to undo mass-dependent scaling used in single-spin ROM
661 
662  // Evaluate reference phase for setting phiRef correctly
663  double phase_change = gsl_spline_eval(spline_phi, fRef_geom, acc_phi) - 2*phiRef;
664 
665  // Assemble waveform from aplitude and phase
666  for (UINT4 i=0; i<freqs->length; i++) { // loop over frequency points in sequence
667  double f = freqs->data[i];
668  if (f > Mf_ROM_max) continue; // We're beyond the highest allowed frequency; since freqs may not be ordered, we'll just skip the current frequency and leave zero in the buffer
669  int j = i + offset; // shift index for frequency series if needed
670  double A = gsl_spline_eval(spline_amp, f, acc_amp);
671  double phase = gsl_spline_eval(spline_phi, f, acc_phi) - phase_change;
672  COMPLEX16 htilde = s*amp0*A * cexp(I*phase);
673  pdata[j] = pcoef * htilde;
674  cdata[j] = -I * ccoef * htilde;
675  }
676 
677  /* Correct phasing so we coalesce at t=0 (with the definition of the epoch=-1/deltaF above) */
678 
679  // Get SEOBNRv2 ringdown frequency for 22 mode
680  double Mf_final = SEOBNRROM_Ringdown_Mf_From_Mtot_Eta(Mtot_sec, eta, chi, chi, SEOBNRv2);
681 
682  UINT4 L = freqs->length;
683  // prevent gsl interpolation errors
684  if (Mf_final > freqs->data[L-1])
685  Mf_final = freqs->data[L-1];
686  if (Mf_final < freqs->data[0])
687  {
689  gsl_spline_free(spline_amp);
690  gsl_spline_free(spline_phi);
691  gsl_interp_accel_free(acc_amp);
692  gsl_interp_accel_free(acc_phi);
693  gsl_vector_free(amp_f);
694  gsl_vector_free(phi_f);
695  SEOBNRROMdata_coeff_Cleanup(romdata_coeff);
696  XLAL_ERROR(XLAL_EDOM, "f_ringdown < f_min");
697  }
698 
699  // Time correction is t(f_final) = 1/(2pi) dphi/df (f_final)
700  // We compute the dimensionless time correction t/M since we use geometric units.
701  REAL8 t_corr = gsl_spline_eval_deriv(spline_phi, Mf_final, acc_phi) / (2*LAL_PI);
702 
703  // Now correct phase
704  for (UINT4 i=0; i<freqs->length; i++) { // loop over frequency points in sequence
705  double f = freqs->data[i] - fRef_geom;
706  int j = i + offset; // shift index for frequency series if needed
707  pdata[j] *= cexp(-2*LAL_PI * I * f * t_corr);
708  cdata[j] *= cexp(-2*LAL_PI * I * f * t_corr);
709  }
710 
712 
713  gsl_spline_free(spline_amp);
714  gsl_spline_free(spline_phi);
715  gsl_interp_accel_free(acc_amp);
716  gsl_interp_accel_free(acc_phi);
717  gsl_vector_free(amp_f);
718  gsl_vector_free(phi_f);
719  SEOBNRROMdata_coeff_Cleanup(romdata_coeff);
720 
721  return(XLAL_SUCCESS);
722 }
723 
724 /**
725  * @addtogroup LALSimIMRSEOBNRROM_c
726  *
727  * @{
728  *
729  * @name SEOBNRv2 Reduced Order Model (Effective Spin)
730  *
731  * @author Michael Puerrer, John Veitch
732  *
733  * @brief C code for SEOBNRv2 reduced order model (equal spin version).
734  * See CQG 31 195010, 2014, arXiv:1402.4146 for details.
735  *
736  * This is a frequency domain model that approximates the time domain SEOBNRv2 model with equal spins.
737  *
738  * The binary data files are available at https://dcc.ligo.org/T1400701-v1.
739  * Put the untared data into a location in your LAL_DATA_PATH.
740  *
741  * @note Note that due to its construction the iFFT of the ROM has a small (~ 20 M) offset
742  * in the peak time that scales with total mass as compared to the time-domain SEOBNRv2 model.
743  *
744  * @note Parameter ranges:
745  * * 0.01 <= eta <= 0.25
746  * * -1 <= chi <= 0.99
747  * * Mtot >= 1.4Msun
748  *
749  * Equal spin chi = chi1 = chi2 in terms of aligned component spins chi1, chi2.
750  * Symmetric mass-ratio eta = m1*m2/(m1+m2)^2.
751  * Total mass Mtot.
752  *
753  * @{
754  */
755 
756 
757 /**
758  * Compute waveform in LAL format at specified frequencies for the SEOBNRv2_ROM_EffectiveSpin model.
759  *
760  * XLALSimIMRSEOBNRv2ROMEffectiveSpin() returns the plus and cross polarizations as a complex
761  * frequency series with equal spacing deltaF and contains zeros from zero frequency
762  * to the starting frequency and zeros beyond the cutoff frequency in the ringdown.
763  *
764  * In contrast, XLALSimIMRSEOBNRv2ROMEffectiveSpinFrequencySequence() returns a
765  * complex frequency series with entries exactly at the frequencies specified in
766  * the sequence freqs (which can be unequally spaced). No zeros are added.
767  *
768  * If XLALSimIMRSEOBNRv2ROMEffectiveSpinFrequencySequence() is called with frequencies that
769  * are beyond the maxium allowed geometric frequency for the ROM, zero strain is returned.
770  * It is not assumed that the frequency sequence is ordered.
771  *
772  * This function is designed as an entry point for reduced order quadratures.
773  */
775  struct tagCOMPLEX16FrequencySeries **hptilde, /**< Output: Frequency-domain waveform h+ */
776  struct tagCOMPLEX16FrequencySeries **hctilde, /**< Output: Frequency-domain waveform hx */
777  const REAL8Sequence *freqs, /**< Frequency points at which to evaluate the waveform (Hz), need to be strictly monotonically increasing */
778  REAL8 phiRef, /**< Orbital phase at reference time */
779  REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
780  REAL8 distance, /**< Distance of source (m) */
781  REAL8 inclination, /**< Inclination of source (rad) */
782  REAL8 m1SI, /**< Mass of companion 1 (kg) */
783  REAL8 m2SI, /**< Mass of companion 2 (kg) */
784  REAL8 chi) /**< Effective aligned spin */
785 {
786 
787  /* Get masses in terms of solar mass */
788  double mass1 = m1SI / LAL_MSUN_SI;
789  double mass2 = m2SI / LAL_MSUN_SI;
790  double Mtot = mass1+mass2;
791  double eta = mass1 * mass2 / (Mtot*Mtot); /* Symmetric mass-ratio */
792  double Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
793 
794  if (!freqs) XLAL_ERROR(XLAL_EFAULT);
795 
796  // Load ROM data if not loaded already
797 #ifdef LAL_PTHREAD_LOCK
798  (void) pthread_once(&SEOBNRv2ROMEffectiveSpin_is_initialized, SEOBNRv2ROMEffectiveSpin_Init_LALDATA);
799 #else
801 #endif
802 
803  if(!SEOBNRv2ROMEffectiveSpin_IsSetup()) XLAL_ERROR(XLAL_EFAILED,"Error setting up SEOBNRv2ROMEffectiveSpin - check your $LAL_DATA_PATH\n");
804 
805  // Call the internal core function with deltaF = 0 to indicate that freqs is non-uniformly
806  // spaced and we want the strain only at these frequencies
807  int retcode = SEOBNRv2ROMEffectiveSpinCore(hptilde,hctilde,
808  phiRef, fRef, distance, inclination, Mtot_sec, eta, chi, freqs, 0);
809 
810  return(retcode);
811 }
812 
813 /**
814  * Compute waveform in LAL format for the SEOBNRv2_ROM_EffectiveSpin model.
815  *
816  * Returns the plus and cross polarizations as a complex frequency series with
817  * equal spacing deltaF and contains zeros from zero frequency to the starting
818  * frequency fLow and zeros beyond the cutoff frequency fHigh to the next power of 2 in
819  * the size of the frequency series.
820  */
822  struct tagCOMPLEX16FrequencySeries **hptilde, /**< Output: Frequency-domain waveform h+ */
823  struct tagCOMPLEX16FrequencySeries **hctilde, /**< Output: Frequency-domain waveform hx */
824  REAL8 phiRef, /**< Orbital phase at reference time */
825  REAL8 deltaF, /**< Sampling frequency (Hz) */
826  REAL8 fLow, /**< Starting GW frequency (Hz) */
827  REAL8 fHigh, /**< End frequency; 0 defaults to Mf=0.14 */
828  REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
829  REAL8 distance, /**< Distance of source (m) */
830  REAL8 inclination, /**< Inclination of source (rad) */
831  REAL8 m1SI, /**< Mass of companion 1 (kg) */
832  REAL8 m2SI, /**< Mass of companion 2 (kg) */
833  REAL8 chi) /**< Effective aligned spin */
834 {
835 
836  /* Get masses in terms of solar mass */
837  double mass1 = m1SI / LAL_MSUN_SI;
838  double mass2 = m2SI / LAL_MSUN_SI;
839  double Mtot = mass1+mass2;
840  double eta = mass1 * mass2 / (Mtot*Mtot); /* Symmetric mass-ratio */
841  double Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
842 
843  if(fRef==0.0)
844  fRef=fLow;
845 
846  // Load ROM data if not loaded already
847 #ifdef LAL_PTHREAD_LOCK
848  (void) pthread_once(&SEOBNRv2ROMEffectiveSpin_is_initialized, SEOBNRv2ROMEffectiveSpin_Init_LALDATA);
849 #else
851 #endif
852 
853  if(!SEOBNRv2ROMEffectiveSpin_IsSetup()) XLAL_ERROR(XLAL_EFAILED,"Error setting up SEOBNRv2ROMEffectiveSpin data - check your $LAL_DATA_PATH\n");
854 
855  // Use fLow, fHigh, deltaF to compute freqs sequence
856  // Instead of building a full sequency we only transfer the boundaries and let
857  // the internal core function do the rest (and properly take care of corner cases).
859  freqs->data[0] = fLow;
860  freqs->data[1] = fHigh;
861 
862  int retcode = SEOBNRv2ROMEffectiveSpinCore(hptilde, hctilde,
863  phiRef, fRef, distance, inclination, Mtot_sec, eta, chi, freqs, deltaF);
864 
866 
867  return(retcode);
868 }
869 
870 /**
871  * Compute the 'time' elapsed in the ROM waveform from a given starting frequency until the ringdown.
872  * UNREVIEWED!
873  *
874  * The notion of elapsed 'time' (in seconds) is defined here as the difference of the
875  * frequency derivative of the frequency domain phase between the ringdown frequency
876  * and the starting frequency ('frequency' argument). This notion of time is similar to the
877  * chirp time, but it includes both the inspiral and the merger ringdown part of SEOBNRv2.
878  *
879  * The allowed frequency range for the starting frequency in geometric frequency is [0.0001, 0.3].
880  * The SEOBNRv2 ringdown frequency can be obtained by calling XLALSimInspiralGetFinalFreq().
881  *
882  * See XLALSimIMRSEOBNRv2ROMEffectiveSpinFrequencyOfTime() for the inverse function.
883  */
885  REAL8 *t, /**< Output: time (s) at frequency */
886  REAL8 frequency, /**< Frequency (Hz) */
887  REAL8 m1SI, /**< Mass of companion 1 (kg) */
888  REAL8 m2SI, /**< Mass of companion 2 (kg) */
889  REAL8 chi /**< Equal aligned spin (chi = chi1 = chi2)*/
890 )
891 {
892  // Set up phase spline
893  gsl_spline *spline_phi;
894  gsl_interp_accel *acc_phi;
895  double Mf_final, Mtot_sec;
896  int ret = SEOBNRv2ROMEffectiveSpinTimeFrequencySetup(&spline_phi, &acc_phi, &Mf_final, &Mtot_sec, m1SI, m2SI, chi);
897  if(ret != 0)
898  XLAL_ERROR(ret);
899 
900  // ROM frequency bounds in Mf
901  double Mf_ROM_min = gPhi[0];
902  double Mf_ROM_max = gPhi[nk_phi-1];
903 
904  // Time correction is t(f_final) = 1/(2pi) dphi/df (f_final)
905  double t_corr = gsl_spline_eval_deriv(spline_phi, Mf_final, acc_phi) / (2*LAL_PI); // t_corr / M
906  XLAL_PRINT_INFO("t_corr[s] = %g\n", t_corr * Mtot_sec);
907 
908  double Mf = frequency * Mtot_sec;
909  if (Mf < Mf_ROM_min || Mf > Mf_ROM_max)
910  {
911  gsl_spline_free(spline_phi);
912  gsl_interp_accel_free(acc_phi);
913  XLAL_ERROR(XLAL_EDOM, "Frequency %g is outside allowed frequency range.\n", frequency);
914  }
915  // Compute time relative to origin at merger
916  double time_M = gsl_spline_eval_deriv(spline_phi, frequency * Mtot_sec, acc_phi) / (2*LAL_PI) - t_corr;
917  *t = time_M * Mtot_sec;
918 
919  gsl_spline_free(spline_phi);
920  gsl_interp_accel_free(acc_phi);
921 
922  return(XLAL_SUCCESS);
923 }
924 
925 /**
926  * Compute the starting frequency so that the given amount of 'time' elapses in the ROM waveform
927  * from the starting frequency until the ringdown.
928  * UNREVIEWED!
929  *
930  * The notion of elapsed 'time' (in seconds) is defined here as the difference of the
931  * frequency derivative of the frequency domain phase between the ringdown frequency
932  * and the starting frequency ('frequency' argument). This notion of time is similar to the
933  * chirp time, but it includes both the inspiral and the merger ringdown part of SEOBNRv2.
934  *
935  * If the frequency that corresponds to the specified elapsed time is lower than the
936  * geometric frequency Mf=0.0001 (ROM starting frequency) or above half of the SEOBNRv2
937  * ringdown frequency an error is thrown.
938  * The SEOBNRv2 ringdown frequency can be obtained by calling XLALSimInspiralGetFinalFreq().
939  *
940  * See XLALSimIMRSEOBNRv2ROMEffectiveSpinTimeOfFrequency() for the inverse function.
941  */
943  REAL8 *frequency, /**< Output: Frequency (Hz) */
944  REAL8 t, /**< Time (s) at frequency */
945  REAL8 m1SI, /**< Mass of companion 1 (kg) */
946  REAL8 m2SI, /**< Mass of companion 2 (kg) */
947  REAL8 chi /**< Effective aligned spin */
948 )
949 {
950  // Set up phase spline
951  gsl_spline *spline_phi;
952  gsl_interp_accel *acc_phi;
953  double Mf_final, Mtot_sec;
954  int ret = SEOBNRv2ROMEffectiveSpinTimeFrequencySetup(&spline_phi, &acc_phi, &Mf_final, &Mtot_sec, m1SI, m2SI, chi);
955  if(ret != 0)
956  XLAL_ERROR(ret);
957 
958  // ROM frequency bounds in Mf
959  double Mf_ROM_min = gPhi[0];
960 
961  // Time correction is t(f_final) = 1/(2pi) dphi/df (f_final)
962  double t_corr = gsl_spline_eval_deriv(spline_phi, Mf_final, acc_phi) / (2*LAL_PI); // t_corr / M
963  XLAL_PRINT_INFO("t_corr[s] = %g\n", t_corr * Mtot_sec);
964 
965  // Assume for now that we only care about f(t) *before* merger so that f(t) - f_ringdown >= 0.
966  // Assume that we only need to cover the frequency range [f_min, f_ringdown/2].
967  int N = 20;
968  double log_f_pts[N];
969  double log_t_pts[N];
970  double log_f_min = log(Mf_ROM_min);
971  double log_f_rng_2 = log(Mf_final/2.0);
972  double dlog_f = (log_f_rng_2 - log_f_min) / (N-1);
973 
974  // Set up data in log-log space
975  for (int i=0; i<N; i++) {
976  log_f_pts[i] = log_f_rng_2 - i*dlog_f; // gsl likes the x-values to be monotonically increasing
977  // Compute time relative to origin at merger
978  double time_M = gsl_spline_eval_deriv(spline_phi, exp(log_f_pts[i]), acc_phi) / (2*LAL_PI) - t_corr;
979  log_t_pts[i] = log(time_M * Mtot_sec);
980  }
981 
982  // Check whether time is in bounds
983  double t_rng_2 = exp(log_t_pts[0]); // time of f_ringdown/2
984  double t_min = exp(log_t_pts[N-1]); // time of f_min
985  if (t < t_rng_2 || t > t_min)
986  {
987  gsl_spline_free(spline_phi);
988  gsl_interp_accel_free(acc_phi);
989  XLAL_ERROR(XLAL_EDOM, "The frequency of time %g is outside allowed frequency range.\n", t);
990  }
991 
992  // create new spline for data
993  gsl_interp_accel *acc = gsl_interp_accel_alloc();
994  gsl_spline *spline = gsl_spline_alloc(gsl_interp_cspline, N);
995  gsl_spline_init(spline, log_t_pts, log_f_pts, N);
996 
997  *frequency = exp(gsl_spline_eval(spline, log(t), acc)) / Mtot_sec;
998 
999  gsl_spline_free(spline);
1000  gsl_interp_accel_free(acc);
1001  gsl_spline_free(spline_phi);
1002  gsl_interp_accel_free(acc_phi);
1003 
1004  return(XLAL_SUCCESS);
1005 }
1006 
1007 /** @} */
1008 /** @} */
1009 
1010 // Auxiliary function to perform setup of phase spline for t(f) and f(t) functions
1012  gsl_spline **spline_phi, // phase spline
1013  gsl_interp_accel **acc_phi, // phase spline accelerator
1014  REAL8 *Mf_final, // ringdown frequency in Mf
1015  REAL8 *Mtot_sec, // total mass in seconds
1016  REAL8 m1SI, // Mass of companion 1 (kg)
1017  REAL8 m2SI, // Mass of companion 2 (kg)
1018  REAL8 chi // Effective aligned spin
1019 )
1020 {
1021  /* Get masses in terms of solar mass */
1022  double mass1 = m1SI / LAL_MSUN_SI;
1023  double mass2 = m2SI / LAL_MSUN_SI;
1024  double Mtot = mass1 + mass2;
1025  double eta = mass1 * mass2 / (Mtot*Mtot); /* Symmetric mass-ratio */
1026  *Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
1027 
1028  // 'Nudge' parameter values to allowed boundary values if close by
1029  nudge(&eta, 0.25, 1e-6);
1030  nudge(&eta, 0.01, 1e-6);
1031  nudge(&chi, -1.0, 1e-6);
1032  nudge(&chi, 0.99, 1e-6);
1033 
1034  if (chi < -1.0 || chi > 0.99)
1035  XLAL_ERROR(XLAL_EDOM, "XLAL Error - %s: chi (%f) smaller than -1 or larger than 0.99!\nSEOBNRv2ROMEffectiveSpin is only available for spins in the range -1 <= a/M <= 0.99.\n", __func__,chi);
1036 
1037  if (eta < 0.01 || eta > 0.25)
1038  XLAL_ERROR(XLAL_EDOM, "XLAL Error - %s: eta (%f) smaller than 0.01 or unphysical!\nSEOBNRv2ROMEffectiveSpin is only available for spins in the range 0.01 <= eta <= 0.25.\n", __func__,eta);
1039 
1040  // Load ROM data if not loaded already
1041 #ifdef LAL_PTHREAD_LOCK
1042  (void) pthread_once(&SEOBNRv2ROMEffectiveSpin_is_initialized, SEOBNRv2ROMEffectiveSpin_Init_LALDATA);
1043 #else
1045 #endif
1046 
1047  SEOBNRROMdata *romdata=&__lalsim_SEOBNRv2ROMSS_data;
1048 
1049  /* Internal storage for w.f. coefficiencts */
1050  SEOBNRROMdata_coeff *romdata_coeff=NULL;
1051  SEOBNRROMdata_coeff_Init(&romdata_coeff);
1052  REAL8 amp_pre;
1053 
1054  /* Interpolate projection coefficients and evaluate them at (eta,chi) */
1055  int retcode=TP_Spline_interpolation_2d(
1056  eta, // Input: eta-value for which projection coefficients should be evaluated
1057  chi, // Input: chi-value for which projection coefficients should be evaluated
1058  romdata->cvec_amp, // Input: data for spline coefficients for amplitude
1059  romdata->cvec_phi, // Input: data for spline coefficients for phase
1060  romdata->cvec_amp_pre, // Input: data for spline coefficients for amplitude prefactor
1061  romdata_coeff->c_amp, // Output: interpolated projection coefficients for amplitude
1062  romdata_coeff->c_phi, // Output: interpolated projection coefficients for phase
1063  &amp_pre // Output: interpolated amplitude prefactor
1064  );
1065 
1066  if(retcode!=0) {
1067  SEOBNRROMdata_coeff_Cleanup(romdata_coeff);
1068  XLAL_ERROR(retcode);
1069  }
1070 
1071  // Compute function values of phase on sparse frequency points by evaluating matrix vector products
1072  // phi_pts = B_phi^T . c_phi
1073  gsl_vector* phi_f = gsl_vector_alloc(nk_phi);
1074  gsl_blas_dgemv(CblasTrans, 1.0, romdata->Bphi, romdata_coeff->c_phi, 0.0, phi_f);
1075 
1076  // Setup 1d phase spline in frequency
1077  *acc_phi = gsl_interp_accel_alloc();
1078  *spline_phi = gsl_spline_alloc(gsl_interp_cspline, nk_phi);
1079  gsl_spline_init(*spline_phi, gPhi, gsl_vector_const_ptr(phi_f,0), nk_phi);
1080 
1081  // Get SEOBNRv2 ringdown frequency for 22 mode
1082  *Mf_final = SEOBNRROM_Ringdown_Mf_From_Mtot_Eta(*Mtot_sec, eta, chi, chi, SEOBNRv2);
1083 
1084  gsl_vector_free(phi_f);
1085  SEOBNRROMdata_coeff_Cleanup(romdata_coeff);
1086 
1087  return(XLAL_SUCCESS);
1088 }
1089 
1090 
1091 /** Setup SEOBNRv2ROMEffectiveSpin model using data files installed in $LAL_DATA_PATH
1092  */
1094 {
1095  if (SEOBNRv2ROMEffectiveSpin_IsSetup()) return;
1096 
1097  // If we find one ROM datafile in a directory listed in LAL_DATA_PATH,
1098  // then we expect the remaining datafiles to also be there.
1099  char datafile[] = "SEOBNRv2ROM_SS_Phase_ciall.dat";
1100 
1101  char *path = XLAL_FILE_RESOLVE_PATH(datafile);
1102  if (path==NULL)
1103  XLAL_ERROR_VOID(XLAL_EIO, "Unable to resolve data file %s in $LAL_DATA_PATH\n", datafile);
1104  char *dir = dirname(path);
1105  int ret = SEOBNRv2ROMEffectiveSpin_Init(dir);
1106  XLALFree(path);
1107 
1108  if(ret!=XLAL_SUCCESS)
1109  XLAL_ERROR_VOID(XLAL_FAILURE, "Unable to find SEOBNRv2ROMEffectiveSpin data files in $LAL_DATA_PATH\n");
1110 }
static const REAL8 Mf_ROM_max
static const REAL8 Mf_ROM_min
static void nudge(REAL8 *x, REAL8 X, REAL8 epsilon)
Auxiliary functions for SEOBNRv1/v2 reduced order modeling codes in LALSimIMRSEOBNRv2ROMDoubleSpin....
static UNUSED double SEOBNRROM_Ringdown_Mf_From_Mtot_Eta(const double Mtot_sec, const double eta, const double chi1, const double chi2, Approximant apx)
static UNUSED REAL8 Interpolate_Coefficent_Matrix(gsl_vector *v, REAL8 eta, REAL8 chi, int ncx, int ncy, gsl_bspline_workspace *bwx, gsl_bspline_workspace *bwy)
static bool SEOBNRv2ROMEffectiveSpin_IsSetup(void)
Helper function to check if the SEOBNRv2ROMEffectiveSpin model has been initialised.
static SEOBNRROMdata __lalsim_SEOBNRv2ROMSS_data
static const double gA[]
static void SEOBNRv2ROMEffectiveSpin_Init_LALDATA(void)
Setup SEOBNRv2ROMEffectiveSpin model using data files installed in $LAL_DATA_PATH.
static int SEOBNRv2ROMEffectiveSpin_Init(const char dir[])
Setup SEOBNRv2ROMEffectiveSpin model using data files installed in dir.
static void SEOBNRROMdata_coeff_Cleanup(SEOBNRROMdata_coeff *romdatacoeff)
static void SplineData_Destroy(SplineData *splinedata)
static const double gPhi[]
static UNUSED REAL8 Interpolate_Coefficent_Tensor(gsl_vector *v, REAL8 eta, REAL8 chi1, REAL8 chi2, int ncy, int ncz, gsl_bspline_workspace *bwx, gsl_bspline_workspace *bwy, gsl_bspline_workspace *bwz)
static void SEOBNRROMdata_coeff_Init(SEOBNRROMdata_coeff **romdatacoeff)
static int read_vector(const char dir[], const char fname[], gsl_vector *v)
static void SEOBNRROMdata_Cleanup(SEOBNRROMdata *romdata)
static void SplineData_Init(SplineData **splinedata)
static int TP_Spline_interpolation_2d(REAL8 q, REAL8 chi, gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_vector *cvec_amp_pre, gsl_vector *c_amp, gsl_vector *c_phi, REAL8 *amp_pre)
static int SEOBNRv2ROMEffectiveSpinCore(COMPLEX16FrequencySeries **hptilde, COMPLEX16FrequencySeries **hctilde, double phiRef, double fRef, double distance, double inclination, double Mtot_sec, double eta, double chi, const REAL8Sequence *freqs, double deltaF)
Core function for computing the ROM waveform.
static int SEOBNRv2ROMEffectiveSpinTimeFrequencySetup(gsl_spline **spline_phi, gsl_interp_accel **acc_phi, REAL8 *Mf_final, REAL8 *Mtot_sec, REAL8 m1SI, REAL8 m2SI, REAL8 chi)
static size_t NextPow2(const size_t n)
static int load_data(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *cvec_amp_pre)
static int SEOBNRROMdata_Init(SEOBNRROMdata *romdata, const char dir[])
static int read_matrix(const char dir[], const char fname[], gsl_matrix *m)
int s
Definition: bh_qnmode.c:137
double i
Definition: bh_ringdown.c:118
double e
Definition: bh_ringdown.c:117
sigmaKerr data[0]
#define XLAL_FILE_RESOLVE_PATH(fname)
COMPLEX16FrequencySeries * XLALCreateCOMPLEX16FrequencySeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaF, const LALUnit *sampleUnits, size_t length)
#define LAL_MSUN_SI
#define LAL_PI
#define LAL_MTSUN_SI
#define LAL_MRSUN_SI
double complex COMPLEX16
double REAL8
uint32_t UINT4
void * XLALCalloc(size_t m, size_t n)
void XLALFree(void *p)
int XLALSimIMRSEOBNRv2ROMEffectiveSpinFrequencyOfTime(REAL8 *frequency, REAL8 t, REAL8 m1SI, REAL8 m2SI, REAL8 chi)
Compute the starting frequency so that the given amount of 'time' elapses in the ROM waveform from th...
int XLALSimIMRSEOBNRv2ROMEffectiveSpinFrequencySequence(struct tagCOMPLEX16FrequencySeries **hptilde, struct tagCOMPLEX16FrequencySeries **hctilde, const REAL8Sequence *freqs, REAL8 phiRef, REAL8 fRef, REAL8 distance, REAL8 inclination, REAL8 m1SI, REAL8 m2SI, REAL8 chi)
Compute waveform in LAL format at specified frequencies for the SEOBNRv2_ROM_EffectiveSpin model.
int XLALSimIMRSEOBNRv2ROMEffectiveSpinTimeOfFrequency(REAL8 *t, REAL8 frequency, REAL8 m1SI, REAL8 m2SI, REAL8 chi)
Compute the 'time' elapsed in the ROM waveform from a given starting frequency until the ringdown.
int XLALSimIMRSEOBNRv2ROMEffectiveSpin(struct tagCOMPLEX16FrequencySeries **hptilde, struct tagCOMPLEX16FrequencySeries **hctilde, REAL8 phiRef, REAL8 deltaF, REAL8 fLow, REAL8 fHigh, REAL8 fRef, REAL8 distance, REAL8 inclination, REAL8 m1SI, REAL8 m2SI, REAL8 chi)
Compute waveform in LAL format for the SEOBNRv2_ROM_EffectiveSpin model.
@ SEOBNRv2
Spin-aligned EOBNR model v2.
static const INT4 m
static const INT4 q
void XLALDestroyREAL8Sequence(REAL8Sequence *sequence)
REAL8Sequence * XLALCreateREAL8Sequence(size_t length)
const LALUnit lalStrainUnit
const LALUnit lalSecondUnit
LALUnit * XLALUnitMultiply(LALUnit *output, const LALUnit *unit1, const LALUnit *unit2)
#define XLAL_ERROR_VOID(...)
#define XLAL_PRINT_INFO(...)
#define XLAL_ERROR(...)
#define XLAL_PRINT_WARNING(...)
int int XLALPrintWarning(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EDOM
XLAL_EIO
XLAL_EFAILED
XLAL_FAILURE
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
path
int N
int pthread_once(pthread_once_t *once_control, void(*init_routine)(void))
REAL8 * data
gsl_bspline_workspace * bwx
gsl_bspline_workspace * bwy