-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfirestarr.cpp
More file actions
218 lines (218 loc) · 6.96 KB
/
firestarr.cpp
File metadata and controls
218 lines (218 loc) · 6.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/* SPDX-License-Identifier: AGPL-3.0-or-later */
/*! \mainpage FireSTARR Documentation
*
* \section intro_sec Introduction
*
* FireSTARR is a probabilistic fire growth model.
*/
#include "fs/ArgumentParser.h"
#include "fs/FWI.h"
#include "fs/Log.h"
#include "fs/Model.h"
#include "fs/Settings.h"
#include "fs/StartPoint.h"
#include "fs/stdafx.h"
#include "fs/Test.h"
#include "fs/TimeUtil.h"
#include "fs/Util.h"
#include "fs/Weather.h"
#include "version.h"
namespace fs
{
using fs::AspectSize;
using fs::Dc;
using fs::Direction;
using fs::Dmc;
using fs::Ffmc;
using fs::FwiWeather;
using fs::INVALID_ASPECT;
using fs::INVALID_SLOPE;
using fs::INVALID_TIME;
using fs::MathSize;
using fs::Model;
using fs::Precipitation;
using fs::RelativeHumidity;
using fs::SlopeSize;
using fs::Speed;
using fs::StartPoint;
using fs::Temperature;
using fs::ThresholdSize;
using fs::Wind;
using fs::logging::Log;
int main(const int argc, const char* const argv[])
{
printf("FireSTARR %s\n\n", SPECIFIC_REVISION);
MainArgumentParser parser{argc, argv};
parser.parse_args();
auto result = -1;
#ifdef NDEBUG
try
{
#endif
const auto opened_log = Log::openLogFile(parser.log_file.c_str());
// HACK: check here so verbosity can affect showing compile info
if (parser.help_requested())
{
fs::logging::note("Specific revision is %s", SPECIFIC_REVISION);
fs::logging::debug("Full hash is: %s", FULL_HASH);
fs::logging::debug("Compiled on: %s", COMPILED_ON);
show_help_and_exit();
}
if (!opened_log)
{
logging::fatal("Can't open log file %s", parser.log_file.c_str());
}
fs::logging::note("Output directory is %s", parser.output_directory.c_str());
fs::logging::note("Output log is %s", parser.log_file.c_str());
// at this point we've parsed positional args and know we're not in test mode
if (!was_parsed("--apcp_prev"))
{
fs::logging::warning(
"Assuming 0 precipitation between noon yesterday and weather start for startup indices"
);
}
if (parser.mode != TEST)
{
// handle surface/simulation positional arguments
// positional arguments should be:
// "./firestarr [surface] <output_dir> <yyyy-mm-dd> <lat> <lon> <HH:MM> [options] [-v | -q]"
string date(parser.get_positional());
tm start_date{};
start_date.tm_year = stoi(date.substr(0, 4)) - TM_YEAR_OFFSET;
start_date.tm_mon = stoi(date.substr(5, 2)) - TM_MONTH_OFFSET;
start_date.tm_mday = stoi(date.substr(8, 2));
const auto latitude = stod(parser.get_positional());
const auto longitude = stod(parser.get_positional());
const StartPoint start_point(latitude, longitude);
size_t num_days = 0;
string arg(parser.get_positional());
tm start{};
if (5 == arg.size() && ':' == arg[2])
{
try
{
// if this is a time then we aren't just running the weather
start_date.tm_hour = stoi(arg.substr(0, 2));
fs::logging::check_fatal(
start_date.tm_hour < 0 || start_date.tm_hour > 23,
"Simulation start time has an invalid hour (%d)",
start_date.tm_hour
);
start_date.tm_min = stoi(arg.substr(3, 2));
fs::logging::check_fatal(
start_date.tm_min < 0 || start_date.tm_min > 59,
"Simulation start time has an invalid minute (%d)",
start_date.tm_min
);
fs::logging::note(
"Simulation start time before fix_tm() is %d-%02d-%02d %02d:%02d",
start_date.tm_year + TM_YEAR_OFFSET,
start_date.tm_mon + TM_MONTH_OFFSET,
start_date.tm_mday,
start_date.tm_hour,
start_date.tm_min
);
fs::fix_tm(&start_date);
fs::logging::note(
"Simulation start time after fix_tm() is %d-%02d-%02d %02d:%02d",
start_date.tm_year + TM_YEAR_OFFSET,
start_date.tm_mon + TM_MONTH_OFFSET,
start_date.tm_mday,
start_date.tm_hour,
start_date.tm_min
);
// we were given a time, so number of days is until end of year
start = start_date;
const auto start_t = mktime(&start);
auto year_end = start;
year_end.tm_mon = 12 - TM_MONTH_OFFSET;
year_end.tm_mday = 31;
const auto seconds = difftime(mktime(&year_end), start_t);
// start day counts too, so +1
// HACK: but we don't want to go to Jan 1 so don't add 1
num_days = static_cast<size_t>(seconds / fs::DAY_SECONDS);
fs::logging::debug("Calculated number of days until end of year: %d", num_days);
// +1 because day 1 counts too
// +2 so that results don't change when we change number of days
num_days = min(num_days, static_cast<size_t>(Settings::maxDateOffset()) + 2);
}
catch (std::exception&)
{
show_usage_and_exit();
}
}
parser.done_positional();
// HACK: ISI for yesterday really doesn't matter so just use any wind
// HACK: it's basically wrong to assign this precip to yesterday's object,
// but don't want to add another argument right now
const FwiWeather yesterday{parser.get_yesterday_weather()};
fs::fix_tm(&start_date);
fs::logging::note(
"Simulation start time after fix_tm() again is %d-%02d-%02d %02d:%02d",
start_date.tm_year + TM_YEAR_OFFSET,
start_date.tm_mon + TM_MONTH_OFFSET,
start_date.tm_mday,
start_date.tm_hour,
start_date.tm_min
);
start = start_date;
log_args();
result = Model::runScenarios(
parser.output_directory,
parser.wx_file_name.c_str(),
yesterday,
Settings::rasterRoot(),
start_point,
start,
parser.perim,
parser.size
);
Log::closeLogFile();
}
else
{
// test mode
if (parser.has_positional())
{
const auto arg = parser.get_positional();
if (0 != strcmp(arg.c_str(), "all"))
{
fs::logging::error(
"Only positional argument allowed for test mode aside from output directory is 'all' but got '%s'",
arg.c_str()
);
show_usage_and_exit();
}
parser.test_all = true;
}
parser.done_positional();
const FwiWeather wx{parser.get_test_weather()};
show_args();
result = fs::test(
parser.output_directory,
parser.hours,
&wx,
parser.fuel_name,
parser.slope,
parser.aspect,
parser.test_all
);
}
#ifdef NDEBUG
}
catch (const std::exception& ex)
{
fs::logging::fatal(ex);
std::terminate();
}
#endif
return result;
}
}
// HACK: keep everything else out of std namepace
int main(const int argc, const char* const argv[])
{
// HACK: want to be able to do tests without changing source files but can't find a nice way
constexpr auto fct_main = fs::main;
exit(fct_main(argc, argv));
}