1 /*
2  * Copyright (c) 2014-2021, The OSKAR Developers.
3  * See the LICENSE file at the top-level directory of this distribution.
4  */
5 
6 #include "apps/oskar_app_settings.h"
7 #include "apps/oskar_settings_log.h"
8 #include "log/oskar_log.h"
9 #include "settings/oskar_option_parser.h"
10 #include "telescope/station/element/oskar_element.h"
11 #include "utility/oskar_dir.h"
12 #include "utility/oskar_get_error_string.h"
13 #include "utility/oskar_version_string.h"
14 
15 #include <cmath>
16 #include <cstdio>
17 #include <cstdlib>
18 #include <iomanip>
19 #include <sstream>
20 
21 using namespace oskar;
22 using std::string;
23 
24 static const char app[] = "oskar_fit_element_data";
25 
26 static string construct_element_pathname(string output_dir,
27         int port, int element_type_index, double frequency_hz);
28 
main(int argc,char ** argv)29 int main(int argc, char** argv)
30 {
31     OptionParser opt(app, oskar_version_string(), oskar_app_settings(app));
32     opt.add_settings_options();
33     opt.add_flag("-q", "Suppress printing.", false, "--quiet");
34     if (!opt.check_options(argc, argv)) return EXIT_FAILURE;
35     const char* settings = opt.get_arg(0);
36     int e = 0;
37 
38     // Load the settings file.
39     SettingsTree* s = oskar_app_settings_tree(app, settings);
40     if (!s)
41     {
42         oskar_log_error(0, "Failed to read settings file '%s'", settings);
43         return EXIT_FAILURE;
44     }
45 
46     // Get/set setting if necessary.
47     if (opt.is_set("--get"))
48     {
49         printf("%s\n", s->to_string(opt.get_arg(1), &e));
50         SettingsTree::free(s);
51         return !e ? 0 : EXIT_FAILURE;
52     }
53     else if (opt.is_set("--set"))
54     {
55         const char* key = opt.get_arg(1);
56         const char* val = opt.get_arg(2);
57         bool ok = val ? s->set_value(key, val) : s->set_default(key);
58         if (!ok) oskar_log_error(0, "Failed to set '%s'='%s'", key, val);
59         SettingsTree::free(s);
60         return ok ? 0 : EXIT_FAILURE;
61     }
62 
63     // Set log parameters.
64     int priority = opt.is_set("-q") ? OSKAR_LOG_WARNING : OSKAR_LOG_STATUS;
65     oskar_Log* log = oskar_log_create(OSKAR_LOG_MESSAGE, priority);
66 
67     // Write settings to log.
68     oskar_log_set_keep_file(log, 0);
69     oskar_settings_log(s, log);
70 
71     // Get the main settings.
72     s->begin_group("element_fit");
73     string input_cst_file = s->to_string("input_cst_file", &e);
74     string input_scalar_file = s->to_string("input_scalar_file", &e);
75     string output_dir = s->to_string("output_directory", &e);
76     string pol_type = s->to_string("pol_type", &e);
77     // string coordinate_system = s->to_string("coordinate_system", &e);
78     int element_type_index = s->to_int("element_type_index", &e);
79     double frequency_hz = s->to_double("frequency_hz", &e);
80     double average_fractional_error =
81             s->to_double("average_fractional_error", &e);
82     double average_fractional_error_factor_increase =
83             s->to_double("average_fractional_error_factor_increase", &e);
84     int ignore_below_horizon = s->to_int("ignore_data_below_horizon", &e);
85     int ignore_at_pole = s->to_int("ignore_data_at_pole", &e);
86     int port = pol_type == "X" ? 1 : pol_type == "Y" ? 2 : 0;
87 
88     // Check that the input and output files have been set.
89     if ((input_cst_file.empty() && input_scalar_file.empty()) ||
90             output_dir.empty())
91     {
92         oskar_log_error(log, "Specify input and output file names.");
93         oskar_log_free(log);
94         SettingsTree::free(s);
95         return EXIT_FAILURE;
96     }
97 
98     // Create an element model.
99     oskar_Element* element = oskar_element_create(OSKAR_DOUBLE, OSKAR_CPU, &e);
100 
101     // Load the CST text file for the correct port, if specified (X=1, Y=2).
102     if (!input_cst_file.empty())
103     {
104         oskar_log_line(log, 'M', ' ');
105         oskar_log_message(log, 'M', 0, "Loading CST element pattern: %s",
106                 input_cst_file.c_str());
107         oskar_element_load_cst(element, port, frequency_hz,
108                 input_cst_file.c_str(), average_fractional_error,
109                 average_fractional_error_factor_increase,
110                 ignore_at_pole, ignore_below_horizon, log, &e);
111 
112         // Construct the output file name based on the settings.
113         if (port == 0)
114         {
115             string output = construct_element_pathname(output_dir, 1,
116                     element_type_index, frequency_hz);
117             oskar_element_write(element, output.c_str(), 1,
118                     frequency_hz, log, &e);
119             output = construct_element_pathname(output_dir, 2,
120                     element_type_index, frequency_hz);
121             oskar_element_write(element, output.c_str(), 2,
122                     frequency_hz, log, &e);
123         }
124         else
125         {
126             string output = construct_element_pathname(output_dir, port,
127                     element_type_index, frequency_hz);
128             oskar_element_write(element, output.c_str(), port,
129                     frequency_hz, log, &e);
130         }
131     }
132 
133     // Load the scalar text file, if specified.
134     if (!input_scalar_file.empty())
135     {
136         oskar_log_message(log, 'M', 0, "Loading scalar element pattern: %s",
137                 input_scalar_file.c_str());
138         oskar_element_load_scalar(element, frequency_hz,
139                 input_scalar_file.c_str(), average_fractional_error,
140                 average_fractional_error_factor_increase,
141                 ignore_at_pole, ignore_below_horizon, log, &e);
142 
143         // Construct the output file name based on the settings.
144         string output = construct_element_pathname(output_dir, 0,
145                 element_type_index, frequency_hz);
146         oskar_element_write(element, output.c_str(), 0, frequency_hz, log, &e);
147     }
148 
149     // Check for errors.
150     if (e)
151     {
152         oskar_log_error(log, "Run failed with code %i: %s.", e,
153             oskar_get_error_string(e));
154     }
155 
156     // Free memory.
157     oskar_element_free(element, &e);
158     oskar_log_free(log);
159     SettingsTree::free(s);
160     return e ? EXIT_FAILURE : EXIT_SUCCESS;
161 }
162 
163 
construct_element_pathname(string output_dir,int port,int element_type_index,double frequency_hz)164 static string construct_element_pathname(string output_dir,
165         int port, int element_type_index, double frequency_hz)
166 {
167     std::ostringstream stream;
168     stream << "element_pattern_fit_";
169     if (port == 0)
170     {
171         stream << "scalar_";
172     }
173     else if (port == 1)
174     {
175         stream << "x_";
176     }
177     else if (port == 2)
178     {
179         stream << "y_";
180     }
181 
182     // Append the element type index.
183     stream << element_type_index << "_";
184 
185     // Append the frequency in MHz.
186     stream << std::fixed << std::setprecision(0)
187     << std::setfill('0') << std::setw(3) << frequency_hz / 1.0e6;
188 
189     // Append the file extension.
190     stream << ".bin";
191 
192     // Construct the full path.
193     char* path = oskar_dir_get_path(output_dir.c_str(), stream.str().c_str());
194     string p = string(path);
195     free(path);
196     return p;
197 }
198