LALSimulation  5.4.0.1-fe68b98
LALSimIMRSEOBNRv2ROMDoubleSpin.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/LALDatatypes.h>
44 #include <lal/SeqFactories.h>
45 #include <lal/LALConstants.h>
46 #include <lal/XLALError.h>
47 #include <lal/FrequencySeries.h>
48 #include <lal/Date.h>
49 #include <lal/StringInput.h>
50 #include <lal/Sequence.h>
51 #include <lal/LALStdio.h>
52 #include <lal/FileIO.h>
53 
54 #include <lal/LALSimInspiral.h>
55 #include <lal/LALSimIMR.h>
57 
58 #include <lal/LALConfig.h>
59 #ifdef LAL_PTHREAD_LOCK
60 #include <pthread.h>
61 #endif
62 
63 
64 /******************************************************************
65  * The double-spin SEOBNRv2 ROM consists of a number of submodels *
66  * for subdomains of the whole parameter space: *
67  * These submodels may change in the future. *
68  * *
69  * "Core" submodel 1 *
70  * B-spline points: 54x24x24 *
71  * Frequency points: {133, 139} *
72  * *
73  * "Near q=1" submodel 2 *
74  * B-spline points: 11x60x60 *
75  * Frequency points: {200, 187} *
76  * *
77  * "High q, high chi1" submodel 3 *
78  * B-spline points: 24x30x24 *
79  * frequency points: {133, 139} *
80  * *
81  *****************************************************************/
82 
83 
84 /********* Input data for spline basis points **************/
85 
86 // The frequency points are not the same for all submodels
87 
88 #define nk_amp_sub1 133 // number of SVD-modes == number of basis functions for amplitude
89 #define nk_phi_sub1 139 // number of SVD-modes == number of basis functions for phase
90 
91 // Frequency points for amplitude and phase
92 static const double gA_sub1[] = {0.0005, 0.000525, 0.00055125, 0.000578812, 0.000607753, 0.000638141, 0.000670048,
93  0.00070355, 0.000738728, 0.000775664, 0.000814447, 0.00085517, 0.000897928, 0.000942825,
94  0.000989966, 0.00103946, 0.00109144, 0.00114601, 0.00120331, 0.00126348, 0.00132665,
95  0.00139298, 0.00146263, 0.00153576, 0.00161255, 0.00169318, 0.00177784, 0.00186673,
96  0.00196006, 0.00205807, 0.00216097, 0.00226902, 0.00238247, 0.00250159, 0.00262667,
97  0.00275801, 0.00289591, 0.0030407, 0.00319274, 0.00335238, 0.00351999, 0.00369599, 0.00388079,
98  0.00407483, 0.00427858, 0.0044925, 0.00471713, 0.00495299, 0.00520063, 0.00546067, 0.0057337,
99  0.00602038, 0.0063214, 0.00663747, 0.00696935, 0.00731782, 0.00768371, 0.00806789, 0.00847129,
100  0.00889485, 0.00933959, 0.00980657, 0.0102969, 0.0108117, 0.0113523, 0.01192, 0.0125159,
101  0.0131417, 0.0137988, 0.0144888, 0.0152132, 0.0159739, 0.0167726, 0.0176112, 0.0184918,
102  0.0194163, 0.0203872, 0.0214065, 0.0224768, 0.0236007, 0.0247807, 0.0260198, 0.0273207,
103  0.0286868, 0.0301211, 0.0316272, 0.0332085, 0.034869, 0.0366124, 0.038443, 0.0403652,
104  0.0423834, 0.0445026, 0.0467277, 0.0490641, 0.0515173, 0.0540932, 0.0567979, 0.0596378,
105  0.0626196, 0.0657506, 0.0690382, 0.0724901, 0.0761146, 0.0799203, 0.0839163, 0.0881121,
106  0.0925177, 0.0971436, 0.102001, 0.107101, 0.112456, 0.118079, 0.123983, 0.130182, 0.136691,
107  0.143525, 0.150702, 0.158237, 0.166149, 0.174456, 0.183179, 0.192338, 0.201955, 0.212052,
108  0.222655, 0.233788, 0.245477, 0.257751, 0.270639, 0.28417, 0.298379, 0.3};
109 
110 static const double gPhi_sub1[] = {0.0005, 0.000509921, 0.000520106, 0.000530563, 0.000541301, 0.000552329, 0.000563659,
111  0.000575299, 0.000587261, 0.000599555, 0.000612194, 0.00062519, 0.000638554, 0.000652301,
112  0.000666444, 0.000680997, 0.000695976, 0.000711395, 0.000727272, 0.000743622, 0.000760465,
113  0.000777818, 0.000795701, 0.000814135, 0.00083314, 0.000852738, 0.000872954, 0.000893812,
114  0.000915337, 0.000937555, 0.000960495, 0.000984187, 0.00100866, 0.00103395, 0.00106009,
115  0.00108711, 0.00111506, 0.00114396, 0.00117387, 0.00120483, 0.00123688, 0.00127008,
116  0.00130446, 0.00134009, 0.00137703, 0.00141533, 0.00145506, 0.00149628, 0.00153906,
117  0.00158349, 0.00162963, 0.00167757, 0.0017274, 0.00177922, 0.00183312, 0.00188921, 0.00194759,
118  0.0020084, 0.00207175, 0.00213777, 0.00220662, 0.00227844, 0.00235339, 0.00243165, 0.0025134,
119  0.00259883, 0.00268816, 0.0027816, 0.0028794, 0.00298181, 0.0030891, 0.00320158, 0.00331954,
120  0.00344334, 0.00357333, 0.00370991, 0.00385349, 0.00400452, 0.0041635, 0.00433095, 0.00450744,
121  0.00469358, 0.00489005, 0.00509755, 0.00531687, 0.00554887, 0.00579446, 0.00605465,
122  0.00633054, 0.00662331, 0.00693427, 0.00726485, 0.0076166, 0.00799125, 0.00839066, 0.00881692,
123  0.00927229, 0.00975928, 0.0102807, 0.0108395, 0.0114393, 0.0120836, 0.0127768, 0.0135236,
124  0.0143291, 0.0151992, 0.0161404, 0.0171602, 0.0182667, 0.0194694, 0.0207788, 0.0222069,
125  0.0237674, 0.0254758, 0.0273498, 0.0294099, 0.0316794, 0.0341854, 0.0369591, 0.0400368,
126  0.043461, 0.0472811, 0.0515553, 0.0563523, 0.0617535, 0.0678557, 0.0747749, 0.0826504,
127  0.0916509, 0.101981, 0.113893, 0.127695, 0.143771, 0.1626, 0.184787, 0.2111, 0.242523,
128  0.280334, 0.3};
129 
130 #define nk_amp_sub3 nk_amp_sub1
131 #define nk_phi_sub3 nk_phi_sub1
132 #define gA_sub3 gA_sub1
133 #define gPhi_sub3 gPhi_sub1
134 
135 #define nk_amp_sub2 200
136 #define nk_phi_sub2 187
137 
138 static const double gA_sub2[] = {0.0005, 0.00051635, 0.000533235, 0.000550671, 0.000568678, \
139 0.000587274, 0.000606478, 0.00062631, 0.00064679, 0.00066794, \
140 0.000689782, 0.000712338, 0.000735631, 0.000759686, 0.000784528, \
141 0.000810182, 0.000836675, 0.000864034, 0.000892288, 0.000921466, \
142 0.000951598, 0.000982715, 0.00101485, 0.00104804, 0.00108231, \
143 0.0011177, 0.00115425, 0.00119199, 0.00123097, 0.00127122, \
144 0.00131279, 0.00135572, 0.00140005, 0.00144583, 0.00149311, \
145 0.00154194, 0.00159236, 0.00164443, 0.0016982, 0.00175373, \
146 0.00181108, 0.0018703, 0.00193146, 0.00199462, 0.00205984, 0.0021272, \
147 0.00219676, 0.00226859, 0.00234277, 0.00241938, 0.0024985, 0.0025802, \
148 0.00266457, 0.0027517, 0.00284168, 0.00293461, 0.00303057, \
149 0.00312967, 0.00323201, 0.00333769, 0.00344684, 0.00355955, \
150 0.00367594, 0.00379615, 0.00392028, 0.00404848, 0.00418086, \
151 0.00431757, 0.00445876, 0.00460456, 0.00475513, 0.00491062, \
152 0.0050712, 0.00523703, 0.00540828, 0.00558513, 0.00576776, \
153 0.00595637, 0.00615114, 0.00635229, 0.00656, 0.00677452, 0.00699604, \
154 0.00722481, 0.00746107, 0.00770504, 0.007957, 0.00821719, 0.00848589, \
155 0.00876338, 0.00904994, 0.00934588, 0.00965149, 0.00996709, 0.010293, \
156 0.0106296, 0.0109772, 0.0113361, 0.0117068, 0.0120896, 0.012485, \
157 0.0128932, 0.0133148, 0.0137502, 0.0141999, 0.0146642, 0.0151437, \
158 0.0156389, 0.0161503, 0.0166784, 0.0172238, 0.017787, 0.0183687, \
159 0.0189693, 0.0195896, 0.0202302, 0.0208917, 0.0215749, 0.0222804, \
160 0.023009, 0.0237614, 0.0245384, 0.0253408, 0.0261694, 0.0270251, \
161 0.0279089, 0.0288215, 0.0297639, 0.0307372, 0.0317423, 0.0327803, \
162 0.0338522, 0.0349592, 0.0361024, 0.0372829, 0.0385021, 0.0397611, \
163 0.0410613, 0.042404, 0.0437906, 0.0452225, 0.0467013, 0.0482284, \
164 0.0498055, 0.0514341, 0.053116, 0.0548529, 0.0566466, 0.058499, \
165 0.0604119, 0.0623874, 0.0644274, 0.0665342, 0.0687099, 0.0709567, \
166 0.073277, 0.0756731, 0.0781476, 0.0807031, 0.083342, 0.0860673, \
167 0.0888817, 0.0917882, 0.0947896, 0.0978893, 0.10109, 0.104396, \
168 0.10781, 0.111335, 0.114976, 0.118735, 0.122618, 0.126628, 0.130768, \
169 0.135044, 0.13946, 0.144021, 0.14873, 0.153594, 0.158616, 0.163803, \
170 0.169159, 0.174691, 0.180403, 0.186302, 0.192395, 0.198686, 0.205183, \
171 0.211892, 0.218821, 0.225977, 0.233366, 0.240997, 0.248878, 0.257016, \
172 0.265421, 0.2741, 0.283063, 0.292319, 0.3};
173 
174 static const double gPhi_sub2[] = {0.000527978, 0.000535297, 0.000542751, 0.000550343, 0.000558078, \
175 0.000565958, 0.000573987, 0.000582167, 0.000590504, 0.000599, \
176 0.00060766, 0.000616487, 0.000625485, 0.000634659, 0.000644013, \
177 0.000653551, 0.000663278, 0.000673198, 0.000683317, 0.000693639, \
178 0.000704169, 0.000714913, 0.000725876, 0.000737064, 0.000748482, \
179 0.000760137, 0.000772035, 0.000784181, 0.000796583, 0.000809247, \
180 0.00082218, 0.00083539, 0.000848883, 0.000862667, 0.000876751, \
181 0.000891143, 0.00090585, 0.000920881, 0.000936246, 0.000951954, \
182 0.000968015, 0.000984437, 0.00100123, 0.00101841, 0.00103598, \
183 0.00105396, 0.00107236, 0.00109118, 0.00111045, 0.00113017, \
184 0.00115036, 0.00117103, 0.0011922, 0.00121388, 0.00123608, \
185 0.00125883, 0.00128214, 0.00130603, 0.00133052, 0.00135561, \
186 0.00138134, 0.00140773, 0.00143478, 0.00146254, 0.00149101, \
187 0.00152022, 0.0015502, 0.00158097, 0.00161255, 0.00164498, \
188 0.00167829, 0.00171249, 0.00174763, 0.00178373, 0.00182083, \
189 0.00185896, 0.00189816, 0.00193847, 0.00197992, 0.00202256, \
190 0.00206643, 0.00211157, 0.00215802, 0.00220585, 0.0022551, \
191 0.00230581, 0.00235806, 0.00241188, 0.00246736, 0.00252454, \
192 0.00258349, 0.00264428, 0.002707, 0.0027717, 0.00283847, 0.00290739, \
193 0.00297856, 0.00305206, 0.00312798, 0.00320644, 0.00328752, \
194 0.00337136, 0.00345806, 0.00354774, 0.00364054, 0.00373658, \
195 0.00383602, 0.00393901, 0.00404569, 0.00415625, 0.00427086, \
196 0.00438969, 0.00451296, 0.00464086, 0.00477362, 0.00491147, \
197 0.00505465, 0.00520342, 0.00535805, 0.00551885, 0.00568611, \
198 0.00586017, 0.00604136, 0.00623006, 0.00642666, 0.00663158, \
199 0.00684526, 0.00706816, 0.00730079, 0.00754369, 0.00779742, \
200 0.0080626, 0.00833986, 0.00862992, 0.0089335, 0.0092514, 0.00958447, \
201 0.00993363, 0.0102998, 0.0106842, 0.0110877, 0.0115118, 0.0119576, \
202 0.0124265, 0.0129201, 0.0134401, 0.0139881, 0.0145661, 0.0151762, \
203 0.0158206, 0.0165017, 0.0172222, 0.0179849, 0.0187931, 0.01965, \
204 0.0205593, 0.0215253, 0.0225522, 0.0236449, 0.0248088, 0.0260497, \
205 0.0273741, 0.0287889, 0.0303021, 0.0319223, 0.033659, 0.0355228, \
206 0.0375255, 0.0396801, 0.0420012, 0.044505, 0.0472099, 0.0501361, \
207 0.0533066, 0.0567473, 0.0604871, 0.0645592, 0.0690008, 0.0738545, \
208 0.0791686, 0.0849986, 0.091408, 0.0984697, 0.106268, 0.1149, 0.12448, \
209 0.13514};
210 
211 /******* B-spline knots over the parameter space *******/
212 static const double etavec_sub1[] = {0.01, 0.011, 0.012, 0.013, 0.014, 0.015, 0.016, 0.017, 0.018, 0.019, \
213  0.02, 0.021, 0.022, 0.023, 0.024, 0.025, 0.026, 0.027, 0.028, 0.029, \
214  0.032, 0.034, 0.036, 0.038, 0.04, 0.042, 0.044, 0.048, 0.05, 0.056, \
215  0.06, 0.065, 0.073, 0.082, 0.089, 0.1, 0.11, 0.12, 0.133, 0.15, \
216  0.162, 0.18, 0.195, 0.21, 0.22, 0.2225, 0.225, 0.2275, 0.23, 0.2325, \
217  0.235, 0.2375, 0.24, 0.25};
218 static const double chi1vec_sub1[] = {-1., -0.9, -0.75, -0.6, -0.45, -0.3, -0.15, 0., 0.15, 0.3, 0.45, 0.6, \
219  0.7, 0.75, 0.8, 0.85, 0.875, 0.9, 0.92, 0.94, 0.96, 0.97, 0.98, 0.99};
220 static const double chi2vec_sub1[] = {-1., -0.9, -0.75, -0.6, -0.45, -0.3, -0.15, 0., 0.15, 0.3, 0.45, 0.6, \
221  0.7, 0.75, 0.8, 0.85, 0.875, 0.9, 0.92, 0.94, 0.96, 0.97, 0.98, 0.99};
222 
223 static const int ncx_sub1 = 54+2; // points in eta + 2
224 static const int ncy_sub1 = 24+2; // points in chi1 + 2
225 static const int ncz_sub1 = 24+2; // points in chi2 + 2
226 
227 
228 static const double etavec_sub2[] = {0.242, 0.244, 0.245, 0.246, 0.247, 0.248, 0.249, 0.2495, 0.2498, \
229 0.2499, 0.25};
230 static const double chi1vec_sub2[] = {-1., -0.95, -0.9, -0.85, -0.8, -0.75, -0.7, -0.65, -0.6, -0.55, \
231 -0.5, -0.45, -0.4, -0.35, -0.3, -0.25, -0.2, -0.15, -0.1, -0.05, 0., \
232 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, \
233 0.65, 0.7, 0.75, 0.8, 0.825, 0.85, 0.875, 0.88, 0.89, 0.9, 0.91, \
234 0.92, 0.93, 0.94, 0.95, 0.96, 0.965, 0.97, 0.975, 0.98, 0.983, 0.985, \
235 0.986, 0.987, 0.988, 0.989, 0.99};
236 static const double chi2vec_sub2[] = {-1., -0.95, -0.9, -0.85, -0.8, -0.75, -0.7, -0.65, -0.6, -0.55, \
237 -0.5, -0.45, -0.4, -0.35, -0.3, -0.25, -0.2, -0.15, -0.1, -0.05, 0., \
238 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, \
239 0.65, 0.7, 0.75, 0.8, 0.825, 0.85, 0.875, 0.88, 0.89, 0.9, 0.91, \
240 0.92, 0.93, 0.94, 0.95, 0.96, 0.965, 0.97, 0.975, 0.98, 0.983, 0.985, \
241 0.986, 0.987, 0.988, 0.989, 0.99};
242 
243 static const int ncx_sub2 = 11+2; // points in eta + 2
244 static const int ncy_sub2 = 60+2; // points in chi1 + 2
245 static const int ncz_sub2 = 60+2; // points in chi2 + 2
246 
247 
248 static const double etavec_sub3[] = {0.01, 0.011, 0.012, 0.013, 0.014, 0.015, 0.016, 0.017, 0.018, 0.019, \
249 0.02, 0.022, 0.024, 0.026, 0.028, 0.03, 0.036, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1};
250 static const double chi1vec_sub3[] = {0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.825, 0.85, 0.875, 0.88, \
251 0.89, 0.9, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.965, 0.97, 0.975, \
252 0.98, 0.983, 0.985, 0.986, 0.987, 0.988, 0.989, 0.99};
253 static const double chi2vec_sub3[] = {-1., -0.9, -0.75, -0.6, -0.45, -0.3, -0.15, 0., 0.15, 0.3, 0.45, \
254 0.6, 0.7, 0.75, 0.8, 0.85, 0.875, 0.9, 0.92, 0.94, 0.96, 0.97, 0.98, 0.99};
255 
256 static const int ncx_sub3 = 24+2; // points in eta + 2
257 static const int ncy_sub3 = 30+2; // points in chi1 + 2
258 static const int ncz_sub3 = 24+2; // points in chi2 + 2
259 
260 #ifdef LAL_PTHREAD_LOCK
261 static pthread_once_t SEOBNRv2ROMDoubleSpin_is_initialized = PTHREAD_ONCE_INIT;
262 #endif
263 
264 /*************** type definitions ******************/
265 
266 typedef struct tagSEOBNRROMdataDS_coeff
267 {
268  gsl_vector* c_amp;
269  gsl_vector* c_phi;
271 
273 {
274  gsl_vector* cvec_amp; // Flattened amplitude projection coefficients
275  gsl_vector* cvec_phi; // Flattened phase projection coefficients
276  gsl_matrix *Bamp; // Reduced SVD basis for amplitude
277  gsl_matrix *Bphi; // Reduced SVD basis for phase
278  gsl_vector* cvec_amp_pre; // AMplitude prefactor coefficient
279  int nk_amp; // Number frequency points for amplitude
280  int nk_phi; // Number of frequency points for phase
281  const double *gA; // Sparse frequency points for amplitude
282  const double *gPhi; // Sparse frequency points for phase
283  const double *etavec; // B-spline knots in eta
284  const double *chi1vec; // B-spline knots in chi1
285  const double *chi2vec; // B-spline knots in chi2
286  int ncx, ncy, ncz; // Number of points in eta, chi1, chi2
287 };
288 typedef struct tagSEOBNRROMdataDS_submodel SEOBNRROMdataDS_submodel;
289 
290 struct tagSEOBNRROMdataDS
291 {
292  UINT4 setup;
293  SEOBNRROMdataDS_submodel* sub1;
294  SEOBNRROMdataDS_submodel* sub2;
295  SEOBNRROMdataDS_submodel* sub3;
296 };
297 typedef struct tagSEOBNRROMdataDS SEOBNRROMdataDS;
298 
299 static SEOBNRROMdataDS __lalsim_SEOBNRv2ROMDS_data;
300 
301 typedef int (*load_dataPtr)(const char*, gsl_vector *, gsl_vector *, gsl_matrix *, gsl_matrix *, gsl_vector *);
302 
303 typedef struct tagSplineData
304 {
305  gsl_bspline_workspace *bwx;
306  gsl_bspline_workspace *bwy;
307  gsl_bspline_workspace *bwz;
308 } SplineData;
309 
310 /**************** Internal functions **********************/
311 
312 static void SEOBNRv2ROMDoubleSpin_Init_LALDATA(void);
313 static int SEOBNRv2ROMDoubleSpin_Init(const char dir[]);
314 static bool SEOBNRv2ROMDoubleSpin_IsSetup(void);
315 
316 static int SEOBNRROMdataDS_Init(SEOBNRROMdataDS *romdata, const char dir[]);
317 static void SEOBNRROMdataDS_Cleanup(SEOBNRROMdataDS *romdata);
318 
319 static int TP_Spline_interpolation_3d(
320  REAL8 eta, // Input: eta-value for which projection coefficients should be evaluated
321  REAL8 chi1, // Input: chi1-value for which projection coefficients should be evaluated
322  REAL8 chi2, // Input: chi2-value for which projection coefficients should be evaluated
323  gsl_vector *cvec_amp, // Input: data for spline coefficients for amplitude
324  gsl_vector *cvec_phi, // Input: data for spline coefficients for phase
325  gsl_vector *cvec_amp_pre, // Input: data for spline coefficients for amplitude prefactor
326  int nk_amp, // number of SVD-modes == number of basis functions for amplitude
327  int nk_phi, // number of SVD-modes == number of basis functions for phase
328  int ncx, // Number of points in eta + 2
329  int ncy, // Number of points in chi1 + 2
330  int ncz, // Number of points in chi2 + 2
331  const double *etavec, // B-spline knots in eta
332  const double *chi1vec, // B-spline knots in chi1
333  const double *chi2vec, // B-spline knots in chi2
334  gsl_vector *c_amp, // Output: interpolated projection coefficients for amplitude
335  gsl_vector *c_phi, // Output: interpolated projection coefficients for phase
336  REAL8 *amp_pre // Output: interpolated amplitude prefactor
337 );
338 
340  SEOBNRROMdataDS_submodel **submodel,
341  const int nk_amp,
342  const int nk_phi,
343  const double *gA,
344  const double *gPhi,
345  const double *etavec,
346  const double *chi1vec,
347  const double *chi2vec,
348  const int ncx,
349  const int ncy,
350  const int ncz,
351  const char dir[],
353 );
354 
355 static void SEOBNRROMdataDS_Cleanup_submodel(SEOBNRROMdataDS_submodel *submodel);
356 
357 /**
358  * Core function for computing the ROM waveform.
359  * Interpolate projection coefficient data and evaluate coefficients at desired (q, chi).
360  * Construct 1D splines for amplitude and phase.
361  * Compute strain waveform from amplitude and phase.
362 */
363 static int SEOBNRv2ROMDoubleSpinCore(
364  COMPLEX16FrequencySeries **hptilde, /**< Output: plus waveform */
365  COMPLEX16FrequencySeries **hctilde, /**< Output: cross waveform */
366  double phiRef, /**< Input: Reference phase */
367  double fRef, /**< Input: Reference frequency */
368  double distance, /**< Input: distance (meters) */
369  double inclination, /**< Input: inclination (radians) */
370  double Mtot_sec, /**< Input: Total Mass (seconds) */
371  double eta, /**< Input: Symmetric mass ratio */
372  double chi1, /**< Input: Dimensionless spin of body 1 */
373  double chi2, /**< Input: Dimensionless spin of body 2 */
374  const REAL8Sequence *freqs_in, /**< Input: Frequency points at which to evaluate the waveform (Hz) */
375  double deltaF, /**< Input: Frequency spacing if freqs_in==NULL. If deltaF==0, will generate a freq series */
376  /* If deltaF > 0, the frequency points given in freqs_in are uniformly spaced with
377  * spacing deltaF. Otherwise, the frequency points are spaced non-uniformly.
378  * Then we will use deltaF = 0 to create the frequency series we return. */
379  int return_af_interpolants, /**< Input: Flag to return amplitude and phase interpolants if true */
380  REAL8Vector **amplitude_interp, /**< Output: amplitude interpolants */
381  REAL8Vector **amplitude_freq_points,/**< Output: frequencies of amp interpolants */
382  REAL8Vector **phase_interp, /**< Output: phase interpolants */
383  REAL8Vector **phase_freq_points /**< Output: frequencies of phase interpolants */
384 );
385 
386 static void SEOBNRROMdataDS_coeff_Init(SEOBNRROMdataDS_coeff **romdatacoeff, int nk_amp, int nk_phi);
387 static void SEOBNRROMdataDS_coeff_Cleanup(SEOBNRROMdataDS_coeff *romdatacoeff);
388 
389 static size_t NextPow2(const size_t n);
390 static void SplineData_Destroy(SplineData *splinedata);
391 static void SplineData_Init(
392  SplineData **splinedata,
393  int ncx, // Number of points in eta + 2
394  int ncy, // Number of points in chi1 + 2
395  int ncz, // Number of points in chi2 + 2
396  const double *etavec, // B-spline knots in eta
397  const double *chi1vec, // B-spline knots in chi1
398  const double *chi2vec // B-spline knots in chi2
399 );
400 
401 static int load_data_sub1(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *cvec_amp_pre);
402 static int load_data_sub2(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *cvec_amp_pre);
403 static int load_data_sub3(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *cvec_amp_pre);
404 
406  gsl_spline **spline_phi, // phase spline
407  gsl_interp_accel **acc_phi, // phase spline accelerator
408  REAL8 *Mf_final, // ringdown frequency in Mf
409  REAL8 *Mtot_sec, // total mass in seconds
410  REAL8 m1SI, // Mass of companion 1 (kg)
411  REAL8 m2SI, // Mass of companion 2 (kg)
412  REAL8 chi1, // Aligned spin of companion 1
413  REAL8 chi2 // Aligned spin of companion 2
414 );
415 
417  gsl_vector *v,
418  REAL8 eta,
419  REAL8 chi,
420  int ncx,
421  int ncy,
422  gsl_bspline_workspace *bwx,
423  gsl_bspline_workspace *bwy
424 );
425 
426 /********************* Definitions begin here ********************/
427 
428 /** Setup SEOBNRv2ROMDoubleSpin model using data files installed in dir
429  */
430 static int SEOBNRv2ROMDoubleSpin_Init(const char dir[]) {
431  if(__lalsim_SEOBNRv2ROMDS_data.setup) {
432  XLALPrintError("Error: DSEOBNRROMdata was already set up!");
434  }
435 
437 
438  if(__lalsim_SEOBNRv2ROMDS_data.setup) {
439  return(XLAL_SUCCESS);
440  }
441  else {
442  return(XLAL_EFAILED);
443  }
444 }
445 
446 /** Helper function to check if the SEOBNRv2ROMDoubleSpin model has been initialised */
447 static bool SEOBNRv2ROMDoubleSpin_IsSetup(void) {
449  return true;
450  else
451  return false;
452 }
453 
454 // Read binary ROM data for basis functions and coefficients for submodel 1
455 static int load_data_sub1(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *cvec_amp_pre) {
456  // Load binary data for amplitude and phase spline coefficients and reduced bases as computed in Mathematica
457  // "Core" submodel 1
458  // B-spline points: 54x24x24
459  // Frequency points: {133, 139}
460  int ret = XLAL_SUCCESS;
461  ret |= read_vector(dir, "SEOBNRv2ROM_DS_sub1_Amp_ciall.dat", cvec_amp);
462  ret |= read_vector(dir, "SEOBNRv2ROM_DS_sub1_Phase_ciall.dat", cvec_phi);
463  ret |= read_matrix(dir, "SEOBNRv2ROM_DS_sub1_Bamp_bin.dat", Bamp);
464  ret |= read_matrix(dir, "SEOBNRv2ROM_DS_sub1_Bphase_bin.dat", Bphi);
465  ret |= read_vector(dir, "SEOBNRv2ROM_DS_sub1_AmpPrefac_ci.dat", cvec_amp_pre);
466  return(ret);
467 }
468 
469 // Read binary ROM data for basis functions and coefficients for submodel 2
470 static int load_data_sub2(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *cvec_amp_pre) {
471  // Load binary data for amplitude and phase spline coefficients and reduced bases as computed in Mathematica
472  // "Near q=1" submodel 2
473  // B-spline points: 11x60x60
474  // Frequency points: {200, 187}
475  int ret = XLAL_SUCCESS;
476  ret |= read_vector(dir, "SEOBNRv2ROM_DS_sub2_Amp_ciall.dat", cvec_amp);
477  ret |= read_vector(dir, "SEOBNRv2ROM_DS_sub2_Phase_ciall.dat", cvec_phi);
478  ret |= read_matrix(dir, "SEOBNRv2ROM_DS_sub2_Bamp_bin.dat", Bamp);
479  ret |= read_matrix(dir, "SEOBNRv2ROM_DS_sub2_Bphase_bin.dat", Bphi);
480  ret |= read_vector(dir, "SEOBNRv2ROM_DS_sub2_AmpPrefac_ci.dat", cvec_amp_pre);
481  return(ret);
482 }
483 
484 // Read binary ROM data for basis functions and coefficients for submodel 3
485 static int load_data_sub3(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *cvec_amp_pre) {
486  // Load binary data for amplitude and phase spline coefficients and reduced bases as computed in Mathematica
487  // "High q, high chi1" submodel 3
488  // B-spline points: 24x30x24
489  // frequency points: {133, 139}
490  int ret = XLAL_SUCCESS;
491  ret |= read_vector(dir, "SEOBNRv2ROM_DS_sub3_Amp_ciall.dat", cvec_amp);
492  ret |= read_vector(dir, "SEOBNRv2ROM_DS_sub3_Phase_ciall.dat", cvec_phi);
493  ret |= read_matrix(dir, "SEOBNRv2ROM_DS_sub3_Bamp_bin.dat", Bamp);
494  ret |= read_matrix(dir, "SEOBNRv2ROM_DS_sub3_Bphase_bin.dat", Bphi);
495  ret |= read_vector(dir, "SEOBNRv2ROM_DS_sub3_AmpPrefac_ci.dat", cvec_amp_pre);
496  return(ret);
497 }
498 
499 // Setup B-spline basis functions for given points
500 static void SplineData_Init(
501  SplineData **splinedata,
502  int ncx, // Number of points in eta + 2
503  int ncy, // Number of points in chi1 + 2
504  int ncz, // Number of points in chi2 + 2
505  const double *etavec, // B-spline knots in eta
506  const double *chi1vec, // B-spline knots in chi1
507  const double *chi2vec // B-spline knots in chi2
508 )
509 {
510  if(!splinedata) exit(1);
511  if(*splinedata) SplineData_Destroy(*splinedata);
512 
513  (*splinedata)=XLALCalloc(1,sizeof(SplineData));
514 
515  // Set up B-spline basis for desired knots
516  const size_t nbreak_x = ncx-2; // must have nbreak = n-2 for cubic splines
517  const size_t nbreak_y = ncy-2; // must have nbreak = n-2 for cubic splines
518  const size_t nbreak_z = ncz-2; // must have nbreak = n-2 for cubic splines
519 
520  // Allocate a cubic bspline workspace (k = 4)
521  gsl_bspline_workspace *bwx = gsl_bspline_alloc(4, nbreak_x);
522  gsl_bspline_workspace *bwy = gsl_bspline_alloc(4, nbreak_y);
523  gsl_bspline_workspace *bwz = gsl_bspline_alloc(4, nbreak_z);
524 
525  // Set breakpoints (and thus knots by hand)
526  gsl_vector *breakpts_x = gsl_vector_alloc(nbreak_x);
527  gsl_vector *breakpts_y = gsl_vector_alloc(nbreak_y);
528  gsl_vector *breakpts_z = gsl_vector_alloc(nbreak_z);
529  for (UINT4 i=0; i<nbreak_x; i++)
530  gsl_vector_set(breakpts_x, i, etavec[i]);
531  for (UINT4 j=0; j<nbreak_y; j++)
532  gsl_vector_set(breakpts_y, j, chi1vec[j]);
533  for (UINT4 k=0; k<nbreak_z; k++)
534  gsl_vector_set(breakpts_z, k, chi2vec[k]);
535 
536  gsl_bspline_knots(breakpts_x, bwx);
537  gsl_bspline_knots(breakpts_y, bwy);
538  gsl_bspline_knots(breakpts_z, bwz);
539 
540  gsl_vector_free(breakpts_x);
541  gsl_vector_free(breakpts_y);
542  gsl_vector_free(breakpts_z);
543 
544  (*splinedata)->bwx=bwx;
545  (*splinedata)->bwy=bwy;
546  (*splinedata)->bwz=bwz;
547 }
548 
549 static void SplineData_Destroy(SplineData *splinedata)
550 {
551  if(!splinedata) return;
552  if(splinedata->bwx) gsl_bspline_free(splinedata->bwx);
553  if(splinedata->bwy) gsl_bspline_free(splinedata->bwy);
554  if(splinedata->bwz) gsl_bspline_free(splinedata->bwz);
555  XLALFree(splinedata);
556 }
557 
558 // Interpolate projection coefficients for amplitude and phase over the parameter space (q, chi).
559 // The multi-dimensional interpolation is carried out via a tensor product decomposition.
561  REAL8 eta, // Input: eta-value for which projection coefficients should be evaluated
562  REAL8 chi1, // Input: chi1-value for which projection coefficients should be evaluated
563  REAL8 chi2, // Input: chi2-value for which projection coefficients should be evaluated
564  gsl_vector *cvec_amp, // Input: data for spline coefficients for amplitude
565  gsl_vector *cvec_phi, // Input: data for spline coefficients for phase
566  gsl_vector *cvec_amp_pre, // Input: data for spline coefficients for amplitude prefactor
567  int nk_amp, // number of SVD-modes == number of basis functions for amplitude
568  int nk_phi, // number of SVD-modes == number of basis functions for phase
569  int ncx, // Number of points in eta + 2
570  int ncy, // Number of points in chi1 + 2
571  int ncz, // Number of points in chi2 + 2
572  const double *etavec, // B-spline knots in eta
573  const double *chi1vec, // B-spline knots in chi1
574  const double *chi2vec, // B-spline knots in chi2
575  gsl_vector *c_amp, // Output: interpolated projection coefficients for amplitude
576  gsl_vector *c_phi, // Output: interpolated projection coefficients for phase
577  REAL8 *amp_pre // Output: interpolated amplitude prefactor
578 ) {
579  SplineData *splinedata=NULL;
580  SplineData_Init(&splinedata, ncx, ncy, ncz, etavec, chi1vec, chi2vec);
581 
582  gsl_bspline_workspace *bwx=splinedata->bwx;
583  gsl_bspline_workspace *bwy=splinedata->bwy;
584  gsl_bspline_workspace *bwz=splinedata->bwz;
585 
586  int N = ncx*ncy*ncz; // Size of the data matrix for one SVD-mode
587 
588  // Evaluate the TP spline for all SVD modes - amplitude
589  for (int k=0; k<nk_amp; k++) { // For each SVD mode
590  gsl_vector v = gsl_vector_subvector(cvec_amp, k*N, N).vector; // Pick out the coefficient matrix corresponding to the k-th SVD mode.
591  REAL8 csum = Interpolate_Coefficent_Tensor(&v, eta, chi1, chi2, ncy, ncz, bwx, bwy, bwz);
592  gsl_vector_set(c_amp, k, csum);
593  }
594 
595  // Evaluate the TP spline for all SVD modes - phase
596  for (int k=0; k<nk_phi; k++) { // For each SVD mode
597  gsl_vector v = gsl_vector_subvector(cvec_phi, k*N, N).vector; // Pick out the coefficient matrix corresponding to the k-th SVD mode.
598  REAL8 csum = Interpolate_Coefficent_Tensor(&v, eta, chi1, chi2, ncy, ncz, bwx, bwy, bwz);
599  gsl_vector_set(c_phi, k, csum);
600  }
601 
602  // Evaluate the TP spline for the amplitude prefactor
603  *amp_pre = Interpolate_Coefficent_Tensor(cvec_amp_pre, eta, chi1, chi2, ncy, ncz, bwx, bwy, bwz);
604 
605  SplineData_Destroy(splinedata);
606 
607  return(0);
608 }
609 
610 /* Set up a new ROM submodel, using data contained in dir */
612  SEOBNRROMdataDS_submodel **submodel,
613  const int nk_amp,
614  const int nk_phi,
615  const double *gA,
616  const double *gPhi,
617  const double *etavec,
618  const double *chi1vec,
619  const double *chi2vec,
620  const int ncx,
621  const int ncy,
622  const int ncz,
623  const char dir[],
625 ) {
626  int ret = XLAL_FAILURE;
627 
628  if(!submodel) exit(1);
629  /* Create storage for submodel structures */
630  if (!*submodel)
631  *submodel = XLALCalloc(1,sizeof(SEOBNRROMdataDS_submodel));
632  else
634 
635  int N = ncx*ncy*ncz; // Total number of points over parameter space = size of the data matrix for one SVD-mode
636 
637  // Initalize actual ROM data
638  (*submodel)->cvec_amp = gsl_vector_alloc(N*nk_amp);
639  (*submodel)->cvec_phi = gsl_vector_alloc(N*nk_phi);
640  (*submodel)->Bamp = gsl_matrix_alloc(nk_amp, nk_amp);
641  (*submodel)->Bphi = gsl_matrix_alloc(nk_phi, nk_phi);
642  (*submodel)->cvec_amp_pre = gsl_vector_alloc(N);
643 
644  // Load ROM data for this submodel
645  ret=load_data(dir, (*submodel)->cvec_amp, (*submodel)->cvec_phi, (*submodel)->Bamp, (*submodel)->Bphi, (*submodel)->cvec_amp_pre);
646 
647  // Initialize other members
648  (*submodel)->nk_amp = nk_amp;
649  (*submodel)->nk_phi = nk_phi;
650  (*submodel)->gA = gA;
651  (*submodel)->gPhi = gPhi;
652  (*submodel)->etavec = etavec;
653  (*submodel)->chi1vec = chi1vec;
654  (*submodel)->chi2vec = chi2vec;
655  (*submodel)->ncx = ncx;
656  (*submodel)->ncy = ncy;
657  (*submodel)->ncz = ncz;
658 
659  return ret;
660 }
661 
662 /* Deallocate contents of the given SEOBNRROMdataDS_submodel structure */
663 static void SEOBNRROMdataDS_Cleanup_submodel(SEOBNRROMdataDS_submodel *submodel) {
664  if(submodel->cvec_amp) gsl_vector_free(submodel->cvec_amp);
665  if(submodel->cvec_phi) gsl_vector_free(submodel->cvec_phi);
666  if(submodel->Bamp) gsl_matrix_free(submodel->Bamp);
667  if(submodel->Bphi) gsl_matrix_free(submodel->Bphi);
668  if(submodel->cvec_amp_pre) gsl_vector_free(submodel->cvec_amp_pre);
669 }
670 
671 /* Set up a new ROM model, using data contained in dir */
672 int SEOBNRROMdataDS_Init(SEOBNRROMdataDS *romdata, const char dir[]) {
673  int ret = XLAL_FAILURE;
674 
675  /* Create storage for structures */
676  if(romdata->setup) {
677  XLALPrintError("WARNING: You tried to setup the SEOBNRv2ROMDoubleSpin model that was already initialised. Ignoring\n");
678  return (XLAL_FAILURE);
679  }
680 
682  ret = SEOBNRROMdataDS_Init_submodel(&(romdata)->sub1, nk_amp_sub1, nk_phi_sub1,
684  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : submodel 1 loaded sucessfully.\n", __func__);
685 
687  ret |= SEOBNRROMdataDS_Init_submodel(&(romdata)->sub2, nk_amp_sub2, nk_phi_sub2,
689  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : submodel 2 loaded sucessfully.\n", __func__);
690 
692  ret |= SEOBNRROMdataDS_Init_submodel(&(romdata)->sub3, nk_amp_sub3, nk_phi_sub3,
694  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : submodel 3 loaded sucessfully.\n", __func__);
695 
696  if(XLAL_SUCCESS==ret)
697  romdata->setup=1;
698  else
699  SEOBNRROMdataDS_Cleanup(romdata);
700 
701  return (ret);
702 }
703 
704 /* Deallocate contents of the given SEOBNRROMdataDS structure */
705 static void SEOBNRROMdataDS_Cleanup(SEOBNRROMdataDS *romdata) {
706  SEOBNRROMdataDS_Cleanup_submodel((romdata)->sub1);
707  XLALFree((romdata)->sub1);
708  (romdata)->sub1 = NULL;
709  romdata->setup=0;
710 }
711 
712 /* Structure for internal use */
713 static void SEOBNRROMdataDS_coeff_Init(SEOBNRROMdataDS_coeff **romdatacoeff, int nk_amp, int nk_phi) {
714 
715  if(!romdatacoeff) exit(1);
716  /* Create storage for structures */
717  if(!*romdatacoeff)
718  *romdatacoeff=XLALCalloc(1,sizeof(SEOBNRROMdataDS_coeff));
719  else
720  SEOBNRROMdataDS_coeff_Cleanup(*romdatacoeff);
721 
722  (*romdatacoeff)->c_amp = gsl_vector_alloc(nk_amp);
723  (*romdatacoeff)->c_phi = gsl_vector_alloc(nk_phi);
724 }
725 
726 /* Deallocate contents of the given SEOBNRROMdataDS_coeff structure */
728  if(romdatacoeff->c_amp) gsl_vector_free(romdatacoeff->c_amp);
729  if(romdatacoeff->c_phi) gsl_vector_free(romdatacoeff->c_phi);
730  XLALFree(romdatacoeff);
731 }
732 
733 /* Return the closest higher power of 2 */
734 // Note: NextPow(2^k) = 2^k for integer values k.
735 static size_t NextPow2(const size_t n) {
736  return 1 << (size_t) ceil(log2(n));
737 }
738 
739 
740 /**
741  * Core function for computing the ROM waveform.
742  * Interpolate projection coefficient data and evaluate coefficients at desired (q, chi1, chi2).
743  * Construct 1D splines for amplitude and phase.
744  * Compute strain waveform from amplitude and phase.
745 */
747  COMPLEX16FrequencySeries **hptilde,
748  COMPLEX16FrequencySeries **hctilde,
749  double phiRef, // orbital reference phase
750  double fRef,
751  double distance,
752  double inclination,
753  double Mtot_sec,
754  double eta,
755  double chi1,
756  double chi2,
757  const REAL8Sequence *freqs_in, /* Frequency points at which to evaluate the waveform (Hz) */
758  double deltaF,
759  /* If deltaF > 0, the frequency points given in freqs are uniformly spaced with
760  * spacing deltaF. Otherwise, the frequency points are spaced non-uniformly.
761  * Then we will use deltaF = 0 to create the frequency series we return. */
762  int return_af_interpolants,
763  REAL8Vector **amplitude_interp, /**< Output: amplitude interpolants */
764  REAL8Vector **amplitude_freq_points,/**< Output: frequencies of amp interpolants */
765  REAL8Vector **phase_interp, /**< Output: phase interpolants */
766  REAL8Vector **phase_freq_points /**< Output: frequencies of phase interpolants */
767  )
768 {
769 
770  /* Check output arrays */
771  if(!hptilde || !hctilde)
773  SEOBNRROMdataDS *romdata=&__lalsim_SEOBNRv2ROMDS_data;
774  if(*hptilde || *hctilde)
775  {
776  XLALPrintError("(*hptilde) and (*hctilde) are supposed to be NULL, but got %p and %p",(*hptilde),(*hctilde));
778  }
779  int retcode=0;
780 
781  // 'Nudge' parameter values to allowed boundary values if close by
782  if (eta > 0.25) nudge(&eta, 0.25, 1e-6);
783  if (eta < 0.01) nudge(&eta, 0.01, 1e-6);
784  if (chi1 < -1.0) nudge(&chi1, -1.0, 1e-6);
785  if (chi1 > 0.99) nudge(&chi1, 0.99, 1e-6);
786  if (chi2 < -1.0) nudge(&chi2, -1.0, 1e-6);
787  if (chi1 > 0.99) nudge(&chi2, 0.99, 1e-6);
788 
789  if ( chi1 < -1.0 || chi2 < -1.0 || chi1 > 0.99 || chi2 > 0.99 ) {
790  XLALPrintError( "XLAL Error - %s: chi1 or chi2 smaller than -1 or larger than 0.99!\nSEOBNRv2ROMDoubleSpin is only available for spins in the range -1 <= a/M <= 0.99.\n", __func__);
792  }
793 
794  if (eta<0.01 || eta > 0.25) {
795  XLALPrintError( "XLAL Error - %s: eta (%f) smaller than 0.01 or unphysical!\nSEOBNRv2ROMDoubleSpin is only available for eta in the range 0.01 <= eta <= 0.25.\n", __func__,eta);
797  }
798 
799  /* Select ROM submodel */
800  SEOBNRROMdataDS_submodel *submodel;
801  if (eta >= 0.242)
802  submodel = romdata->sub2;
803  else if (eta < 0.1 && chi1 > 0.5)
804  submodel = romdata->sub3;
805  else
806  submodel = romdata->sub1;
807 
808  /* Find frequency bounds */
809  if (!freqs_in) XLAL_ERROR(XLAL_EFAULT);
810  double fLow = freqs_in->data[0];
811  double fHigh = freqs_in->data[freqs_in->length - 1];
812 
813  if(fRef==0.0)
814  fRef=fLow;
815 
816  /* Convert to geometric units for frequency */
817  double Mf_ROM_min = fmax(submodel->gA[0], submodel->gPhi[0]); // lowest allowed geometric frequency for ROM
818  double Mf_ROM_max = fmin(submodel->gA[submodel->nk_amp-1], submodel->gPhi[submodel->nk_phi-1]); // highest allowed geometric frequency for ROM
819  double fLow_geom = fLow * Mtot_sec;
820  double fHigh_geom = fHigh * Mtot_sec;
821  double fRef_geom = fRef * Mtot_sec;
822  double deltaF_geom = deltaF * Mtot_sec;
823 
824  // Enforce allowed geometric frequency range
825  if (fLow_geom < Mf_ROM_min)
826  XLAL_ERROR(XLAL_EDOM, "Starting frequency Mflow=%g is smaller than lowest frequency in ROM Mf=%g.\n", fLow_geom, Mf_ROM_min);
827  if (fHigh_geom == 0)
828  fHigh_geom = Mf_ROM_max;
829  else if (fHigh_geom > Mf_ROM_max) {
830  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);
831  fHigh_geom = Mf_ROM_max;
832  }
833  else if (fHigh_geom < Mf_ROM_min)
834  XLAL_ERROR(XLAL_EDOM, "End frequency %g is smaller than starting frequency %g!\n", fHigh_geom, fLow_geom);
835  if (fRef_geom > Mf_ROM_max) {
836  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);
837  fRef_geom = Mf_ROM_max; // If fref > fhigh we reset fref to default value of cutoff frequency.
838  }
839  if (fRef_geom < Mf_ROM_min) {
840  XLALPrintWarning("Reference frequency Mf_ref=%g is smaller than lowest frequency in ROM Mf=%g. Starting at lowest frequency in ROM.\n", fRef_geom, Mf_ROM_min);
841  fRef_geom = Mf_ROM_min;
842  }
843 
844  /* Internal storage for waveform coefficiencts */
845  SEOBNRROMdataDS_coeff *romdata_coeff=NULL;
846  SEOBNRROMdataDS_coeff_Init(&romdata_coeff, submodel->nk_amp, submodel->nk_phi);
847  REAL8 amp_pre;
848 
849  /* Interpolate projection coefficients and evaluate them at (q,chi1,chi2) */
851  eta, // Input: eta-value for which projection coefficients should be evaluated
852  chi1, // Input: chi1-value for which projection coefficients should be evaluated
853  chi2, // Input: chi2-value for which projection coefficients should be evaluated
854  submodel->cvec_amp, // Input: data for spline coefficients for amplitude
855  submodel->cvec_phi, // Input: data for spline coefficients for phase
856  submodel->cvec_amp_pre, // Input: data for spline coefficients for amplitude prefactor
857  submodel->nk_amp, // number of SVD-modes == number of basis functions for amplitude
858  submodel->nk_phi, // number of SVD-modes == number of basis functions for phase
859  submodel->ncx, // Number of points in eta + 2
860  submodel->ncy, // Number of points in chi1 + 2
861  submodel->ncz, // Number of points in chi2 + 2
862  submodel->etavec, // B-spline knots in eta
863  submodel->chi1vec, // B-spline knots in chi1
864  submodel->chi2vec, // B-spline knots in chi2
865  romdata_coeff->c_amp, // Output: interpolated projection coefficients for amplitude
866  romdata_coeff->c_phi, // Output: interpolated projection coefficients for phase
867  &amp_pre // Output: interpolated amplitude prefactor
868  );
869 
870  if(retcode!=0) {
871  SEOBNRROMdataDS_coeff_Cleanup(romdata_coeff);
872  XLAL_ERROR(retcode, "Parameter-space interpolation failed.");
873  }
874 
875  // Compute function values of amplitude an phase on sparse frequency points by evaluating matrix vector products
876  // amp_pts = B_A^T . c_A
877  // phi_pts = B_phi^T . c_phi
878  gsl_vector* amp_f = gsl_vector_alloc(submodel->nk_amp);
879  gsl_vector* phi_f = gsl_vector_alloc(submodel->nk_phi);
880  gsl_blas_dgemv(CblasTrans, 1.0, submodel->Bamp, romdata_coeff->c_amp, 0.0, amp_f);
881  gsl_blas_dgemv(CblasTrans, 1.0, submodel->Bphi, romdata_coeff->c_phi, 0.0, phi_f);
882 
883  // Setup 1d splines in frequency
884  gsl_interp_accel *acc_amp = gsl_interp_accel_alloc();
885  gsl_spline *spline_amp = gsl_spline_alloc(gsl_interp_cspline, submodel->nk_amp);
886  gsl_spline_init(spline_amp, submodel->gA, gsl_vector_const_ptr(amp_f,0), submodel->nk_amp);
887 
888  gsl_interp_accel *acc_phi = gsl_interp_accel_alloc();
889  gsl_spline *spline_phi = gsl_spline_alloc(gsl_interp_cspline, submodel->nk_phi);
890  gsl_spline_init(spline_phi, submodel->gPhi, gsl_vector_const_ptr(phi_f,0), submodel->nk_phi);
891 
892  if ( return_af_interpolants)
893  {
894  int interp_idx;
895 
896  /* create memory to store the interpolants for this M,q,chi */
897  *amplitude_interp = XLALCreateREAL8Vector( submodel->nk_amp );
898  *amplitude_freq_points = XLALCreateREAL8Vector( submodel->nk_amp );
899  *phase_interp = XLALCreateREAL8Vector( submodel->nk_phi );
900  *phase_freq_points = XLALCreateREAL8Vector( submodel->nk_phi );
901 
902  /* store the amplitude and phase interpolant frequency points */
903  for ( interp_idx = 0; interp_idx < submodel->nk_amp; ++interp_idx )
904  {
905  (*amplitude_freq_points)->data[interp_idx] = (REAL8) submodel->gA[interp_idx];
906  }
907  for ( interp_idx = 0; interp_idx < submodel->nk_phi; ++interp_idx )
908  {
909  (*phase_freq_points)->data[interp_idx] = (REAL8) submodel->gPhi[interp_idx];
910  }
911  }
912 
913  size_t npts = 0;
914  LIGOTimeGPS tC = {0, 0};
915  UINT4 offset = 0; // Index shift between freqs and the frequency series
916  REAL8Sequence *freqs = NULL;
917  if (deltaF > 0) { // freqs contains uniform frequency grid with spacing deltaF; we start at frequency 0
918  /* Set up output array with size closest power of 2 */
919  npts = NextPow2(fHigh_geom / deltaF_geom) + 1;
920  if (fHigh_geom < fHigh * Mtot_sec) /* Resize waveform if user wants f_max larger than cutoff frequency */
921  npts = NextPow2(fHigh * Mtot_sec / deltaF_geom) + 1;
922 
923  XLALGPSAdd(&tC, -1. / deltaF); /* coalesce at t=0 */
924  *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, npts);
925  *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, npts);
926 
927  // Recreate freqs using only the lower and upper bounds
928  // Use fLow, fHigh and deltaF rather than geometric frequencies for numerical accuracy
929  double fHigh_temp = fHigh_geom / Mtot_sec;
930  UINT4 iStart = (UINT4) ceil(fLow / deltaF);
931  UINT4 iStop = (UINT4) ceil(fHigh_temp / deltaF);
932  freqs = XLALCreateREAL8Sequence(iStop - iStart);
933  if (!freqs) {
934  XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
935  }
936  for (UINT4 i=iStart; i<iStop; i++)
937  freqs->data[i-iStart] = i*deltaF_geom;
938 
939  offset = iStart;
940  } else { // freqs contains frequencies with non-uniform spacing; we start at lowest given frequency
941  npts = freqs_in->length;
942  *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &tC, fLow, 0, &lalStrainUnit, npts);
943  *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &tC, fLow, 0, &lalStrainUnit, npts);
944  offset = 0;
945 
946  freqs = XLALCreateREAL8Sequence(freqs_in->length);
947  if (!freqs) {
948  XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
949  }
950  for (UINT4 i=0; i<freqs_in->length; i++)
951  freqs->data[i] = freqs_in->data[i] * Mtot_sec;
952  }
953 
954  if (!(*hptilde) || !(*hctilde))
955  {
957  gsl_spline_free(spline_amp);
958  gsl_spline_free(spline_phi);
959  gsl_interp_accel_free(acc_amp);
960  gsl_interp_accel_free(acc_phi);
961  gsl_vector_free(amp_f);
962  gsl_vector_free(phi_f);
963  SEOBNRROMdataDS_coeff_Cleanup(romdata_coeff);
964  XLAL_ERROR(XLAL_EFUNC, "Waveform allocation failed.");
965  }
966  memset((*hptilde)->data->data, 0, npts * sizeof(COMPLEX16));
967  memset((*hctilde)->data->data, 0, npts * sizeof(COMPLEX16));
968 
969  XLALUnitMultiply(&(*hptilde)->sampleUnits, &(*hptilde)->sampleUnits, &lalSecondUnit);
970  XLALUnitMultiply(&(*hctilde)->sampleUnits, &(*hctilde)->sampleUnits, &lalSecondUnit);
971 
972  COMPLEX16 *pdata=(*hptilde)->data->data;
973  COMPLEX16 *cdata=(*hctilde)->data->data;
974 
975  REAL8 cosi = cos(inclination);
976  REAL8 pcoef = 0.5*(1.0 + cosi*cosi);
977  REAL8 ccoef = cosi;
978 
979  REAL8 s = 0.5; // Scale polarization amplitude so that strain agrees with FFT of SEOBNRv2
980  double Mtot = Mtot_sec / LAL_MTSUN_SI;
981  double amp0 = Mtot * amp_pre * Mtot_sec * LAL_MRSUN_SI / (distance); // Correct overall amplitude to undo mass-dependent scaling used in ROM
982 
983  // Evaluate reference phase for setting phiRef correctly
984  double phase_change = gsl_spline_eval(spline_phi, fRef_geom, acc_phi) - 2*phiRef;
985 
986  if ( return_af_interpolants)
987  {
988  int interp_idx;
989 
990  /* store the amplitude and phase interpolant frequency points */
991  for ( interp_idx = 0; interp_idx < submodel->nk_amp; ++interp_idx )
992  {
993  (*amplitude_interp)->data[interp_idx] = (REAL8) s * amp0 * gsl_vector_get( amp_f, interp_idx);
994  }
995  for ( interp_idx = 0; interp_idx < submodel->nk_phi; ++interp_idx )
996  {
997  (*phase_interp)->data[interp_idx] = (REAL8) gsl_vector_get( phi_f, interp_idx) - phase_change;
998  }
999  }
1000 
1001  // Assemble waveform from aplitude and phase
1002  for (UINT4 i=0; i<freqs->length; i++) { // loop over frequency points in sequence
1003  double f = freqs->data[i];
1004  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
1005  int j = i + offset; // shift index for frequency series if needed
1006  double A = gsl_spline_eval(spline_amp, f, acc_amp);
1007  double phase = gsl_spline_eval(spline_phi, f, acc_phi) - phase_change;
1008  COMPLEX16 htilde = s*amp0*A * cexp(I*phase);
1009  pdata[j] = pcoef * htilde;
1010  cdata[j] = -I * ccoef * htilde;
1011  }
1012 
1013  /* Correct phasing so we coalesce at t=0 (with the definition of the epoch=-1/deltaF above) */
1014 
1015  // Get SEOBNRv2 ringdown frequency for 22 mode
1016  double Mf_final = SEOBNRROM_Ringdown_Mf_From_Mtot_Eta(Mtot_sec, eta, chi1, chi2, SEOBNRv2);
1017 
1018  UINT4 L = freqs->length;
1019  // prevent gsl interpolation errors
1020  if (Mf_final > freqs->data[L-1])
1021  Mf_final = freqs->data[L-1];
1022  if (Mf_final < freqs->data[0])
1023  {
1024  XLALDestroyREAL8Sequence(freqs);
1025  gsl_spline_free(spline_amp);
1026  gsl_spline_free(spline_phi);
1027  gsl_interp_accel_free(acc_amp);
1028  gsl_interp_accel_free(acc_phi);
1029  gsl_vector_free(amp_f);
1030  gsl_vector_free(phi_f);
1031  SEOBNRROMdataDS_coeff_Cleanup(romdata_coeff);
1032  XLAL_ERROR(XLAL_EDOM, "f_ringdown < f_min");
1033  }
1034  // Time correction is t(f_final) = 1/(2pi) dphi/df (f_final)
1035  // We compute the dimensionless time correction t/M since we use geometric units.
1036  REAL8 t_corr = gsl_spline_eval_deriv(spline_phi, Mf_final, acc_phi) / (2*LAL_PI);
1037 
1038  // Now correct phase
1039  for (UINT4 i=0; i<freqs->length; i++) { // loop over frequency points in sequence
1040  double f = freqs->data[i] - fRef_geom;
1041  int j = i + offset; // shift index for frequency series if needed
1042  pdata[j] *= cexp(-2*LAL_PI * I * f * t_corr);
1043  cdata[j] *= cexp(-2*LAL_PI * I * f * t_corr);
1044  }
1045 
1046  XLALDestroyREAL8Sequence(freqs);
1047 
1048  gsl_spline_free(spline_amp);
1049  gsl_spline_free(spline_phi);
1050  gsl_interp_accel_free(acc_amp);
1051  gsl_interp_accel_free(acc_phi);
1052  gsl_vector_free(amp_f);
1053  gsl_vector_free(phi_f);
1054  SEOBNRROMdataDS_coeff_Cleanup(romdata_coeff);
1055 
1056  return(XLAL_SUCCESS);
1057 }
1058 
1059 /**
1060  * @addtogroup LALSimIMRSEOBNRROM_c
1061  *
1062  * @{
1063  *
1064  * @name SEOBNRv2 Reduced Order Model (Double Spin)
1065  *
1066  * @author Michael Puerrer, John Veitch
1067  *
1068  * @brief C code for SEOBNRv2 reduced order model (double spin version).
1069  * See CQG 31 195010, 2014, arXiv:1402.4146 for the basic approach.
1070  * Further details in PRD 93, 064041, 2016, arXiv:1512.02248.
1071  *
1072  * This is a frequency domain model that approximates the time domain SEOBNRv2 model.
1073  *
1074  * The binary data files are available at https://dcc.ligo.org/T1400701-v1.
1075  * Put the untared data into a location in your LAL_DATA_PATH.
1076  *
1077  * @note Note that due to its construction the iFFT of the ROM has a small (~ 20 M) offset
1078  * in the peak time that scales with total mass as compared to the time-domain SEOBNRv2 model.
1079  *
1080  * @note Parameter ranges:
1081  * * 0.01 <= eta <= 0.25
1082  * * -1 <= chi_i <= 0.99
1083  * * Mtot >= 12Msun
1084  *
1085  * Aligned component spins chi1, chi2.
1086  * Symmetric mass-ratio eta = m1*m2/(m1+m2)^2.
1087  * Total mass Mtot.
1088  *
1089  * @{
1090  */
1091 
1092 /**
1093  * Compute waveform in LAL format at specified frequencies for the SEOBNRv2_ROM_DoubleSpin model.
1094  *
1095  * XLALSimIMRSEOBNRv2ROMDoubleSpin() returns the plus and cross polarizations as a complex
1096  * frequency series with equal spacing deltaF and contains zeros from zero frequency
1097  * to the starting frequency and zeros beyond the cutoff frequency in the ringdown.
1098  *
1099  * In contrast, XLALSimIMRSEOBNRv2ROMDoubleSpinFrequencySequence() returns a
1100  * complex frequency series with entries exactly at the frequencies specified in
1101  * the sequence freqs (which can be unequally spaced). No zeros are added.
1102  *
1103  * If XLALSimIMRSEOBNRv2ROMDoubleSpinFrequencySequence() is called with frequencies that
1104  * are beyond the maxium allowed geometric frequency for the ROM, zero strain is returned.
1105  * It is not assumed that the frequency sequence is ordered.
1106  *
1107  * This function is designed as an entry point for reduced order quadratures.
1108  */
1110  struct tagCOMPLEX16FrequencySeries **hptilde, /**< Output: Frequency-domain waveform h+ */
1111  struct tagCOMPLEX16FrequencySeries **hctilde, /**< Output: Frequency-domain waveform hx */
1112  const REAL8Sequence *freqs, /**< Frequency points at which to evaluate the waveform (Hz), need to be strictly monotonically increasing */
1113  REAL8 phiRef, /**< Orbital phase at reference time */
1114  REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
1115  REAL8 distance, /**< Distance of source (m) */
1116  REAL8 inclination, /**< Inclination of source (rad) */
1117  REAL8 m1SI, /**< Mass of companion 1 (kg) */
1118  REAL8 m2SI, /**< Mass of companion 2 (kg) */
1119  REAL8 chi1, /**< Dimensionless aligned component spin 1 */
1120  REAL8 chi2 /**< Dimensionless aligned component spin 2 */
1121 )
1122 {
1123  /* Internally we need m1 > m2, so change around if this is not the case */
1124  if (m1SI < m2SI) {
1125  // Swap m1 and m2
1126  double m1temp = m1SI;
1127  double chi1temp = chi1;
1128  m1SI = m2SI;
1129  chi1 = chi2;
1130  m2SI = m1temp;
1131  chi2 = chi1temp;
1132  }
1133 
1134  /* Get masses in terms of solar mass */
1135  double mass1 = m1SI / LAL_MSUN_SI;
1136  double mass2 = m2SI / LAL_MSUN_SI;
1137  double Mtot = mass1+mass2;
1138  double eta = mass1 * mass2 / (Mtot*Mtot); /* Symmetric mass-ratio */
1139  double Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
1140 
1141  if (!freqs) XLAL_ERROR(XLAL_EFAULT);
1142 
1143  // Load ROM data if not loaded already
1144 #ifdef LAL_PTHREAD_LOCK
1145  (void) pthread_once(&SEOBNRv2ROMDoubleSpin_is_initialized, SEOBNRv2ROMDoubleSpin_Init_LALDATA);
1146 #else
1148 #endif
1149 
1150  if(!SEOBNRv2ROMDoubleSpin_IsSetup()) XLAL_ERROR(XLAL_EFAILED,"Error setting up SEOBNRv2ROMDoubleSpin data - check your $LAL_DATA_PATH\n");
1151 
1152  // Call the internal core function with deltaF = 0 to indicate that freqs is non-uniformly
1153  // spaced and we want the strain only at these frequencies
1154  int retcode = SEOBNRv2ROMDoubleSpinCore(hptilde,hctilde,
1155  phiRef, fRef, distance, inclination, Mtot_sec, eta, chi1, chi2, freqs, 0,
1156  0, NULL, NULL, NULL, NULL);
1157 
1158 
1159  return(retcode);
1160 }
1161 
1162 /**
1163  * Compute waveform in LAL format for the SEOBNRv2_ROM_DoubleSpin model.
1164  *
1165  * Returns the plus and cross polarizations as a complex frequency series with
1166  * equal spacing deltaF and contains zeros from zero frequency to the starting
1167  * frequency fLow and zeros beyond the cutoff frequency fHigh to the next power of 2 in
1168  * the size of the frequency series.
1169  */
1171  struct tagCOMPLEX16FrequencySeries **hptilde, /**< Output: Frequency-domain waveform h+ */
1172  struct tagCOMPLEX16FrequencySeries **hctilde, /**< Output: Frequency-domain waveform hx */
1173  REAL8 phiRef, /**< Orbital phase at reference frequency*/
1174  REAL8 deltaF, /**< Sampling frequency (Hz) */
1175  REAL8 fLow, /**< Starting GW frequency (Hz) */
1176  REAL8 fHigh, /**< End frequency; 0 defaults to Mf=0.14 */
1177  REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
1178  REAL8 distance, /**< Distance of source (m) */
1179  REAL8 inclination, /**< Inclination of source (rad) */
1180  REAL8 m1SI, /**< Mass of companion 1 (kg) */
1181  REAL8 m2SI, /**< Mass of companion 2 (kg) */
1182  REAL8 chi1, /**< Dimensionless aligned component spin 1 */
1183  REAL8 chi2) /**< Dimensionless aligned component spin 2 */
1184 {
1185  /* Internally we need m1 > m2, so change around if this is not the case */
1186  if (m1SI < m2SI) {
1187  // Swap m1 and m2
1188  double m1temp = m1SI;
1189  double chi1temp = chi1;
1190  m1SI = m2SI;
1191  chi1 = chi2;
1192  m2SI = m1temp;
1193  chi2 = chi1temp;
1194  }
1195 
1196  /* Get masses in terms of solar mass */
1197  double mass1 = m1SI / LAL_MSUN_SI;
1198  double mass2 = m2SI / LAL_MSUN_SI;
1199  double Mtot = mass1+mass2;
1200  double eta = mass1 * mass2 / (Mtot*Mtot); /* Symmetric mass-ratio */
1201  double Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
1202 
1203  if(fRef==0.0)
1204  fRef=fLow;
1205 
1206  // Load ROM data if not loaded already
1207 #ifdef LAL_PTHREAD_LOCK
1208  (void) pthread_once(&SEOBNRv2ROMDoubleSpin_is_initialized, SEOBNRv2ROMDoubleSpin_Init_LALDATA);
1209 #else
1211 #endif
1212 
1213  if(!SEOBNRv2ROMDoubleSpin_IsSetup()) XLAL_ERROR(XLAL_EFAILED,"Error setting up SEOBNRv2ROMDoubleSpin data - check your $LAL_DATA_PATH\n");
1214 
1215  // Use fLow, fHigh, deltaF to compute freqs sequence
1216  // Instead of building a full sequency we only transfer the boundaries and let
1217  // the internal core function do the rest (and properly take care of corner cases).
1219  freqs->data[0] = fLow;
1220  freqs->data[1] = fHigh;
1221 
1222  int retcode = SEOBNRv2ROMDoubleSpinCore(hptilde,hctilde,
1223  phiRef, fRef, distance, inclination, Mtot_sec, eta, chi1, chi2, freqs, deltaF,
1224  0, NULL, NULL, NULL, NULL);
1225 
1226  XLALDestroyREAL8Sequence(freqs);
1227 
1228  return(retcode);
1229 }
1230 
1231 /**
1232  * Compute the Amplitude and Phase interpolants for the SEOBNRv2DoubleSpin
1233  * model. Return A, psi, f_A, and f_Psi, given the parameters of a waveform
1234  *
1235  */
1237  struct tagREAL8Vector **amplitude_interp, /**< Output: amplitude interpolants */
1238  struct tagREAL8Vector **amplitude_freq_points,/**< Output: frequencies of amp interpolants */
1239  struct tagREAL8Vector **phase_interp, /**< Output: phase interpolants */
1240  struct tagREAL8Vector **phase_freq_points, /**< Output: frequencies of phase interpolants */
1241  REAL8 phiRef, /**< Orbital phase at reference frequency*/
1242  REAL8 deltaF, /**< Sampling frequency (Hz) */
1243  REAL8 fLow, /**< Starting GW frequency (Hz) */
1244  REAL8 fHigh, /**< End frequency; 0 defaults to Mf=0.14 */
1245  REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
1246  REAL8 distance, /**< Distance of source (m) */
1247  REAL8 inclination, /**< Inclination of source (rad) */
1248  REAL8 m1SI, /**< Mass of companion 1 (kg) */
1249  REAL8 m2SI, /**< Mass of companion 2 (kg) */
1250  REAL8 chi1, /**< Dimensionless aligned component spin 1 */
1251  REAL8 chi2) /**< Dimensionless aligned component spin 2 */
1252 {
1253  int return_af_interpolants = 1;
1254 
1255  /* Internally we need m1 > m2, so change around if this is not the case */
1256  if (m1SI < m2SI) {
1257  // Swap m1 and m2
1258  double m1temp = m1SI;
1259  double chi1temp = chi1;
1260  m1SI = m2SI;
1261  chi1 = chi2;
1262  m2SI = m1temp;
1263  chi2 = chi1temp;
1264  }
1265 
1266  /* Get masses in terms of solar mass */
1267  double mass1 = m1SI / LAL_MSUN_SI;
1268  double mass2 = m2SI / LAL_MSUN_SI;
1269  double Mtot = mass1+mass2;
1270  double eta = mass1 * mass2 / (Mtot*Mtot); /* Symmetric mass-ratio */
1271  double Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
1272 
1273  if(fRef==0.0)
1274  fRef=fLow;
1275 
1276  // Load ROM data if not loaded already
1277 #ifdef LAL_PTHREAD_LOCK
1278  (void) pthread_once(&SEOBNRv2ROMDoubleSpin_is_initialized, SEOBNRv2ROMDoubleSpin_Init_LALDATA);
1279 #else
1281 #endif
1282 
1283  if(!SEOBNRv2ROMDoubleSpin_IsSetup()) XLAL_ERROR(XLAL_EFAILED,"Error setting up SEOBNRv2ROMDoubleSpin data - check your $LAL_DATA_PATH\n");
1284 
1285  // Use fLow, fHigh, deltaF to compute freqs sequence
1286  // Instead of building a full sequency we only transfer the boundaries and let
1287  // the internal core function do the rest (and properly take care of corner cases).
1289  freqs->data[0] = fLow;
1290  freqs->data[1] = fHigh;
1291 
1292  COMPLEX16FrequencySeries *hptilde = NULL;
1293  COMPLEX16FrequencySeries *hctilde = NULL;
1294 
1295  int retcode = SEOBNRv2ROMDoubleSpinCore(&hptilde,&hctilde,
1296  phiRef, fRef, distance, inclination, Mtot_sec, eta, chi1, chi2, freqs, deltaF,
1297  return_af_interpolants, amplitude_interp, amplitude_freq_points, phase_interp, phase_freq_points);
1298 
1299  XLALDestroyREAL8Sequence(freqs);
1300 
1303 
1304  return(retcode);
1305 }
1306 
1307 /**
1308  * Compute the 'time' elapsed in the ROM waveform from a given starting frequency until the ringdown.
1309  * UNREVIEWED!
1310  *
1311  * The notion of elapsed 'time' (in seconds) is defined here as the difference of the
1312  * frequency derivative of the frequency domain phase between the ringdown frequency
1313  * and the starting frequency ('frequency' argument). This notion of time is similar to the
1314  * chirp time, but it includes both the inspiral and the merger ringdown part of SEOBNRv2.
1315  *
1316  * The allowed frequency range for the starting frequency in geometric frequency is [0.00053, 0.135].
1317  * The SEOBNRv2 ringdown frequency can be obtained by calling XLALSimInspiralGetFinalFreq().
1318  *
1319  * See XLALSimIMRSEOBNRv2ROMDoubleSpinFrequencyOfTime() for the inverse function.
1320  */
1322  REAL8 *t, /**< Output: time (s) elapsed from starting frequency to ringdown */
1323  REAL8 frequency, /**< Starting frequency (Hz) */
1324  REAL8 m1SI, /**< Mass of companion 1 (kg) */
1325  REAL8 m2SI, /**< Mass of companion 2 (kg) */
1326  REAL8 chi1, /**< Dimensionless aligned component spin 1 */
1327  REAL8 chi2 /**< Dimensionless aligned component spin 2 */
1328 )
1329 {
1330  /* Internally we need m1 > m2, so change around if this is not the case */
1331  if (m1SI < m2SI) {
1332  // Swap m1 and m2
1333  double m1temp = m1SI;
1334  double chi1temp = chi1;
1335  m1SI = m2SI;
1336  chi1 = chi2;
1337  m2SI = m1temp;
1338  chi2 = chi1temp;
1339  }
1340 
1341  // Set up phase spline
1342  gsl_spline *spline_phi;
1343  gsl_interp_accel *acc_phi;
1344  double Mf_final, Mtot_sec;
1345  int ret = SEOBNRv2ROMDoubleSpinTimeFrequencySetup(&spline_phi, &acc_phi, &Mf_final, &Mtot_sec, m1SI, m2SI, chi1, chi2);
1346  if(ret != 0)
1347  XLAL_ERROR(ret);
1348 
1349  // ROM frequency bounds in Mf
1350  double Mf_ROM_min = 0.00053;
1351  double Mf_ROM_max = 0.135;
1352 
1353  // Time correction is t(f_final) = 1/(2pi) dphi/df (f_final)
1354  double t_corr = gsl_spline_eval_deriv(spline_phi, Mf_final, acc_phi) / (2*LAL_PI); // t_corr / M
1355  XLAL_PRINT_INFO("t_corr[s] = %g\n", t_corr * Mtot_sec);
1356 
1357  double Mf = frequency * Mtot_sec;
1358  if (Mf < Mf_ROM_min || Mf > Mf_ROM_max || Mf > Mf_final)
1359  {
1360  gsl_spline_free(spline_phi);
1361  gsl_interp_accel_free(acc_phi);
1362  XLAL_ERROR(XLAL_EDOM, "Frequency %g is outside allowed frequency range.\n", frequency);
1363  }
1364  // Compute time relative to origin at merger
1365  double time_M = gsl_spline_eval_deriv(spline_phi, frequency * Mtot_sec, acc_phi) / (2*LAL_PI) - t_corr;
1366  *t = time_M * Mtot_sec;
1367 
1368  gsl_spline_free(spline_phi);
1369  gsl_interp_accel_free(acc_phi);
1370 
1371  return(XLAL_SUCCESS);
1372 }
1373 
1374 /**
1375  * Compute the starting frequency so that the given amount of 'time' elapses in the ROM waveform
1376  * from the starting frequency until the ringdown.
1377  * UNREVIEWED!
1378  *
1379  * The notion of elapsed 'time' (in seconds) is defined here as the difference of the
1380  * frequency derivative of the frequency domain phase between the ringdown frequency
1381  * and the starting frequency ('frequency' argument). This notion of time is similar to the
1382  * chirp time, but it includes both the inspiral and the merger ringdown part of SEOBNRv2.
1383  *
1384  * If the frequency that corresponds to the specified elapsed time is lower than the
1385  * geometric frequency Mf=0.00053 (ROM starting frequency) or above half of the SEOBNRv2
1386  * ringdown frequency an error is thrown.
1387  * The SEOBNRv2 ringdown frequency can be obtained by calling XLALSimInspiralGetFinalFreq().
1388  *
1389  * See XLALSimIMRSEOBNRv2ROMDoubleSpinTimeOfFrequency() for the inverse function.
1390  */
1392  REAL8 *frequency, /**< Output: Frequency (Hz) */
1393  REAL8 t, /**< Time (s) at frequency */
1394  REAL8 m1SI, /**< Mass of companion 1 (kg) */
1395  REAL8 m2SI, /**< Mass of companion 2 (kg) */
1396  REAL8 chi1, /**< Dimensionless aligned component spin 1 */
1397  REAL8 chi2 /**< Dimensionless aligned component spin 2 */
1398 )
1399 {
1400  /* Internally we need m1 > m2, so change around if this is not the case */
1401  if (m1SI < m2SI) {
1402  // Swap m1 and m2
1403  double m1temp = m1SI;
1404  double chi1temp = chi1;
1405  m1SI = m2SI;
1406  chi1 = chi2;
1407  m2SI = m1temp;
1408  chi2 = chi1temp;
1409  }
1410 
1411  // Set up phase spline
1412  gsl_spline *spline_phi;
1413  gsl_interp_accel *acc_phi;
1414  double Mf_final, Mtot_sec;
1415  int ret = SEOBNRv2ROMDoubleSpinTimeFrequencySetup(&spline_phi, &acc_phi, &Mf_final, &Mtot_sec, m1SI, m2SI, chi1, chi2);
1416  if(ret != 0)
1417  XLAL_ERROR(ret);
1418 
1419  // ROM frequency bounds in Mf
1420  double Mf_ROM_min = 0.00053;
1421 
1422  // Time correction is t(f_final) = 1/(2pi) dphi/df (f_final)
1423  double t_corr = gsl_spline_eval_deriv(spline_phi, Mf_final, acc_phi) / (2*LAL_PI); // t_corr / M
1424  XLAL_PRINT_INFO("t_corr[s] = %g\n", t_corr * Mtot_sec);
1425 
1426  // Assume for now that we only care about f(t) *before* merger so that f(t) - f_ringdown >= 0.
1427  // Assume that we only need to cover the frequency range [f_min, f_ringdown/2].
1428  int N = 20;
1429  double log_f_pts[N];
1430  double log_t_pts[N];
1431  double log_f_min = log(Mf_ROM_min);
1432  double log_f_rng_2 = log(Mf_final/2.0);
1433  double dlog_f = (log_f_rng_2 - log_f_min) / (N-1);
1434 
1435  // Set up data in log-log space
1436  for (int i=0; i<N; i++) {
1437  log_f_pts[i] = log_f_rng_2 - i*dlog_f; // gsl likes the x-values to be monotonically increasing
1438  // Compute time relative to origin at merger
1439  double time_M = gsl_spline_eval_deriv(spline_phi, exp(log_f_pts[i]), acc_phi) / (2*LAL_PI) - t_corr;
1440  log_t_pts[i] = log(time_M * Mtot_sec);
1441  }
1442 
1443  // Check whether time is in bounds
1444  double t_rng_2 = exp(log_t_pts[0]); // time of f_ringdown/2
1445  double t_min = exp(log_t_pts[N-1]); // time of f_min
1446  if (t < t_rng_2 || t > t_min)
1447  {
1448  gsl_spline_free(spline_phi);
1449  gsl_interp_accel_free(acc_phi);
1450  XLAL_ERROR(XLAL_EDOM, "The frequency of time %g is outside allowed frequency range.\n", t);
1451  }
1452  // create new spline for data
1453  gsl_interp_accel *acc = gsl_interp_accel_alloc();
1454  gsl_spline *spline = gsl_spline_alloc(gsl_interp_cspline, N);
1455  gsl_spline_init(spline, log_t_pts, log_f_pts, N);
1456 
1457  *frequency = exp(gsl_spline_eval(spline, log(t), acc)) / Mtot_sec;
1458 
1459  gsl_spline_free(spline);
1460  gsl_interp_accel_free(acc);
1461  gsl_spline_free(spline_phi);
1462  gsl_interp_accel_free(acc_phi);
1463 
1464  return(XLAL_SUCCESS);
1465 }
1466 
1467 /** @} */
1468 /** @} */
1469 
1470 // Auxiliary function to perform setup of phase spline for t(f) and f(t) functions
1472  gsl_spline **spline_phi, // phase spline
1473  gsl_interp_accel **acc_phi, // phase spline accelerator
1474  REAL8 *Mf_final, // ringdown frequency in Mf
1475  REAL8 *Mtot_sec, // total mass in seconds
1476  REAL8 m1SI, // Mass of companion 1 (kg)
1477  REAL8 m2SI, // Mass of companion 2 (kg)
1478  REAL8 chi1, // Aligned spin of companion 1
1479  REAL8 chi2 // Aligned spin of companion 2
1480 )
1481 {
1482  /* Get masses in terms of solar mass */
1483  double mass1 = m1SI / LAL_MSUN_SI;
1484  double mass2 = m2SI / LAL_MSUN_SI;
1485  double Mtot = mass1 + mass2;
1486  double eta = mass1 * mass2 / (Mtot*Mtot); /* Symmetric mass-ratio */
1487  *Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
1488 
1489  // 'Nudge' parameter values to allowed boundary values if close by
1490  nudge(&eta, 0.25, 1e-6);
1491  nudge(&eta, 0.01, 1e-6);
1492  nudge(&chi1, -1.0, 1e-6);
1493  nudge(&chi1, 0.99, 1e-6);
1494  nudge(&chi2, -1.0, 1e-6);
1495  nudge(&chi2, 0.99, 1e-6);
1496 
1497  if ( chi1 < -1.0 || chi2 < -1.0 || chi1 > 0.99 || chi2 > 0.99 ) {
1498  XLALPrintError( "XLAL Error - %s: chi1 or chi2 smaller than -1 or larger than 0.99!\nSEOBNRv2ROMDoubleSpin is only available for spins in the range -1 <= a/M <= 0.99.\n", __func__);
1499  XLAL_ERROR( XLAL_EDOM );
1500  }
1501 
1502  if (eta<0.01 || eta > 0.25) {
1503  XLALPrintError( "XLAL Error - %s: eta (%f) smaller than 0.01 or unphysical!\nSEOBNRv2ROMDoubleSpin is only available for spins in the range 0.01 <= eta <= 0.25.\n", __func__,eta);
1504  XLAL_ERROR( XLAL_EDOM );
1505  }
1506 
1507  // Load ROM data if not loaded already
1508 #ifdef LAL_PTHREAD_LOCK
1509  (void) pthread_once(&SEOBNRv2ROMDoubleSpin_is_initialized, SEOBNRv2ROMDoubleSpin_Init_LALDATA);
1510 #else
1512 #endif
1513 
1514  SEOBNRROMdataDS *romdata=&__lalsim_SEOBNRv2ROMDS_data;
1515 
1516  /* Select ROM submodel */
1517  SEOBNRROMdataDS_submodel *submodel;
1518  if (eta >= 0.242)
1519  submodel = romdata->sub2;
1520  else if (eta < 0.1 && chi1 > 0.5)
1521  submodel = romdata->sub3;
1522  else
1523  submodel = romdata->sub1;
1524 
1525  /* Internal storage for w.f. coefficiencts */
1526  SEOBNRROMdataDS_coeff *romdata_coeff=NULL;
1527  SEOBNRROMdataDS_coeff_Init(&romdata_coeff, submodel->nk_amp, submodel->nk_phi);
1528  REAL8 amp_pre;
1529 
1530  /* Interpolate projection coefficients and evaluate them at (eta,chi1,chi2) */
1531  int retcode=TP_Spline_interpolation_3d(
1532  eta, // Input: eta-value for which projection coefficients should be evaluated
1533  chi1, // Input: chi1-value for which projection coefficients should be evaluated
1534  chi2, // Input: chi2-value for which projection coefficients should be evaluated
1535  submodel->cvec_amp, // Input: data for spline coefficients for amplitude
1536  submodel->cvec_phi, // Input: data for spline coefficients for phase
1537  submodel->cvec_amp_pre, // Input: data for spline coefficients for amplitude prefactor
1538  submodel->nk_amp, // number of SVD-modes == number of basis functions for amplitude
1539  submodel->nk_phi, // number of SVD-modes == number of basis functions for phase
1540  submodel->ncx, // Number of points in eta + 2
1541  submodel->ncy, // Number of points in chi1 + 2
1542  submodel->ncz, // Number of points in chi2 + 2
1543  submodel->etavec, // B-spline knots in eta
1544  submodel->chi1vec, // B-spline knots in chi1
1545  submodel->chi2vec, // B-spline knots in chi2
1546  romdata_coeff->c_amp, // Output: interpolated projection coefficients for amplitude
1547  romdata_coeff->c_phi, // Output: interpolated projection coefficients for phase
1548  &amp_pre // Output: interpolated amplitude prefactor
1549  );
1550 
1551  if(retcode!=0) {
1552  SEOBNRROMdataDS_coeff_Cleanup(romdata_coeff);
1553  XLAL_ERROR(retcode);
1554  }
1555 
1556  // Compute function values of phase on sparse frequency points by evaluating matrix vector products
1557  // phi_pts = B_phi^T . c_phi
1558  gsl_vector* phi_f = gsl_vector_alloc(submodel->nk_phi);
1559  gsl_blas_dgemv(CblasTrans, 1.0, submodel->Bphi, romdata_coeff->c_phi, 0.0, phi_f);
1560 
1561  // Setup 1d phase spline in frequency
1562  *acc_phi = gsl_interp_accel_alloc();
1563  *spline_phi = gsl_spline_alloc(gsl_interp_cspline, submodel->nk_phi);
1564  gsl_spline_init(*spline_phi, submodel->gPhi, gsl_vector_const_ptr(phi_f,0), submodel->nk_phi);
1565 
1566  // Get SEOBNRv2 ringdown frequency for 22 mode
1567  *Mf_final = SEOBNRROM_Ringdown_Mf_From_Mtot_Eta(*Mtot_sec, eta, chi1, chi2, SEOBNRv2);
1568 
1569  gsl_vector_free(phi_f);
1570  SEOBNRROMdataDS_coeff_Cleanup(romdata_coeff);
1571 
1572  return(XLAL_SUCCESS);
1573 }
1574 
1575 
1576 
1577 /** Setup SEOBNRv2ROMDoubleSpin model using data files installed in $LAL_DATA_PATH
1578  */
1580 {
1581  if (SEOBNRv2ROMDoubleSpin_IsSetup()) return;
1582 
1583  // If we find one ROM datafile in a directory listed in LAL_DATA_PATH,
1584  // then we expect the remaining datafiles to also be there.
1585  char datafile[] = "SEOBNRv2ROM_DS_sub1_Phase_ciall.dat";
1586 
1587  char *path = XLAL_FILE_RESOLVE_PATH(datafile);
1588  if (path==NULL)
1589  XLAL_ERROR_VOID(XLAL_EIO, "Unable to resolve data file %s in $LAL_DATA_PATH\n", datafile);
1590  char *dir = dirname(path);
1591  int ret = SEOBNRv2ROMDoubleSpin_Init(dir);
1592  XLALFree(path);
1593 
1594  if(ret!=XLAL_SUCCESS)
1595  XLAL_ERROR_VOID(XLAL_FAILURE, "Unable to find SEOBNRv2ROMDoubleSpin data files in $LAL_DATA_PATH\n");
1596 }
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 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 UNUSED int read_vector(const char dir[], const char fname[], gsl_vector *v)
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 int read_matrix(const char dir[], const char fname[], gsl_matrix *m)
static const double gA[]
static const double gPhi[]
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 const double chi1vec_sub1[]
static const double gPhi_sub2[]
static const double etavec_sub1[]
static const int ncx_sub2
static int SEOBNRROMdataDS_Init_submodel(SEOBNRROMdataDS_submodel **submodel, const int nk_amp, const int nk_phi, const double *gA, const double *gPhi, const double *etavec, const double *chi1vec, const double *chi2vec, const int ncx, const int ncy, const int ncz, const char dir[], load_dataPtr load_data)
static bool SEOBNRv2ROMDoubleSpin_IsSetup(void)
Helper function to check if the SEOBNRv2ROMDoubleSpin model has been initialised.
static const double chi1vec_sub2[]
int(* load_dataPtr)(const char *, gsl_vector *, gsl_vector *, gsl_matrix *, gsl_matrix *, gsl_vector *)
static const double gPhi_sub1[]
static const int ncy_sub1
static const int ncx_sub1
static void SEOBNRv2ROMDoubleSpin_Init_LALDATA(void)
Setup SEOBNRv2ROMDoubleSpin model using data files installed in $LAL_DATA_PATH.
static const int ncz_sub1
static int SEOBNRv2ROMDoubleSpin_Init(const char dir[])
Setup SEOBNRv2ROMDoubleSpin model using data files installed in dir.
static const double etavec_sub3[]
#define nk_phi_sub1
static const int ncz_sub3
static void SplineData_Destroy(SplineData *splinedata)
static const int ncx_sub3
static const double chi2vec_sub1[]
static const int ncy_sub2
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 const int ncz_sub2
static SEOBNRROMdataDS __lalsim_SEOBNRv2ROMDS_data
static void SplineData_Init(SplineData **splinedata, int ncx, int ncy, int ncz, const double *etavec, const double *chi1vec, const double *chi2vec)
static int load_data_sub1(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *cvec_amp_pre)
static int SEOBNRv2ROMDoubleSpinCore(COMPLEX16FrequencySeries **hptilde, COMPLEX16FrequencySeries **hctilde, double phiRef, double fRef, double distance, double inclination, double Mtot_sec, double eta, double chi1, double chi2, const REAL8Sequence *freqs_in, double deltaF, int return_af_interpolants, REAL8Vector **amplitude_interp, REAL8Vector **amplitude_freq_points, REAL8Vector **phase_interp, REAL8Vector **phase_freq_points)
Core function for computing the ROM waveform.
static int load_data_sub3(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *cvec_amp_pre)
static const double gA_sub1[]
static int load_data_sub2(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *cvec_amp_pre)
static const double chi2vec_sub3[]
static const double etavec_sub2[]
static const double chi2vec_sub2[]
static void SEOBNRROMdataDS_coeff_Init(SEOBNRROMdataDS_coeff **romdatacoeff, int nk_amp, int nk_phi)
static void SEOBNRROMdataDS_Cleanup_submodel(SEOBNRROMdataDS_submodel *submodel)
static void SEOBNRROMdataDS_coeff_Cleanup(SEOBNRROMdataDS_coeff *romdatacoeff)
static int SEOBNRv2ROMDoubleSpinTimeFrequencySetup(gsl_spline **spline_phi, gsl_interp_accel **acc_phi, REAL8 *Mf_final, REAL8 *Mtot_sec, REAL8 m1SI, REAL8 m2SI, REAL8 chi1, REAL8 chi2)
static void SEOBNRROMdataDS_Cleanup(SEOBNRROMdataDS *romdata)
static int TP_Spline_interpolation_3d(REAL8 eta, REAL8 chi1, REAL8 chi2, gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_vector *cvec_amp_pre, int nk_amp, int nk_phi, int ncx, int ncy, int ncz, const double *etavec, const double *chi1vec, const double *chi2vec, gsl_vector *c_amp, gsl_vector *c_phi, REAL8 *amp_pre)
static size_t NextPow2(const size_t n)
static const double gA_sub2[]
#define nk_amp_sub1
static const double chi1vec_sub3[]
static const int ncy_sub3
static int SEOBNRROMdataDS_Init(SEOBNRROMdataDS *romdata, const char dir[])
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)
void XLALDestroyCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *series)
#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 XLALSimIMRSEOBNRv2ROMDoubleSpin(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 chi1, REAL8 chi2)
Compute waveform in LAL format for the SEOBNRv2_ROM_DoubleSpin model.
int XLALSimIMRSEOBNRv2ROMDoubleSpinAmpPhaseInterpolants(struct tagREAL8Vector **amplitude_interp, struct tagREAL8Vector **amplitude_freq_points, struct tagREAL8Vector **phase_interp, struct tagREAL8Vector **phase_freq_points, REAL8 phiRef, REAL8 deltaF, REAL8 fLow, REAL8 fHigh, REAL8 fRef, REAL8 distance, REAL8 inclination, REAL8 m1SI, REAL8 m2SI, REAL8 chi1, REAL8 chi2)
Compute the Amplitude and Phase interpolants for the SEOBNRv2DoubleSpin model.
int XLALSimIMRSEOBNRv2ROMDoubleSpinFrequencySequence(struct tagCOMPLEX16FrequencySeries **hptilde, struct tagCOMPLEX16FrequencySeries **hctilde, const REAL8Sequence *freqs, REAL8 phiRef, REAL8 fRef, REAL8 distance, REAL8 inclination, REAL8 m1SI, REAL8 m2SI, REAL8 chi1, REAL8 chi2)
Compute waveform in LAL format at specified frequencies for the SEOBNRv2_ROM_DoubleSpin model.
int XLALSimIMRSEOBNRv2ROMDoubleSpinFrequencyOfTime(REAL8 *frequency, REAL8 t, REAL8 m1SI, REAL8 m2SI, REAL8 chi1, REAL8 chi2)
Compute the starting frequency so that the given amount of 'time' elapses in the ROM waveform from th...
int XLALSimIMRSEOBNRv2ROMDoubleSpinTimeOfFrequency(REAL8 *t, REAL8 frequency, REAL8 m1SI, REAL8 m2SI, REAL8 chi1, REAL8 chi2)
Compute the 'time' elapsed in the ROM waveform from a given starting frequency until the ringdown.
@ SEOBNRv2
Spin-aligned EOBNR model v2.
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)
REAL8Vector * XLALCreateREAL8Vector(UINT4 length)
#define XLAL_ERROR_VOID(...)
#define XLAL_PRINT_INFO(...)
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_ERROR(...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
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 * bwz
gsl_bspline_workspace * bwy
SEOBNRROMdataDS_submodel * sub2
SEOBNRROMdataDS_submodel * sub1
SEOBNRROMdataDS_submodel * sub3