1 /*
2 * Copyright (c) 2016-2021, The OSKAR Developers.
3 * See the LICENSE file at the top-level directory of this distribution.
4 */
5
6 #include <Python.h>
7
8 #include <oskar.h>
9 #include <oskar_version.h>
10 #include <string.h>
11
12 /* http://docs.scipy.org/doc/numpy-dev/reference/c-api.deprecations.html */
13 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
14 #include <numpy/arrayobject.h>
15
16 static const char module_doc[] =
17 "This module provides an interface to the OSKAR telescope model.";
18 static const char name[] = "oskar_Telescope";
19
get_handle(PyObject * capsule,const char * name)20 static void* get_handle(PyObject* capsule, const char* name)
21 {
22 void* h = 0;
23 if (!PyCapsule_CheckExact(capsule))
24 {
25 PyErr_SetString(PyExc_RuntimeError, "Object is not a PyCapsule.");
26 return 0;
27 }
28 if (!(h = PyCapsule_GetPointer(capsule, name)))
29 {
30 PyErr_Format(PyExc_RuntimeError, "Capsule is not of type %s.", name);
31 return 0;
32 }
33 return h;
34 }
35
36
telescope_free(PyObject * capsule)37 static void telescope_free(PyObject* capsule)
38 {
39 int status = 0;
40 oskar_telescope_free((oskar_Telescope*) get_handle(capsule, name), &status);
41 }
42
43
capsule_name(PyObject * self,PyObject * args)44 static PyObject* capsule_name(PyObject* self, PyObject* args)
45 {
46 PyObject *capsule = 0;
47 if (!PyArg_ParseTuple(args, "O", &capsule)) return 0;
48 if (!PyCapsule_CheckExact(capsule))
49 {
50 PyErr_SetString(PyExc_RuntimeError, "Object is not a PyCapsule.");
51 return 0;
52 }
53 return Py_BuildValue("s", PyCapsule_GetName(capsule));
54 }
55
56
create(PyObject * self,PyObject * args)57 static PyObject* create(PyObject* self, PyObject* args)
58 {
59 oskar_Telescope* h = 0;
60 PyObject* capsule = 0;
61 int status = 0, prec = 0;
62 const char* type;
63 if (!PyArg_ParseTuple(args, "s", &type)) return 0;
64 prec = (type[0] == 'S' || type[0] == 's') ? OSKAR_SINGLE : OSKAR_DOUBLE;
65 h = oskar_telescope_create(prec, OSKAR_CPU, 0, &status);
66 capsule = PyCapsule_New((void*)h, name,
67 (PyCapsule_Destructor)telescope_free);
68 return Py_BuildValue("N", capsule); /* Don't increment refcount. */
69 }
70
71
load(PyObject * self,PyObject * args)72 static PyObject* load(PyObject* self, PyObject* args)
73 {
74 oskar_Telescope* h = 0;
75 PyObject* capsule = 0;
76 int status = 0;
77 const char* dir_name;
78 if (!PyArg_ParseTuple(args, "Os", &capsule, &dir_name)) return 0;
79 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
80 oskar_telescope_load(h, dir_name, 0, &status);
81
82 /* Check for errors. */
83 if (status)
84 {
85 PyErr_Format(PyExc_RuntimeError,
86 "oskar_telescope_load() failed with code %d (%s).",
87 status, oskar_get_error_string(status));
88 return 0;
89 }
90 return Py_BuildValue("");
91 }
92
93
identical_stations(PyObject * self,PyObject * args)94 static PyObject* identical_stations(PyObject* self, PyObject* args)
95 {
96 PyErr_Format(PyExc_RuntimeError,
97 "This method is no longer available.");
98 return 0;
99 }
100
101
max_station_depth(PyObject * self,PyObject * args)102 static PyObject* max_station_depth(PyObject* self, PyObject* args)
103 {
104 oskar_Telescope* h = 0;
105 PyObject* capsule = 0;
106 if (!PyArg_ParseTuple(args, "O", &capsule)) return 0;
107 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
108 return Py_BuildValue("i", oskar_telescope_max_station_depth(h));
109 }
110
111
max_station_size(PyObject * self,PyObject * args)112 static PyObject* max_station_size(PyObject* self, PyObject* args)
113 {
114 oskar_Telescope* h = 0;
115 PyObject* capsule = 0;
116 if (!PyArg_ParseTuple(args, "O", &capsule)) return 0;
117 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
118 return Py_BuildValue("i", oskar_telescope_max_station_size(h));
119 }
120
121
num_baselines(PyObject * self,PyObject * args)122 static PyObject* num_baselines(PyObject* self, PyObject* args)
123 {
124 oskar_Telescope* h = 0;
125 PyObject* capsule = 0;
126 if (!PyArg_ParseTuple(args, "O", &capsule)) return 0;
127 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
128 return Py_BuildValue("i", oskar_telescope_num_baselines(h));
129 }
130
131
num_stations(PyObject * self,PyObject * args)132 static PyObject* num_stations(PyObject* self, PyObject* args)
133 {
134 oskar_Telescope* h = 0;
135 PyObject* capsule = 0;
136 if (!PyArg_ParseTuple(args, "O", &capsule)) return 0;
137 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
138 return Py_BuildValue("i", oskar_telescope_num_stations(h));
139 }
140
141
override_element_cable_length_errors(PyObject * self,PyObject * args)142 static PyObject* override_element_cable_length_errors(
143 PyObject* self, PyObject* args)
144 {
145 oskar_Telescope* h = 0;
146 PyObject* capsule = 0;
147 int feed = 0, seed = 0, status = 0;
148 double mean = 0.0, std = 0.0;
149 if (!PyArg_ParseTuple(args, "Oiidd", &capsule, &feed, &seed, &mean, &std))
150 return 0;
151 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
152 #if OSKAR_VERSION >= 0x020800
153 oskar_telescope_override_element_cable_length_errors(h, feed, seed,
154 mean, std, &status);
155 if (status)
156 {
157 PyErr_Format(PyExc_RuntimeError,
158 "oskar_telescope_override_element_cable_length_errors() failed "
159 "with code %d (%s).", status, oskar_get_error_string(status));
160 return 0;
161 }
162 return Py_BuildValue("");
163 #elif OSKAR_VERSION > 0x020701
164 oskar_telescope_override_element_cable_length_errors(h, seed,
165 mean, std, &status);
166 if (status)
167 {
168 PyErr_Format(PyExc_RuntimeError,
169 "oskar_telescope_override_element_cable_length_errors() failed "
170 "with code %d (%s).", status, oskar_get_error_string(status));
171 return 0;
172 }
173 return Py_BuildValue("");
174 #else
175 (void) h;
176 (void) status;
177 PyErr_SetString(PyExc_RuntimeError,
178 "This function is not available in OSKAR " OSKAR_VERSION_STR ". "
179 "Please update to a newer version.");
180 return 0;
181 #endif
182 }
183
184
override_element_gains(PyObject * self,PyObject * args)185 static PyObject* override_element_gains(PyObject* self, PyObject* args)
186 {
187 oskar_Telescope* h = 0;
188 PyObject* capsule = 0;
189 int feed = 0, seed = 0, status = 0;
190 double mean = 0.0, std = 0.0;
191 if (!PyArg_ParseTuple(args, "Oiidd", &capsule, &feed, &seed, &mean, &std))
192 return 0;
193 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
194 #if OSKAR_VERSION >= 0x020800
195 oskar_telescope_override_element_gains(h, feed, seed, mean, std, &status);
196 if (status)
197 {
198 PyErr_Format(PyExc_RuntimeError,
199 "oskar_telescope_override_element_gains() failed "
200 "with code %d (%s).", status, oskar_get_error_string(status));
201 return 0;
202 }
203 return Py_BuildValue("");
204 #elif OSKAR_VERSION > 0x020701
205 oskar_telescope_override_element_gains(h, seed, mean, std, &status);
206 if (status)
207 {
208 PyErr_Format(PyExc_RuntimeError,
209 "oskar_telescope_override_element_gains() failed "
210 "with code %d (%s).", status, oskar_get_error_string(status));
211 return 0;
212 }
213 return Py_BuildValue("");
214 #else
215 (void) h;
216 (void) status;
217 PyErr_SetString(PyExc_RuntimeError,
218 "This function is not available in OSKAR " OSKAR_VERSION_STR ". "
219 "Please update to a newer version.");
220 return 0;
221 #endif
222 }
223
224
override_element_phases(PyObject * self,PyObject * args)225 static PyObject* override_element_phases(PyObject* self, PyObject* args)
226 {
227 oskar_Telescope* h = 0;
228 PyObject* capsule = 0;
229 int feed = 0, seed = 0, status = 0;
230 double std_rad = 0.0;
231 if (!PyArg_ParseTuple(args, "Oiid", &capsule, &feed, &seed, &std_rad))
232 return 0;
233 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
234 #if OSKAR_VERSION >= 0x020800
235 oskar_telescope_override_element_phases(h, feed, seed, std_rad, &status);
236 if (status)
237 {
238 PyErr_Format(PyExc_RuntimeError,
239 "oskar_telescope_override_element_phases() failed "
240 "with code %d (%s).", status, oskar_get_error_string(status));
241 return 0;
242 }
243 return Py_BuildValue("");
244 #elif OSKAR_VERSION > 0x020701
245 oskar_telescope_override_element_phases(h, seed, std_rad, &status);
246 if (status)
247 {
248 PyErr_Format(PyExc_RuntimeError,
249 "oskar_telescope_override_element_phases() failed "
250 "with code %d (%s).", status, oskar_get_error_string(status));
251 return 0;
252 }
253 return Py_BuildValue("");
254 #else
255 (void) h;
256 (void) status;
257 PyErr_SetString(PyExc_RuntimeError,
258 "This function is not available in OSKAR " OSKAR_VERSION_STR ". "
259 "Please update to a newer version.");
260 return 0;
261 #endif
262 }
263
264
set_allow_station_beam_duplication(PyObject * self,PyObject * args)265 static PyObject* set_allow_station_beam_duplication(PyObject* self,
266 PyObject* args)
267 {
268 oskar_Telescope* h = 0;
269 PyObject* capsule = 0;
270 int value = 0;
271 if (!PyArg_ParseTuple(args, "Oi", &capsule, &value)) return 0;
272 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
273 oskar_telescope_set_allow_station_beam_duplication(h, value);
274 return Py_BuildValue("");
275 }
276
277
set_channel_bandwidth(PyObject * self,PyObject * args)278 static PyObject* set_channel_bandwidth(PyObject* self, PyObject* args)
279 {
280 oskar_Telescope* h = 0;
281 PyObject* capsule = 0;
282 double channel_bandwidth_hz = 0.0;
283 if (!PyArg_ParseTuple(args, "Od", &capsule,
284 &channel_bandwidth_hz)) return 0;
285 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
286 oskar_telescope_set_channel_bandwidth(h, channel_bandwidth_hz);
287 return Py_BuildValue("");
288 }
289
290
set_enable_noise(PyObject * self,PyObject * args)291 static PyObject* set_enable_noise(PyObject* self, PyObject* args)
292 {
293 oskar_Telescope* h = 0;
294 PyObject* capsule = 0;
295 int value = 0, seed = 0;
296 if (!PyArg_ParseTuple(args, "Oii", &capsule, &value, &seed)) return 0;
297 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
298 oskar_telescope_set_enable_noise(h, value, (unsigned int) seed);
299 return Py_BuildValue("");
300 }
301
302
set_enable_numerical_patterns(PyObject * self,PyObject * args)303 static PyObject* set_enable_numerical_patterns(PyObject* self, PyObject* args)
304 {
305 oskar_Telescope* h = 0;
306 PyObject* capsule = 0;
307 int value = 0;
308 if (!PyArg_ParseTuple(args, "Oi", &capsule, &value)) return 0;
309 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
310 oskar_telescope_set_enable_numerical_patterns(h, value);
311 return Py_BuildValue("");
312 }
313
314
set_gaussian_station_beam_width(PyObject * self,PyObject * args)315 static PyObject* set_gaussian_station_beam_width(PyObject* self,
316 PyObject* args)
317 {
318 oskar_Telescope* h = 0;
319 PyObject* capsule = 0;
320 double fwhm_deg = 0.0, ref_freq_hz = 0.0;
321 if (!PyArg_ParseTuple(args, "Odd", &capsule, &fwhm_deg, &ref_freq_hz))
322 return 0;
323 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
324
325 /* Check stations exist. */
326 if (oskar_telescope_num_stations(h) == 0)
327 {
328 PyErr_Format(PyExc_RuntimeError, "No stations in telescope model!");
329 return 0;
330 }
331 oskar_telescope_set_gaussian_station_beam_width(h, fwhm_deg, ref_freq_hz);
332 return Py_BuildValue("");
333 }
334
335
set_noise_freq(PyObject * self,PyObject * args)336 static PyObject* set_noise_freq(PyObject* self, PyObject* args)
337 {
338 oskar_Telescope* h = 0;
339 PyObject* capsule = 0;
340 int num_channels = 0, status = 0;
341 double start_hz = 0.0, inc_hz = 0.0;
342 if (!PyArg_ParseTuple(args, "Oddi", &capsule, &start_hz, &inc_hz,
343 &num_channels)) return 0;
344 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
345
346 /* Check stations exist. */
347 if (oskar_telescope_num_stations(h) == 0)
348 {
349 PyErr_Format(PyExc_RuntimeError, "No stations in telescope model!");
350 return 0;
351 }
352 oskar_telescope_set_noise_freq(h, start_hz, inc_hz, num_channels, &status);
353
354 /* Check for errors. */
355 if (status)
356 {
357 PyErr_Format(PyExc_RuntimeError,
358 "oskar_telescope_set_noise_freq() failed with code %d (%s).",
359 status, oskar_get_error_string(status));
360 return 0;
361 }
362 return Py_BuildValue("");
363 }
364
365
set_noise_rms(PyObject * self,PyObject * args)366 static PyObject* set_noise_rms(PyObject* self, PyObject* args)
367 {
368 oskar_Telescope* h = 0;
369 PyObject* capsule = 0;
370 int status = 0;
371 double start = 0.0, end = 0.0;
372 if (!PyArg_ParseTuple(args, "Odd", &capsule, &start, &end)) return 0;
373 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
374
375 /* Check stations exist. */
376 if (oskar_telescope_num_stations(h) == 0)
377 {
378 PyErr_Format(PyExc_RuntimeError, "No stations in telescope model!");
379 return 0;
380 }
381 oskar_telescope_set_noise_rms(h, start, end, &status);
382
383 /* Check for errors. */
384 if (status)
385 {
386 PyErr_Format(PyExc_RuntimeError,
387 "oskar_telescope_set_noise_rms() failed "
388 "with code %d (%s).\n\n"
389 "Remember to set noise frequencies first!",
390 status, oskar_get_error_string(status));
391 return 0;
392 }
393 return Py_BuildValue("");
394 }
395
396
set_phase_centre(PyObject * self,PyObject * args)397 static PyObject* set_phase_centre(PyObject* self, PyObject* args)
398 {
399 oskar_Telescope* h = 0;
400 PyObject* capsule = 0;
401 double ra_rad = 0.0, dec_rad = 0.0;
402 if (!PyArg_ParseTuple(args, "Odd", &capsule, &ra_rad, &dec_rad)) return 0;
403 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
404
405 /* Check stations exist. */
406 if (oskar_telescope_num_stations(h) == 0)
407 {
408 PyErr_Format(PyExc_RuntimeError, "No stations in telescope model!");
409 return 0;
410 }
411 #if OSKAR_VERSION >= 0x020800
412 oskar_telescope_set_phase_centre(h, OSKAR_COORDS_RADEC,
413 ra_rad, dec_rad);
414 #else
415 oskar_telescope_set_phase_centre(h, OSKAR_SPHERICAL_TYPE_EQUATORIAL,
416 ra_rad, dec_rad);
417 #endif
418 return Py_BuildValue("");
419 }
420
421
set_pol_mode(PyObject * self,PyObject * args)422 static PyObject* set_pol_mode(PyObject* self, PyObject* args)
423 {
424 oskar_Telescope* h = 0;
425 PyObject* capsule = 0;
426 int status = 0;
427 const char* mode;
428 if (!PyArg_ParseTuple(args, "Os", &capsule, &mode)) return 0;
429 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
430 oskar_telescope_set_pol_mode(h, mode, &status);
431 if (status)
432 {
433 PyErr_SetString(PyExc_RuntimeError, "Unknown polarisation mode.");
434 return 0;
435 }
436 return Py_BuildValue("");
437 }
438
439
set_position(PyObject * self,PyObject * args)440 static PyObject* set_position(PyObject* self, PyObject* args)
441 {
442 oskar_Telescope* h = 0;
443 PyObject* capsule = 0;
444 double longitude_rad = 0.0, latitude_rad = 0.0, altitude_m = 0.0;
445 if (!PyArg_ParseTuple(args, "Oddd", &capsule,
446 &longitude_rad, &latitude_rad, &altitude_m)) return 0;
447 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
448 oskar_telescope_set_position(h, longitude_rad, latitude_rad, altitude_m);
449 return Py_BuildValue("");
450 }
451
452
set_station_coords_ecef(PyObject * self,PyObject * args)453 static PyObject* set_station_coords_ecef(PyObject* self, PyObject* args)
454 {
455 oskar_Telescope* h = 0;
456 PyObject *obj[] = {0, 0, 0, 0, 0, 0, 0};
457 oskar_Mem *x_c, *y_c, *z_c, *x_err_c, *y_err_c, *z_err_c;
458 PyArrayObject *x = 0, *y = 0, *z = 0, *x_err = 0, *y_err = 0, *z_err = 0;
459 int status = 0, flags, i, num_stations;
460 double longitude, latitude, altitude;
461
462 /* Parse inputs. */
463 if (!PyArg_ParseTuple(args, "OdddOOOOOO", &obj[0],
464 &longitude, &latitude, &altitude,
465 &obj[1], &obj[2], &obj[3], &obj[4], &obj[5], &obj[6])) return 0;
466 if (!(h = (oskar_Telescope*) get_handle(obj[0], name))) return 0;
467
468 /* Make sure input objects are arrays. Convert if required. */
469 flags = NPY_ARRAY_FORCECAST | NPY_ARRAY_IN_ARRAY;
470 x = (PyArrayObject*) PyArray_FROM_OTF(obj[1], NPY_DOUBLE, flags);
471 y = (PyArrayObject*) PyArray_FROM_OTF(obj[2], NPY_DOUBLE, flags);
472 z = (PyArrayObject*) PyArray_FROM_OTF(obj[3], NPY_DOUBLE, flags);
473 x_err = (PyArrayObject*) PyArray_FROM_OTF(obj[4], NPY_DOUBLE, flags);
474 y_err = (PyArrayObject*) PyArray_FROM_OTF(obj[5], NPY_DOUBLE, flags);
475 z_err = (PyArrayObject*) PyArray_FROM_OTF(obj[6], NPY_DOUBLE, flags);
476 if (!x || !y || !z || !x_err || !y_err || !z_err)
477 goto fail;
478
479 /* Check size of input arrays. */
480 num_stations = (int) PyArray_SIZE(x);
481 if (num_stations != (int) PyArray_SIZE(y) ||
482 num_stations != (int) PyArray_SIZE(z) ||
483 num_stations != (int) PyArray_SIZE(x_err) ||
484 num_stations != (int) PyArray_SIZE(y_err) ||
485 num_stations != (int) PyArray_SIZE(z_err))
486 {
487 PyErr_SetString(PyExc_RuntimeError, "Input data dimension mismatch.");
488 goto fail;
489 }
490
491 /* Pointers to input arrays. */
492 x_c = oskar_mem_create_alias_from_raw(PyArray_DATA(x),
493 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
494 y_c = oskar_mem_create_alias_from_raw(PyArray_DATA(y),
495 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
496 z_c = oskar_mem_create_alias_from_raw(PyArray_DATA(z),
497 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
498 x_err_c = oskar_mem_create_alias_from_raw(PyArray_DATA(x_err),
499 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
500 y_err_c = oskar_mem_create_alias_from_raw(PyArray_DATA(y_err),
501 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
502 z_err_c = oskar_mem_create_alias_from_raw(PyArray_DATA(z_err),
503 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
504
505 /* Set data. */
506 #if OSKAR_VERSION >= 0x020800
507 oskar_telescope_set_station_coords_ecef(h, longitude, latitude, altitude,
508 num_stations, x_c, y_c, z_c, x_err_c, y_err_c, z_err_c, &status);
509 oskar_telescope_resize_station_array(h, 1, &status);
510 for (i = 0; i < 1; ++i)
511 {
512 oskar_Station* station = oskar_telescope_station(h, i);
513 oskar_station_resize(station, 1, &status);
514 oskar_station_resize_element_types(station, 1, &status);
515 }
516 oskar_telescope_set_station_ids_and_coords(h, &status);
517 #else
518 oskar_telescope_set_station_coords_ecef(h, longitude, latitude, altitude,
519 num_stations, x_c, y_c, z_c, x_err_c, y_err_c, z_err_c, &status);
520 for (i = 0; i < num_stations; ++i)
521 {
522 oskar_Station* station = oskar_telescope_station(h, i);
523 oskar_station_resize(station, 1, &status);
524 oskar_station_resize_element_types(station, 1, &status);
525 }
526 #endif
527
528 /* Free memory. */
529 oskar_mem_free(x_c, &status);
530 oskar_mem_free(y_c, &status);
531 oskar_mem_free(z_c, &status);
532 oskar_mem_free(x_err_c, &status);
533 oskar_mem_free(y_err_c, &status);
534 oskar_mem_free(z_err_c, &status);
535
536 Py_XDECREF(x);
537 Py_XDECREF(y);
538 Py_XDECREF(z);
539 Py_XDECREF(x_err);
540 Py_XDECREF(y_err);
541 Py_XDECREF(z_err);
542 return Py_BuildValue("");
543
544 fail:
545 Py_XDECREF(x);
546 Py_XDECREF(y);
547 Py_XDECREF(z);
548 Py_XDECREF(x_err);
549 Py_XDECREF(y_err);
550 Py_XDECREF(z_err);
551 return 0;
552 }
553
554
set_station_coords_enu(PyObject * self,PyObject * args)555 static PyObject* set_station_coords_enu(PyObject* self, PyObject* args)
556 {
557 oskar_Telescope* h = 0;
558 PyObject *obj[] = {0, 0, 0, 0, 0, 0, 0};
559 oskar_Mem *x_c, *y_c, *z_c, *x_err_c, *y_err_c, *z_err_c;
560 PyArrayObject *x = 0, *y = 0, *z = 0, *x_err = 0, *y_err = 0, *z_err = 0;
561 int status = 0, flags, i, num_stations;
562 double longitude, latitude, altitude;
563
564 /* Parse inputs. */
565 if (!PyArg_ParseTuple(args, "OdddOOOOOO", &obj[0],
566 &longitude, &latitude, &altitude,
567 &obj[1], &obj[2], &obj[3], &obj[4], &obj[5], &obj[6])) return 0;
568 if (!(h = (oskar_Telescope*) get_handle(obj[0], name))) return 0;
569
570 /* Make sure input objects are arrays. Convert if required. */
571 flags = NPY_ARRAY_FORCECAST | NPY_ARRAY_IN_ARRAY;
572 x = (PyArrayObject*) PyArray_FROM_OTF(obj[1], NPY_DOUBLE, flags);
573 y = (PyArrayObject*) PyArray_FROM_OTF(obj[2], NPY_DOUBLE, flags);
574 z = (PyArrayObject*) PyArray_FROM_OTF(obj[3], NPY_DOUBLE, flags);
575 x_err = (PyArrayObject*) PyArray_FROM_OTF(obj[4], NPY_DOUBLE, flags);
576 y_err = (PyArrayObject*) PyArray_FROM_OTF(obj[5], NPY_DOUBLE, flags);
577 z_err = (PyArrayObject*) PyArray_FROM_OTF(obj[6], NPY_DOUBLE, flags);
578 if (!x || !y || !z || !x_err || !y_err || !z_err)
579 goto fail;
580
581 /* Check size of input arrays. */
582 num_stations = (int) PyArray_SIZE(x);
583 if (num_stations != (int) PyArray_SIZE(y) ||
584 num_stations != (int) PyArray_SIZE(z) ||
585 num_stations != (int) PyArray_SIZE(x_err) ||
586 num_stations != (int) PyArray_SIZE(y_err) ||
587 num_stations != (int) PyArray_SIZE(z_err))
588 {
589 PyErr_SetString(PyExc_RuntimeError, "Input data dimension mismatch.");
590 goto fail;
591 }
592
593 /* Pointers to input arrays. */
594 x_c = oskar_mem_create_alias_from_raw(PyArray_DATA(x),
595 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
596 y_c = oskar_mem_create_alias_from_raw(PyArray_DATA(y),
597 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
598 z_c = oskar_mem_create_alias_from_raw(PyArray_DATA(z),
599 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
600 x_err_c = oskar_mem_create_alias_from_raw(PyArray_DATA(x_err),
601 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
602 y_err_c = oskar_mem_create_alias_from_raw(PyArray_DATA(y_err),
603 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
604 z_err_c = oskar_mem_create_alias_from_raw(PyArray_DATA(z_err),
605 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
606
607 /* Set data. */
608 #if OSKAR_VERSION >= 0x020800
609 oskar_telescope_set_station_coords_enu(h, longitude, latitude, altitude,
610 num_stations, x_c, y_c, z_c, x_err_c, y_err_c, z_err_c, &status);
611 oskar_telescope_resize_station_array(h, 1, &status);
612 for (i = 0; i < 1; ++i)
613 {
614 oskar_Station* station = oskar_telescope_station(h, i);
615 oskar_station_resize(station, 1, &status);
616 oskar_station_resize_element_types(station, 1, &status);
617 }
618 oskar_telescope_set_station_ids_and_coords(h, &status);
619 #else
620 oskar_telescope_set_station_coords_enu(h, longitude, latitude, altitude,
621 num_stations, x_c, y_c, z_c, x_err_c, y_err_c, z_err_c, &status);
622 for (i = 0; i < num_stations; ++i)
623 {
624 oskar_Station* station = oskar_telescope_station(h, i);
625 oskar_station_resize(station, 1, &status);
626 oskar_station_resize_element_types(station, 1, &status);
627 }
628 #endif
629
630 /* Free memory. */
631 oskar_mem_free(x_c, &status);
632 oskar_mem_free(y_c, &status);
633 oskar_mem_free(z_c, &status);
634 oskar_mem_free(x_err_c, &status);
635 oskar_mem_free(y_err_c, &status);
636 oskar_mem_free(z_err_c, &status);
637
638 Py_XDECREF(x);
639 Py_XDECREF(y);
640 Py_XDECREF(z);
641 Py_XDECREF(x_err);
642 Py_XDECREF(y_err);
643 Py_XDECREF(z_err);
644 return Py_BuildValue("");
645
646 fail:
647 Py_XDECREF(x);
648 Py_XDECREF(y);
649 Py_XDECREF(z);
650 Py_XDECREF(x_err);
651 Py_XDECREF(y_err);
652 Py_XDECREF(z_err);
653 return 0;
654 }
655
656
set_station_coords_wgs84(PyObject * self,PyObject * args)657 static PyObject* set_station_coords_wgs84(PyObject* self, PyObject* args)
658 {
659 oskar_Telescope* h = 0;
660 PyObject *obj[] = {0, 0, 0, 0};
661 oskar_Mem *lon_deg_c, *lat_deg_c, *alt_m_c;
662 PyArrayObject *lon_deg = 0, *lat_deg = 0, *alt_m = 0;
663 int status = 0, flags, i, num_stations;
664 double longitude, latitude, altitude;
665
666 /* Parse inputs. */
667 if (!PyArg_ParseTuple(args, "OdddOOO", &obj[0],
668 &longitude, &latitude, &altitude,
669 &obj[1], &obj[2], &obj[3])) return 0;
670 if (!(h = (oskar_Telescope*) get_handle(obj[0], name))) return 0;
671
672 /* Make sure input objects are arrays. Convert if required. */
673 flags = NPY_ARRAY_FORCECAST | NPY_ARRAY_IN_ARRAY;
674 lon_deg = (PyArrayObject*) PyArray_FROM_OTF(obj[1], NPY_DOUBLE, flags);
675 lat_deg = (PyArrayObject*) PyArray_FROM_OTF(obj[2], NPY_DOUBLE, flags);
676 alt_m = (PyArrayObject*) PyArray_FROM_OTF(obj[3], NPY_DOUBLE, flags);
677 if (!lon_deg || !lat_deg || !alt_m)
678 goto fail;
679
680 /* Check size of input arrays. */
681 num_stations = (int) PyArray_SIZE(lon_deg);
682 if (num_stations != (int) PyArray_SIZE(lat_deg) ||
683 num_stations != (int) PyArray_SIZE(alt_m))
684 {
685 PyErr_SetString(PyExc_RuntimeError, "Input data dimension mismatch.");
686 goto fail;
687 }
688
689 /* Pointers to input arrays. */
690 lon_deg_c = oskar_mem_create_alias_from_raw(PyArray_DATA(lon_deg),
691 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
692 lat_deg_c = oskar_mem_create_alias_from_raw(PyArray_DATA(lat_deg),
693 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
694 alt_m_c = oskar_mem_create_alias_from_raw(PyArray_DATA(alt_m),
695 OSKAR_DOUBLE, OSKAR_CPU, num_stations, &status);
696
697 /* Set data. */
698 #if OSKAR_VERSION >= 0x020800
699 oskar_telescope_set_station_coords_wgs84(h, longitude, latitude, altitude,
700 num_stations, lon_deg_c, lat_deg_c, alt_m_c, &status);
701 oskar_telescope_resize_station_array(h, 1, &status);
702 for (i = 0; i < 1; ++i)
703 {
704 oskar_Station* station = oskar_telescope_station(h, i);
705 oskar_station_resize(station, 1, &status);
706 oskar_station_resize_element_types(station, 1, &status);
707 }
708 oskar_telescope_set_station_ids_and_coords(h, &status);
709 #else
710 oskar_telescope_set_station_coords_wgs84(h, longitude, latitude, altitude,
711 num_stations, lon_deg_c, lat_deg_c, alt_m_c, &status);
712 for (i = 0; i < num_stations; ++i)
713 {
714 oskar_Station* station = oskar_telescope_station(h, i);
715 oskar_station_resize(station, 1, &status);
716 oskar_station_resize_element_types(station, 1, &status);
717 }
718 #endif
719
720 /* Free memory. */
721 oskar_mem_free(lon_deg_c, &status);
722 oskar_mem_free(lat_deg_c, &status);
723 oskar_mem_free(alt_m_c, &status);
724
725 Py_XDECREF(lon_deg);
726 Py_XDECREF(lat_deg);
727 Py_XDECREF(alt_m);
728 return Py_BuildValue("");
729
730 fail:
731 Py_XDECREF(lon_deg);
732 Py_XDECREF(lat_deg);
733 Py_XDECREF(alt_m);
734 return 0;
735 }
736
737
set_station_type(PyObject * self,PyObject * args)738 static PyObject* set_station_type(PyObject* self, PyObject* args)
739 {
740 oskar_Telescope* h = 0;
741 PyObject* capsule = 0;
742 int status = 0;
743 const char* type_string = 0;
744 if (!PyArg_ParseTuple(args, "Os", &capsule, &type_string)) return 0;
745 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
746
747 /* Check stations exist. */
748 if (oskar_telescope_num_stations(h) == 0)
749 {
750 PyErr_Format(PyExc_RuntimeError, "No stations in telescope model!");
751 return 0;
752 }
753 oskar_telescope_set_station_type(h, type_string, &status);
754 if (status)
755 {
756 PyErr_SetString(PyExc_RuntimeError, "Unknown station type.");
757 return 0;
758 }
759 return Py_BuildValue("");
760 }
761
762
set_time_average(PyObject * self,PyObject * args)763 static PyObject* set_time_average(PyObject* self, PyObject* args)
764 {
765 oskar_Telescope* h = 0;
766 PyObject* capsule = 0;
767 double time_average_sec = 0.0;
768 if (!PyArg_ParseTuple(args, "Od", &capsule, &time_average_sec)) return 0;
769 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
770 oskar_telescope_set_time_average(h, time_average_sec);
771 return Py_BuildValue("");
772 }
773
774
set_uv_filter(PyObject * self,PyObject * args)775 static PyObject* set_uv_filter(PyObject* self, PyObject* args)
776 {
777 oskar_Telescope* h = 0;
778 PyObject* capsule = 0;
779 int status = 0;
780 double uv_filter_min = 0.0, uv_filter_max = 0.0;
781 const char* units = 0;
782 if (!PyArg_ParseTuple(args, "Odds", &capsule,
783 &uv_filter_min, &uv_filter_max, &units)) return 0;
784 if (!(h = (oskar_Telescope*) get_handle(capsule, name))) return 0;
785
786 oskar_telescope_set_uv_filter(h,
787 uv_filter_min, uv_filter_max, units, &status);
788 if (status)
789 {
790 PyErr_SetString(PyExc_RuntimeError, "Unknown units.");
791 return 0;
792 }
793 return Py_BuildValue("");
794 }
795
796
797 /* Method table. */
798 static PyMethodDef methods[] =
799 {
800 {"capsule_name", (PyCFunction)capsule_name,
801 METH_VARARGS, "capsule_name()"},
802 {"create", (PyCFunction)create, METH_VARARGS, "create(type)"},
803 {"load", (PyCFunction)load, METH_VARARGS, "load(input_dir)"},
804 {"identical_stations", (PyCFunction)identical_stations,
805 METH_VARARGS, "identical_stations()"},
806 {"max_station_depth", (PyCFunction)max_station_depth,
807 METH_VARARGS, "max_station_depth()"},
808 {"max_station_size", (PyCFunction)max_station_size,
809 METH_VARARGS, "max_station_size()"},
810 {"num_baselines", (PyCFunction)num_baselines,
811 METH_VARARGS, "num_baselines()"},
812 {"num_stations", (PyCFunction)num_stations,
813 METH_VARARGS, "num_stations()"},
814 {"override_element_cable_length_errors",
815 (PyCFunction)override_element_cable_length_errors,
816 METH_VARARGS,
817 "override_element_cable_length_errors(feed, seed, mean, std)"},
818 {"override_element_gains", (PyCFunction)override_element_gains,
819 METH_VARARGS, "override_element_gains(feed, seed, mean, std)"},
820 {"override_element_phases", (PyCFunction)override_element_phases,
821 METH_VARARGS, "override_element_phases(feed, seed, std)"},
822 {"set_allow_station_beam_duplication",
823 (PyCFunction)set_allow_station_beam_duplication,
824 METH_VARARGS, "set_allow_station_beam_duplication(value)"},
825 {"set_channel_bandwidth", (PyCFunction)set_channel_bandwidth,
826 METH_VARARGS, "set_channel_bandwidth(channel_bandwidth_hz)"},
827 {"set_enable_noise", (PyCFunction)set_enable_noise,
828 METH_VARARGS, "set_enable_noise(value, seed)"},
829 {"set_enable_numerical_patterns",
830 (PyCFunction)set_enable_numerical_patterns,
831 METH_VARARGS, "set_enable_numerical_patterns(value)"},
832 {"set_gaussian_station_beam_width",
833 (PyCFunction)set_gaussian_station_beam_width, METH_VARARGS,
834 "set_gaussian_station_beam_width(fwhm_deg, ref_freq_hz)"},
835 {"set_noise_freq", (PyCFunction)set_noise_freq, METH_VARARGS,
836 "set_noise_freq(start_freq_hz, inc_hz, num_channels)"},
837 {"set_noise_rms", (PyCFunction)set_noise_rms,
838 METH_VARARGS, "set_noise_rms(start, end)"},
839 {"set_phase_centre", (PyCFunction)set_phase_centre,
840 METH_VARARGS, "set_phase_centre(ra_rad, dec_rad)"},
841 {"set_pol_mode", (PyCFunction)set_pol_mode,
842 METH_VARARGS, "set_pol_mode(type)"},
843 {"set_position", (PyCFunction)set_position,
844 METH_VARARGS, "set_position(longitude, latitude, altitude)"},
845 {"set_station_coords_ecef", (PyCFunction)set_station_coords_ecef,
846 METH_VARARGS, "set_station_coords_ecef(longitude, latitude, "
847 "altitude, x, y, z, x_err, y_err, z_err)"},
848 {"set_station_coords_enu", (PyCFunction)set_station_coords_enu,
849 METH_VARARGS, "set_station_coords_enu(longitude, latitude, "
850 "altitude, x, y, z, x_err, y_err, z_err)"},
851 {"set_station_coords_wgs84", (PyCFunction)set_station_coords_wgs84,
852 METH_VARARGS, "set_station_coords_wgs84(longitude, latitude, "
853 "altitude, station_longitudes, station_latitudes, "
854 "station_altitudes)"},
855 {"set_station_type", (PyCFunction)set_station_type,
856 METH_VARARGS, "set_station_type(type_string)"},
857 {"set_time_average", (PyCFunction)set_time_average,
858 METH_VARARGS, "set_time_average(time_average_sec)"},
859 {"set_uv_filter", (PyCFunction)set_uv_filter, METH_VARARGS,
860 "set_uv_filter(uv_filter_min, uv_filter_max, units)"},
861 {NULL, NULL, 0, NULL}
862 };
863
864
865 #if PY_MAJOR_VERSION >= 3
866 static PyModuleDef moduledef = {
867 PyModuleDef_HEAD_INIT,
868 "_telescope_lib", /* m_name */
869 module_doc, /* m_doc */
870 -1, /* m_size */
871 methods /* m_methods */
872 };
873 #endif
874
875
moduleinit(void)876 static PyObject* moduleinit(void)
877 {
878 PyObject* m;
879 #if PY_MAJOR_VERSION >= 3
880 m = PyModule_Create(&moduledef);
881 #else
882 m = Py_InitModule3("_telescope_lib", methods, module_doc);
883 #endif
884 return m;
885 }
886
887 #if PY_MAJOR_VERSION >= 3
PyInit__telescope_lib(void)888 PyMODINIT_FUNC PyInit__telescope_lib(void)
889 {
890 import_array();
891 return moduleinit();
892 }
893 #else
894 /* The init function name has to match that of the compiled module
895 * with the pattern 'init<module name>'. This module is called '_telescope_lib' */
init_telescope_lib(void)896 PyMODINIT_FUNC init_telescope_lib(void)
897 {
898 import_array();
899 moduleinit();
900 return;
901 }
902 #endif
903
904