INSTINCT Code Coverage Report


Directory: src/
File: Navigation/Atmosphere/Troposphere/Troposphere.cpp
Date: 2025-02-07 16:54:41
Exec Total Coverage
Lines: 105 345 30.4%
Functions: 6 13 46.2%
Branches: 112 528 21.2%

Line Branch Exec Source
1 // This file is part of INSTINCT, the INS Toolkit for Integrated
2 // Navigation Concepts and Training by the Institute of Navigation of
3 // the University of Stuttgart, Germany.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9 #include "Troposphere.hpp"
10
11 #include "internal/gui/widgets/EnumCombo.hpp"
12 #include "internal/gui/NodeEditorApplication.hpp"
13 #include "util/Logger.hpp"
14
15 #include "Models/Saastamoinen.hpp"
16 #include "Models/GPT.hpp"
17
18 #include "MappingFunctions/Cosecant.hpp"
19 #include "MappingFunctions/GMF.hpp"
20 #include "MappingFunctions/NiellMappingFunction.hpp"
21 #include "Navigation/Transformations/Units.hpp"
22
23 namespace NAV
24 {
25
26 const char* to_string(TroposphereModel troposphereZhdModel)
27 {
28 switch (troposphereZhdModel)
29 {
30 case TroposphereModel::None:
31 return "None";
32 case TroposphereModel::Saastamoinen:
33 return "Saastamoinen";
34 case TroposphereModel::GPT2:
35 return "GPT2";
36 case TroposphereModel::GPT3:
37 return "GPT3";
38 case TroposphereModel::COUNT:
39 break;
40 }
41 return "";
42 }
43
44 const char* to_string(MappingFunction mappingFunction)
45 {
46 switch (mappingFunction)
47 {
48 case MappingFunction::None:
49 return "None";
50 case MappingFunction::Cosecant:
51 return "Cosecant(elevation)";
52 case MappingFunction::GMF:
53 return "GMF";
54 case MappingFunction::NMF:
55 return "NMF";
56 case MappingFunction::VMF_GPT2:
57 return "VMF(GPT2)";
58 case MappingFunction::VMF_GPT3:
59 return "VMF(GPT3)";
60 case MappingFunction::COUNT:
61 break;
62 }
63 return "";
64 }
65
66 namespace
67 {
68
69 AtmosphereModels MappingFunctionDefaults(MappingFunction mappingFunction)
70 {
71 switch (mappingFunction)
72 {
73 case MappingFunction::Cosecant:
74 return { .pressureModel = PressureModel::ISA,
75 .temperatureModel = TemperatureModel::ISA,
76 .waterVaporModel = WaterVaporModel::ISA };
77 case MappingFunction::GMF:
78 return { .pressureModel = PressureModel::ISA,
79 .temperatureModel = TemperatureModel::ISA,
80 .waterVaporModel = WaterVaporModel::ISA };
81 case MappingFunction::NMF:
82 return { .pressureModel = PressureModel::ISA,
83 .temperatureModel = TemperatureModel::ISA,
84 .waterVaporModel = WaterVaporModel::ISA };
85 case MappingFunction::VMF_GPT2:
86 return { .pressureModel = PressureModel::GPT2,
87 .temperatureModel = TemperatureModel::GPT2,
88 .waterVaporModel = WaterVaporModel::GPT2 };
89 case MappingFunction::VMF_GPT3:
90 return { .pressureModel = PressureModel::GPT3,
91 .temperatureModel = TemperatureModel::GPT3,
92 .waterVaporModel = WaterVaporModel::GPT3 };
93 case MappingFunction::None:
94 case MappingFunction::COUNT:
95 break;
96 }
97 return { .pressureModel = PressureModel::None,
98 .temperatureModel = TemperatureModel::None,
99 .waterVaporModel = WaterVaporModel::None };
100 }
101
102 /// @brief Returns the default atmosphere model, mapping function and mapping function atmosphere model for the given troposphere model
103 /// @param troposphereModel Troposphere model to give the defaults for
104 /// @return Tuple of <atmosphere model, mapping function, mapping function atmosphere model>
105 std::tuple<AtmosphereModels, MappingFunction, AtmosphereModels> ModelDefaults(TroposphereModel troposphereModel)
106 {
107 switch (troposphereModel)
108 {
109 case TroposphereModel::Saastamoinen:
110 return { AtmosphereModels{ .pressureModel = PressureModel::ISA,
111 .temperatureModel = TemperatureModel::ISA,
112 .waterVaporModel = WaterVaporModel::ISA },
113 MappingFunction::GMF,
114 MappingFunctionDefaults(MappingFunction::GMF) };
115 case TroposphereModel::GPT2:
116 return { AtmosphereModels{ .pressureModel = PressureModel::GPT2,
117 .temperatureModel = TemperatureModel::GPT2,
118 .waterVaporModel = WaterVaporModel::GPT2 },
119 MappingFunction::VMF_GPT2,
120 MappingFunctionDefaults(MappingFunction::VMF_GPT2) };
121 case TroposphereModel::GPT3:
122 return { AtmosphereModels{ .pressureModel = PressureModel::GPT3,
123 .temperatureModel = TemperatureModel::GPT3,
124 .waterVaporModel = WaterVaporModel::GPT3 },
125 MappingFunction::VMF_GPT3,
126 MappingFunctionDefaults(MappingFunction::VMF_GPT3) };
127 case TroposphereModel::None:
128 case TroposphereModel::COUNT:
129 break;
130 }
131
132 return { AtmosphereModels{ .pressureModel = PressureModel::None,
133 .temperatureModel = TemperatureModel::None,
134 .waterVaporModel = WaterVaporModel::None },
135 MappingFunction::None,
136 MappingFunctionDefaults(MappingFunction::None) };
137 }
138
139 } // namespace
140
141 bool ComboTroposphereModel(const char* label, TroposphereModelSelection& troposphereModelSelection, float width)
142 {
143 bool changed = false;
144
145 const float BUTTON_WIDTH = 25.0F * gui::NodeEditorApplication::windowFontRatio();
146
147 std::string mapFuncPreview;
148 if (troposphereModelSelection.zwdMappingFunction.first != std::get<1>(ModelDefaults(troposphereModelSelection.zwdModel.first))
149 || troposphereModelSelection.zhdMappingFunction.first != std::get<1>(ModelDefaults(troposphereModelSelection.zhdModel.first)))
150 {
151 mapFuncPreview = fmt::format(" + {}", troposphereModelSelection.zhdMappingFunction.first);
152
153 if (troposphereModelSelection.zhdMappingFunction.first != troposphereModelSelection.zwdMappingFunction.first)
154 {
155 mapFuncPreview += fmt::format(" | {}", troposphereModelSelection.zwdMappingFunction.first);
156 }
157 }
158
159 ImGui::SetNextItemWidth(width - BUTTON_WIDTH - 2 * ImGui::GetStyle().ItemInnerSpacing.x);
160 if (gui::widgets::EnumCombo(fmt::format("##{}", label).c_str(),
161 troposphereModelSelection.zhdModel.first,
162 troposphereModelSelection.zwdModel.first,
163 mapFuncPreview.c_str()))
164 {
165 std::tie(troposphereModelSelection.zhdModel.second,
166 troposphereModelSelection.zhdMappingFunction.first,
167 troposphereModelSelection.zhdMappingFunction.second) = ModelDefaults(troposphereModelSelection.zhdModel.first);
168 std::tie(troposphereModelSelection.zwdModel.second,
169 troposphereModelSelection.zwdMappingFunction.first,
170 troposphereModelSelection.zwdMappingFunction.second) = ModelDefaults(troposphereModelSelection.zwdModel.first);
171 changed = true;
172 }
173 ImGui::SameLine();
174 if (ImGui::Button(fmt::format("...##{}", label).c_str(), ImVec2(BUTTON_WIDTH, 0)))
175 {
176 ImGui::OpenPopup(fmt::format("{} Popup", label).c_str());
177 }
178 if (ImGui::BeginPopup(fmt::format("{} Popup", label).c_str()))
179 {
180 const float ATMOSPHERE_COMBO_WIDTH = 95.0F * gui::NodeEditorApplication::windowFontRatio();
181 if (ImGui::BeginTable(fmt::format("{} Table", label).c_str(), 5))
182 {
183 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
184 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
185 ImGui::TableSetupColumn("Pressure", ImGuiTableColumnFlags_WidthFixed);
186 ImGui::TableSetupColumn("Temperature", ImGuiTableColumnFlags_WidthFixed);
187 ImGui::TableSetupColumn("Water vapor", ImGuiTableColumnFlags_WidthFixed);
188 ImGui::TableHeadersRow();
189
190 ImGui::TableNextColumn();
191 ImGui::TextUnformatted("ZHD model");
192 ImGui::TableNextColumn();
193 ImGui::SetNextItemWidth(width);
194 if (gui::widgets::EnumCombo(fmt::format("##{} ZHD - Combo", label).c_str(), troposphereModelSelection.zhdModel.first))
195 {
196 std::tie(troposphereModelSelection.zhdModel.second,
197 troposphereModelSelection.zhdMappingFunction.first,
198 troposphereModelSelection.zhdMappingFunction.second) = ModelDefaults(troposphereModelSelection.zhdModel.first);
199 changed = true;
200 }
201 if (troposphereModelSelection.zhdModel.first == TroposphereModel::None) { ImGui::BeginDisabled(); }
202 ImGui::TableNextColumn();
203 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
204 changed |= ComboPressureModel(fmt::format("##{} ZHD - Pressure", label).c_str(), troposphereModelSelection.zhdModel.second.pressureModel);
205 ImGui::TableNextColumn();
206 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
207 changed |= ComboTemperatureModel(fmt::format("##{} ZHD - Temperature", label).c_str(), troposphereModelSelection.zhdModel.second.temperatureModel);
208 ImGui::TableNextColumn();
209 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
210 changed |= ComboWaterVaporModel(fmt::format("##{} ZHD - Water vapor", label).c_str(), troposphereModelSelection.zhdModel.second.waterVaporModel);
211 if (troposphereModelSelection.zhdModel.first == TroposphereModel::None) { ImGui::EndDisabled(); }
212
213 ImGui::TableNextColumn();
214 ImGui::TextUnformatted("ZWD model");
215 ImGui::TableNextColumn();
216 ImGui::SetNextItemWidth(width);
217 if (gui::widgets::EnumCombo(fmt::format("##{} ZWD - Combo", label).c_str(), troposphereModelSelection.zwdModel.first))
218 {
219 std::tie(troposphereModelSelection.zwdModel.second,
220 troposphereModelSelection.zwdMappingFunction.first,
221 troposphereModelSelection.zwdMappingFunction.second) = ModelDefaults(troposphereModelSelection.zwdModel.first);
222 changed = true;
223 }
224 if (troposphereModelSelection.zwdModel.first == TroposphereModel::None) { ImGui::BeginDisabled(); }
225 ImGui::TableNextColumn();
226 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
227 changed |= ComboPressureModel(fmt::format("##{} ZWD - Pressure", label).c_str(), troposphereModelSelection.zwdModel.second.pressureModel);
228 ImGui::TableNextColumn();
229 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
230 changed |= ComboTemperatureModel(fmt::format("##{} ZWD - Temperature", label).c_str(), troposphereModelSelection.zwdModel.second.temperatureModel);
231 ImGui::TableNextColumn();
232 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
233 changed |= ComboWaterVaporModel(fmt::format("##{} ZWD - Water vapor", label).c_str(), troposphereModelSelection.zwdModel.second.waterVaporModel);
234 if (troposphereModelSelection.zwdModel.first == TroposphereModel::None) { ImGui::EndDisabled(); }
235
236 if (troposphereModelSelection.zhdModel.first == TroposphereModel::None) { ImGui::BeginDisabled(); }
237 ImGui::TableNextColumn();
238 ImGui::TextUnformatted("Mapping function ZHD");
239 ImGui::TableNextColumn();
240 ImGui::SetNextItemWidth(width);
241 if (gui::widgets::EnumCombo(fmt::format("##{} MapZHD - Combo", label).c_str(), troposphereModelSelection.zhdMappingFunction.first))
242 {
243 troposphereModelSelection.zhdMappingFunction.second = MappingFunctionDefaults(troposphereModelSelection.zhdMappingFunction.first);
244 changed = true;
245 }
246 if (troposphereModelSelection.zhdModel.first != TroposphereModel::None
247 && troposphereModelSelection.zhdMappingFunction.first == MappingFunction::None) { ImGui::BeginDisabled(); }
248 ImGui::TableNextColumn();
249 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
250 changed |= ComboPressureModel(fmt::format("##{} MapZHD - Pressure", label).c_str(), troposphereModelSelection.zhdMappingFunction.second.pressureModel);
251 ImGui::TableNextColumn();
252 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
253 changed |= ComboTemperatureModel(fmt::format("##{} MapZHD - Temperature", label).c_str(), troposphereModelSelection.zhdMappingFunction.second.temperatureModel);
254 ImGui::TableNextColumn();
255 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
256 changed |= ComboWaterVaporModel(fmt::format("##{} MapZHD - Water vapor", label).c_str(), troposphereModelSelection.zhdMappingFunction.second.waterVaporModel);
257 if (troposphereModelSelection.zhdModel.first == TroposphereModel::None
258 || troposphereModelSelection.zhdMappingFunction.first == MappingFunction::None) { ImGui::EndDisabled(); }
259
260 if (troposphereModelSelection.zwdModel.first == TroposphereModel::None) { ImGui::BeginDisabled(); }
261 ImGui::TableNextColumn();
262 ImGui::TextUnformatted("Mapping function ZWD");
263 ImGui::TableNextColumn();
264 ImGui::SetNextItemWidth(width);
265 if (gui::widgets::EnumCombo(fmt::format("##{} MapZWD - Combo", label).c_str(), troposphereModelSelection.zwdMappingFunction.first))
266 {
267 troposphereModelSelection.zwdMappingFunction.second = MappingFunctionDefaults(troposphereModelSelection.zwdMappingFunction.first);
268 changed = true;
269 }
270 if (troposphereModelSelection.zwdModel.first != TroposphereModel::None
271 && troposphereModelSelection.zwdMappingFunction.first == MappingFunction::None) { ImGui::BeginDisabled(); }
272 ImGui::TableNextColumn();
273 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
274 changed |= ComboPressureModel(fmt::format("##{} MapZWD - Pressure", label).c_str(), troposphereModelSelection.zwdMappingFunction.second.pressureModel);
275 ImGui::TableNextColumn();
276 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
277 changed |= ComboTemperatureModel(fmt::format("##{} MapZWD - Temperature", label).c_str(), troposphereModelSelection.zwdMappingFunction.second.temperatureModel);
278 ImGui::TableNextColumn();
279 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
280 changed |= ComboWaterVaporModel(fmt::format("##{} MapZWD - Water vapor", label).c_str(), troposphereModelSelection.zwdMappingFunction.second.waterVaporModel);
281 if (troposphereModelSelection.zwdModel.first == TroposphereModel::None
282 || troposphereModelSelection.zwdMappingFunction.first == MappingFunction::None) { ImGui::EndDisabled(); }
283
284 ImGui::EndTable();
285 }
286
287 ImGui::EndPopup();
288 }
289
290 ImGui::SameLine(0.0F, ImGui::GetStyle().ItemInnerSpacing.x);
291 std::string labelStr = label;
292 ImGui::TextUnformatted(labelStr.substr(0, labelStr.find('#')).c_str());
293
294 return changed;
295 }
296
297 41798 ZenithDelay calcTroposphericDelayAndMapping(const InsTime& insTime, const Eigen::Vector3d& lla_pos, double elevation, double /* azimuth */,
298 const TroposphereModelSelection& troposphereModels, [[maybe_unused]] const std::string& nameId)
299 {
300
2/2
✓ Branch 0 taken 19413 times.
✓ Branch 1 taken 22385 times.
41798 if (troposphereModels.zhdModel.first == TroposphereModel::None
301
1/2
✓ Branch 0 taken 19413 times.
✗ Branch 1 not taken.
19413 && troposphereModels.zwdModel.first == TroposphereModel::None) { return {}; }
302
303
9/12
✓ Branch 1 taken 22385 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22237 times.
✓ Branch 4 taken 148 times.
✓ Branch 6 taken 22237 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 21941 times.
✓ Branch 9 taken 296 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 21941 times.
✓ Branch 13 taken 444 times.
✓ Branch 14 taken 21941 times.
22385 if (lla_pos(2) < -1000 || lla_pos(2) > 1e4 || std::isnan(elevation))
304 {
305 LOG_TRACE("{}: Not calculating tropospheric delay, due to altitude being invalid: {}m", nameId, lla_pos(2));
306 444 return {};
307 }
308
309 enum : uint8_t
310 {
311 ZHD,
312 ZWD,
313 ZHDMapFunc,
314 ZWDMapFunc,
315 COUNT,
316 };
317
318 const std::array<std::reference_wrapper<const AtmosphereModels>, COUNT> atmosphereModels = {
319 21941 troposphereModels.zhdModel.second,
320 21941 troposphereModels.zwdModel.second,
321 21941 troposphereModels.zhdMappingFunction.second,
322 21941 troposphereModels.zwdMappingFunction.second,
323 21941 };
324 21941 std::array<double, COUNT> pressure{}; // Total barometric pressure in [millibar]
325 21941 std::array<double, COUNT> temperature{}; // Absolute temperature in [K]
326 21941 std::array<double, COUNT> waterVapor{}; // Partial pressure of water vapour in [hPa]
327
328 21941 GPT2output gpt2outputs;
329 21941 GPT3output gpt3outputs;
330 // UTC->GPST
331
2/4
✓ Branch 1 taken 21941 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 21941 times.
✗ Branch 6 not taken.
21941 auto epoch_temp = InsTime(insTime) + std::chrono::duration<long double>(insTime.leapGps2UTC());
332
2/4
✓ Branch 2 taken 21941 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 21941 times.
✗ Branch 7 not taken.
21941 double mjd = static_cast<double>(epoch_temp.toMJD().mjd_day) + static_cast<double>(epoch_temp.toMJD().mjd_frac);
333
334 43882 if (troposphereModels.zhdModel.first == TroposphereModel::GPT2
335
1/2
✓ Branch 0 taken 21941 times.
✗ Branch 1 not taken.
21941 || troposphereModels.zwdModel.first == TroposphereModel::GPT2
336
1/2
✓ Branch 0 taken 21941 times.
✗ Branch 1 not taken.
21941 || troposphereModels.zhdMappingFunction.first == MappingFunction::VMF_GPT2
337
1/2
✓ Branch 0 taken 21941 times.
✗ Branch 1 not taken.
21941 || troposphereModels.zwdMappingFunction.first == MappingFunction::VMF_GPT2
338
4/8
✓ Branch 0 taken 21941 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 21941 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 21941 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 21941 times.
43882 || std::ranges::any_of(atmosphereModels,
339 87764 [](const auto& model) { return model.get().pressureModel == PressureModel::GPT2
340
1/2
✓ Branch 2 taken 87764 times.
✗ Branch 3 not taken.
175528 || model.get().temperatureModel == TemperatureModel::GPT2
341
2/4
✓ Branch 0 taken 87764 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 87764 times.
175528 || model.get().waterVaporModel == WaterVaporModel::GPT2; }))
342 {
343 LOG_DATA("{}: Calculating GPT2 parameters", nameId);
344 gpt2outputs = GPT2_param(mjd, lla_pos);
345 }
346
347 43882 if (troposphereModels.zhdModel.first == TroposphereModel::GPT3
348
1/2
✓ Branch 0 taken 21941 times.
✗ Branch 1 not taken.
21941 || troposphereModels.zwdModel.first == TroposphereModel::GPT3
349
1/2
✓ Branch 0 taken 21941 times.
✗ Branch 1 not taken.
21941 || troposphereModels.zhdMappingFunction.first == MappingFunction::VMF_GPT3
350
1/2
✓ Branch 0 taken 21941 times.
✗ Branch 1 not taken.
21941 || troposphereModels.zwdMappingFunction.first == MappingFunction::VMF_GPT3
351
4/8
✓ Branch 0 taken 21941 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 21941 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 21941 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 21941 times.
43882 || std::ranges::any_of(atmosphereModels,
352 87764 [](const auto& model) { return model.get().pressureModel == PressureModel::GPT3
353
1/2
✓ Branch 2 taken 87764 times.
✗ Branch 3 not taken.
175528 || model.get().temperatureModel == TemperatureModel::GPT3
354
2/4
✓ Branch 0 taken 87764 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 87764 times.
175528 || model.get().waterVaporModel == WaterVaporModel::GPT3; }))
355 {
356 LOG_DATA("{}: Calculating GPT3 parameters", nameId);
357 gpt3outputs = GPT3_param(mjd, lla_pos);
358 }
359
360 LOG_DATA("{}: Calculating Atmosphere parameters ZHD=({},{}) ZWD=({},{}) [el={}°, pos={} {} {}]", nameId,
361 troposphereModels.zhdModel.first, troposphereModels.zhdMappingFunction.first,
362 troposphereModels.zwdModel.first, troposphereModels.zwdMappingFunction.first,
363 rad2deg(elevation), rad2deg(lla_pos(0)), rad2deg(lla_pos(1)), lla_pos(2));
364
2/2
✓ Branch 0 taken 87764 times.
✓ Branch 1 taken 21941 times.
109705 for (size_t i = 0; i < COUNT; i++)
365 {
366 87764 bool alreadyCalculated = false;
367
2/2
✓ Branch 0 taken 65823 times.
✓ Branch 1 taken 21941 times.
87764 for (size_t j = 0; j < i; j++)
368 {
369
3/6
✓ Branch 1 taken 65823 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 65823 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 65823 times.
✗ Branch 9 not taken.
65823 if (atmosphereModels.at(i).get().pressureModel == atmosphereModels.at(j).get().pressureModel)
370 {
371
2/4
✓ Branch 1 taken 65823 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 65823 times.
✗ Branch 5 not taken.
65823 pressure.at(i) = pressure.at(j);
372 65823 alreadyCalculated = true;
373 65823 break;
374 }
375 }
376
377
2/2
✓ Branch 0 taken 21941 times.
✓ Branch 1 taken 65823 times.
87764 if (!alreadyCalculated)
378 {
379
2/4
✓ Branch 1 taken 21941 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 21941 times.
21941 if (atmosphereModels.at(i).get().pressureModel == PressureModel::GPT2)
380 {
381 pressure.at(i) = gpt2outputs.p;
382 }
383
2/4
✓ Branch 1 taken 21941 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 21941 times.
21941 else if (atmosphereModels.at(i).get().pressureModel == PressureModel::GPT3)
384 {
385 pressure.at(i) = gpt3outputs.p;
386 }
387 else
388 {
389
4/8
✓ Branch 1 taken 21941 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 21941 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 21941 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 21941 times.
✗ Branch 12 not taken.
21941 pressure.at(i) = calcTotalPressure(lla_pos(2), atmosphereModels.at(i).get().pressureModel);
390 }
391 }
392 LOG_DATA("{}: [{}]: {} - p {} [millibar] (Total barometric pressure) - value {}", nameId, i, atmosphereModels.at(i).get().pressureModel,
393 pressure.at(i), alreadyCalculated ? "reused" : "calculated");
394
395 87764 alreadyCalculated = false;
396
2/2
✓ Branch 0 taken 65823 times.
✓ Branch 1 taken 21941 times.
87764 for (size_t j = 0; j < i; j++)
397 {
398
3/6
✓ Branch 1 taken 65823 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 65823 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 65823 times.
✗ Branch 10 not taken.
65823 if (atmosphereModels.at(i).get().temperatureModel == atmosphereModels.at(j).get().temperatureModel)
399 {
400
2/4
✓ Branch 1 taken 65823 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 65823 times.
✗ Branch 5 not taken.
65823 temperature.at(i) = temperature.at(j);
401 65823 alreadyCalculated = true;
402 65823 break;
403 }
404 }
405
406
2/2
✓ Branch 0 taken 21941 times.
✓ Branch 1 taken 65823 times.
87764 if (!alreadyCalculated)
407 {
408
2/4
✓ Branch 1 taken 21941 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 21941 times.
21941 if (atmosphereModels.at(i).get().temperatureModel == TemperatureModel::GPT2)
409 {
410 temperature.at(i) = gpt2outputs.T;
411 }
412
2/4
✓ Branch 1 taken 21941 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 21941 times.
21941 else if (atmosphereModels.at(i).get().temperatureModel == TemperatureModel::GPT3)
413 {
414 temperature.at(i) = gpt3outputs.T;
415 }
416 else
417 {
418
4/8
✓ Branch 1 taken 21941 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 21941 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 21941 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 21941 times.
✗ Branch 12 not taken.
21941 temperature.at(i) = atmosphereModels.at(i).get().temperatureModel.calcAbsoluteTemperature(lla_pos(2));
419 }
420 }
421 LOG_DATA("{}: [{}]: {} - T {} [K] (Absolute temperature) - value {}", nameId, i, atmosphereModels.at(i).get().temperatureModel,
422 temperature.at(i), alreadyCalculated ? "reused" : "calculated");
423
424 87764 alreadyCalculated = false;
425
2/2
✓ Branch 0 taken 65823 times.
✓ Branch 1 taken 21941 times.
87764 for (size_t j = 0; j < i; j++)
426 {
427
3/6
✓ Branch 1 taken 65823 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 65823 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 65823 times.
✗ Branch 9 not taken.
65823 if (atmosphereModels.at(i).get().waterVaporModel == atmosphereModels.at(j).get().waterVaporModel)
428 {
429
2/4
✓ Branch 1 taken 65823 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 65823 times.
✗ Branch 5 not taken.
65823 waterVapor.at(i) = waterVapor.at(j);
430 65823 alreadyCalculated = true;
431 65823 break;
432 }
433 }
434
435 // Partial pressure of water vapour in [millibar] - RTKLIB ch. E.5, p. 149 specifies 70%
436
2/2
✓ Branch 0 taken 21941 times.
✓ Branch 1 taken 65823 times.
87764 if (!alreadyCalculated)
437 {
438
2/4
✓ Branch 1 taken 21941 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 21941 times.
21941 if (atmosphereModels.at(i).get().waterVaporModel == WaterVaporModel::GPT2)
439 {
440 waterVapor.at(i) = gpt2outputs.e;
441 }
442
2/4
✓ Branch 1 taken 21941 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 21941 times.
21941 else if (atmosphereModels.at(i).get().waterVaporModel == WaterVaporModel::GPT3)
443 {
444 waterVapor.at(i) = gpt3outputs.e;
445 }
446 else
447 {
448
4/8
✓ Branch 1 taken 21941 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 21941 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 21941 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 21941 times.
✗ Branch 12 not taken.
21941 waterVapor.at(i) = calcWaterVaporPartialPressure(temperature.at(i), 0.7, atmosphereModels.at(i).get().waterVaporModel);
449 }
450 }
451 LOG_DATA("{}: [{}]: {} - e {} [millibar] (Partial pressure of water vapour) - value {}", nameId, i,
452 atmosphereModels.at(i).get().waterVaporModel, waterVapor.at(i), alreadyCalculated ? "reused" : "calculated");
453 }
454
455 21941 double zhd = 0.0;
456
1/3
✓ Branch 0 taken 21941 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
21941 switch (troposphereModels.zhdModel.first)
457 {
458 21941 case TroposphereModel::Saastamoinen:
459 case TroposphereModel::GPT2:
460 case TroposphereModel::GPT3:
461
1/2
✓ Branch 2 taken 21941 times.
✗ Branch 3 not taken.
21941 zhd = calcZHD_Saastamoinen(lla_pos, pressure[ZHD]);
462 21941 break;
463 case TroposphereModel::None:
464 case TroposphereModel::COUNT:
465 break;
466 }
467
468 21941 double zwd = 0.0;
469
1/5
✓ Branch 0 taken 21941 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
21941 switch (troposphereModels.zwdModel.first)
470 {
471 21941 case TroposphereModel::Saastamoinen:
472
1/2
✓ Branch 3 taken 21941 times.
✗ Branch 4 not taken.
21941 zwd = calcZWD_Saastamoinen(temperature[ZWD], waterVapor[ZWD]);
473 21941 break;
474 case TroposphereModel::GPT2:
475 zwd = asknewet(waterVapor[ZWD], gpt2outputs.Tm, gpt2outputs.la);
476 break;
477 case TroposphereModel::GPT3:
478 zwd = asknewet(waterVapor[ZWD], gpt3outputs.Tm, gpt3outputs.la);
479 break;
480 case TroposphereModel::None:
481 case TroposphereModel::COUNT:
482 break;
483 }
484
485 21941 double zhdMappingFactor = 1.0;
486
2/7
✓ Branch 0 taken 15556 times.
✓ Branch 1 taken 6385 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
21941 switch (troposphereModels.zhdMappingFunction.first)
487 {
488 15556 case MappingFunction::Cosecant:
489
1/2
✓ Branch 1 taken 15556 times.
✗ Branch 2 not taken.
15556 zhdMappingFactor = calcTropoMapFunc_cosecant(elevation);
490 15556 break;
491 6385 case MappingFunction::GMF:
492
1/2
✓ Branch 1 taken 6385 times.
✗ Branch 2 not taken.
6385 zhdMappingFactor = calcTropoMapFunc_GMFH(mjd, lla_pos, elevation);
493 6385 break;
494 case MappingFunction::NMF:
495 zhdMappingFactor = calcTropoMapFunc_NMFH(insTime, lla_pos, elevation);
496 break;
497 case MappingFunction::VMF_GPT2:
498 zhdMappingFactor = vmf1h(gpt2outputs.ah, mjd, lla_pos(0), lla_pos(2), M_PI / 2.0 - elevation);
499 break;
500 case MappingFunction::VMF_GPT3:
501 zhdMappingFactor = vmf1h(gpt3outputs.ah, mjd, lla_pos(0), lla_pos(2), M_PI / 2.0 - elevation);
502 break;
503 case MappingFunction::None:
504 case MappingFunction::COUNT:
505 break;
506 }
507
508 21941 double zwdMappingFactor = 1.0;
509
2/7
✓ Branch 0 taken 15556 times.
✓ Branch 1 taken 6385 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
21941 switch (troposphereModels.zwdMappingFunction.first)
510 {
511 15556 case MappingFunction::Cosecant:
512
1/2
✓ Branch 1 taken 15556 times.
✗ Branch 2 not taken.
15556 zwdMappingFactor = calcTropoMapFunc_cosecant(elevation);
513 15556 break;
514 6385 case MappingFunction::GMF:
515
1/2
✓ Branch 1 taken 6385 times.
✗ Branch 2 not taken.
6385 zwdMappingFactor = calcTropoMapFunc_GMFW(mjd, lla_pos, elevation);
516 6385 break;
517 case MappingFunction::NMF:
518 zwdMappingFactor = calcTropoMapFunc_NMFW(lla_pos, elevation);
519 break;
520 case MappingFunction::VMF_GPT2:
521 zwdMappingFactor = vmf1w(gpt2outputs.aw, M_PI / 2.0 - elevation);
522 break;
523 case MappingFunction::VMF_GPT3:
524 zwdMappingFactor = vmf1w(gpt3outputs.aw, M_PI / 2.0 - elevation);
525 break;
526 case MappingFunction::None:
527 case MappingFunction::COUNT:
528 break;
529 }
530 LOG_DATA("{}: el = {}, ZHD = {}, ZWD = {}, ZHDMF = {}, ZWDMF = {}", nameId, elevation, zhd, zwd, zhdMappingFactor, zwdMappingFactor);
531
532 return { .ZHD = zhd,
533 .ZWD = zwd,
534 .zhdMappingFactor = zhdMappingFactor,
535 21941 .zwdMappingFactor = zwdMappingFactor };
536 }
537
538 41798 double tropoErrorVar(double dpsr_T, double elevation)
539 {
540 41798 constexpr double ERR_SAAS = 0.3; // Saastamoinen model error std [m] (maximum zenith wet delay - formulas with worst possible values)
541
542
2/2
✓ Branch 0 taken 21941 times.
✓ Branch 1 taken 19857 times.
41798 return dpsr_T == 0.0 ? 0.0 : std::pow(ERR_SAAS / (std::sin(elevation) + 0.1), 2);
543 }
544
545 void to_json(json& j, const AtmosphereModels& obj)
546 {
547 j = json{
548 { "pressureModel", obj.pressureModel },
549 { "temperatureModel", obj.temperatureModel },
550 { "waterVaporModel", obj.waterVaporModel },
551 };
552 }
553
554 32 void from_json(const json& j, AtmosphereModels& obj)
555 {
556
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 if (j.contains("pressureModel")) { j.at("pressureModel").get_to(obj.pressureModel); }
557
3/6
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 32 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 32 times.
32 if (j.contains("temperatureModel") && !j.at("temperatureModel").is_number()) { j.at("temperatureModel").get_to(obj.temperatureModel); }
558
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 if (j.contains("waterVaporModel")) { j.at("waterVaporModel").get_to(obj.waterVaporModel); }
559 32 }
560
561 void to_json(json& j, const TroposphereModelSelection& obj)
562 {
563 j = json{
564 { "zhdModel", obj.zhdModel },
565 { "zwdModel", obj.zwdModel },
566 { "zhdMappingFunction", obj.zhdMappingFunction },
567 { "zwdMappingFunction", obj.zwdMappingFunction },
568 };
569 }
570
571 8 void from_json(const json& j, TroposphereModelSelection& obj)
572 {
573
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (j.contains("zhdModel")) { j.at("zhdModel").get_to(obj.zhdModel); }
574
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (j.contains("zwdModel")) { j.at("zwdModel").get_to(obj.zwdModel); }
575
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (j.contains("zhdMappingFunction")) { j.at("zhdMappingFunction").get_to(obj.zhdMappingFunction); }
576
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (j.contains("zwdMappingFunction")) { j.at("zwdMappingFunction").get_to(obj.zwdMappingFunction); }
577 8 }
578
579 } // namespace NAV
580