1 /*
2 * Copyright (c) 2012-2021, The OSKAR Developers.
3 * See the LICENSE file at the top-level directory of this distribution.
4 */
5
6 #include "log/oskar_log.h"
7 #include "settings/oskar_option_parser.h"
8 #include "utility/oskar_get_error_string.h"
9 #include "utility/oskar_version_string.h"
10 #include "vis/oskar_vis_block.h"
11 #include "vis/oskar_vis_header.h"
12
13 #include <cfloat>
14 #include <cmath>
15 #include <cstdio>
16 #include <cstdlib>
17
18 using namespace std;
19
20 static bool is_compatible(
21 const oskar_VisHeader* vis1, const oskar_VisHeader* vis2);
22
main(int argc,char ** argv)23 int main(int argc, char** argv)
24 {
25 int status = 0;
26
27 oskar::OptionParser opt("oskar_vis_add", oskar_version_string());
28 opt.set_description("Application to combine OSKAR visibility files.");
29 opt.add_required("OSKAR visibility files...");
30 opt.add_flag("-o", "Output visibility file name", 1, "out.vis", false, "--output");
31 opt.add_flag("-q", "Disable log messages", false, "--quiet");
32 opt.add_example("oskar_vis_add file1.vis file2.vis");
33 opt.add_example("oskar_vis_add file1.vis file2.vis -o combined.vis");
34 opt.add_example("oskar_vis_add -q file1.vis file2.vis file3.vis");
35 opt.add_example("oskar_vis_add *.vis");
36 if (!opt.check_options(argc, argv)) return EXIT_FAILURE;
37
38 // Get the options.
39 int num_in_files = 0;
40 const char* const* in_files = opt.get_input_files(2, &num_in_files);
41 const char* out_path = opt.get_string("-o");
42 const bool verbose = opt.is_set("-q") ? false : true;
43 if (num_in_files < 2)
44 {
45 opt.error("Please provide 2 or more visibility files to combine.");
46 return EXIT_FAILURE;
47 }
48
49 // Print if verbose.
50 if (verbose)
51 {
52 printf("Output visibility file: %s\n", out_path);
53 printf("Combining the %d input files:\n", num_in_files);
54 for (int i = 0; i < num_in_files; ++i)
55 {
56 printf(" [%02d] %s\n", i, in_files[i]);
57 }
58 }
59
60 // Read all the visibility headers and check consistency.
61 oskar_Binary **files = 0, *out_file = 0;
62 oskar_VisHeader** headers = 0;
63 oskar_VisBlock *block0 = 0, *block1 = 0;
64 files = (oskar_Binary**) calloc(num_in_files, sizeof(oskar_Binary*));
65 headers = (oskar_VisHeader**) calloc(num_in_files, sizeof(oskar_VisHeader*));
66 for (int i = 0; i < num_in_files; ++i)
67 {
68 files[i] = oskar_binary_create(in_files[i], 'r', &status);
69 headers[i] = oskar_vis_header_read(files[i], &status);
70 if (status)
71 {
72 oskar_log_error(0,
73 "Failed to read visibility data file '%s'", in_files[i]);
74 break;
75 }
76 if (i > 0 && !is_compatible(headers[0], headers[i]))
77 {
78 status = OSKAR_ERR_TYPE_MISMATCH;
79 oskar_log_error(0,
80 "Input visibility file '%s' does not have "
81 "the same dimensions", in_files[i]);
82 break;
83 }
84 }
85
86 // Write the output file using the first header.
87 if (!status)
88 {
89 block0 = oskar_vis_block_create_from_header(
90 OSKAR_CPU, headers[0], &status);
91 block1 = oskar_vis_block_create_from_header(
92 OSKAR_CPU, headers[0], &status);
93 oskar_mem_clear_contents(oskar_vis_header_settings(
94 headers[0]), &status);
95 oskar_mem_clear_contents(oskar_vis_header_telescope_path(
96 headers[0]), &status);
97 out_file = oskar_vis_header_write(headers[0], out_path, &status);
98 if (status)
99 {
100 oskar_log_error(0,
101 "Failed to write output visibility data file '%s'",
102 out_path);
103 }
104 }
105
106 // Loop over each block in each file.
107 const int num_blocks = oskar_vis_header_num_blocks(headers[0]);
108 for (int b = 0; (b < num_blocks) && !status; ++b)
109 {
110 // Read reference block.
111 oskar_vis_block_read(block0, headers[0], files[0], b, &status);
112
113 // Read blocks from other files and combine them.
114 for (int i = 1; (i < num_in_files) && !status; ++i)
115 {
116 oskar_vis_block_read(block1, headers[i], files[i], b, &status);
117 if (status)
118 {
119 oskar_log_error(0, "Failed to read visibility block in '%s'",
120 in_files[i]);
121 break;
122 }
123 oskar_Mem* b0 = oskar_vis_block_cross_correlations(block0);
124 const oskar_Mem* b1 =
125 oskar_vis_block_cross_correlations_const(block1);
126 oskar_mem_add(b0, b0, b1, 0, 0, 0, oskar_mem_length(b0), &status);
127 }
128
129 // Write combined block.
130 oskar_vis_block_write(block0, out_file, b, &status);
131 }
132
133 // Free memory and close files.
134 oskar_vis_block_free(block0, &status);
135 oskar_vis_block_free(block1, &status);
136 for (int i = 0; i < num_in_files; ++i)
137 {
138 oskar_vis_header_free(headers[i], &status);
139 oskar_binary_free(files[i]);
140 }
141 oskar_binary_free(out_file);
142 free(files);
143 free(headers);
144
145 return status ? EXIT_FAILURE : EXIT_SUCCESS;
146 }
147
is_compatible(const oskar_VisHeader * v1,const oskar_VisHeader * v2)148 static bool is_compatible(const oskar_VisHeader* v1, const oskar_VisHeader* v2)
149 {
150 if (oskar_vis_header_num_channels_total(v1) !=
151 oskar_vis_header_num_channels_total(v2))
152 {
153 return false;
154 }
155 if (oskar_vis_header_max_channels_per_block(v1) !=
156 oskar_vis_header_max_channels_per_block(v2))
157 {
158 return false;
159 }
160 if (oskar_vis_header_num_times_total(v1) !=
161 oskar_vis_header_num_times_total(v2))
162 {
163 return false;
164 }
165 if (oskar_vis_header_max_times_per_block(v1) !=
166 oskar_vis_header_max_times_per_block(v2))
167 {
168 return false;
169 }
170 if (oskar_vis_header_num_stations(v1) !=
171 oskar_vis_header_num_stations(v2))
172 {
173 return false;
174 }
175 if (fabs(oskar_vis_header_freq_start_hz(v1) -
176 oskar_vis_header_freq_start_hz(v2)) > DBL_EPSILON)
177 {
178 return false;
179 }
180 if (fabs(oskar_vis_header_freq_inc_hz(v1) -
181 oskar_vis_header_freq_inc_hz(v2)) > DBL_EPSILON)
182 {
183 return false;
184 }
185 if (oskar_vis_header_amp_type(v1) != oskar_vis_header_amp_type(v2))
186 {
187 return false;
188 }
189 if (oskar_vis_header_pol_type(v1) != oskar_vis_header_pol_type(v2))
190 {
191 return false;
192 }
193
194 return true;
195 }
196