FireSTARR
Loading...
Searching...
No Matches
Environment.h
1/* Copyright (c) Queen's Printer for Ontario, 2020. */
2/* Copyright (c) His Majesty the King in Right of Canada as represented by the Minister of Natural Resources, 2021-2025. */
3
4/* SPDX-License-Identifier: AGPL-3.0-or-later */
5
6#pragma once
7#include "stdafx.h"
8#include "Cell.h"
9#include "ConstantGrid.h"
10#include "Event.h"
11#include "FuelType.h"
12#include "GridMap.h"
13#include "IntensityMap.h"
14#include "Point.h"
15#include "Settings.h"
16
17namespace fs::topo
18{
19using FuelGrid = data::ConstantGrid<const fuel::FuelType*, FuelSize>;
20using ElevationGrid = data::ConstantGrid<ElevationSize>;
21using CellGrid = data::ConstantGrid<Cell, Topo>;
49{
50public:
60 [[nodiscard]] static Environment loadEnvironment(
61 const string dir_out,
62 const string& path,
63 const Point& point,
64 const string& perimeter,
65 int year);
73 [[nodiscard]] static Environment load(const string dir_out,
74 const Point& point,
75 const string& in_fuel,
76 const string& in_elevation);
84 [[nodiscard]] unique_ptr<Coordinates> findCoordinates(
85 const Point& point,
86 bool flipped) const;
91 Environment(Environment&& rhs) noexcept = default;
96 Environment(const Environment& rhs) noexcept = default;
102 Environment& operator=(Environment&& rhs) noexcept = default;
108 Environment& operator=(const Environment& rhs) noexcept = default;
113 [[nodiscard]] constexpr const string& proj4() const
114 {
115 return cells_->proj4();
116 }
121 [[nodiscard]] constexpr Idx rows() const
122 {
123 return cells_->rows();
124 }
129 [[nodiscard]] constexpr Idx columns() const
130 {
131 return cells_->columns();
132 }
137 [[nodiscard]] constexpr MathSize cellSize() const
138 {
139 return cells_->cellSize();
140 }
145 [[nodiscard]] constexpr ElevationSize elevation() const
146 {
147 return elevation_;
148 }
155 [[nodiscard]]
156#ifdef NDEBUG
157 CONSTEXPR
158#endif
159 Cell
160 cell(const Idx row, const Idx column) const
161 {
162 return cells_->at(Location(row, column));
163 }
169 template <class P>
170 [[nodiscard]] constexpr Cell cell(const Position<P>& position) const
171 {
172 return cells_->at(position);
173 }
179 // [[nodiscard]] constexpr Cell cell(const HashSize hash_size) const
180 // {
181 // return cells_->at(hash_size);
182 // }
190 [[nodiscard]]
191#ifdef NDEBUG
192 CONSTEXPR
193#endif
194 Cell
195 offset(const sim::Event& event,
196 const Idx row,
197 const Idx column) const
198 {
199 const auto& p = event.cell();
200 // return cell(p.hash() + column + static_cast<HashSize>(MAX_COLUMNS) * row);
201 return cell(Location(p.row() + row, p.column() + column));
202 }
213 [[nodiscard]] sim::ProbabilityMap* makeProbabilityMap(DurationSize time,
214 DurationSize start_time) const;
221 template <class Other>
222 [[nodiscard]] unique_ptr<data::GridMap<Other>> makeMap(const Other nodata) const
223 {
224 return make_unique<data::GridMap<Other>>(*cells_, nodata);
225 }
230 [[nodiscard]] unique_ptr<sim::BurnedData> makeBurnedData() const
231 {
232 auto result = make_unique<sim::BurnedData>(*not_burnable_);
233 return result;
234 }
239 void resetBurnedData(sim::BurnedData* data) const noexcept
240 {
241 // setting to {} probably makes a bitset of the same size on the stack?
242 // *data = {};
243 *data = *not_burnable_;
244 }
245protected:
251 [[nodiscard]] static CellGrid* makeCells(
252 const FuelGrid& fuel,
254 {
255 logging::check_equal(fuel.yllcorner(), elevation.yllcorner(), "yllcorner");
256 static Cell nodata{};
257 auto values = vector<Cell>{fuel.data.size()};
258 vector<HashSize> hashes{};
259 // for (HashSize h = 0; h < static_cast<size_t>(MAX_ROWS) * MAX_COLUMNS; ++h)
260 // {
261 // hashes.emplace_back(h);
262 // }
263 for (Idx r = 0; r < fuel.rows(); ++r)
264 {
265 for (Idx c = 0; c < fuel.columns(); ++c)
266 {
267 const auto h = hashes.emplace_back(Location(r, c).hash());
268 // hashes.emplace_back(Location(r, c).hash());
269 // }
270 // }
271 // std::for_each(
272 // std::execution::par_unseq,
273 // hashes.begin(),
274 // hashes.end(),
275 // [&fuel, &values, &elevation](auto&& h)
276 // {
277 const topo::Location loc{r, c, h};
278 // const topo::Location loc{static_cast<Idx>(h / MAX_COLUMNS),
279 // static_cast<Idx>(h % MAX_COLUMNS),
280 // h};
281 // const auto r = loc.row();
282 // const auto c = loc.column();
283 // const auto f = fuel::FuelType::safeCode(fuel.at(h));
284 if (r >= 0 && r < fuel.rows() && c >= 0 && c < fuel.columns())
285 {
286 // NOTE: this needs to translate to internal codes?
287 const auto f = fuel::FuelType::safeCode(fuel.at(loc));
288 auto s = static_cast<SlopeSize>(INVALID_SLOPE);
289 auto a = static_cast<AspectSize>(INVALID_ASPECT);
290 // HACK: don't calculate for outside box of cells
291 if (r > 0 && r < fuel.rows() - 1 && c > 0 && c < fuel.columns() - 1)
292 {
293 MathSize dem[9];
294 bool valid = true;
295 for (int i = -1; i < 2; ++i)
296 {
297 for (int j = -1; j < 2; ++j)
298 {
299 // grid is (0, 0) at bottom left, but want [0] in array to be NW corner
300 auto actual_row = static_cast<Idx>(r - i);
301 auto actual_column = static_cast<Idx>(c + j);
302 auto cur_loc = Location{actual_row, actual_column};
303 // auto cur_h = cur_loc.hash();
304 // dem[3 * (i + 1) + (j + 1)] = 1.0 * elevation.at(cur_h);
305 const auto v = elevation.at(cur_loc);
306 // can't calculate slope & aspect if any surrounding cell is nodata
307 if (elevation.nodataValue() == v)
308 {
309 valid = false;
310 break;
311 }
312 dem[3 * (i + 1) + (j + 1)] = 1.0 * v;
313 }
314 if (!valid)
315 {
316 break;
317 }
318 }
319 if (valid)
320 {
321 // Horn's algorithm
322 const MathSize dx = ((dem[2] + dem[5] + dem[5] + dem[8])
323 - (dem[0] + dem[3] + dem[3] + dem[6]))
324 / elevation.cellSize();
325 const MathSize dy = ((dem[6] + dem[7] + dem[7] + dem[8])
326 - (dem[0] + dem[1] + dem[1] + dem[2]))
327 / elevation.cellSize();
328 const MathSize key = (dx * dx + dy * dy);
329 auto slope_pct = static_cast<float>(100 * (sqrt(key) / 8.0));
330 s = min(static_cast<SlopeSize>(MAX_SLOPE_FOR_DISTANCE), static_cast<SlopeSize>(round(slope_pct)));
331 static_assert(std::numeric_limits<SlopeSize>::max() >= MAX_SLOPE_FOR_DISTANCE);
332 MathSize aspect_azimuth = 0.0;
333
334 if (s > 0 && (dx != 0 || dy != 0))
335 {
336 aspect_azimuth = atan2(dy, -dx) * M_RADIANS_TO_DEGREES;
337 // NOTE: need to change this out of 'math' direction into 'real' direction (i.e. N is 0, not E)
338 aspect_azimuth = (aspect_azimuth > 90.0) ? (450.0 - aspect_azimuth) : (90.0 - aspect_azimuth);
339 if (aspect_azimuth == 360.0)
340 {
341 aspect_azimuth = 0.0;
342 }
343 }
344
345 a = static_cast<AspectSize>(round(aspect_azimuth));
346 }
347 }
348 const auto cell = Cell{h, s, a, f};
349 values.at(h) = cell;
350#ifdef DEBUG_GRIDS
351#ifndef VLD_RPTHOOK_INSTALL
352 logging::check_equal(cell.row(), r, "Cell row");
353 logging::check_equal(cell.column(), c, "Cell column");
354 const auto v = values.at(h);
355 logging::check_equal(v.row(), r, "Row");
356 logging::check_equal(v.column(), c, "Column");
357 if (!(INVALID_SLOPE == cell.slope() || INVALID_ASPECT == cell.aspect() || INVALID_FUEL_CODE == cell.fuelCode()))
358 {
359 logging::check_equal(cell.slope(), s, "Cell slope");
360 logging::check_equal(v.slope(), s, "Slope");
361 if (0 != s)
362 {
363 logging::check_equal(cell.aspect(), a, "Cell aspect");
364 logging::check_equal(v.aspect(), a, "Aspect");
365 }
366 else
367 {
368 logging::check_equal(cell.aspect(), a, "Cell aspect when slope is 0");
369 logging::check_equal(v.aspect(), 0, "Aspect when slope is 0");
370 }
371 logging::check_equal(v.fuelCode(), f, "Fuel");
372 logging::check_equal(cell.fuelCode(), f, "Cell fuel");
373 }
374 else
375 {
376 logging::check_equal(cell.slope(), INVALID_SLOPE, "Invalid Cell slope");
377 logging::check_equal(cell.aspect(), INVALID_ASPECT, "Invalid Cell aspect");
378 logging::check_equal(cell.fuelCode(), INVALID_FUEL_CODE, "Invalid Cell fuel");
379 logging::check_equal(v.slope(), INVALID_SLOPE, "Invalid slope");
380 logging::check_equal(v.aspect(), INVALID_ASPECT, "Invalid aspect");
381 logging::check_equal(v.fuelCode(), INVALID_FUEL_CODE, "Invalid fuel");
382 }
383#endif
384#endif
385 }
386 // });
387 }
388 }
389 return new topo::CellGrid(
390 fuel.cellSize(),
391 fuel.rows(),
392 fuel.columns(),
393 nodata.fullHash(),
394 nodata,
395 fuel.xllcorner(),
396 fuel.yllcorner(),
397 fuel.xurcorner(),
398 fuel.yurcorner(),
399 string(fuel.proj4()),
400 std::move(values));
401 }
405 shared_ptr<sim::BurnedData> initializeNotBurnable(const CellGrid& cells) const
406 {
407 // shared_ptr<sim::BurnedData> result{};
408 // std::fill(not_burnable_.begin(), not_burnable_.end(), false);
409 // make a template we can copy to reset things
410 auto result = make_shared<sim::BurnedData>();
411 for (Idx r = 0; r < rows(); ++r)
412 {
413 for (Idx c = 0; c < columns(); ++c)
414 {
415 const Location location(r, c);
416 // HACK: just mark outside edge as unburnable so we never need to check
417 bool is_outer = 0 == r
418 || 0 == c
419 || (rows() - 1) == r
420 || (columns() - 1) == c;
421 // (*result)[location.hash()] = (nullptr == fuel::fuel_by_code(cells.at(location).fuelCode()));
422 (*result)[location.hash()] = is_outer || fuel::is_null_fuel(cells.at(location));
423 // if (fuel::is_null_fuel(cell(location)))
424 // {
425 // not_burnable_[location.hash()] = true;
426 // }
427 }
428 }
429 return result;
430 }
436 Environment(const string dir_out,
437 CellGrid* cells,
438 const ElevationSize elevation) noexcept
439 : dir_out_(dir_out),
440 cells_(cells),
443 {
444 // try
445 // {
446 // initializeNotBurnable();
447 // }
448 // catch (...)
449 // {
450 // std::terminate();
451 // }
452 }
459 const string dir_out,
460 const FuelGrid& fuel,
462 const Point& point)
463 : Environment(dir_out,
464 makeCells(fuel,
465 elevation),
466 elevation.at(Location(*elevation.findCoordinates(point, false).get())))
467 {
468 // take elevation at point so that if max grid size changes elevation doesn't
469 logging::note("Start elevation is %d", elevation_);
470 }
471private:
472#ifdef CPP23
473 const
474#endif
475 string dir_out_;
483 shared_ptr<const sim::BurnedData> not_burnable_;
487 ElevationSize elevation_;
488};
489}
A GridData<T, V, const vector<T>> that cannot change once initialized.
Definition ConstantGrid.h:27
constexpr T at(const Location &location) const noexcept override
Value for grid at given Location.
Definition ConstantGrid.h:34
constexpr MathSize xurcorner() const noexcept
Upper right corner X coordinate in meters.
Definition Grid.h:116
constexpr const string & proj4() const noexcept
Proj4 string defining coordinate system for this grid. Must be a UTM projection.
Definition Grid.h:132
constexpr MathSize cellSize() const noexcept
Cell size used for GridBase.
Definition Grid.h:72
constexpr MathSize yllcorner() const noexcept
Lower left corner Y coordinate in meters.
Definition Grid.h:108
constexpr MathSize xllcorner() const noexcept
Lower left corner X coordinate in meters.
Definition Grid.h:100
constexpr MathSize yurcorner() const noexcept
Upper right corner Y coordinate in meters.
Definition Grid.h:124
D data
Structure that holds data represented by this GridData.
Definition Grid.h:506
constexpr Idx rows() const noexcept
Number of rows in the GridBase.
Definition Grid.h:257
constexpr Idx columns() const noexcept
Number of columns in the GridBase.
Definition Grid.h:265
static constexpr FuelCodeSize safeCode(const FuelType *fuel)
Convert FuelType to its code, or 0 if nullptr.
Definition FuelType.h:62
A specific Event scheduled in a specific Scenario.
Definition Event.h:19
Map of the percentage of simulations in which a Cell burned in each intensity category.
Definition ProbabilityMap.h:31
A Position with a Slope, Aspect, and Fuel.
Definition Cell.h:20
static constexpr AspectSize aspect(const SpreadKey value) noexcept
Aspect (degrees)
Definition Cell.h:126
static constexpr FuelCodeSize fuelCode(const SpreadKey value) noexcept
Fuel.
Definition Cell.h:136
static constexpr SlopeSize slope(const SpreadKey value) noexcept
Slope (degrees)
Definition Cell.h:145
The area that a Model is run for, with Fuel, Slope, and Aspect grids.
Definition Environment.h:49
ElevationSize elevation_
Elevation at StartPoint.
Definition Environment.h:487
void resetBurnedData(sim::BurnedData *data) const noexcept
Reset with known non-fuel cells.
Definition Environment.h:239
Environment(const string dir_out, const FuelGrid &fuel, const ElevationGrid &elevation, const Point &point)
Load from rasters.
Definition Environment.h:458
Environment & operator=(const Environment &rhs) noexcept=default
Copy assignment.
sim::ProbabilityMap * makeProbabilityMap(DurationSize time, DurationSize start_time) const
Make a ProbabilityMap that covers this Environment.
Definition Environment.cpp:38
static Environment load(const string dir_out, const Point &point, const string &in_fuel, const string &in_elevation)
Load from rasters.
Definition Environment.cpp:23
shared_ptr< const sim::BurnedData > not_burnable_
BurnedData of cells that are not burnable.
Definition Environment.h:483
Cell offset(const sim::Event &event, const Idx row, const Idx column) const
Cell at Location with given hash.
Definition Environment.h:195
shared_ptr< sim::BurnedData > initializeNotBurnable(const CellGrid &cells) const
Creates a map of areas that are not burnable either because of fuel or the initial perimeter.
Definition Environment.h:405
constexpr const string & proj4() const
UTM projection that this uses.
Definition Environment.h:113
CellGrid * cells_
Cells representing Environment.
Definition Environment.h:479
unique_ptr< data::GridMap< Other > > makeMap(const Other nodata) const
Create a GridMap<Other> covering this Environment.
Definition Environment.h:222
Environment & operator=(Environment &&rhs) noexcept=default
Move assignment.
Environment(const string dir_out, CellGrid *cells, const ElevationSize elevation) noexcept
Construct from cells and elevation.
Definition Environment.h:436
constexpr Idx columns() const
Number of columns in grid.
Definition Environment.h:129
static Environment loadEnvironment(const string dir_out, const string &path, const Point &point, const string &perimeter, int year)
Load from rasters in folder that have same projection as Perimeter.
Definition Environment.cpp:46
Environment(Environment &&rhs) noexcept=default
Move constructor.
constexpr Cell cell(const Position< P > &position) const
Cell at given Location.
Definition Environment.h:170
static CellGrid * makeCells(const FuelGrid &fuel, const ElevationGrid &elevation)
Combine rasters into ConstantGrid<Cell, Topo>
Definition Environment.h:251
unique_ptr< sim::BurnedData > makeBurnedData() const
Create BurnedData and set burned bits based on Perimeter.
Definition Environment.h:230
Cell cell(const Idx row, const Idx column) const
Cell at given row and column.
Definition Environment.h:160
constexpr MathSize cellSize() const
Cell width and height (m)
Definition Environment.h:137
Environment(const Environment &rhs) noexcept=default
Copy constructor.
constexpr Idx rows() const
Number of rows in grid.
Definition Environment.h:121
unique_ptr< Coordinates > findCoordinates(const Point &point, bool flipped) const
Determine Coordinates in the grid for the Point.
Definition Environment.cpp:145
constexpr ElevationSize elevation() const
Elevation of the origin Point.
Definition Environment.h:145
Definition Location.h:229
A geographic location in lat/long coordinates.
Definition Point.h:13
A Position with a row and column.
Definition Location.h:57
constexpr Idx row() const noexcept
Row.
Definition Location.h:64
constexpr HashSize hash() const noexcept
Hash derived from row and column.
Definition Location.h:80
constexpr Idx column() const noexcept
Column.
Definition Location.h:72
Definition util.h:14