Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALSimulation 6.2.0.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
LALSimInspiralGeneratorPython.c
Go to the documentation of this file.
1#include "config.h"
2
3#ifdef __GNUC__
4#define UNUSED __attribute__ ((unused))
5#else
6#define UNUSED
7#endif
8
9#ifndef HAVE_PYTHON3_EMBED
10
11#include <lal/LALStdlib.h>
12#include <lal/LALDict.h>
13#include <lal/LALSimInspiral.h>
15
16static int initialize(UNUSED LALSimInspiralGenerator *myself, UNUSED LALDict *params)
17{
18 XLAL_ERROR(XLAL_EINVAL, "Python generator not implemented");
19}
20
21const LALSimInspiralGenerator lalPythonGeneratorTemplate = {
22 .name = "ExternalPython",
23 .initialize = initialize,
24 .finalize = NULL,
25 .generate_td_waveform = NULL,
26 .generate_fd_waveform = NULL,
27 .generate_td_modes = NULL,
28 .generate_fd_modes = NULL,
29 .internal_data = NULL
30};
31
32#else /* HAVE_PYTHON_EMBED */
33
34/* Python.h requires the assert macro, so don't poison it */
35#undef LAL_STRICT_DEFS_ENABLED
36#include <lal/LALStddef.h>
37
38#include <lal/LALStdlib.h>
39#include <lal/LALDict.h>
40#include <lal/LALSimInspiral.h>
42
43#include <lal/Date.h>
44#include <lal/Units.h>
45#include <lal/LALString.h>
46#include <lal/LALValue.h>
47#include <lal/Sequence.h>
48#include <lal/FrequencySeries.h>
49#include <lal/TimeSeries.h>
50#include <lal/LALSimSphHarmSeries.h>
52
53#include <Python.h>
54
55#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
56#ifdef __GNUC__
57#pragma GCC diagnostic push
58#pragma GCC diagnostic ignored "-Wcast-qual"
59#endif
60#include <numpy/arrayobject.h>
61#ifdef __GNUC__
62#pragma GCC diagnostic pop
63#endif
64
65/* Create laldict where the units of all the parameters in LALSimInspiralWavofrmParams_common.c are inserted as strings */
66static LALDict *create_waveform_parameter_units_dict(void)
67{
68
69 LALDict *dict;
70 dict = XLALCreateDict();
71 if (dict == NULL)
73
77 XLALDestroyDict(dict);
79 }
80
81 return dict;
82}
83
84/* emit error messages corresponding to python exceptions */
85static int python_error(void)
86{
87 if (PyErr_Occurred()) {
88 XLAL_PRINT_ERROR("Python exception raised");
89 PyErr_Print();
90 return 1;
91 }
92 return 0;
93}
94
95
96/* ROUTINES TO ENCODE A LALDICT AS A PYTHON DICT */
97
98/* Helper struct containing a python dictionary, an astropy quantity and a laldict containing the SI units of the waveform parameters */
99struct add_to_dict_params {
100 PyObject *dict;
101 PyObject *quantity;
102 LALDict *waveform_parameter_units;
103};
104
105/* Set a new value for a particular key in a input python dictionary (thunk.dict) */
106static void add_to_dict(char *key, LALValue *value, void *thunk)
107{
108 struct add_to_dict_params *add_to_dict_params = thunk;
109 LALDict *units = add_to_dict_params->waveform_parameter_units;
110 PyObject *quantity = add_to_dict_params->quantity;
111 PyObject *dict = add_to_dict_params->dict; /* python dict */
112 PyObject *args = NULL;
113 PyObject *val = NULL; /* python value */
114 /* Transform LALValue to python value */
115 switch (XLALValueGetType(value)) {
117 val = PyUnicode_FromString(XLALValueGetString(value));
118 XLAL_CHECK_FAIL(val && !PyErr_Occurred(), XLAL_EFAILED, "Failed to create Python value for parameter %s", key);
119 break;
120 case LAL_I4_TYPE_CODE:
121 val = PyLong_FromLong(XLALValueGetINT4(value));
122 XLAL_CHECK_FAIL(val && !PyErr_Occurred(), XLAL_EFAILED, "Failed to create Python value for parameter %s", key);
123 break;
124 case LAL_D_TYPE_CODE:
125 val = PyFloat_FromDouble(XLALValueGetREAL8(value));
126 XLAL_CHECK_FAIL(val && !PyErr_Occurred(), XLAL_EFAILED, "Failed to create Python value for parameter %s", key);
127 /* Use an astropy quantity. The input LALValue is assumed to be in SI units, those are read from thunk.waveform_parameter_units */
128 if (quantity && units) {
129 const char *unit = ""; /* dimensionless */
130 if (XLALDictContains(units, key))
131 unit = XLALDictLookupStringValue(units, key);
133 args = Py_BuildValue("Os", val, unit);
134 XLAL_CHECK_FAIL(args, XLAL_EFAILED, "Failed to build args for parameter %s", key);
135 Py_CLEAR(val);
136 val = PyObject_CallObject(quantity, args);
137 XLAL_CHECK_FAIL(val, XLAL_EFAILED, "Failed to create Quantity for parameter %s with unit %s", key, unit);
138 Py_CLEAR(args);
139 }
140 break;
141 default:
142 XLAL_ERROR_FAIL(XLAL_ETYPE, "Invalid type for parameter %s", key);
143 break;
144 }
145 /* Insert value in python dictionary */
146 XLAL_CHECK_FAIL(PyDict_SetItemString(dict, key, val) == 0, XLAL_EFAILED, "Failed to insert parameter %s in Python dict", key);
147 Py_DECREF(val);
148 return;
149
150XLAL_FAIL:
151 python_error();
152 Py_XDECREF(args);
153 Py_XDECREF(val);
154 return;
155}
156
157/* Transform a laldictionary into a python dictionary */
158static PyObject *PyDict_FromLALDict(LALDict *ldict, PyObject *quantity, LALDict *waveform_parameter_units)
159{
160 struct add_to_dict_params add_to_dict_params;
161 PyObject *dict;
162 int errnum;
164 dict = PyDict_New();
165 XLAL_CHECK_NULL(dict, XLAL_EFAILED, "Could not create Python dict");
166 add_to_dict_params.dict = dict;
167 add_to_dict_params.quantity = quantity;
168 add_to_dict_params.waveform_parameter_units = waveform_parameter_units;
169 errnum = XLALClearErrno(); /* clear xlalErrno and preserve value */
170 /* Loop over all the keys in the laldict and insert the values into the python dictionary */
171 XLALDictForeach(ldict, add_to_dict, &add_to_dict_params);
172 if (XLALGetBaseErrno()) { /* something failed... */
173 Py_DECREF(dict);
175 }
176 XLALSetErrno(errnum); /* restore previous value of xlalErrno */
177 return dict;
178}
179
180
181/* ROUTINES TO CONVERT NUMPY ARRAYS AS C ARRAYS */
182
183/*
184 * Store data from PyArrayObject in buf of size bufsz, returns number of bytes.
185 * If buf is NULL then return the number of bytes in the array.
186 * Routine fails if buf is not NULL and bufsz is not equal to the number of
187 * bytes in the array; if buf needs to be allocated, call the routine once
188 * with buf == NULL to determine the amount of memory to allocate to buf.
189 */
190static size_t PyArray_AsBytes(void *buf, size_t bufsz, PyArrayObject *arr)
191{
192 size_t nbytes;
194 nbytes = PyArray_NBYTES(arr);
195 if (buf) {
196 XLAL_CHECK(nbytes == bufsz, XLAL_ESIZE, "Inconsisent number of bytes");
197 memcpy(buf, PyArray_DATA(arr), bufsz);
198 }
199 return nbytes;
200}
201
202/* Macro to define helper functions that return the number of bytes needed to allocate a numpy array of a specific type */
203#define DEFINE_PYARRAY_ASTYPE(LALTYPE, NPYTYPE) \
204 static size_t PyArray_As ## LALTYPE (LALTYPE *data, size_t length, PyObject *o) \
205 { \
206 PyArrayObject *arr; \
207 size_t nbytes; \
208 XLAL_CHECK(o, XLAL_EFAULT); \
209 XLAL_CHECK(PyArray_Check(o), XLAL_EINVAL, "Python object is not a ndarray"); \
210 arr = (PyArrayObject *)PyArray_FROM_OF(o, NPY_ARRAY_IN_ARRAY); \
211 if (python_error()) \
212 XLAL_ERROR(XLAL_EFAILED); \
213 XLAL_CHECK(PyArray_TYPE(arr) == NPYTYPE, XLAL_ETYPE, "Ndarray has wrong dtype"); \
214 nbytes = PyArray_AsBytes(data, length * sizeof(*data), arr); \
215 if ((ssize_t)(nbytes) < 0) \
216 XLAL_ERROR(XLAL_EFUNC); \
217 return nbytes / sizeof(LALTYPE); \
218 }
219
220/* Only a few of these are used... */
221// DEFINE_PYARRAY_ASTYPE(CHAR, NPY_BYTE)
222// DEFINE_PYARRAY_ASTYPE(INT2, NPY_INT16)
223// DEFINE_PYARRAY_ASTYPE(INT4, NPY_INT32)
224// DEFINE_PYARRAY_ASTYPE(INT8, NPY_INT64)
225// DEFINE_PYARRAY_ASTYPE(UCHAR, NPY_UBYTE)
226// DEFINE_PYARRAY_ASTYPE(UINT2, NPY_UINT16)
227// DEFINE_PYARRAY_ASTYPE(UINT4, NPY_UINT32)
228// DEFINE_PYARRAY_ASTYPE(UINT8, NPY_UINT64)
229// DEFINE_PYARRAY_ASTYPE(REAL4, NPY_FLOAT)
230DEFINE_PYARRAY_ASTYPE(REAL8, NPY_DOUBLE)
231// DEFINE_PYARRAY_ASTYPE(COMPLEX8, NPY_CFLOAT)
232DEFINE_PYARRAY_ASTYPE(COMPLEX16, NPY_CDOUBLE)
233
234
235/* ROUTINES TO CONVERT NUMPY ARRAYS AS LAL SEQUENCES */
236
237#define DEFINE_PYARRAY_ASSEQTYPE(LALTYPE) \
238 static LALTYPE ## Sequence * PyArray_As ## LALTYPE ## Sequence (PyObject *o) \
239 { \
240 LALTYPE ## Sequence *seq; \
241 size_t length; \
242 XLAL_CHECK_NULL(o, XLAL_EFAULT); \
243 if ((ssize_t)(length = PyArray_As ## LALTYPE(NULL, 0, o)) < 0) \
244 XLAL_ERROR_NULL(XLAL_EFUNC); \
245 if ((seq = XLALCreate ## LALTYPE ## Sequence(length)) == NULL) \
246 XLAL_ERROR_NULL(XLAL_EFUNC); \
247 if (PyArray_As ## LALTYPE(seq->data, seq->length, o) != length) { \
248 XLALDestroy ## LALTYPE ## Sequence(seq); \
249 XLAL_ERROR_NULL(XLAL_ESIZE, "Failed to read ndarray"); \
250 } \
251 return seq; \
252 }
253
254/* Only a few of these are used... */
255// DEFINE_PYARRAY_ASSEQTYPE(CHAR)
256// DEFINE_PYARRAY_ASSEQTYPE(INT2)
257// DEFINE_PYARRAY_ASSEQTYPE(INT4)
258// DEFINE_PYARRAY_ASSEQTYPE(INT8)
259// DEFINE_PYARRAY_ASSEQTYPE(UCHAR)
260// DEFINE_PYARRAY_ASSEQTYPE(UINT2)
261// DEFINE_PYARRAY_ASSEQTYPE(UINT4)
262// DEFINE_PYARRAY_ASSEQTYPE(UINT8)
263// DEFINE_PYARRAY_ASSEQTYPE(REAL4)
264DEFINE_PYARRAY_ASSEQTYPE(REAL8)
265// DEFINE_PYARRAY_ASSEQTYPE(COMPLEX8)
266DEFINE_PYARRAY_ASSEQTYPE(COMPLEX16)
267
268
269/* ROUTINE TO CONVERT ASTROPY TIME AND UNIT AS LAL */
270
271static int AstropyTime_AsLIGOTimeGPS(LIGOTimeGPS *lt, PyObject *at)
272{
273 PyObject *gpstime = NULL;
274 PyObject *result = NULL;
275 double sec, nan;
276
279
280 /* get the gps time at full precision */
281 gpstime = PyObject_CallMethod(at, "to_value", "ss", "gps", "decimal");
282 XLAL_CHECK_FAIL(gpstime, XLAL_EFAILED, "Could not call method .to_value()");
283
284 /* break it into seconds and nanoseconds */
285 result = PyObject_CallMethod(gpstime, "__divmod__", "i", 1);
286 XLAL_CHECK_FAIL(result, XLAL_EFAILED, "Could not call method .__divmod__(1)");
287 Py_CLEAR(gpstime);
288
289 /* result must be a tuple of two objects */
290 XLAL_CHECK_FAIL(PyTuple_Check(result), XLAL_EFAILED, "Invalid result of method .__divmod__(1)");
291 XLAL_CHECK_FAIL(PyTuple_Size(result) == 2, XLAL_EFAILED, "Invalid result of method .__divmod__(1)");
292 sec = PyFloat_AsDouble(PyTuple_GetItem(result, 0));
293 if (PyErr_Occurred())
294 XLAL_ERROR_FAIL(XLAL_EFAILED, "Could not convert GPS seconds to double");
295 nan = PyFloat_AsDouble(PyTuple_GetItem(result, 1));
296 if (PyErr_Occurred())
297 XLAL_ERROR_FAIL(XLAL_EFAILED, "Could not convert GPS nanoseconds to double");
298 Py_CLEAR(result);
299
300 XLALGPSSet(lt, sec, 1e9 * nan);
301 return 0;
302
303XLAL_FAIL:
304 python_error();
305 Py_XDECREF(gpstime);
306 Py_XDECREF(result);
307 return (int)XLAL_FAILURE;
308}
309
310static double AstropyUnit_AsLALUnit(LALUnit *lu, PyObject *au)
311{
312 PyObject *si = NULL;
313 PyObject *scale = NULL;
314 PyObject *bases = NULL;
315 PyObject *powers = NULL;
316 double scale_factor;
317
320
321 /* Get the astropy value in SI units */
322 si = PyObject_GetAttrString(au, "si");
323 XLAL_CHECK_FAIL(si, XLAL_EFAILED, "Could not get attribute .si");
324
325 /* Get the 3 attributes of the CompositeUnit astropy class (scale, bases, powers) */
326 scale = PyObject_GetAttrString(si, "scale");
327 XLAL_CHECK_FAIL(scale, XLAL_EFAILED, "Could not get attribute .scale");
328 XLAL_CHECK_FAIL(PyFloat_Check(scale), XLAL_EFAILED, "Attribute .scale is not a float");
329 scale_factor = PyFloat_AsDouble(scale);
330 if (PyErr_Occurred())
331 XLAL_ERROR_FAIL(XLAL_EFAILED, "Could not convert attribute .scale to double");
332 Py_CLEAR(scale);
333
334 bases = PyObject_GetAttrString(si, "bases");
335 XLAL_CHECK_FAIL(bases, XLAL_EFAILED, "Could not get attribute .bases");
336
337 powers = PyObject_GetAttrString(si, "powers");
338 XLAL_CHECK_FAIL(powers, XLAL_EFAILED, "Could not get attribute .powers");
339
340 Py_CLEAR(si);
341
342 if (!PyList_Check(bases) || !PyList_Check(powers))
343 XLAL_ERROR_FAIL(XLAL_EFAILED, "Invalid astropy unit data");
344 if (PyList_Size(bases) != PyList_Size(powers))
345 XLAL_ERROR_FAIL(XLAL_EFAILED, "Internal data inconsistency");
346
347 /* The bases attribute contains a sequence of units this unit is composed of.
348 * We loop over each of them and transform them into a LALUnit.
349 * The powers item tell us the power of the corresponding base unit (this is a general convention to describe units) and to account for
350 * float powers they are decomposed into a fraction of integer numbers (numerator and denominator) which are passed then to the LALUnit struct.
351 */
352 memset(lu, 0, sizeof(*lu));
353 for (Py_ssize_t i = 0; i < PyList_Size(bases); ++i) {
354 PyObject *base = PyList_GetItem(bases, i); // borrowed reference
355 PyObject *power = PyList_GetItem(powers, i); // borrowed reference
356 PyObject *intratio = NULL;
357 PyObject *basename = NULL;
358 int numerator;
359 int denominator;
360
361 intratio = PyObject_CallMethod(power, "as_integer_ratio", NULL);
362 if (intratio == NULL || !PyTuple_Check(intratio)) {
363 Py_XDECREF(intratio);
364 XLAL_ERROR_FAIL(XLAL_EFAILED, "Failed method .as_integer_ratio");
365 }
366 if (!PyArg_ParseTuple(intratio, "ii", &numerator, &denominator)) {
367 Py_DECREF(intratio);
368 XLAL_ERROR_FAIL(XLAL_EFAILED, "Failed to unpack integer ratio");
369 }
370 Py_DECREF(intratio);
371
372 basename = PyObject_GetAttrString(base, "name");
373 if (basename == NULL || !PyUnicode_Check(basename)) {
374 Py_XDECREF(basename);
375 XLAL_ERROR_FAIL(XLAL_EFAILED, "Failed get attribute .name");
376 }
377
378 if (PyUnicode_CompareWithASCIIString(basename, "m") == 0) {
379 lu->unitNumerator[LALUnitIndexMeter] = numerator;
380 lu->unitDenominatorMinusOne[LALUnitIndexMeter] = denominator - 1;
381 } else if (PyUnicode_CompareWithASCIIString(basename, "kg") == 0) {
382 lu->unitNumerator[LALUnitIndexKiloGram] = numerator;
383 lu->unitDenominatorMinusOne[LALUnitIndexKiloGram] = denominator - 1;
384 } else if (PyUnicode_CompareWithASCIIString(basename, "s") == 0) {
385 lu->unitNumerator[LALUnitIndexSecond] = numerator;
386 lu->unitDenominatorMinusOne[LALUnitIndexSecond] = denominator - 1;
387 } else if (PyUnicode_CompareWithASCIIString(basename, "A") == 0) {
388 lu->unitNumerator[LALUnitIndexAmpere] = numerator;
389 lu->unitDenominatorMinusOne[LALUnitIndexAmpere] = denominator - 1;
390 } else if (PyUnicode_CompareWithASCIIString(basename, "K") == 0) {
391 lu->unitNumerator[LALUnitIndexKelvin] = numerator;
392 lu->unitDenominatorMinusOne[LALUnitIndexKelvin] = denominator - 1;
393 } else if (PyUnicode_CompareWithASCIIString(basename, "strain") == 0) {
394 lu->unitNumerator[LALUnitIndexStrain] = numerator;
395 lu->unitDenominatorMinusOne[LALUnitIndexStrain] = denominator - 1;
396 } else if (PyUnicode_CompareWithASCIIString(basename, "ct") == 0) {
397 lu->unitNumerator[LALUnitIndexADCCount] = numerator;
398 lu->unitDenominatorMinusOne[LALUnitIndexADCCount] = denominator - 1;
399 } else if (PyUnicode_CompareWithASCIIString(basename, "rad") == 0) {
400 ; /* this is just dimensionless in LAL */
401 } else {
402 Py_DECREF(basename);
403 XLAL_ERROR_FAIL(XLAL_EFAILED, "Astropy unit has no associated LAL unit");
404 }
405
406 Py_DECREF(basename);
407 }
408
409 Py_DECREF(bases);
410 Py_DECREF(powers);
411 return scale_factor;
412
413XLAL_FAIL:
414 python_error();
415 Py_XDECREF(si);
416 Py_XDECREF(bases);
417 Py_XDECREF(powers);
418 return XLAL_REAL8_FAIL_NAN;
419}
420
421
422/* ROUTINES TO CONVERT GWPY TIME/FREQUENCY SERIES AS LAL SERIES */
423
424#define DEFINE_GWPY_TIMESERIES_TO_LAL_TIMESERIES(TYPE) \
425 static TYPE ## TimeSeries *GWpyTimeSeries_As ## TYPE ## TimeSeries(PyObject *gwpyser) \
426 { \
427 TYPE ## TimeSeries *series; \
428 double scale; \
429 PyObject *name = NULL; \
430 PyObject *bytes = NULL; \
431 PyObject *epoch = NULL; \
432 PyObject *dt = NULL; \
433 PyObject *value = NULL; \
434 PyObject *units = NULL; \
435 PyObject *si = NULL; \
436 \
437 series = XLALCalloc(1, sizeof(*series)); \
438 XLAL_CHECK_NULL(series, XLAL_ENOMEM); \
439 \
440 /* extract the metadata */ \
441 \
442 name = PyObject_GetAttrString(gwpyser, "name"); \
443 XLAL_CHECK_FAIL(name, XLAL_EFAILED, "Could not get attribute .name"); \
444 XLAL_CHECK_FAIL(PyUnicode_Check(name), XLAL_EFAILED, "Attribute .name is not a string"); \
445 bytes = PyUnicode_AsASCIIString(name); \
446 XLAL_CHECK_FAIL(PyBytes_Check(bytes), XLAL_EFAILED, "Could not decode attribute .name as ASCII string"); \
447 Py_CLEAR(name); \
448 XLALStringCopy(series->name, PyBytes_AsString(bytes), sizeof(series->name)); \
449 Py_CLEAR(bytes); \
450 \
451 epoch = PyObject_GetAttrString(gwpyser, "epoch"); \
452 XLAL_CHECK_FAIL(epoch, XLAL_EFAILED, "Could not get attribute .epoch"); \
453 if (AstropyTime_AsLIGOTimeGPS(&series->epoch, epoch) < 0) \
454 XLAL_ERROR_FAIL(XLAL_EFUNC); \
455 Py_CLEAR(epoch); \
456 \
457 dt = PyObject_GetAttrString(gwpyser, "dt"); \
458 XLAL_CHECK_FAIL(dt, XLAL_EFAILED, "Could not get attribute .dt"); \
459 si = PyObject_GetAttrString(dt, "si"); \
460 XLAL_CHECK_FAIL(si, XLAL_EFAILED, "Could not get attribute .si"); \
461 Py_CLEAR(dt); \
462 value = PyObject_GetAttrString(si, "value"); \
463 XLAL_CHECK_FAIL(value, XLAL_EFAILED, "Could not get attribute .value"); \
464 Py_CLEAR(si); \
465 XLAL_CHECK_FAIL(PyFloat_Check(value), XLAL_EFAILED, "Attribute .value is not a float"); \
466 series->deltaT = PyFloat_AsDouble(value); \
467 if (PyErr_Occurred()) \
468 XLAL_ERROR_FAIL(XLAL_EFAILED, "Could not convert attribute .value to double"); \
469 Py_CLEAR(value); \
470 \
471 /* extract the data */ \
472 value = PyObject_GetAttrString(gwpyser, "value"); \
473 XLAL_CHECK_FAIL(value, XLAL_EFAILED, "Could not get attribute .value"); \
474 units = PyObject_GetAttrString(gwpyser, "unit"); \
475 XLAL_CHECK_FAIL(units, XLAL_EFAILED, "Could not get attribute .unit"); \
476 scale = AstropyUnit_AsLALUnit(&series->sampleUnits, units); \
477 if (XLAL_IS_REAL8_FAIL_NAN(scale)) \
478 XLAL_ERROR_FAIL(XLAL_EFUNC); \
479 Py_CLEAR(units); \
480 series->data = PyArray_As ## TYPE ## Sequence(value); \
481 XLAL_CHECK_FAIL(series->data, XLAL_EFUNC); \
482 Py_CLEAR(value); \
483 if (scale != 1.0) \
484 for (ssize_t i = 0; i < series->data->length; ++i) \
485 series->data->data[i] *= scale; \
486 \
487 return series; \
488 \
489 XLAL_FAIL: \
490 python_error(); \
491 Py_XDECREF(name); \
492 Py_XDECREF(bytes); \
493 Py_XDECREF(epoch); \
494 Py_XDECREF(dt); \
495 Py_XDECREF(value); \
496 Py_XDECREF(units); \
497 Py_XDECREF(si); \
498 XLALDestroy ## TYPE ## TimeSeries(series); \
499 return NULL; \
500 }
501
502#define DEFINE_GWPY_FREQUENCYSERIES_TO_LAL_FREQUENCYSERIES(TYPE) \
503 static TYPE ## FrequencySeries *GWpyFrequencySeries_As ## TYPE ## FrequencySeries(PyObject *gwpyser) \
504 { \
505 TYPE ## FrequencySeries *series; \
506 double scale; \
507 PyObject *name = NULL; \
508 PyObject *bytes = NULL; \
509 PyObject *epoch = NULL; \
510 PyObject *f0 = NULL; \
511 PyObject *df = NULL; \
512 PyObject *value = NULL; \
513 PyObject *units = NULL; \
514 PyObject *si = NULL; \
515 \
516 series = XLALCalloc(1, sizeof(*series)); \
517 XLAL_CHECK_NULL(series, XLAL_ENOMEM); \
518 \
519 /* extract the metadata */ \
520 \
521 name = PyObject_GetAttrString(gwpyser, "name"); \
522 XLAL_CHECK_FAIL(name, XLAL_EFAILED, "Could not get attribute .name"); \
523 XLAL_CHECK_FAIL(PyUnicode_Check(name), XLAL_EFAILED, "Attribute .name is not a string"); \
524 bytes = PyUnicode_AsASCIIString(name); \
525 XLAL_CHECK_FAIL(PyBytes_Check(bytes), XLAL_EFAILED, "Could not decode attribute .name as ASCII string"); \
526 Py_CLEAR(name); \
527 XLALStringCopy(series->name, PyBytes_AsString(bytes), sizeof(series->name)); \
528 Py_CLEAR(bytes); \
529 \
530 epoch = PyObject_GetAttrString(gwpyser, "epoch"); \
531 XLAL_CHECK_FAIL(epoch, XLAL_EFAILED, "Could not get attribute .epoch"); \
532 if (AstropyTime_AsLIGOTimeGPS(&series->epoch, epoch) < 0) \
533 XLAL_ERROR_FAIL(XLAL_EFUNC); \
534 Py_CLEAR(epoch); \
535 \
536 f0 = PyObject_GetAttrString(gwpyser, "f0"); \
537 XLAL_CHECK_FAIL(f0, XLAL_EFAILED, "Could not get attribute .f0"); \
538 si = PyObject_GetAttrString(f0, "si"); \
539 XLAL_CHECK_FAIL(si, XLAL_EFAILED, "Could not get attribute .si"); \
540 Py_CLEAR(f0); \
541 value = PyObject_GetAttrString(si, "value"); \
542 XLAL_CHECK_FAIL(value, XLAL_EFAILED, "Could not get attribute .value"); \
543 Py_CLEAR(si); \
544 XLAL_CHECK_FAIL(PyFloat_Check(value), XLAL_EFAILED, "Attribute .value is not a float"); \
545 series->f0 = PyFloat_AsDouble(value); \
546 if (PyErr_Occurred()) \
547 XLAL_ERROR_FAIL(XLAL_EFAILED, "Could not convert attribute .value to double"); \
548 Py_CLEAR(value); \
549 \
550 df = PyObject_GetAttrString(gwpyser, "df"); \
551 XLAL_CHECK_FAIL(df, XLAL_EFAILED, "Could not get attribute .df"); \
552 si = PyObject_GetAttrString(df, "si"); \
553 XLAL_CHECK_FAIL(si, XLAL_EFAILED, "Could not get attribute .si"); \
554 Py_CLEAR(df); \
555 value = PyObject_GetAttrString(si, "value"); \
556 XLAL_CHECK_FAIL(value, XLAL_EFAILED, "Could not get attribute .value"); \
557 Py_CLEAR(si); \
558 XLAL_CHECK_FAIL(PyFloat_Check(value), XLAL_EFAILED, "Attribute .value is not a float"); \
559 series->deltaF = PyFloat_AsDouble(value); \
560 if (PyErr_Occurred()) \
561 XLAL_ERROR_FAIL(XLAL_EFAILED, "Could not convert attribute .value to double"); \
562 Py_CLEAR(value); \
563 \
564 /* extract the data */ \
565 value = PyObject_GetAttrString(gwpyser, "value"); \
566 XLAL_CHECK_FAIL(value, XLAL_EFAILED, "Could not get attribute .value"); \
567 units = PyObject_GetAttrString(gwpyser, "unit"); \
568 XLAL_CHECK_FAIL(units, XLAL_EFAILED, "Could not get attribute .unit"); \
569 scale = AstropyUnit_AsLALUnit(&series->sampleUnits, units); \
570 if (XLAL_IS_REAL8_FAIL_NAN(scale)) \
571 XLAL_ERROR_FAIL(XLAL_EFUNC); \
572 Py_CLEAR(units); \
573 series->data = PyArray_As ## TYPE ## Sequence(value); \
574 XLAL_CHECK_FAIL(series->data, XLAL_EFUNC); \
575 Py_CLEAR(value); \
576 if (scale != 1.0) \
577 for (ssize_t i = 0; i < series->data->length; ++i) \
578 series->data->data[i] *= scale; \
579 \
580 return series; \
581 \
582 XLAL_FAIL: \
583 python_error(); \
584 Py_XDECREF(name); \
585 Py_XDECREF(bytes); \
586 Py_XDECREF(epoch); \
587 Py_XDECREF(f0); \
588 Py_XDECREF(df); \
589 Py_XDECREF(value); \
590 Py_XDECREF(units); \
591 Py_XDECREF(si); \
592 XLALDestroy ## TYPE ## FrequencySeries(series); \
593 return NULL; \
594 }
595
596DEFINE_GWPY_TIMESERIES_TO_LAL_TIMESERIES(REAL8)
597DEFINE_GWPY_TIMESERIES_TO_LAL_TIMESERIES(COMPLEX16)
598DEFINE_GWPY_FREQUENCYSERIES_TO_LAL_FREQUENCYSERIES(COMPLEX16)
599
600
601/* STANDARD GENERATOR METHODS */
602
603static int generate_td_modes(
604 SphHarmTimeSeries **hlm,
605 LALDict *params,
606 LALSimInspiralGenerator *myself
607);
608
609static int generate_td_waveform(
610 REAL8TimeSeries **hplus,
611 REAL8TimeSeries **hcross,
612 LALDict *params,
613 LALSimInspiralGenerator *myself
614);
615
616static int generate_fd_modes(
618 LALDict *params,
619 LALSimInspiralGenerator *myself
620);
621
622static int generate_fd_waveform(
625 LALDict *params,
626 LALSimInspiralGenerator *myself
627);
628
629/* Helper struct to store the python quantity and objects used for waveform generation */
630struct internal_data {
631 PyObject *module;
632 PyObject *object;
633 PyObject *instance;
634 PyObject *generate_td_modes;
635 PyObject *generate_fd_modes;
636 PyObject *generate_td_waveform;
637 PyObject *generate_fd_waveform;
638 PyObject *quantity;
639 LALDict *waveform_parameter_units;
640};
641
642/* Free internal_data struct */
643static void free_internal_data(struct internal_data *internal_data)
644{
645 if (internal_data) {
646 Py_XDECREF(internal_data->module);
647 Py_XDECREF(internal_data->object);
648 Py_XDECREF(internal_data->instance);
649 Py_XDECREF(internal_data->generate_td_modes);
650 Py_XDECREF(internal_data->generate_fd_modes);
651 Py_XDECREF(internal_data->generate_td_waveform);
652 Py_XDECREF(internal_data->generate_fd_waveform);
653 Py_XDECREF(internal_data->quantity);
654 XLALDestroyDict(internal_data->waveform_parameter_units);
656 }
657}
658
659/* Initialize python generator.
660 * The path to the python code that actually generates the model is stored in internal_data.module and .object
661 */
662static int initialize(LALSimInspiralGenerator *myself, LALDict *params)
663{
664 struct internal_data *internal_data = NULL;
665 const char *module_name;
666 const char *object_name;
667 LALDict *genparams = NULL;
668 PyObject *args = NULL;
669 PyObject *kwargs = NULL;
670 PyObject *fromlist = NULL;
671 PyObject *result = NULL;
672
673 XLAL_CHECK(myself, XLAL_EFAULT);
675
676 module_name = XLALDictLookupStringValue(params, "module");
677 object_name = XLALDictLookupStringValue(params, "object");
678 XLAL_CHECK(module_name, XLAL_EINVAL, "No parameter \"module\" found");
679 XLAL_CHECK(object_name, XLAL_EINVAL, "No parameter \"object\" found");
680
681 Py_Initialize();
682 if (_import_array() < 0) {
683 PyErr_Print();
684 PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import");
685 XLAL_ERROR(XLAL_EFAILED, "Failed to import numpy.core.multiarray");
686 }
687
688 internal_data = XLALCalloc(1, sizeof(struct internal_data));
690
691 internal_data->waveform_parameter_units = create_waveform_parameter_units_dict();
692 XLAL_CHECK_FAIL(internal_data->waveform_parameter_units, XLAL_EFUNC);
693
694 /* from astropy.units import Quantity */
695 fromlist = Py_BuildValue("(s)", "Quantity");
696 XLAL_CHECK_FAIL(fromlist, XLAL_EFAILED, "Could not build fromlist");
697 result = PyImport_ImportModuleEx("astropy.units", NULL, NULL, fromlist);
698 XLAL_CHECK_FAIL(result, XLAL_EFAILED, "Could not load module astropy.units");
699 Py_CLEAR(fromlist);
700
701 internal_data->quantity = PyObject_GetAttrString(result, "Quantity");
702 XLAL_CHECK_FAIL(internal_data->quantity, XLAL_EFAILED, "Could not load Quantity from module astropy.units");
703 Py_CLEAR(result);
704
705 /* import specified module */
706 internal_data->module = PyImport_ImportModule(module_name);
707 XLAL_CHECK_FAIL(internal_data->module, XLAL_EFAILED, "Could not find module %s", module_name);
708
709 /* load specified object from module */
710 internal_data->object = PyObject_GetAttrString(internal_data->module, object_name);
711 XLAL_CHECK_FAIL(internal_data->object, XLAL_EFAILED, "Could not find object %s in module %s", object_name, module_name);
712
713 /* parameters to pass off to the python generator's .__init__ */
714 genparams = XLALDictDuplicate(params);
715 XLALDictRemove(genparams, "module");
716 XLALDictRemove(genparams, "object");
717 kwargs = PyDict_FromLALDict(genparams, NULL, NULL);
719 XLALDestroyDict(genparams);
720 genparams = NULL;
721 args = PyTuple_New(0); /* empty args */
722 XLAL_CHECK_FAIL(args, XLAL_EFAILED, "Could not create tuple");
723
724 /* create an instance of the specified object from module */
725 internal_data->instance = PyObject_Call(internal_data->object, args, kwargs);
726 XLAL_CHECK_FAIL(internal_data->instance, XLAL_EFAILED, "Could not create instance of object %s in module %s", object_name, module_name);
727 Py_CLEAR(args);
728 Py_CLEAR(kwargs);
729
730 /* figure out what methods the object supports */
731
732 /* generate_td_waveform */
733 if (PyObject_HasAttrString(internal_data->object, "generate_td_waveform")) {
734 internal_data->generate_td_waveform = PyObject_GetAttrString(internal_data->object, "generate_td_waveform");
735 XLAL_CHECK_FAIL(internal_data->generate_td_waveform, XLAL_EFAILED, "Failed to get method generate_td_waveform");
736 } else
737 internal_data->generate_td_waveform = NULL;
738
739 /* generate_fd_waveform */
740 if (PyObject_HasAttrString(internal_data->object, "generate_fd_waveform")) {
741 internal_data->generate_fd_waveform = PyObject_GetAttrString(internal_data->object, "generate_fd_waveform");
742 XLAL_CHECK_FAIL(internal_data->generate_fd_waveform, XLAL_EFAILED, "Failed to get method generate_fd_waveform");
743 } else
744 internal_data->generate_fd_waveform = NULL;
745
746 /* generate_td_modes */
747 if (PyObject_HasAttrString(internal_data->object, "generate_td_modes")) {
748 internal_data->generate_td_modes = PyObject_GetAttrString(internal_data->object, "generate_td_modes");
749 XLAL_CHECK_FAIL(internal_data->generate_td_modes, XLAL_EFAILED, "Failed to get method generate_td_modes");
750 } else
751 internal_data->generate_td_modes = NULL;
752
753 /* generate_fd_modes */
754 if (PyObject_HasAttrString(internal_data->object, "generate_fd_modes")) {
755 internal_data->generate_fd_modes = PyObject_GetAttrString(internal_data->object, "generate_fd_modes");
756 XLAL_CHECK_FAIL(internal_data->generate_fd_modes, XLAL_EFAILED, "Failed to get method generate_fd_modes");
757 } else
758 internal_data->generate_fd_modes = NULL;
759
760 /* make sure that at least one method is defined */
761 XLAL_CHECK_FAIL(internal_data->generate_td_waveform || internal_data->generate_fd_waveform || internal_data->generate_td_modes || internal_data->generate_fd_modes, XLAL_EFAILED, "Object %s in module %s must provide at least one following methods: generate_td_waveform, generate_fd_waveform, generate_td_modes, generate_fd_modes", object_name, module_name);
762
763 /* attach those methods that are found to myself */
764 if (internal_data->generate_td_waveform)
765 myself->generate_td_waveform = generate_td_waveform;
766 if (internal_data->generate_fd_waveform)
767 myself->generate_fd_waveform = generate_fd_waveform;
768 if (internal_data->generate_td_modes)
769 myself->generate_td_modes = generate_td_modes;
770 if (internal_data->generate_fd_modes)
771 myself->generate_fd_modes = generate_fd_modes;
772
773 myself->internal_data = internal_data;
774 return 0;
775
776XLAL_FAIL:
777 python_error();
778 free_internal_data(internal_data);
779 XLALDestroyDict(genparams);
780 Py_XDECREF(args);
781 Py_XDECREF(kwargs);
782 Py_XDECREF(result);
783 Py_XDECREF(fromlist);
784 return (int)XLAL_FAILURE;
785}
786
787/* Free memory */
788static int finalize(LALSimInspiralGenerator *myself)
789{
790 XLAL_CHECK(myself, XLAL_EFAULT);
791 XLAL_CHECK(myself->internal_data, XLAL_EINVAL);
792 free_internal_data(myself->internal_data);
793 myself->generate_td_waveform = NULL;
794 myself->generate_fd_waveform = NULL;
795 myself->generate_td_modes = NULL;
796 myself->generate_fd_modes = NULL;
797 myself->internal_data = NULL;
798 /* don't Py_Finalize() since other things might be using the interpreter */
799 // Py_Finalize();
800 return 0;
801}
802
803/* Generate time-domain polarizations for python generator */
804static int generate_td_waveform(
805 REAL8TimeSeries **hplus,
806 REAL8TimeSeries **hcross,
807 LALDict *params,
808 LALSimInspiralGenerator *myself
809)
810{
812 PyObject *method;
813 PyObject *args = NULL;
814 PyObject *kwargs = NULL;
815 PyObject *result = NULL;
816 PyObject *hp; /* borrowed reference */
817 PyObject *hc; /* borrowed reference */
818
819 /* sanity check arguments */
820 XLAL_CHECK(hplus, XLAL_EFAULT);
821 XLAL_CHECK(hcross, XLAL_EFAULT);
823 XLAL_CHECK(myself, XLAL_EFAULT);
824 XLAL_CHECK(*hplus == NULL, XLAL_EINVAL, "Argument hplus must be a pointer to NULL");
825 XLAL_CHECK(*hcross == NULL, XLAL_EINVAL, "Argument hcross must be a pointer to NULL");
826
827 internal_data = myself->internal_data;
829
830 method = internal_data->generate_td_waveform;
831 XLAL_CHECK(method, XLAL_EFAILED, "Object does not provide method %s", __func__);
832
833 /* call method */
834 args = PyTuple_Pack(1, internal_data->instance); /* self */
835 XLAL_CHECK_FAIL(args, XLAL_EFAILED, "Failed to create tuple");
836 kwargs = PyDict_FromLALDict(params, internal_data->quantity, internal_data->waveform_parameter_units);
838 result = PyObject_Call(method, args, kwargs);
839 XLAL_CHECK_FAIL(result, XLAL_EFUNC, "Failed to call method %s", __func__);
840 Py_CLEAR(kwargs);
841 Py_CLEAR(args);
842
843 /* unpack result */
844 /* should be a tuple of size 2 */
845 XLAL_CHECK_FAIL(PyTuple_Check(result), XLAL_EFAILED, "Invalid value returned by method %s", __func__);
846 XLAL_CHECK_FAIL(PyTuple_Size(result) == 2, XLAL_EFAILED, "Invalid value returned by method %s", __func__);
847 hp = PyTuple_GetItem(result, 0);
848 hc = PyTuple_GetItem(result, 1);
849 XLAL_CHECK_FAIL(hp && hc, XLAL_EFAILED, "Invalid value returned by method %s", __func__);
850
851 /* convert results */
852 *hplus = GWpyTimeSeries_AsREAL8TimeSeries(hp);
854 *hcross = GWpyTimeSeries_AsREAL8TimeSeries(hc);
855 XLAL_CHECK_FAIL(*hcross, XLAL_EFUNC);
856
857 Py_CLEAR(result);
858 Py_CLEAR(hp);
859 Py_CLEAR(hc);
860 return 0;
861
862XLAL_FAIL:
863 python_error();
866 Py_XDECREF(args);
867 Py_XDECREF(kwargs);
868 Py_XDECREF(result);
869 return (int)XLAL_FAILURE;
870}
871
872/* Generate time-domain modes for python generator */
873static int generate_td_modes(
874 SphHarmTimeSeries **hlm,
875 LALDict *params,
876 LALSimInspiralGenerator *myself
877)
878{
880 PyObject *method;
881 PyObject *args = NULL;
882 PyObject *kwargs = NULL;
883 PyObject *result = NULL;
884 PyObject *key; /* borrowed reference */
885 PyObject *val; /* borrowed reference */
886 Py_ssize_t pos = 0;
887
888 /* sanity check arguments */
891 XLAL_CHECK(myself, XLAL_EFAULT);
892 XLAL_CHECK(*hlm == NULL, XLAL_EINVAL, "Argument hplus must be a pointer to NULL");
893
894 internal_data = myself->internal_data;
896
897 method = internal_data->generate_td_modes;
898 XLAL_CHECK(method, XLAL_EFAILED, "Object does not provide method %s", __func__);
899
900 /* call method */
901 args = PyTuple_Pack(1, internal_data->instance); /* self */
902 XLAL_CHECK_FAIL(args, XLAL_EFAILED, "Failed to create tuple");
903 kwargs = PyDict_FromLALDict(params, internal_data->quantity, internal_data->waveform_parameter_units);
905 result = PyObject_Call(method, args, kwargs);
906 XLAL_CHECK_FAIL(result, XLAL_EFUNC, "Failed to call method %s", __func__);
907 Py_CLEAR(kwargs);
908 Py_CLEAR(args);
909
910 /* unpack result */
911 /* make sure it is a dict */
912 XLAL_CHECK_FAIL(PyDict_Check(result), XLAL_EFAILED, "Invalid value returned by method %s", __func__);
913
914 /* loop over items in dict */
915 while (PyDict_Next(result, &pos, &key, &val)) {
916 SphHarmTimeSeries *this;
917 PyObject *l; /* borrowed reference */
918 PyObject *m; /* borrowed reference */
919
920 /* prepend this mode */
921 this = XLALCalloc(1, sizeof(*this));
923 this->next = *hlm;
924 *hlm = this;
925
926 /* key should be a tuple of size 2 */
927 XLAL_CHECK_FAIL(PyTuple_Check(key) && PyTuple_Size(key) == 2, XLAL_EFAILED, "Invalid value returned by method %s", __func__);
928 l = PyTuple_GetItem(key, 0);
929 m = PyTuple_GetItem(key, 1);
930 XLAL_CHECK_FAIL(l && m && PyLong_Check(l) && PyLong_Check(m), XLAL_EFAILED, "Invalid value returned by method %s", __func__);
931
932 /* convert results */
933 this->l = PyLong_AsUnsignedLong(l);
934 XLAL_CHECK_FAIL(!PyErr_Occurred(), XLAL_EFAILED, "Invalid value returned by method %s", __func__);
935 this->m = PyLong_AsLong(m);
936 XLAL_CHECK_FAIL(!PyErr_Occurred(), XLAL_EFAILED, "Invalid value returned by method %s", __func__);
937 this->mode = GWpyTimeSeries_AsCOMPLEX16TimeSeries(val);
938 XLAL_CHECK_FAIL(this->mode, XLAL_EFUNC);
939 }
940
941 Py_CLEAR(result);
942 return 0;
943
944XLAL_FAIL:
945 python_error();
947 *hlm = NULL;
948 Py_XDECREF(args);
949 Py_XDECREF(kwargs);
950 Py_XDECREF(result);
951 return (int)XLAL_FAILURE;
952}
953
954/* Generate Fourier-domain polarizations for python generator */
955static int generate_fd_waveform(
958 LALDict *params,
959 LALSimInspiralGenerator *myself
960)
961{
963 PyObject *method;
964 PyObject *args = NULL;
965 PyObject *kwargs = NULL;
966 PyObject *result = NULL;
967 PyObject *hp; /* borrowed reference */
968 PyObject *hc; /* borrowed reference */
969
970 /* sanity check arguments */
971 XLAL_CHECK(hplus, XLAL_EFAULT);
972 XLAL_CHECK(hcross, XLAL_EFAULT);
974 XLAL_CHECK(myself, XLAL_EFAULT);
975 XLAL_CHECK(*hplus == NULL, XLAL_EINVAL, "Argument hplus must be a pointer to NULL");
976 XLAL_CHECK(*hcross == NULL, XLAL_EINVAL, "Argument hcross must be a pointer to NULL");
977
978 internal_data = myself->internal_data;
980
981 method = internal_data->generate_fd_waveform;
982 XLAL_CHECK(method, XLAL_EFAILED, "Object does not provide method %s", __func__);
983
984 /* call method */
985 args = PyTuple_Pack(1, internal_data->instance); /* self */
986 XLAL_CHECK_FAIL(args, XLAL_EFAILED, "Failed to create tuple");
987 kwargs = PyDict_FromLALDict(params, internal_data->quantity, internal_data->waveform_parameter_units);
989 result = PyObject_Call(method, args, kwargs);
990 XLAL_CHECK_FAIL(result, XLAL_EFUNC, "Failed to call method %s", __func__);
991 Py_CLEAR(kwargs);
992 Py_CLEAR(args);
993
994 /* unpack result */
995 /* should be a tuple of size 2 */
996 XLAL_CHECK_FAIL(PyTuple_Check(result), XLAL_EFAILED, "Invalid value returned by method %s", __func__);
997 XLAL_CHECK_FAIL(PyTuple_Size(result) == 2, XLAL_EFAILED, "Invalid value returned by method %s", __func__);
998 hp = PyTuple_GetItem(result, 0);
999 hc = PyTuple_GetItem(result, 1);
1000 XLAL_CHECK_FAIL(hp && hc, XLAL_EFAILED, "Invalid value returned by method %s", __func__);
1001
1002 /* convert results */
1003 *hplus = GWpyFrequencySeries_AsCOMPLEX16FrequencySeries(hp);
1004 XLAL_CHECK_FAIL(*hplus, XLAL_EFUNC);
1005 *hcross = GWpyFrequencySeries_AsCOMPLEX16FrequencySeries(hc);
1006 XLAL_CHECK_FAIL(*hcross, XLAL_EFUNC);
1007
1008
1009 Py_CLEAR(result);
1010 Py_CLEAR(hp);
1011 Py_CLEAR(hc);
1012 return 0;
1013
1014XLAL_FAIL:
1015 python_error();
1018 Py_XDECREF(args);
1019 Py_XDECREF(kwargs);
1020 Py_XDECREF(result);
1021 return (int)XLAL_FAILURE;
1022}
1023
1024/* Generate Fourier-domain modes for python generator */
1025static int generate_fd_modes(
1027 LALDict *params,
1028 LALSimInspiralGenerator *myself
1029)
1030{
1032 PyObject *method;
1033 PyObject *args = NULL;
1034 PyObject *kwargs = NULL;
1035 PyObject *result = NULL;
1036 PyObject *key; /* borrowed reference */
1037 PyObject *val; /* borrowed reference */
1038 Py_ssize_t pos = 0;
1039
1040 /* sanity check arguments */
1041 XLAL_CHECK(hlm, XLAL_EFAULT);
1043 XLAL_CHECK(myself, XLAL_EFAULT);
1044 XLAL_CHECK(*hlm == NULL, XLAL_EINVAL, "Argument hplus must be a pointer to NULL");
1045
1046 internal_data = myself->internal_data;
1048
1049 method = internal_data->generate_fd_modes;
1050 XLAL_CHECK(method, XLAL_EFAILED, "Object does not provide method %s", __func__);
1051
1052 /* call method */
1053 args = PyTuple_Pack(1, internal_data->instance); /* self */
1054 XLAL_CHECK_FAIL(args, XLAL_EFAILED, "Failed to create tuple");
1055 kwargs = PyDict_FromLALDict(params, internal_data->quantity, internal_data->waveform_parameter_units);
1056 XLAL_CHECK_FAIL(kwargs, XLAL_EFUNC);
1057 result = PyObject_Call(method, args, kwargs);
1058 XLAL_CHECK_FAIL(result, XLAL_EFUNC, "Failed to call method %s", __func__);
1059 Py_CLEAR(kwargs);
1060 Py_CLEAR(args);
1061
1062 /* unpack result */
1063 /* make sure it is a dict */
1064 XLAL_CHECK_FAIL(PyDict_Check(result), XLAL_EFAILED, "Invalid value returned by method %s", __func__);
1065
1066 /* loop over items in dict */
1067 while (PyDict_Next(result, &pos, &key, &val)) {
1069 PyObject *l; /* borrowed reference */
1070 PyObject *m; /* borrowed reference */
1071
1072 /* prepend this mode */
1073 this = XLALCalloc(1, sizeof(*this));
1075 this->next = *hlm;
1076 *hlm = this;
1077
1078 /* key should be a tuple of size 2 */
1079 XLAL_CHECK_FAIL(PyTuple_Check(key) && PyTuple_Size(key) == 2, XLAL_EFAILED, "Invalid value returned by method %s", __func__);
1080 l = PyTuple_GetItem(key, 0);
1081 m = PyTuple_GetItem(key, 1);
1082 XLAL_CHECK_FAIL(l && m && PyLong_Check(l) && PyLong_Check(m), XLAL_EFAILED, "Invalid value returned by method %s", __func__);
1083
1084 /* convert results */
1085 this->l = PyLong_AsUnsignedLong(l);
1086 XLAL_CHECK_FAIL(!PyErr_Occurred(), XLAL_EFAILED, "Invalid value returned by method %s", __func__);
1087 this->m = PyLong_AsLong(m);
1088 XLAL_CHECK_FAIL(!PyErr_Occurred(), XLAL_EFAILED, "Invalid value returned by method %s", __func__);
1089 this->mode = GWpyFrequencySeries_AsCOMPLEX16FrequencySeries(val);
1090 XLAL_CHECK_FAIL(this->mode, XLAL_EFUNC);
1091 }
1092
1093 Py_CLEAR(result);
1094 return 0;
1095
1096XLAL_FAIL:
1097 python_error();
1099 *hlm = NULL;
1100 Py_XDECREF(args);
1101 Py_XDECREF(kwargs);
1102 Py_XDECREF(result);
1103 return (int)XLAL_FAILURE;
1104}
1105
1106/* Define methods supported by the python generator.
1107 * For any external python model, the approximant name must be ExternalPython.
1108 * The path to the python code that actually generates the model is stored in internal_data.module and .object
1109 */
1110const LALSimInspiralGenerator lalPythonGeneratorTemplate = {
1111 .name = "ExternalPython",
1112 .initialize = initialize,
1113 .finalize = finalize,
1114 .generate_td_waveform = generate_td_waveform,
1115 .generate_fd_waveform = generate_fd_waveform,
1116 .generate_td_modes = generate_td_modes,
1117 .generate_fd_modes = generate_fd_modes,
1118 .internal_data = NULL
1119};
1120
1121#endif /* HAVE_PYTHON_EMBED */
int XLALDictContains(const LALDict *dict, const char *key)
const char * XLALDictLookupStringValue(const LALDict *dict, const char *key)
int XLALDictRemove(LALDict *dict, const char *key)
void XLALDestroyDict(LALDict *dict)
LALDict * XLALDictDuplicate(const LALDict *orig)
LALDict * XLALCreateDict(void)
int XLALDictInsertStringValue(LALDict *dict, const char *key, const char *string)
void XLALDictForeach(LALDict *dict, void(*func)(char *, LALValue *, void *), void *thunk)
static int finalize(LALSimInspiralGenerator *myself)
static int generate_fd_waveform(COMPLEX16FrequencySeries **hplus, COMPLEX16FrequencySeries **hcross, LALDict *params, LALSimInspiralGenerator *myself)
Fourier domain polarizations.
static int generate_fd_modes(SphHarmFrequencySeries **hlm, LALDict *params, LALSimInspiralGenerator *myself)
Define waveform generator methods to generate polarizations or modes in time or Fourier domain for le...
static int generate_td_waveform(REAL8TimeSeries **hplus, REAL8TimeSeries **hcross, LALDict *params, LALSimInspiralGenerator *myself)
Time domain polarizations.
static int generate_td_modes(SphHarmTimeSeries **hlm, LALDict *params, LALSimInspiralGenerator *myself)
Time domain modes.
const LALSimInspiralGenerator lalPythonGeneratorTemplate
static int initialize(UNUSED LALSimInspiralGenerator *myself, UNUSED LALDict *params)
static struct @1 lalSimInspiralREAL8WaveformParams[]
const char * name
const char * unit
const char * XLALValueGetString(const LALValue *value)
LALTYPECODE XLALValueGetType(const LALValue *value)
REAL8 XLALValueGetREAL8(const LALValue *value)
INT4 XLALValueGetINT4(const LALValue *value)
int l
Definition: bh_qnmode.c:135
double i
Definition: bh_ringdown.c:118
void XLALDestroyCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *series)
#define XLAL_NUM_ELEM(x)
double complex COMPLEX16
double REAL8
LALUnitIndexKelvin
LALUnitIndexMeter
LALUnitIndexKiloGram
LALUnitIndexSecond
LALUnitIndexADCCount
LALUnitIndexStrain
LALUnitIndexAmpere
LAL_CHAR_TYPE_CODE
LAL_D_TYPE_CODE
LAL_I4_TYPE_CODE
void * XLALCalloc(size_t m, size_t n)
void XLALFree(void *p)
void XLALDestroySphHarmTimeSeries(SphHarmTimeSeries *ts)
Delete list from current pointer to the end of the list.
void XLALDestroySphHarmFrequencySeries(SphHarmFrequencySeries *ts)
Delete list from current pointer to the end of the list.
static const INT4 m
void XLALDestroyREAL8TimeSeries(REAL8TimeSeries *series)
#define XLAL_ERROR_NULL(...)
int XLALGetBaseErrno(void)
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
int XLALSetErrno(int errnum)
#define XLAL_REAL8_FAIL_NAN
#define XLAL_CHECK_FAIL(assertion,...)
#define XLAL_CHECK_REAL8(assertion,...)
#define XLAL_CHECK_NULL(assertion,...)
int XLALClearErrno(void)
#define XLAL_PRINT_ERROR(...)
#define XLAL_ERROR_FAIL(...)
XLAL_ENOMEM
XLAL_EFAULT
XLAL_EFUNC
XLAL_ETYPE
XLAL_ESIZE
XLAL_EINVAL
XLAL_EFAILED
XLAL_FAILURE
LIGOTimeGPS * XLALGPSSet(LIGOTimeGPS *epoch, INT4 gpssec, INT8 gpsnan)
UINT2 unitDenominatorMinusOne[LALNumUnits]
INT2 unitNumerator[LALNumUnits]
Structure to carry a collection of spherical harmonic modes in COMPLEX16 time series.
Definition: burst.c:245