1 /*
2  * Copyright (c) 2013-2021, The OSKAR Developers.
3  * See the LICENSE file at the top-level directory of this distribution.
4  */
5 
6 #include "telescope/private_telescope.h"
7 #include "telescope/oskar_telescope.h"
8 
9 #include "math/oskar_cmath.h"
10 
11 #include <ctype.h>
12 #include <string.h>
13 
14 #ifdef __cplusplus
15 extern "C" {
16 #endif
17 
18 /* Properties and metadata. */
19 
oskar_telescope_precision(const oskar_Telescope * model)20 int oskar_telescope_precision(const oskar_Telescope* model)
21 {
22     return model->precision;
23 }
24 
oskar_telescope_mem_location(const oskar_Telescope * model)25 int oskar_telescope_mem_location(const oskar_Telescope* model)
26 {
27     return model->mem_location;
28 }
29 
oskar_telescope_lon_rad(const oskar_Telescope * model)30 double oskar_telescope_lon_rad(const oskar_Telescope* model)
31 {
32     return model->lon_rad;
33 }
34 
oskar_telescope_lat_rad(const oskar_Telescope * model)35 double oskar_telescope_lat_rad(const oskar_Telescope* model)
36 {
37     return model->lat_rad;
38 }
39 
oskar_telescope_alt_metres(const oskar_Telescope * model)40 double oskar_telescope_alt_metres(const oskar_Telescope* model)
41 {
42     return model->alt_metres;
43 }
44 
oskar_telescope_polar_motion_x_rad(const oskar_Telescope * model)45 double oskar_telescope_polar_motion_x_rad(const oskar_Telescope* model)
46 {
47     return model->pm_x_rad;
48 }
49 
oskar_telescope_polar_motion_y_rad(const oskar_Telescope * model)50 double oskar_telescope_polar_motion_y_rad(const oskar_Telescope* model)
51 {
52     return model->pm_y_rad;
53 }
54 
oskar_telescope_phase_centre_coord_type(const oskar_Telescope * model)55 int oskar_telescope_phase_centre_coord_type(const oskar_Telescope* model)
56 {
57     return model->phase_centre_coord_type;
58 }
59 
oskar_telescope_phase_centre_longitude_rad(const oskar_Telescope * model)60 double oskar_telescope_phase_centre_longitude_rad(const oskar_Telescope* model)
61 {
62     return model->phase_centre_rad[0];
63 }
64 
oskar_telescope_phase_centre_latitude_rad(const oskar_Telescope * model)65 double oskar_telescope_phase_centre_latitude_rad(const oskar_Telescope* model)
66 {
67     return model->phase_centre_rad[1];
68 }
69 
oskar_telescope_channel_bandwidth_hz(const oskar_Telescope * model)70 double oskar_telescope_channel_bandwidth_hz(const oskar_Telescope* model)
71 {
72     return model->channel_bandwidth_hz;
73 }
74 
oskar_telescope_tec_screen_height_km(const oskar_Telescope * model)75 double oskar_telescope_tec_screen_height_km(const oskar_Telescope* model)
76 {
77     return model->tec_screen_height_km;
78 }
79 
oskar_telescope_tec_screen_pixel_size_m(const oskar_Telescope * model)80 double oskar_telescope_tec_screen_pixel_size_m(const oskar_Telescope* model)
81 {
82     return model->tec_screen_pixel_size_m;
83 }
84 
oskar_telescope_tec_screen_time_interval_sec(const oskar_Telescope * model)85 double oskar_telescope_tec_screen_time_interval_sec(
86         const oskar_Telescope* model)
87 {
88     return model->tec_screen_time_interval_sec;
89 }
90 
oskar_telescope_isoplanatic_screen(const oskar_Telescope * model)91 int oskar_telescope_isoplanatic_screen(const oskar_Telescope* model)
92 {
93     return model->isoplanatic_screen;
94 }
95 
oskar_telescope_time_average_sec(const oskar_Telescope * model)96 double oskar_telescope_time_average_sec(const oskar_Telescope* model)
97 {
98     return model->time_average_sec;
99 }
100 
oskar_telescope_uv_filter_min(const oskar_Telescope * model)101 double oskar_telescope_uv_filter_min(const oskar_Telescope* model)
102 {
103     return model->uv_filter_min;
104 }
105 
oskar_telescope_uv_filter_max(const oskar_Telescope * model)106 double oskar_telescope_uv_filter_max(const oskar_Telescope* model)
107 {
108     return model->uv_filter_max;
109 }
110 
oskar_telescope_uv_filter_units(const oskar_Telescope * model)111 int oskar_telescope_uv_filter_units(const oskar_Telescope* model)
112 {
113     return model->uv_filter_units;
114 }
115 
oskar_telescope_pol_mode(const oskar_Telescope * model)116 int oskar_telescope_pol_mode(const oskar_Telescope* model)
117 {
118     return model->pol_mode;
119 }
120 
oskar_telescope_num_baselines(const oskar_Telescope * model)121 int oskar_telescope_num_baselines(const oskar_Telescope* model)
122 {
123     return ((model->num_stations * (model->num_stations - 1)) / 2);
124 }
125 
oskar_telescope_num_stations(const oskar_Telescope * model)126 int oskar_telescope_num_stations(const oskar_Telescope* model)
127 {
128     return model->num_stations;
129 }
130 
oskar_telescope_num_station_models(const oskar_Telescope * model)131 int oskar_telescope_num_station_models(const oskar_Telescope* model)
132 {
133     return model->num_station_models;
134 }
135 
oskar_telescope_allow_station_beam_duplication(const oskar_Telescope * model)136 int oskar_telescope_allow_station_beam_duplication(
137         const oskar_Telescope* model)
138 {
139     return model->allow_station_beam_duplication;
140 }
141 
oskar_telescope_ionosphere_screen_type(const oskar_Telescope * model)142 char oskar_telescope_ionosphere_screen_type(const oskar_Telescope* model)
143 {
144     return (char) (model->ionosphere_screen_type);
145 }
146 
oskar_telescope_enable_numerical_patterns(const oskar_Telescope * model)147 int oskar_telescope_enable_numerical_patterns(const oskar_Telescope* model)
148 {
149     return model->enable_numerical_patterns;
150 }
151 
oskar_telescope_max_station_size(const oskar_Telescope * model)152 int oskar_telescope_max_station_size(const oskar_Telescope* model)
153 {
154     return model->max_station_size;
155 }
156 
oskar_telescope_max_station_depth(const oskar_Telescope * model)157 int oskar_telescope_max_station_depth(const oskar_Telescope* model)
158 {
159     return model->max_station_depth;
160 }
161 
162 
163 /* Station models. */
164 
oskar_telescope_station(oskar_Telescope * model,int i)165 oskar_Station* oskar_telescope_station(oskar_Telescope* model, int i)
166 {
167     if (i >= model->num_station_models) return 0;
168     return model->station[i];
169 }
170 
oskar_telescope_station_const(const oskar_Telescope * model,int i)171 const oskar_Station* oskar_telescope_station_const(
172         const oskar_Telescope* model, int i)
173 {
174     if (i >= model->num_station_models) return 0;
175     return model->station[i];
176 }
177 
178 
179 /* Arrays. */
180 
oskar_telescope_station_type_map(oskar_Telescope * model)181 oskar_Mem* oskar_telescope_station_type_map(oskar_Telescope* model)
182 {
183     return model->station_type_map;
184 }
185 
oskar_telescope_station_type_map_const(const oskar_Telescope * model)186 const oskar_Mem* oskar_telescope_station_type_map_const(
187         const oskar_Telescope* model)
188 {
189     return model->station_type_map;
190 }
191 
oskar_telescope_station_measured_offset_ecef_metres(oskar_Telescope * model,int dim)192 oskar_Mem* oskar_telescope_station_measured_offset_ecef_metres(
193         oskar_Telescope* model, int dim)
194 {
195     return model->station_measured_offset_ecef_metres[dim];
196 }
197 
oskar_telescope_station_measured_offset_ecef_metres_const(const oskar_Telescope * model,int dim)198 const oskar_Mem* oskar_telescope_station_measured_offset_ecef_metres_const(
199         const oskar_Telescope* model, int dim)
200 {
201     return model->station_measured_offset_ecef_metres[dim];
202 }
203 
oskar_telescope_station_measured_enu_metres(oskar_Telescope * model,int dim)204 oskar_Mem* oskar_telescope_station_measured_enu_metres(
205         oskar_Telescope* model, int dim)
206 {
207     return model->station_measured_enu_metres[dim];
208 }
209 
oskar_telescope_station_measured_enu_metres_const(const oskar_Telescope * model,int dim)210 const oskar_Mem* oskar_telescope_station_measured_enu_metres_const(
211         const oskar_Telescope* model, int dim)
212 {
213     return model->station_measured_enu_metres[dim];
214 }
215 
oskar_telescope_station_true_offset_ecef_metres(oskar_Telescope * model,int dim)216 oskar_Mem* oskar_telescope_station_true_offset_ecef_metres(
217         oskar_Telescope* model, int dim)
218 {
219     return model->station_true_offset_ecef_metres[dim];
220 }
221 
oskar_telescope_station_true_offset_ecef_metres_const(const oskar_Telescope * model,int dim)222 const oskar_Mem* oskar_telescope_station_true_offset_ecef_metres_const(
223         const oskar_Telescope* model, int dim)
224 {
225     return model->station_true_offset_ecef_metres[dim];
226 }
227 
oskar_telescope_station_true_enu_metres(oskar_Telescope * model,int dim)228 oskar_Mem* oskar_telescope_station_true_enu_metres(
229         oskar_Telescope* model, int dim)
230 {
231     return model->station_true_enu_metres[dim];
232 }
233 
oskar_telescope_station_true_enu_metres_const(const oskar_Telescope * model,int dim)234 const oskar_Mem* oskar_telescope_station_true_enu_metres_const(
235         const oskar_Telescope* model, int dim)
236 {
237     return model->station_true_enu_metres[dim];
238 }
239 
oskar_telescope_noise_enabled(const oskar_Telescope * model)240 int oskar_telescope_noise_enabled(const oskar_Telescope* model)
241 {
242     return model->noise_enabled;
243 }
244 
oskar_telescope_noise_seed(const oskar_Telescope * model)245 unsigned int oskar_telescope_noise_seed(const oskar_Telescope* model)
246 {
247     return model->noise_seed;
248 }
249 
oskar_telescope_tec_screen_path(const oskar_Telescope * model)250 const char* oskar_telescope_tec_screen_path(const oskar_Telescope* model)
251 {
252     return oskar_mem_char_const(model->tec_screen_path);
253 }
254 
oskar_telescope_gains(oskar_Telescope * model)255 oskar_Gains* oskar_telescope_gains(oskar_Telescope* model)
256 {
257     return model->gains;
258 }
259 
oskar_telescope_gains_const(const oskar_Telescope * model)260 const oskar_Gains* oskar_telescope_gains_const(const oskar_Telescope* model)
261 {
262     return model->gains;
263 }
264 
265 
266 /* Setters. */
267 
oskar_telescope_set_allow_station_beam_duplication(oskar_Telescope * model,int value)268 void oskar_telescope_set_allow_station_beam_duplication(oskar_Telescope* model,
269         int value)
270 {
271     model->allow_station_beam_duplication = value;
272 }
273 
oskar_telescope_set_ionosphere_screen_type(oskar_Telescope * model,const char * type)274 void oskar_telescope_set_ionosphere_screen_type(oskar_Telescope* model,
275         const char* type)
276 {
277     model->ionosphere_screen_type = toupper(type[0]);
278 }
279 
oskar_telescope_set_isoplanatic_screen(oskar_Telescope * model,int flag)280 void oskar_telescope_set_isoplanatic_screen(oskar_Telescope* model, int flag)
281 {
282     model->isoplanatic_screen = flag;
283 }
284 
oskar_telescope_set_enable_noise(oskar_Telescope * model,int value,unsigned int seed)285 void oskar_telescope_set_enable_noise(oskar_Telescope* model,
286         int value, unsigned int seed)
287 {
288     model->noise_enabled = value;
289     model->noise_seed = seed;
290 }
291 
oskar_telescope_set_enable_numerical_patterns(oskar_Telescope * model,int value)292 void oskar_telescope_set_enable_numerical_patterns(oskar_Telescope* model,
293         int value)
294 {
295     model->enable_numerical_patterns = value;
296 }
297 
oskar_telescope_set_gaussian_station_beam_p(oskar_Station * station,double fwhm_rad,double ref_freq_hz)298 static void oskar_telescope_set_gaussian_station_beam_p(oskar_Station* station,
299         double fwhm_rad, double ref_freq_hz)
300 {
301     oskar_station_set_gaussian_beam_values(station, fwhm_rad, ref_freq_hz);
302     if (oskar_station_has_child(station))
303     {
304         int i = 0;
305         const int num_elements = oskar_station_num_elements(station);
306         for (i = 0; i < num_elements; ++i)
307         {
308             oskar_telescope_set_gaussian_station_beam_p(
309                     oskar_station_child(station, i), fwhm_rad, ref_freq_hz);
310         }
311     }
312 }
313 
oskar_telescope_set_gaussian_station_beam_width(oskar_Telescope * model,double fwhm_deg,double ref_freq_hz)314 void oskar_telescope_set_gaussian_station_beam_width(oskar_Telescope* model,
315         double fwhm_deg, double ref_freq_hz)
316 {
317     int i = 0;
318     for (i = 0; i < model->num_station_models; ++i)
319     {
320         oskar_telescope_set_gaussian_station_beam_p(model->station[i],
321                 fwhm_deg * M_PI / 180.0, ref_freq_hz);
322     }
323 }
324 
oskar_telescope_set_noise_freq_file(oskar_Telescope * model,const char * filename,int * status)325 void oskar_telescope_set_noise_freq_file(oskar_Telescope* model,
326         const char* filename, int* status)
327 {
328     int i = 0;
329     if (*status) return;
330     for (i = 0; i < model->num_station_models; ++i)
331     {
332         if (!model->station[i]) continue;
333         oskar_mem_load_ascii(filename, 1, status,
334                 oskar_station_noise_freq_hz(model->station[i]), "");
335     }
336 }
337 
oskar_telescope_set_noise_freq(oskar_Telescope * model,double start_hz,double inc_hz,int num_channels,int * status)338 void oskar_telescope_set_noise_freq(oskar_Telescope* model,
339         double start_hz, double inc_hz, int num_channels, int* status)
340 {
341     int i = 0;
342     oskar_Mem* noise_freq_hz = 0;
343     noise_freq_hz = oskar_mem_create(model->precision, OSKAR_CPU,
344             num_channels, status);
345     if (*status) return;
346     if (model->precision == OSKAR_DOUBLE)
347     {
348         double* f = oskar_mem_double(noise_freq_hz, status);
349         for (i = 0; i < num_channels; ++i) f[i] = start_hz + i * inc_hz;
350     }
351     else
352     {
353         float* f = oskar_mem_float(noise_freq_hz, status);
354         for (i = 0; i < num_channels; ++i) f[i] = start_hz + i * inc_hz;
355     }
356 
357     /* Set noise frequency for all top-level stations. */
358     for (i = 0; i < model->num_station_models; ++i)
359     {
360         oskar_Mem* t = 0;
361         if (!model->station[i]) continue;
362         t = oskar_station_noise_freq_hz(model->station[i]);
363         oskar_mem_realloc(t, num_channels, status);
364         oskar_mem_copy(t, noise_freq_hz, status);
365     }
366     oskar_mem_free(noise_freq_hz, status);
367 }
368 
oskar_telescope_set_noise_rms_file(oskar_Telescope * model,const char * filename,int * status)369 void oskar_telescope_set_noise_rms_file(oskar_Telescope* model,
370         const char* filename, int* status)
371 {
372     int i = 0;
373     if (*status) return;
374     for (i = 0; i < model->num_station_models; ++i)
375     {
376         if (!model->station[i]) continue;
377         oskar_mem_load_ascii(filename, 1, status,
378                 oskar_station_noise_rms_jy(model->station[i]), "");
379     }
380 }
381 
oskar_telescope_set_noise_rms(oskar_Telescope * model,double start,double end,int * status)382 void oskar_telescope_set_noise_rms(oskar_Telescope* model,
383         double start, double end, int* status)
384 {
385     int i = 0, j = 0, num_channels = 0;
386     double inc = 0.0;
387     oskar_Station* s = 0;
388     oskar_Mem *noise_rms_jy = 0, *h = 0;
389 
390     /* Set noise RMS for all top-level stations. */
391     if (*status) return;
392     for (i = 0; i < model->num_station_models; ++i)
393     {
394         s = model->station[i];
395         if (!s) continue;
396         h = oskar_station_noise_rms_jy(s);
397         num_channels = (int)oskar_mem_length(oskar_station_noise_freq_hz(s));
398         if (num_channels == 0)
399         {
400             *status = OSKAR_ERR_OUT_OF_RANGE;
401             return;
402         }
403         oskar_mem_realloc(h, num_channels, status);
404         noise_rms_jy = oskar_mem_create(model->precision, OSKAR_CPU,
405                 num_channels, status);
406         inc = (end - start) / (double)num_channels;
407         if (model->precision == OSKAR_DOUBLE)
408         {
409             double* r = oskar_mem_double(noise_rms_jy, status);
410             for (j = 0; j < num_channels; ++j) r[j] = start + j * inc;
411         }
412         else
413         {
414             float* r = oskar_mem_float(noise_rms_jy, status);
415             for (j = 0; j < num_channels; ++j) r[j] = start + j * inc;
416         }
417         oskar_mem_copy(h, noise_rms_jy, status);
418         oskar_mem_free(noise_rms_jy, status);
419     }
420 }
421 
oskar_telescope_set_position(oskar_Telescope * model,double longitude_rad,double latitude_rad,double altitude_metres)422 void oskar_telescope_set_position(oskar_Telescope* model,
423         double longitude_rad, double latitude_rad, double altitude_metres)
424 {
425     model->lon_rad = longitude_rad;
426     model->lat_rad = latitude_rad;
427     model->alt_metres = altitude_metres;
428 }
429 
oskar_telescope_set_polar_motion(oskar_Telescope * model,double pm_x_rad,double pm_y_rad)430 void oskar_telescope_set_polar_motion(oskar_Telescope* model,
431         double pm_x_rad, double pm_y_rad)
432 {
433     int i = 0;
434     model->pm_x_rad = pm_x_rad;
435     model->pm_y_rad = pm_y_rad;
436 
437     /* Set for all stations, too. */
438     for (i = 0; i < model->num_station_models; ++i)
439     {
440         oskar_station_set_polar_motion(model->station[i], pm_x_rad, pm_y_rad);
441     }
442 }
443 
oskar_telescope_set_station_phase_centre(oskar_Station * station,int coord_type,double longitude_rad,double latitude_rad)444 static void oskar_telescope_set_station_phase_centre(oskar_Station* station,
445         int coord_type, double longitude_rad, double latitude_rad)
446 {
447     oskar_station_set_phase_centre(station, coord_type, longitude_rad,
448             latitude_rad);
449     if (oskar_station_has_child(station))
450     {
451         int i = 0, num_elements = 0;
452         num_elements = oskar_station_num_elements(station);
453         for (i = 0; i < num_elements; ++i)
454         {
455             oskar_telescope_set_station_phase_centre(
456                     oskar_station_child(station, i),
457                     coord_type, longitude_rad, latitude_rad);
458         }
459     }
460 }
461 
oskar_telescope_set_phase_centre(oskar_Telescope * model,int coord_type,double longitude_rad,double latitude_rad)462 void oskar_telescope_set_phase_centre(oskar_Telescope* model,
463         int coord_type, double longitude_rad, double latitude_rad)
464 {
465     int i = 0;
466     model->phase_centre_coord_type = coord_type;
467     model->phase_centre_rad[0] = longitude_rad;
468     model->phase_centre_rad[1] = latitude_rad;
469     for (i = 0; i < model->num_station_models; ++i)
470     {
471         oskar_telescope_set_station_phase_centre(model->station[i],
472                 coord_type, longitude_rad, latitude_rad);
473     }
474 }
475 
oskar_telescope_set_tec_screen_height(oskar_Telescope * model,double height_km)476 void oskar_telescope_set_tec_screen_height(oskar_Telescope* model,
477         double height_km)
478 {
479     model->tec_screen_height_km = height_km;
480 }
481 
oskar_telescope_set_tec_screen_pixel_size(oskar_Telescope * model,double pixel_size_m)482 void oskar_telescope_set_tec_screen_pixel_size(oskar_Telescope* model,
483         double pixel_size_m)
484 {
485     model->tec_screen_pixel_size_m = pixel_size_m;
486 }
487 
oskar_telescope_set_tec_screen_time_interval(oskar_Telescope * model,double time_interval_sec)488 void oskar_telescope_set_tec_screen_time_interval(oskar_Telescope* model,
489         double time_interval_sec)
490 {
491     model->tec_screen_time_interval_sec = time_interval_sec;
492 }
493 
oskar_telescope_set_tec_screen_path(oskar_Telescope * model,const char * path)494 void oskar_telescope_set_tec_screen_path(oskar_Telescope* model,
495         const char* path)
496 {
497     int status = 0;
498     const size_t len = 1 + strlen(path);
499     oskar_mem_realloc(model->tec_screen_path, len, &status);
500     memcpy(oskar_mem_void(model->tec_screen_path), path, len);
501 }
502 
oskar_telescope_set_channel_bandwidth(oskar_Telescope * model,double bandwidth_hz)503 void oskar_telescope_set_channel_bandwidth(oskar_Telescope* model,
504         double bandwidth_hz)
505 {
506     model->channel_bandwidth_hz = bandwidth_hz;
507 }
508 
oskar_telescope_set_time_average(oskar_Telescope * model,double time_average_sec)509 void oskar_telescope_set_time_average(oskar_Telescope* model,
510         double time_average_sec)
511 {
512     model->time_average_sec = time_average_sec;
513 }
514 
oskar_telescope_set_station_type_p(oskar_Station * station,int type)515 static void oskar_telescope_set_station_type_p(oskar_Station* station, int type)
516 {
517     oskar_station_set_station_type(station, type);
518     if (oskar_station_has_child(station))
519     {
520         int i = 0, num_elements = 0;
521         num_elements = oskar_station_num_elements(station);
522         for (i = 0; i < num_elements; ++i)
523         {
524             oskar_telescope_set_station_type_p(
525                     oskar_station_child(station, i), type);
526         }
527     }
528 }
529 
oskar_telescope_set_station_type(oskar_Telescope * model,const char * type,int * status)530 void oskar_telescope_set_station_type(oskar_Telescope* model, const char* type,
531         int* status)
532 {
533     int i = 0, t = 0;
534     if (*status) return;
535     if (!strncmp(type, "A", 1) || !strncmp(type, "a", 1))
536     {
537         t = OSKAR_STATION_TYPE_AA;
538     }
539     else if (!strncmp(type, "G", 1) || !strncmp(type, "g", 1))
540     {
541         t = OSKAR_STATION_TYPE_GAUSSIAN_BEAM;
542     }
543     else if (!strncmp(type, "I", 1) || !strncmp(type, "i", 1))
544     {
545         t = OSKAR_STATION_TYPE_ISOTROPIC;
546     }
547     else if (!strncmp(type, "V", 1) || !strncmp(type, "v", 1))
548     {
549         t = OSKAR_STATION_TYPE_VLA_PBCOR;
550     }
551     else
552     {
553         *status = OSKAR_ERR_INVALID_ARGUMENT;
554         return;
555     }
556     for (i = 0; i < model->num_station_models; ++i)
557     {
558         oskar_telescope_set_station_type_p(model->station[i], t);
559     }
560 }
561 
oskar_telescope_set_unique_stations(oskar_Telescope * model,int value,int * status)562 void oskar_telescope_set_unique_stations(oskar_Telescope* model,
563         int value, int* status)
564 {
565     if (value)
566     {
567         int i = 0;
568         int* type_map = oskar_mem_int(model->station_type_map, status);
569         for (i = 0; i < model->num_stations; ++i) type_map[i] = i;
570     }
571     else
572     {
573         oskar_mem_clear_contents(model->station_type_map, status);
574     }
575 }
576 
oskar_telescope_set_uv_filter(oskar_Telescope * model,double uv_filter_min,double uv_filter_max,const char * units,int * status)577 void oskar_telescope_set_uv_filter(oskar_Telescope* model,
578         double uv_filter_min, double uv_filter_max, const char* units,
579         int* status)
580 {
581     if (!strncmp(units, "M", 1) || !strncmp(units, "m", 1))
582     {
583         model->uv_filter_units = OSKAR_METRES;
584     }
585     else if (!strncmp(units, "W",  1) || !strncmp(units, "w",  1))
586     {
587         model->uv_filter_units = OSKAR_WAVELENGTHS;
588     }
589     else
590     {
591         *status = OSKAR_ERR_INVALID_ARGUMENT;
592         return;
593     }
594     model->uv_filter_min = uv_filter_min;
595     model->uv_filter_max = uv_filter_max;
596 }
597 
oskar_telescope_set_pol_mode(oskar_Telescope * model,const char * mode,int * status)598 void oskar_telescope_set_pol_mode(oskar_Telescope* model, const char* mode,
599         int* status)
600 {
601     if (*status) return;
602     if (!strncmp(mode, "S", 1) || !strncmp(mode, "s", 1))
603     {
604         model->pol_mode = OSKAR_POL_MODE_SCALAR;
605     }
606     else if (!strncmp(mode, "F",  1) || !strncmp(mode, "f",  1))
607     {
608         model->pol_mode = OSKAR_POL_MODE_FULL;
609     }
610     else
611     {
612         *status = OSKAR_ERR_INVALID_ARGUMENT;
613     }
614 }
615 
616 #ifdef __cplusplus
617 }
618 #endif
619