Skip to content

Utilities Reference

The embrs.utilities package provides shared constants, helper functions, and support classes used throughout the EMBRS codebase. fire_util defines cell states, hexagonal grid math, and general-purpose utility functions. action provides classes for representing discrete suppression operations that can be scheduled and performed on a simulation. unit_conversions and numba_utils supply unit conversion helpers and JIT compilation wrappers respectively.

Fire Utilities

Core constants and utility functions for fire simulation.

This module provides essential data structures, constants, and helper functions used throughout the EMBRS codebase, including cell states, hexagonal grid math, road constants, and various utility functions.

Classes:

Name Description
- CellStates

Enumeration of cell states (BURNT, FUEL, FIRE).

- CrownStatus

Crown fire status constants.

- CanopySpecies

Canopy species definitions and properties.

- RoadConstants

Road type definitions and standard dimensions.

- HexGridMath

Hexagonal grid neighbor calculations.

- SpreadDecomp

Fire spread direction decomposition mappings.

- UtilFuncs

General utility functions.

.. autoclass:: CellStates :members:

.. autoclass:: CrownStatus :members:

.. autoclass:: CanopySpecies :members:

.. autoclass:: RoadConstants :members:

.. autoclass:: HexGridMath :members:

.. autoclass:: SpreadDecomp :members:

.. autoclass:: UtilFuncs :members:

CanopySpecies

Canopy species definitions and properties for spotting calculations.

Contains species identification mappings and physical properties used in firebrand lofting and spotting distance calculations.

Attributes:

Name Type Description
species_names dict

Maps species ID (int) to species name (str).

species_ids dict

Maps species name (str) to species ID (int).

properties ndarray

Physical properties matrix where each row corresponds to a species ID. Columns are species-specific parameters for spotting calculations. TODO:verify column definitions and units. (find the source and cite it here)

Source code in embrs/utilities/fire_util.py
 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
class CanopySpecies:
    """Canopy species definitions and properties for spotting calculations.

    Contains species identification mappings and physical properties used
    in firebrand lofting and spotting distance calculations.

    Attributes:
        species_names (dict): Maps species ID (int) to species name (str).
        species_ids (dict): Maps species name (str) to species ID (int).
        properties (np.ndarray): Physical properties matrix where each row
            corresponds to a species ID. Columns are species-specific parameters
            for spotting calculations. TODO:verify column definitions and units. (find the source and cite it here)
    """

    species_names = {
        0: "Engelmann spruce",
        1: "Douglas fir",
        2: "Western hemlock",
        3: "Ponderosa pine",
        4: "White pine",
        5: "Grand fir",
        6: "Longleaf pine",
        7: "Pond pine",
        8: "Loblolly pine"
    }

    species_ids = {
        "Engelmann spruce": 0,
        "Douglas fir": 1,
        "Western hemlock": 2,
        "Ponderosa pine": 3,
        "White pine": 4,
        "Grand fir": 5,
        "Longleaf pine": 6,
        "Pond pine": 7,
        "Loblolly pine": 8
    }

    properties = np.array([
        [15.7, 0.451, 12.6, 0.256],
        [15.7, 0.451, 10.7, 0.278],
        [15.7, 0.451, 6.3, 0.249],
        [12.9, 0.453, 12.6, 0.256],
        [12.9, 0.453, 10.7, 0.278],
        [16.5, 0.515, 10.7, 0.278],
        [2.71, 1.0, 11.9, 0.389],
        [2.71, 1.0, 7.91, 0.344],
        [2.71, 1.0, 13.5, 0.544]
    ])

CellStates

Enumeration of possible cell states.

Attributes:

Name Type Description
BURNT int

Cell has been burnt, no fuel remaining (value: 0).

FUEL int

Cell contains fuel and is not on fire (value: 1).

FIRE int

Cell is currently burning (value: 2).

Source code in embrs/utilities/fire_util.py
137
138
139
140
141
142
143
144
145
146
class CellStates:
    """Enumeration of possible cell states.

    Attributes:
        BURNT (int): Cell has been burnt, no fuel remaining (value: 0).
        FUEL (int): Cell contains fuel and is not on fire (value: 1).
        FIRE (int): Cell is currently burning (value: 2).
    """

    BURNT, FUEL, FIRE = 0, 1, 2

CrownStatus

Enumeration of crown fire status values.

Attributes:

Name Type Description
NONE int

No crown fire activity (value: 0).

PASSIVE int

Passive crown fire (value: 1).

ACTIVE int

Active crown fire (value: 2).

Source code in embrs/utilities/fire_util.py
76
77
78
79
80
81
82
83
84
class CrownStatus:
    """Enumeration of crown fire status values.

    Attributes:
        NONE (int): No crown fire activity (value: 0).
        PASSIVE (int): Passive crown fire (value: 1).
        ACTIVE (int): Active crown fire (value: 2).
    """
    NONE, PASSIVE, ACTIVE = 0, 1, 2

HexGridMath

Data structures for hexagonal grid neighbor calculations.

Provides mappings for finding neighbors of cells in a point-up hexagonal grid. Even and odd rows have different neighbor offsets due to the staggered grid layout.

Neighbor letters (A-F) identify the six directions around a hexagon, starting from the upper-right and proceeding clockwise.

Attributes:

Name Type Description
even_neighborhood list

Relative (row, col) offsets for neighbors of cells in even-numbered rows.

even_neighbor_letters dict

Maps letter (A-F) to (row, col) offset for even rows.

even_neighbor_rev_letters dict

Maps (row, col) offset to letter for even rows.

odd_neighborhood list

Relative (row, col) offsets for neighbors of cells in odd-numbered rows.

odd_neighbor_letters dict

Maps letter (A-F) to (row, col) offset for odd rows.

odd_neighbor_rev_letters dict

Maps (row, col) offset to letter for odd rows.

Source code in embrs/utilities/fire_util.py
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
class HexGridMath:
    """Data structures for hexagonal grid neighbor calculations.

    Provides mappings for finding neighbors of cells in a point-up hexagonal
    grid. Even and odd rows have different neighbor offsets due to the
    staggered grid layout.

    Neighbor letters (A-F) identify the six directions around a hexagon,
    starting from the upper-right and proceeding clockwise.

    Attributes:
        even_neighborhood (list): Relative (row, col) offsets for neighbors
            of cells in even-numbered rows.
        even_neighbor_letters (dict): Maps letter (A-F) to (row, col) offset
            for even rows.
        even_neighbor_rev_letters (dict): Maps (row, col) offset to letter
            for even rows.
        odd_neighborhood (list): Relative (row, col) offsets for neighbors
            of cells in odd-numbered rows.
        odd_neighbor_letters (dict): Maps letter (A-F) to (row, col) offset
            for odd rows.
        odd_neighbor_rev_letters (dict): Maps (row, col) offset to letter
            for odd rows.
    """

    even_neighborhood = [(-1, 1), (0, 1), (1, 0), (0, -1), (-1, -1), (-1, 0)]
    even_neighbor_letters = {'F': (-1, 1),
                             'A': (0, 1),
                             'B': (1, 0),
                             'C': (0, -1),
                             'D': (-1, -1),
                             'E': (-1, 0)}

    even_neighbor_rev_letters = {(-1, 1): 'F',
                                (0, 1): 'A',
                                (1, 0): 'B',
                                (0, -1): 'C',
                                (-1, -1): 'D',
                                (-1, 0): 'E'}

    odd_neighborhood = [(1, 0), (1, 1), (0, 1), (-1, 0), (0, -1), (1, -1)]
    odd_neighbor_letters = {'B': (1, 0),
                            'A': (1, 1),
                            'F': (0, 1),
                            'E': (-1, 0),
                            'D': (0, -1),
                            'C': (1, -1)}

    odd_neighbor_rev_letters = {(1, 0): 'B',
                                (1, 1): 'A',
                                (0, 1): 'F',
                                (-1, 0): 'E',
                                (0, -1): 'D',
                                (1, -1): 'C'}

RoadConstants

Constants for road types imported from OpenStreetMap.

Defines standard road classifications, lane widths, shoulder widths, and visualization colors for roads used as fuel breaks in simulation.

Attributes:

Name Type Description
major_road_types list

List of supported OSM road type strings.

lane_widths_m dict

Lane width in meters for each road type.

shoulder_widths_m dict

Total shoulder width in meters for each road type.

default_lanes int

Default number of lanes (2).

road_color_mapping dict

Hex color codes for visualization by road type.

TODO dict

verify the source for the lane widths

Source code in embrs/utilities/fire_util.py
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
class RoadConstants:
    """Constants for road types imported from OpenStreetMap.

    Defines standard road classifications, lane widths, shoulder widths,
    and visualization colors for roads used as fuel breaks in simulation.

    Attributes:
        major_road_types (list): List of supported OSM road type strings.
        lane_widths_m (dict): Lane width in meters for each road type.
        shoulder_widths_m (dict): Total shoulder width in meters for each road type.
        default_lanes (int): Default number of lanes (2).
        road_color_mapping (dict): Hex color codes for visualization by road type.
        TODO:verify the source for the lane widths
    """

    major_road_types = ['motorway', 'trunk', 'primary', 'secondary',
                        'tertiary', 'residential']

    lane_widths_m = {
        'motorway': 3.66,
        'big_motorway': 3.66,
        'trunk': 3.66,
        'primary': 3.66,
        'secondary': 3.05,
        'tertiary': 3.05,
        'residential': 3.05
    }

    shoulder_widths_m = {
        'motorway': 4.27,
        'big_motorway': 6.10,
        'trunk': 4.27,
        'primary': 4.27,
        'secondary': 1.83,
        'tertiary': 1.83,
        'residential': 1.83
    }

    default_lanes = 2

    road_color_mapping = {
        'motorway': '#4B0082',
        'big_motorway': '#4B0082',
        'trunk': '#800080',
        'primary': '#9400D3',
        'secondary': '#9932CC',
        'tertiary': '#BA55D3',
        'residential': '#EE82EE',
    }

SpreadDecomp

Mapping for fire spread direction decomposition across cell boundaries.

Maps spread endpoint locations on a cell's boundary to corresponding entry points on neighboring cells. Used for tracking fire propagation between adjacent hexagonal cells.

Attributes:

Name Type Description
self_loc_to_neighbor_loc_mapping dict

Maps edge location indices (1-12) to list of tuples (neighbor_edge_loc, neighbor_letter) indicating where fire enters the adjacent cell.

Source code in embrs/utilities/fire_util.py
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
class SpreadDecomp:
    """Mapping for fire spread direction decomposition across cell boundaries.

    Maps spread endpoint locations on a cell's boundary to corresponding
    entry points on neighboring cells. Used for tracking fire propagation
    between adjacent hexagonal cells.

    Attributes:
        self_loc_to_neighbor_loc_mapping (dict): Maps edge location indices (1-12)
            to list of tuples (neighbor_edge_loc, neighbor_letter) indicating
            where fire enters the adjacent cell.
    """

    self_loc_to_neighbor_loc_mapping = {
        1: [(7, 'A')],
        2: [(6, 'A'), (10, 'B')],
        3: [(9, 'B')],
        4: [(8, 'B'), (12, 'C')],
        5: [(11, 'C')],
        6: [(10, 'C'), (2, 'D')],
        7: [(1, 'D')],
        8: [(12, 'D'), (4, 'E')],
        9: [(3, 'E')],
        10: [(2, 'E'), (6, 'F')],
        11: [(5, 'F')],
        12: [(4, 'F'), (8, 'A')]
    }

UtilFuncs

Collection of utility functions used across the codebase.

Source code in embrs/utilities/fire_util.py
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
class UtilFuncs:
    """Collection of utility functions used across the codebase."""

    def get_indices_from_xy(x_m: float, y_m: float, cell_size: float, grid_width: int,
                            grid_height: int) -> Tuple[int, int]:
        """Get grid indices for a point in spatial coordinates.

        Calculates the (row, col) indices in the cell_grid array for the cell
        containing the point (x_m, y_m). Does not require a FireSim object.

        Args:
            x_m (float): X position in meters.
            y_m (float): Y position in meters.
            cell_size (float): Cell size in meters (hexagon side length).
            grid_width (int): Number of columns in the grid.
            grid_height (int): Number of rows in the grid.

        Returns:
            Tuple[int, int]: (row, col) indices of the cell containing the point.

        Raises:
            ValueError: If the point is outside the grid bounds.
        """
        row = int(y_m // (cell_size * 1.5))

        if row % 2 == 0:
            col = int(x_m // (cell_size * np.sqrt(3))) + 1
        else:
            col = int((x_m // (cell_size * np.sqrt(3))) - 0.5) + 1

        if col < 0 or row < 0 or row >= grid_height or col >= grid_width:
            msg = (f'Point ({x_m}, {y_m}) is outside the grid. '
                f'Column: {col}, Row: {row}, '
                f'simSize: ({grid_height} , {grid_width})')
            raise ValueError(msg)

        return row, col

    def get_time_str(time_s: int, show_sec: bool = False) -> str:
        """Format a time value in seconds as a human-readable string.

        Args:
            time_s (int): Time value in seconds.
            show_sec (bool): If True, include seconds in output. Defaults to False.

        Returns:
            str: Formatted time string (e.g., "2 h 30 min" or "2 h 30 min 15 s").
        """
        hours = int(time_s // 3600)
        minutes = int((time_s % 3600) // 60)

        if show_sec:
            seconds = int((time_s % 3600) % 60)

            if hours > 0:
                result = f"{hours} h {minutes} min {seconds} s"
            elif minutes > 0:
                result = f"{minutes} min {seconds} s"
            else:
                result = f"{seconds} s"
            return result

        if hours > 0:
            result = f"{hours} h {minutes} min"
        else:
            result = f"{minutes} min"
        return result

    def get_dominant_fuel_type(fuel_map: np.ndarray) -> int:
        """Find the most common fuel type in a fuel map.

        Args:
            fuel_map (np.ndarray): 2D array of fuel type IDs.

        Returns:
            int: Fuel type ID that occurs most frequently.
        """
        counts = np.bincount(fuel_map.ravel())

        return np.argmax(counts)

    def get_cell_polygons(cells: List["Cell"]) -> Optional[List[Polygon]]:
        """Merge cell polygons into minimal covering polygons.

        Args:
            cells (List[Cell]): List of Cell objects to convert.

        Returns:
            Optional[List[Polygon]]: List of shapely Polygon objects representing
                the merged cells, or None if cells is empty.
        """
        if not cells:
            return None

        polygons = [cell.polygon for cell in cells]

        merged_polygon = unary_union(polygons)

        if isinstance(merged_polygon, MultiPolygon):
            return list(merged_polygon.geoms)

        return [merged_polygon]

    @staticmethod
    def hexagon_vertices(x: float, y: float, s: float) -> List[Tuple[float, float]]:
        """Calculate vertex positions for a point-up hexagon.

        Args:
            x (float): X coordinate of hexagon center in meters.
            y (float): Y coordinate of hexagon center in meters.
            s (float): Side length of hexagon in meters.

        Returns:
            List[Tuple[float, float]]: Six (x, y) vertex coordinates, starting
                from the top vertex and proceeding clockwise.
        """
        vertices = [
            (x, y + s),
            (x + s * np.sqrt(3) / 2, y + s / 2),
            (x + s * np.sqrt(3) / 2, y - s / 2),
            (x, y - s),
            (x - s * np.sqrt(3) / 2, y - s / 2),
            (x - s * np.sqrt(3) / 2, y + s / 2)
        ]
        return vertices


    def get_dist(edge_loc: int, idx_diff: int, cell_size: float) -> float:
        """Calculate distance from an edge location to an endpoint on the cell boundary.

        Used internally for fire spread calculations to determine the distance
        fire must travel from its current position to reach a cell boundary point.

        Args:
            edge_loc (int): Starting edge location index (0 for center, 1-12 for
                boundary positions where odd=edge midpoints, even=corners).
            idx_diff (int): Absolute difference between edge_loc and target endpoint
                index (range 1-6 due to hexagon symmetry).
            cell_size (float): Hexagon side length in meters.

        Returns:
            float: Distance in meters from edge_loc to the target endpoint.
        """
        odd_loc_distance_dict = {
            1: cell_size / 2,
            2: (np.sqrt(3)/2) * cell_size, # Law of sines
            3: (np.sqrt(7)/2) * cell_size, # Law of cosines
            4: (3 * cell_size) / 2,
            5: (np.sqrt(13) * cell_size) / 2, # Law of cosines
            6: np.sqrt(3) * cell_size
        }

        even_loc_distance_dict = {
            2: cell_size,
            3: (np.sqrt(7)/2) * cell_size,
            4: np.sqrt(3) * cell_size,
            5: (np.sqrt(13) * cell_size) / 2,
            6: 2 * cell_size,
        }

        # Handle case where ignition starts at center
        if edge_loc == 0:
            if idx_diff % 2 == 0:
                return cell_size
            else:
                return (np.sqrt(3) * cell_size)/2

        elif edge_loc %  2 == 0:
            return even_loc_distance_dict[idx_diff]

        else:
            return odd_loc_distance_dict[idx_diff]

    @lru_cache
    def get_ign_parameters(edge_loc: int, cell_size: float) -> Tuple[np.ndarray, np.ndarray, tuple]:
        """Compute fire spread parameters from an ignition point within a cell.

        Calculates the spread directions, distances to cell boundary endpoints,
        and neighbor cell entry points for fire propagating from a given ignition
        location. Results are cached for performance.

        Args:
            edge_loc (int): Ignition location index. 0 for cell center, 1-12 for
                boundary positions (odd indices are edge midpoints, even indices
                are corner vertices).
            cell_size (float): Hexagon side length in meters.

        Returns:
            Tuple containing:
                - np.ndarray: Spread direction angles in degrees (0-360).
                - np.ndarray: Distances to each boundary endpoint in meters.
                - tuple: Nested tuples of (neighbor_edge_loc, neighbor_letter)
                    pairs indicating where fire enters adjacent cells.
        """
        if edge_loc == 0:
            # Ignition is at the center of cell
            start_angle = 30
            end_angle = 360

            directions = np.linspace(start_angle, end_angle, 12)

            start_end_point = 1
            end_end_point = 12

        elif edge_loc % 2 == 0:
            # Ignition is at a corner point
            start_angle = (30 * edge_loc + 120) % 360
            end_angle = (start_angle + 120)

            directions = [
                start_angle,
                start_angle + 19.107,
                start_angle + 30,
                start_angle + 46.102,
                start_angle + 60,
                end_angle - 46.102,
                end_angle - 30,
                end_angle - 19.107,
                end_angle 
            ]

            start_end_point = (edge_loc + 2) % 12 or 12
            end_end_point = (start_end_point + 8) % 12 or 12

        else:
            # Ignition is along an edge
            start_angle = (30 * edge_loc + 90) % 360
            end_angle = (start_angle + 180)

            directions = [
                start_angle,
                start_angle + 30,
                start_angle + 40.893,
                start_angle + 60,
                start_angle + 73.898,
                start_angle + 90,
                end_angle - 73.898,
                end_angle - 60,
                end_angle - 40.893,
                end_angle - 30,
                end_angle 
            ]

            start_end_point = (edge_loc + 1) % 12 or 12
            end_end_point = (12 + (edge_loc - 1)) % 12 or 12

        directions = np.array([direction % 360 for direction in directions])

        if end_end_point < start_end_point:
            self_end_points = np.concatenate([
                np.arange(start_end_point, 13),
                np.arange(1, end_end_point + 1)
            ])

        else:
            self_end_points = np.arange(start_end_point, end_end_point + 1)

        end_points = []
        distances = []

        for end_point in self_end_points:

            idx_diff = np.abs(end_point - edge_loc)

            if idx_diff > 6:
                idx_diff = 12 - idx_diff


            dist = UtilFuncs.get_dist(edge_loc, idx_diff, cell_size)

            distances.append(dist)

            neighbor_locs = SpreadDecomp.self_loc_to_neighbor_loc_mapping[end_point]
            end_points.append(neighbor_locs)

        end_points = tuple(tuple(neighbor_locs) for neighbor_locs in end_points)

        return np.array(directions), np.array(distances), end_points

get_cell_polygons(cells)

Merge cell polygons into minimal covering polygons.

Parameters:

Name Type Description Default
cells List[Cell]

List of Cell objects to convert.

required

Returns:

Type Description
Optional[List[Polygon]]

Optional[List[Polygon]]: List of shapely Polygon objects representing the merged cells, or None if cells is empty.

Source code in embrs/utilities/fire_util.py
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
def get_cell_polygons(cells: List["Cell"]) -> Optional[List[Polygon]]:
    """Merge cell polygons into minimal covering polygons.

    Args:
        cells (List[Cell]): List of Cell objects to convert.

    Returns:
        Optional[List[Polygon]]: List of shapely Polygon objects representing
            the merged cells, or None if cells is empty.
    """
    if not cells:
        return None

    polygons = [cell.polygon for cell in cells]

    merged_polygon = unary_union(polygons)

    if isinstance(merged_polygon, MultiPolygon):
        return list(merged_polygon.geoms)

    return [merged_polygon]

get_dist(edge_loc, idx_diff, cell_size)

Calculate distance from an edge location to an endpoint on the cell boundary.

Used internally for fire spread calculations to determine the distance fire must travel from its current position to reach a cell boundary point.

Parameters:

Name Type Description Default
edge_loc int

Starting edge location index (0 for center, 1-12 for boundary positions where odd=edge midpoints, even=corners).

required
idx_diff int

Absolute difference between edge_loc and target endpoint index (range 1-6 due to hexagon symmetry).

required
cell_size float

Hexagon side length in meters.

required

Returns:

Name Type Description
float float

Distance in meters from edge_loc to the target endpoint.

Source code in embrs/utilities/fire_util.py
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
def get_dist(edge_loc: int, idx_diff: int, cell_size: float) -> float:
    """Calculate distance from an edge location to an endpoint on the cell boundary.

    Used internally for fire spread calculations to determine the distance
    fire must travel from its current position to reach a cell boundary point.

    Args:
        edge_loc (int): Starting edge location index (0 for center, 1-12 for
            boundary positions where odd=edge midpoints, even=corners).
        idx_diff (int): Absolute difference between edge_loc and target endpoint
            index (range 1-6 due to hexagon symmetry).
        cell_size (float): Hexagon side length in meters.

    Returns:
        float: Distance in meters from edge_loc to the target endpoint.
    """
    odd_loc_distance_dict = {
        1: cell_size / 2,
        2: (np.sqrt(3)/2) * cell_size, # Law of sines
        3: (np.sqrt(7)/2) * cell_size, # Law of cosines
        4: (3 * cell_size) / 2,
        5: (np.sqrt(13) * cell_size) / 2, # Law of cosines
        6: np.sqrt(3) * cell_size
    }

    even_loc_distance_dict = {
        2: cell_size,
        3: (np.sqrt(7)/2) * cell_size,
        4: np.sqrt(3) * cell_size,
        5: (np.sqrt(13) * cell_size) / 2,
        6: 2 * cell_size,
    }

    # Handle case where ignition starts at center
    if edge_loc == 0:
        if idx_diff % 2 == 0:
            return cell_size
        else:
            return (np.sqrt(3) * cell_size)/2

    elif edge_loc %  2 == 0:
        return even_loc_distance_dict[idx_diff]

    else:
        return odd_loc_distance_dict[idx_diff]

get_dominant_fuel_type(fuel_map)

Find the most common fuel type in a fuel map.

Parameters:

Name Type Description Default
fuel_map ndarray

2D array of fuel type IDs.

required

Returns:

Name Type Description
int int

Fuel type ID that occurs most frequently.

Source code in embrs/utilities/fire_util.py
321
322
323
324
325
326
327
328
329
330
331
332
def get_dominant_fuel_type(fuel_map: np.ndarray) -> int:
    """Find the most common fuel type in a fuel map.

    Args:
        fuel_map (np.ndarray): 2D array of fuel type IDs.

    Returns:
        int: Fuel type ID that occurs most frequently.
    """
    counts = np.bincount(fuel_map.ravel())

    return np.argmax(counts)

get_ign_parameters(edge_loc, cell_size) cached

Compute fire spread parameters from an ignition point within a cell.

Calculates the spread directions, distances to cell boundary endpoints, and neighbor cell entry points for fire propagating from a given ignition location. Results are cached for performance.

Parameters:

Name Type Description Default
edge_loc int

Ignition location index. 0 for cell center, 1-12 for boundary positions (odd indices are edge midpoints, even indices are corner vertices).

required
cell_size float

Hexagon side length in meters.

required

Returns:

Type Description
Tuple[ndarray, ndarray, tuple]

Tuple containing: - np.ndarray: Spread direction angles in degrees (0-360). - np.ndarray: Distances to each boundary endpoint in meters. - tuple: Nested tuples of (neighbor_edge_loc, neighbor_letter) pairs indicating where fire enters adjacent cells.

Source code in embrs/utilities/fire_util.py
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
@lru_cache
def get_ign_parameters(edge_loc: int, cell_size: float) -> Tuple[np.ndarray, np.ndarray, tuple]:
    """Compute fire spread parameters from an ignition point within a cell.

    Calculates the spread directions, distances to cell boundary endpoints,
    and neighbor cell entry points for fire propagating from a given ignition
    location. Results are cached for performance.

    Args:
        edge_loc (int): Ignition location index. 0 for cell center, 1-12 for
            boundary positions (odd indices are edge midpoints, even indices
            are corner vertices).
        cell_size (float): Hexagon side length in meters.

    Returns:
        Tuple containing:
            - np.ndarray: Spread direction angles in degrees (0-360).
            - np.ndarray: Distances to each boundary endpoint in meters.
            - tuple: Nested tuples of (neighbor_edge_loc, neighbor_letter)
                pairs indicating where fire enters adjacent cells.
    """
    if edge_loc == 0:
        # Ignition is at the center of cell
        start_angle = 30
        end_angle = 360

        directions = np.linspace(start_angle, end_angle, 12)

        start_end_point = 1
        end_end_point = 12

    elif edge_loc % 2 == 0:
        # Ignition is at a corner point
        start_angle = (30 * edge_loc + 120) % 360
        end_angle = (start_angle + 120)

        directions = [
            start_angle,
            start_angle + 19.107,
            start_angle + 30,
            start_angle + 46.102,
            start_angle + 60,
            end_angle - 46.102,
            end_angle - 30,
            end_angle - 19.107,
            end_angle 
        ]

        start_end_point = (edge_loc + 2) % 12 or 12
        end_end_point = (start_end_point + 8) % 12 or 12

    else:
        # Ignition is along an edge
        start_angle = (30 * edge_loc + 90) % 360
        end_angle = (start_angle + 180)

        directions = [
            start_angle,
            start_angle + 30,
            start_angle + 40.893,
            start_angle + 60,
            start_angle + 73.898,
            start_angle + 90,
            end_angle - 73.898,
            end_angle - 60,
            end_angle - 40.893,
            end_angle - 30,
            end_angle 
        ]

        start_end_point = (edge_loc + 1) % 12 or 12
        end_end_point = (12 + (edge_loc - 1)) % 12 or 12

    directions = np.array([direction % 360 for direction in directions])

    if end_end_point < start_end_point:
        self_end_points = np.concatenate([
            np.arange(start_end_point, 13),
            np.arange(1, end_end_point + 1)
        ])

    else:
        self_end_points = np.arange(start_end_point, end_end_point + 1)

    end_points = []
    distances = []

    for end_point in self_end_points:

        idx_diff = np.abs(end_point - edge_loc)

        if idx_diff > 6:
            idx_diff = 12 - idx_diff


        dist = UtilFuncs.get_dist(edge_loc, idx_diff, cell_size)

        distances.append(dist)

        neighbor_locs = SpreadDecomp.self_loc_to_neighbor_loc_mapping[end_point]
        end_points.append(neighbor_locs)

    end_points = tuple(tuple(neighbor_locs) for neighbor_locs in end_points)

    return np.array(directions), np.array(distances), end_points

get_indices_from_xy(x_m, y_m, cell_size, grid_width, grid_height)

Get grid indices for a point in spatial coordinates.

Calculates the (row, col) indices in the cell_grid array for the cell containing the point (x_m, y_m). Does not require a FireSim object.

Parameters:

Name Type Description Default
x_m float

X position in meters.

required
y_m float

Y position in meters.

required
cell_size float

Cell size in meters (hexagon side length).

required
grid_width int

Number of columns in the grid.

required
grid_height int

Number of rows in the grid.

required

Returns:

Type Description
Tuple[int, int]

Tuple[int, int]: (row, col) indices of the cell containing the point.

Raises:

Type Description
ValueError

If the point is outside the grid bounds.

Source code in embrs/utilities/fire_util.py
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
def get_indices_from_xy(x_m: float, y_m: float, cell_size: float, grid_width: int,
                        grid_height: int) -> Tuple[int, int]:
    """Get grid indices for a point in spatial coordinates.

    Calculates the (row, col) indices in the cell_grid array for the cell
    containing the point (x_m, y_m). Does not require a FireSim object.

    Args:
        x_m (float): X position in meters.
        y_m (float): Y position in meters.
        cell_size (float): Cell size in meters (hexagon side length).
        grid_width (int): Number of columns in the grid.
        grid_height (int): Number of rows in the grid.

    Returns:
        Tuple[int, int]: (row, col) indices of the cell containing the point.

    Raises:
        ValueError: If the point is outside the grid bounds.
    """
    row = int(y_m // (cell_size * 1.5))

    if row % 2 == 0:
        col = int(x_m // (cell_size * np.sqrt(3))) + 1
    else:
        col = int((x_m // (cell_size * np.sqrt(3))) - 0.5) + 1

    if col < 0 or row < 0 or row >= grid_height or col >= grid_width:
        msg = (f'Point ({x_m}, {y_m}) is outside the grid. '
            f'Column: {col}, Row: {row}, '
            f'simSize: ({grid_height} , {grid_width})')
        raise ValueError(msg)

    return row, col

get_time_str(time_s, show_sec=False)

Format a time value in seconds as a human-readable string.

Parameters:

Name Type Description Default
time_s int

Time value in seconds.

required
show_sec bool

If True, include seconds in output. Defaults to False.

False

Returns:

Name Type Description
str str

Formatted time string (e.g., "2 h 30 min" or "2 h 30 min 15 s").

Source code in embrs/utilities/fire_util.py
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
def get_time_str(time_s: int, show_sec: bool = False) -> str:
    """Format a time value in seconds as a human-readable string.

    Args:
        time_s (int): Time value in seconds.
        show_sec (bool): If True, include seconds in output. Defaults to False.

    Returns:
        str: Formatted time string (e.g., "2 h 30 min" or "2 h 30 min 15 s").
    """
    hours = int(time_s // 3600)
    minutes = int((time_s % 3600) // 60)

    if show_sec:
        seconds = int((time_s % 3600) % 60)

        if hours > 0:
            result = f"{hours} h {minutes} min {seconds} s"
        elif minutes > 0:
            result = f"{minutes} min {seconds} s"
        else:
            result = f"{seconds} s"
        return result

    if hours > 0:
        result = f"{hours} h {minutes} min"
    else:
        result = f"{minutes} min"
    return result

hexagon_vertices(x, y, s) staticmethod

Calculate vertex positions for a point-up hexagon.

Parameters:

Name Type Description Default
x float

X coordinate of hexagon center in meters.

required
y float

Y coordinate of hexagon center in meters.

required
s float

Side length of hexagon in meters.

required

Returns:

Type Description
List[Tuple[float, float]]

List[Tuple[float, float]]: Six (x, y) vertex coordinates, starting from the top vertex and proceeding clockwise.

Source code in embrs/utilities/fire_util.py
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
@staticmethod
def hexagon_vertices(x: float, y: float, s: float) -> List[Tuple[float, float]]:
    """Calculate vertex positions for a point-up hexagon.

    Args:
        x (float): X coordinate of hexagon center in meters.
        y (float): Y coordinate of hexagon center in meters.
        s (float): Side length of hexagon in meters.

    Returns:
        List[Tuple[float, float]]: Six (x, y) vertex coordinates, starting
            from the top vertex and proceeding clockwise.
    """
    vertices = [
        (x, y + s),
        (x + s * np.sqrt(3) / 2, y + s / 2),
        (x + s * np.sqrt(3) / 2, y - s / 2),
        (x, y - s),
        (x - s * np.sqrt(3) / 2, y - s / 2),
        (x - s * np.sqrt(3) / 2, y + s / 2)
    ]
    return vertices

Action Classes

Suppression action classes for fire control operations.

This module defines action classes that represent discrete fire suppression operations such as setting ignitions, dropping retardant, water drops, and constructing firelines. Actions are meant to be instantiated and then performed on a fire simulation instance.

Classes:

Name Description
- Action

Base class for all actions.

- SetIgnition

Set an ignition at a specified location.

- DropRetardant

Drop fire retardant at a location.

- DropWaterAsRain

Simulate water drop as rainfall.

- DropWaterAsMoistureInc

Increase fuel moisture at a location.

- ConstructFireline

Construct a fireline along a path.

.. autoclass:: Action :members:

.. autoclass:: SetIgnition :members:

.. autoclass:: DropRetardant :members:

.. autoclass:: DropWaterAsRain :members:

.. autoclass:: DropWaterAsMoistureInc :members:

.. autoclass:: ConstructFireline :members:

Action

Base class for all fire suppression actions.

Actions are sortable by time and location for scheduling purposes. Note that the time attribute is for user reference only; actions execute at whatever simulation time they are called, not at their stored time.

Attributes:

Name Type Description
time float

Reference time for the action in seconds.

loc tuple

Location (x, y) of the action in meters.

Source code in embrs/utilities/action.py
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
class Action:
    """Base class for all fire suppression actions.

    Actions are sortable by time and location for scheduling purposes.
    Note that the time attribute is for user reference only; actions execute
    at whatever simulation time they are called, not at their stored time.

    Attributes:
        time (float): Reference time for the action in seconds.
        loc (tuple): Location (x, y) of the action in meters.
    """

    def __init__(self, time: float, x: float, y: float):
        """Initialize an action.

        Args:
            time (float): Reference time for the action in seconds.
            x (float): X location of the action in meters.
            y (float): Y location of the action in meters.
        """
        self.time = time
        self.loc = (x, y)

    def __lt__(self, other) -> bool:
        """Compare actions for sorting by time, then location.

        Args:
            other (Action): Another action to compare against.

        Returns:
            bool: True if this action should come before the other.
        """
        if self.time != other.time:
            return self.time < other.time

        elif self.loc[0] != self.loc[0]:
            return self.loc[0] < self.loc[1]

        elif self.loc[1] != self.loc[1]:
            return self.loc[1] < self.loc[1]

        else:
            return True

__init__(time, x, y)

Initialize an action.

Parameters:

Name Type Description Default
time float

Reference time for the action in seconds.

required
x float

X location of the action in meters.

required
y float

Y location of the action in meters.

required
Source code in embrs/utilities/action.py
52
53
54
55
56
57
58
59
60
61
def __init__(self, time: float, x: float, y: float):
    """Initialize an action.

    Args:
        time (float): Reference time for the action in seconds.
        x (float): X location of the action in meters.
        y (float): Y location of the action in meters.
    """
    self.time = time
    self.loc = (x, y)

__lt__(other)

Compare actions for sorting by time, then location.

Parameters:

Name Type Description Default
other Action

Another action to compare against.

required

Returns:

Name Type Description
bool bool

True if this action should come before the other.

Source code in embrs/utilities/action.py
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
def __lt__(self, other) -> bool:
    """Compare actions for sorting by time, then location.

    Args:
        other (Action): Another action to compare against.

    Returns:
        bool: True if this action should come before the other.
    """
    if self.time != other.time:
        return self.time < other.time

    elif self.loc[0] != self.loc[0]:
        return self.loc[0] < self.loc[1]

    elif self.loc[1] != self.loc[1]:
        return self.loc[1] < self.loc[1]

    else:
        return True

ConstructFireline

Bases: Action

Action to construct a fireline along a path.

Constructs a fireline (fuel break) along the specified line geometry. If construction_rate is None, the fireline is applied instantly. Otherwise, the fireline is constructed progressively at the specified rate over simulation time steps.

Attributes:

Name Type Description
time float

Reference time for the action in seconds.

loc tuple

Starting location (x, y) of the fireline in meters.

line LineString

Shapely LineString defining the fireline path.

width_m float

Width of the fireline in meters.

construction_rate float

Construction rate in meters per second. If None, the fireline is applied instantly.

Source code in embrs/utilities/action.py
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
class ConstructFireline(Action):
    """Action to construct a fireline along a path.

    Constructs a fireline (fuel break) along the specified line geometry.
    If construction_rate is None, the fireline is applied instantly.
    Otherwise, the fireline is constructed progressively at the specified
    rate over simulation time steps.

    Attributes:
        time (float): Reference time for the action in seconds.
        loc (tuple): Starting location (x, y) of the fireline in meters.
        line (LineString): Shapely LineString defining the fireline path.
        width_m (float): Width of the fireline in meters.
        construction_rate (float): Construction rate in meters per second.
            If None, the fireline is applied instantly.
    """

    def __init__(self, time, x, y, line: LineString, width_m: float,
                 construction_rate: float = None):
        """Initialize a construct fireline action.

        Args:
            time (float): Reference time for the action in seconds.
            x (float): X location of the action origin in meters.
            y (float): Y location of the action origin in meters.
            line (LineString): Shapely LineString defining the fireline path.
            width_m (float): Width of the fireline in meters.
            construction_rate (float): Construction rate in meters per second.
                If None, the fireline is applied instantly. Defaults to None.
        """
        super().__init__(time, x, y)

        self.line = line
        self.width_m = width_m
        self.construction_rate = construction_rate

    def perform(self, fire: BaseFireSim):
        """Execute the fireline construction on the fire simulation.

        If construction_rate is None, the entire fireline is applied instantly.
        Otherwise, an active fireline is created that progresses over time.

        Args:
            fire (BaseFireSim): Fire simulation instance to modify.
        """
        fire.construct_fireline(self.line, self.width_m, self.construction_rate)

__init__(time, x, y, line, width_m, construction_rate=None)

Initialize a construct fireline action.

Parameters:

Name Type Description Default
time float

Reference time for the action in seconds.

required
x float

X location of the action origin in meters.

required
y float

Y location of the action origin in meters.

required
line LineString

Shapely LineString defining the fireline path.

required
width_m float

Width of the fireline in meters.

required
construction_rate float

Construction rate in meters per second. If None, the fireline is applied instantly. Defaults to None.

None
Source code in embrs/utilities/action.py
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
def __init__(self, time, x, y, line: LineString, width_m: float,
             construction_rate: float = None):
    """Initialize a construct fireline action.

    Args:
        time (float): Reference time for the action in seconds.
        x (float): X location of the action origin in meters.
        y (float): Y location of the action origin in meters.
        line (LineString): Shapely LineString defining the fireline path.
        width_m (float): Width of the fireline in meters.
        construction_rate (float): Construction rate in meters per second.
            If None, the fireline is applied instantly. Defaults to None.
    """
    super().__init__(time, x, y)

    self.line = line
    self.width_m = width_m
    self.construction_rate = construction_rate

perform(fire)

Execute the fireline construction on the fire simulation.

If construction_rate is None, the entire fireline is applied instantly. Otherwise, an active fireline is created that progresses over time.

Parameters:

Name Type Description Default
fire BaseFireSim

Fire simulation instance to modify.

required
Source code in embrs/utilities/action.py
269
270
271
272
273
274
275
276
277
278
def perform(self, fire: BaseFireSim):
    """Execute the fireline construction on the fire simulation.

    If construction_rate is None, the entire fireline is applied instantly.
    Otherwise, an active fireline is created that progresses over time.

    Args:
        fire (BaseFireSim): Fire simulation instance to modify.
    """
    fire.construct_fireline(self.line, self.width_m, self.construction_rate)

DropRetardant

Bases: Action

Action to drop fire retardant at a location.

Applies long-term fire retardant to the cell at the specified location.

Attributes:

Name Type Description
time float

Reference time for the action in seconds.

loc tuple

Location (x, y) of the drop in meters.

duration_hr float

Duration of retardant effectiveness in hours.

effectiveness float

Effectiveness factor of the retardant (0,1).

Source code in embrs/utilities/action.py
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
class DropRetardant(Action):
    """Action to drop fire retardant at a location.

    Applies long-term fire retardant to the cell at the specified location.

    Attributes:
        time (float): Reference time for the action in seconds.
        loc (tuple): Location (x, y) of the drop in meters.
        duration_hr (float): Duration of retardant effectiveness in hours.
        effectiveness (float): Effectiveness factor of the retardant (0,1).
    """

    def __init__(self, time, x, y, duration_hr: float, effectiveness: float):
        """Initialize a drop retardant action.

        Args:
            time (float): Reference time for the action in seconds.
            x (float): X location of the drop in meters.
            y (float): Y location of the drop in meters.
            duration_hr (float): Duration of retardant effectiveness in hours.
            effectiveness (float): Effectiveness factor of the retardant.
        """
        super().__init__(time, x, y)

        self.duration_hr = duration_hr
        self.effectiveness = effectiveness

    def perform(self, fire: BaseFireSim):
        """Execute the retardant drop on the fire simulation.

        Args:
            fire (BaseFireSim): Fire simulation instance to modify.
        """

        cell = fire.get_cell_from_xy(self.loc[0], self.loc[1], oob_ok=True)
        if cell is not None:
            fire.add_retardant_at_cell(cell)

__init__(time, x, y, duration_hr, effectiveness)

Initialize a drop retardant action.

Parameters:

Name Type Description Default
time float

Reference time for the action in seconds.

required
x float

X location of the drop in meters.

required
y float

Y location of the drop in meters.

required
duration_hr float

Duration of retardant effectiveness in hours.

required
effectiveness float

Effectiveness factor of the retardant.

required
Source code in embrs/utilities/action.py
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def __init__(self, time, x, y, duration_hr: float, effectiveness: float):
    """Initialize a drop retardant action.

    Args:
        time (float): Reference time for the action in seconds.
        x (float): X location of the drop in meters.
        y (float): Y location of the drop in meters.
        duration_hr (float): Duration of retardant effectiveness in hours.
        effectiveness (float): Effectiveness factor of the retardant.
    """
    super().__init__(time, x, y)

    self.duration_hr = duration_hr
    self.effectiveness = effectiveness

perform(fire)

Execute the retardant drop on the fire simulation.

Parameters:

Name Type Description Default
fire BaseFireSim

Fire simulation instance to modify.

required
Source code in embrs/utilities/action.py
147
148
149
150
151
152
153
154
155
156
def perform(self, fire: BaseFireSim):
    """Execute the retardant drop on the fire simulation.

    Args:
        fire (BaseFireSim): Fire simulation instance to modify.
    """

    cell = fire.get_cell_from_xy(self.loc[0], self.loc[1], oob_ok=True)
    if cell is not None:
        fire.add_retardant_at_cell(cell)

DropWaterAsMoistureInc

Bases: Action

Action to increase fuel moisture at a location.

Directly increases the fuel moisture content of the cell at the specified location.

Attributes:

Name Type Description
time float

Reference time for the action in seconds.

loc tuple

Location (x, y) of the action in meters.

moisture_inc float

Moisture content increase as a fraction.

Source code in embrs/utilities/action.py
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
class DropWaterAsMoistureInc(Action):
    """Action to increase fuel moisture at a location.

    Directly increases the fuel moisture content of the cell at the
    specified location.

    Attributes:
        time (float): Reference time for the action in seconds.
        loc (tuple): Location (x, y) of the action in meters.
        moisture_inc (float): Moisture content increase as a fraction.
    """

    def __init__(self, time, x, y, moisture_inc: float):
        """Initialize a moisture increase action.

        Args:
            time (float): Reference time for the action in seconds.
            x (float): X location of the action in meters.
            y (float): Y location of the action in meters.
            moisture_inc (float): Moisture content increase as a fraction.
        """
        super().__init__(time, x, y)

        self.moisture_inc = moisture_inc

    def perform(self, fire: BaseFireSim):
        """Execute the moisture increase on the fire simulation.

        Args:
            fire (BaseFireSim): Fire simulation instance to modify.
        """
        cell = fire.get_cell_from_xy(self.loc[0], self.loc[1], oob_ok=True)
        if cell is not None:
            fire.water_drop_at_cell_as_moisture_bump(cell, self.moisture_inc)

__init__(time, x, y, moisture_inc)

Initialize a moisture increase action.

Parameters:

Name Type Description Default
time float

Reference time for the action in seconds.

required
x float

X location of the action in meters.

required
y float

Y location of the action in meters.

required
moisture_inc float

Moisture content increase as a fraction.

required
Source code in embrs/utilities/action.py
209
210
211
212
213
214
215
216
217
218
219
220
def __init__(self, time, x, y, moisture_inc: float):
    """Initialize a moisture increase action.

    Args:
        time (float): Reference time for the action in seconds.
        x (float): X location of the action in meters.
        y (float): Y location of the action in meters.
        moisture_inc (float): Moisture content increase as a fraction.
    """
    super().__init__(time, x, y)

    self.moisture_inc = moisture_inc

perform(fire)

Execute the moisture increase on the fire simulation.

Parameters:

Name Type Description Default
fire BaseFireSim

Fire simulation instance to modify.

required
Source code in embrs/utilities/action.py
222
223
224
225
226
227
228
229
230
def perform(self, fire: BaseFireSim):
    """Execute the moisture increase on the fire simulation.

    Args:
        fire (BaseFireSim): Fire simulation instance to modify.
    """
    cell = fire.get_cell_from_xy(self.loc[0], self.loc[1], oob_ok=True)
    if cell is not None:
        fire.water_drop_at_cell_as_moisture_bump(cell, self.moisture_inc)

DropWaterAsRain

Bases: Action

Action to simulate water drop as rainfall at a location.

Models water application as equivalent rainfall depth to affect fuel moisture calculations.

Attributes:

Name Type Description
time float

Reference time for the action in seconds.

loc tuple

Location (x, y) of the drop in meters.

water_depth_cm float

Equivalent rainfall depth in centimeters.

Source code in embrs/utilities/action.py
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
class DropWaterAsRain(Action):
    """Action to simulate water drop as rainfall at a location.

    Models water application as equivalent rainfall depth to affect
    fuel moisture calculations.

    Attributes:
        time (float): Reference time for the action in seconds.
        loc (tuple): Location (x, y) of the drop in meters.
        water_depth_cm (float): Equivalent rainfall depth in centimeters.
    """

    def __init__(self, time, x, y, water_depth_cm: float = 0.0):
        """Initialize a water drop (as rain) action.

        Args:
            time (float): Reference time for the action in seconds.
            x (float): X location of the drop in meters.
            y (float): Y location of the drop in meters.
            water_depth_cm (float): Equivalent rainfall depth in centimeters.
                Defaults to 0.0.
        """
        super().__init__(time, x, y)

        self.water_depth_cm = water_depth_cm

    def perform(self, fire: BaseFireSim):
        """Execute the water drop on the fire simulation.

        Args:
            fire (BaseFireSim): Fire simulation instance to modify.
        """

        cell = fire.get_cell_from_xy(self.loc[0], self.loc[1], oob_ok=True)
        if cell is not None:
            fire.water_drop_at_cell_as_rain(cell, self.water_depth_cm)

__init__(time, x, y, water_depth_cm=0.0)

Initialize a water drop (as rain) action.

Parameters:

Name Type Description Default
time float

Reference time for the action in seconds.

required
x float

X location of the drop in meters.

required
y float

Y location of the drop in meters.

required
water_depth_cm float

Equivalent rainfall depth in centimeters. Defaults to 0.0.

0.0
Source code in embrs/utilities/action.py
171
172
173
174
175
176
177
178
179
180
181
182
183
def __init__(self, time, x, y, water_depth_cm: float = 0.0):
    """Initialize a water drop (as rain) action.

    Args:
        time (float): Reference time for the action in seconds.
        x (float): X location of the drop in meters.
        y (float): Y location of the drop in meters.
        water_depth_cm (float): Equivalent rainfall depth in centimeters.
            Defaults to 0.0.
    """
    super().__init__(time, x, y)

    self.water_depth_cm = water_depth_cm

perform(fire)

Execute the water drop on the fire simulation.

Parameters:

Name Type Description Default
fire BaseFireSim

Fire simulation instance to modify.

required
Source code in embrs/utilities/action.py
185
186
187
188
189
190
191
192
193
194
def perform(self, fire: BaseFireSim):
    """Execute the water drop on the fire simulation.

    Args:
        fire (BaseFireSim): Fire simulation instance to modify.
    """

    cell = fire.get_cell_from_xy(self.loc[0], self.loc[1], oob_ok=True)
    if cell is not None:
        fire.water_drop_at_cell_as_rain(cell, self.water_depth_cm)

SetIgnition

Bases: Action

Action to set an ignition at a specified location.

When performed, ignites the cell containing the specified (x, y) location.

Attributes:

Name Type Description
time float

Reference time for the action in seconds.

loc tuple

Location (x, y) of the ignition in meters.

Source code in embrs/utilities/action.py
 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
class SetIgnition(Action):
    """Action to set an ignition at a specified location.

    When performed, ignites the cell containing the specified (x, y) location.

    Attributes:
        time (float): Reference time for the action in seconds.
        loc (tuple): Location (x, y) of the ignition in meters.
    """

    def __init__(self, time: float, x: float, y: float):
        """Initialize a set ignition action.

        Args:
            time (float): Reference time for the action in seconds.
            x (float): X location of the ignition in meters.
            y (float): Y location of the ignition in meters.
        """
        super().__init__(time, x, y)

    def perform(self, fire: BaseFireSim):
        """Execute the ignition action on the fire simulation.

        The ignition occurs at the current simulation time, not the stored
        time attribute.

        Args:
            fire (BaseFireSim): Fire simulation instance to modify.
        """

        cell = fire.get_cell_from_xy(self.loc[0], self.loc[1], oob_ok=True)
        if cell is not None:
            fire.set_ignition_at_cell(cell)

__init__(time, x, y)

Initialize a set ignition action.

Parameters:

Name Type Description Default
time float

Reference time for the action in seconds.

required
x float

X location of the ignition in meters.

required
y float

Y location of the ignition in meters.

required
Source code in embrs/utilities/action.py
 95
 96
 97
 98
 99
100
101
102
103
def __init__(self, time: float, x: float, y: float):
    """Initialize a set ignition action.

    Args:
        time (float): Reference time for the action in seconds.
        x (float): X location of the ignition in meters.
        y (float): Y location of the ignition in meters.
    """
    super().__init__(time, x, y)

perform(fire)

Execute the ignition action on the fire simulation.

The ignition occurs at the current simulation time, not the stored time attribute.

Parameters:

Name Type Description Default
fire BaseFireSim

Fire simulation instance to modify.

required
Source code in embrs/utilities/action.py
105
106
107
108
109
110
111
112
113
114
115
116
117
def perform(self, fire: BaseFireSim):
    """Execute the ignition action on the fire simulation.

    The ignition occurs at the current simulation time, not the stored
    time attribute.

    Args:
        fire (BaseFireSim): Fire simulation instance to modify.
    """

    cell = fire.get_cell_from_xy(self.loc[0], self.loc[1], oob_ok=True)
    if cell is not None:
        fire.set_ignition_at_cell(cell)

Logger Schemas

Data schemas for logged simulation entries.

This module defines dataclass schemas for various log entry types used by the Logger to record simulation state over time.

Classes:

Name Description
- CellLogEntry

Schema for cell state log entries.

- AgentLogEntry

Schema for agent position log entries.

- ActionsEntry

Schema for suppression action log entries.

- PredictionEntry

Schema for fire prediction log entries.

.. autoclass:: CellLogEntry :members:

.. autoclass:: AgentLogEntry :members:

.. autoclass:: ActionsEntry :members:

.. autoclass:: PredictionEntry :members:

ActionsEntry dataclass

Log entry for a suppression action at a simulation timestamp.

Attributes:

Name Type Description
timestamp int

Simulation time in seconds.

action_type str

Type of action ('long_term_retardant', 'short_term_suppressant', or 'active_fireline').

x_coords List[float]

X coordinates of action geometry in meters.

y_coords List[float]

Y coordinates of action geometry in meters.

width float

Width of action (for firelines) in meters.

effectiveness List[float]

Effectiveness values for the action.

Source code in embrs/utilities/logger_schemas.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
@dataclass
class ActionsEntry:
    """Log entry for a suppression action at a simulation timestamp.

    Attributes:
        timestamp (int): Simulation time in seconds.
        action_type (str): Type of action ('long_term_retardant',
            'short_term_suppressant', or 'active_fireline').
        x_coords (List[float]): X coordinates of action geometry in meters.
        y_coords (List[float]): Y coordinates of action geometry in meters.
        width (float): Width of action (for firelines) in meters.
        effectiveness (List[float]): Effectiveness values for the action.
    """

    timestamp: int
    action_type: Literal['long_term_retardant', 'short_term_suppressant', 'active_fireline']
    x_coords: List[float] = None
    y_coords: List[float] = None
    width: float = None
    effectiveness: List[float] = None

    def to_dict(self) -> dict:
        """Convert entry to dictionary for serialization."""
        return asdict(self)

to_dict()

Convert entry to dictionary for serialization.

Source code in embrs/utilities/logger_schemas.py
131
132
133
def to_dict(self) -> dict:
    """Convert entry to dictionary for serialization."""
    return asdict(self)

AgentLogEntry dataclass

Log entry for agent position at a simulation timestamp.

Attributes:

Name Type Description
timestamp int

Simulation time in seconds.

id int

Unique agent identifier.

label str

Agent display label.

x float

Agent x position in meters.

y float

Agent y position in meters.

marker str

Matplotlib marker style.

color str

Matplotlib color string.

Source code in embrs/utilities/logger_schemas.py
 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
@dataclass
class AgentLogEntry:
    """Log entry for agent position at a simulation timestamp.

    Attributes:
        timestamp (int): Simulation time in seconds.
        id (int): Unique agent identifier.
        label (str): Agent display label.
        x (float): Agent x position in meters.
        y (float): Agent y position in meters.
        marker (str): Matplotlib marker style.
        color (str): Matplotlib color string.
    """

    timestamp: int
    id: int
    label: str
    x: float
    y: float
    marker: str
    color: str

    def to_dict(self) -> dict:
        """Convert entry to dictionary for serialization."""
        return asdict(self)

to_dict()

Convert entry to dictionary for serialization.

Source code in embrs/utilities/logger_schemas.py
105
106
107
def to_dict(self) -> dict:
    """Convert entry to dictionary for serialization."""
    return asdict(self)

CellLogEntry dataclass

Log entry for cell state at a simulation timestamp.

Attributes:

Name Type Description
timestamp int

Simulation time in seconds.

id int

Unique cell identifier.

x float

Cell center x position in meters.

y float

Cell center y position in meters.

fuel int

Fuel model type ID.

state int

Cell state (0=BURNT, 1=FUEL, 2=FIRE).

crown_state int

Crown fire status (0=NONE, 1=PASSIVE, 2=ACTIVE).

w_n_dead float

Net dead fuel loading.

w_n_dead_start float

Initial dead fuel loading.

w_n_live float

Net live fuel loading.

dfm_1hr float

1-hour dead fuel moisture content (fraction).

dfm_10hr float

10-hour dead fuel moisture content (fraction).

dfm_100hr float

100-hour dead fuel moisture content (fraction).

ros float

Rate of spread in m/s.

I_ss float

Steady-state fireline intensity. btu/ft/min

wind_speed float

Wind speed in m/s.

wind_dir float

Wind direction in degrees.

retardant bool

Whether retardant is applied to this cell.

arrival_time float

Time when fire arrived at this cell in seconds.

Source code in embrs/utilities/logger_schemas.py
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
@dataclass
class CellLogEntry:
    """Log entry for cell state at a simulation timestamp.

    Attributes:
        timestamp (int): Simulation time in seconds.
        id (int): Unique cell identifier.
        x (float): Cell center x position in meters.
        y (float): Cell center y position in meters.
        fuel (int): Fuel model type ID.
        state (int): Cell state (0=BURNT, 1=FUEL, 2=FIRE).
        crown_state (int): Crown fire status (0=NONE, 1=PASSIVE, 2=ACTIVE).
        w_n_dead (float): Net dead fuel loading.
        w_n_dead_start (float): Initial dead fuel loading.
        w_n_live (float): Net live fuel loading.
        dfm_1hr (float): 1-hour dead fuel moisture content (fraction).
        dfm_10hr (float): 10-hour dead fuel moisture content (fraction).
        dfm_100hr (float): 100-hour dead fuel moisture content (fraction).
        ros (float): Rate of spread in m/s.
        I_ss (float): Steady-state fireline intensity. btu/ft/min
        wind_speed (float): Wind speed in m/s.
        wind_dir (float): Wind direction in degrees.
        retardant (bool): Whether retardant is applied to this cell.
        arrival_time (float): Time when fire arrived at this cell in seconds.
    """

    timestamp: int
    id: int
    x: float
    y: float
    fuel: int
    state: int
    crown_state: int
    w_n_dead: float
    w_n_dead_start: float
    w_n_live: float
    dfm_1hr: float
    dfm_10hr: float
    dfm_100hr: float
    ros: float
    I_ss: float
    wind_speed: float
    wind_dir: float
    retardant: bool
    arrival_time: float
    suppression_count: int = 0
    n_disabled_locs: int = 0

    def to_dict(self) -> dict:
        """Convert entry to dictionary for serialization."""
        return asdict(self)

to_dict()

Convert entry to dictionary for serialization.

Source code in embrs/utilities/logger_schemas.py
78
79
80
def to_dict(self) -> dict:
    """Convert entry to dictionary for serialization."""
    return asdict(self)

PredictionEntry dataclass

Log entry for a fire spread prediction.

Attributes:

Name Type Description
timestamp int

Simulation time when prediction was made in seconds.

prediction dict

Prediction data mapping time to cell positions.

Source code in embrs/utilities/logger_schemas.py
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
@dataclass
class PredictionEntry:
    """Log entry for a fire spread prediction.

    Attributes:
        timestamp (int): Simulation time when prediction was made in seconds.
        prediction (dict): Prediction data mapping time to cell positions.
    """

    timestamp: int
    prediction: Dict[int, Tuple[int, int]]

    def to_dict(self) -> dict:
        """Convert entry to dictionary with JSON-serializable prediction."""
        serializable_pred = {str(k): list(v) for k, v in self.prediction.items()}
        return {
            "timestamp": self.timestamp,
            "prediction": json.dumps(serializable_pred)
        }

to_dict()

Convert entry to dictionary with JSON-serializable prediction.

Source code in embrs/utilities/logger_schemas.py
148
149
150
151
152
153
154
def to_dict(self) -> dict:
    """Convert entry to dictionary with JSON-serializable prediction."""
    serializable_pred = {str(k): list(v) for k, v in self.prediction.items()}
    return {
        "timestamp": self.timestamp,
        "prediction": json.dumps(serializable_pred)
    }

Unit Conversions

Unit conversion functions for fire modeling calculations.

This module provides conversion functions between imperial and metric units commonly used in fire behavior modeling (Rothermel equations use imperial units internally).

Functions are organized by conversion type: temperature, length, speed, fuel loading, heat flux, and heat content.

BTU_ft2_min_to_kW_m2(f_btu_ft2_min)

Convert heat flux from BTU/(ft^2*min) to kW/m^2.

Parameters:

Name Type Description Default
f_btu_ft2_min float

Heat flux in BTU/(ft^2*min).

required

Returns:

Name Type Description
float float

Heat flux in kW/m^2.

Source code in embrs/utilities/unit_conversions.py
220
221
222
223
224
225
226
227
228
229
def BTU_ft2_min_to_kW_m2(f_btu_ft2_min: float) -> float:
    """Convert heat flux from BTU/(ft^2*min) to kW/m^2.

    Args:
        f_btu_ft2_min (float): Heat flux in BTU/(ft^2*min).

    Returns:
        float: Heat flux in kW/m^2.
    """
    return f_btu_ft2_min * _BTU_FT2_MIN_TO_KW_M2

BTU_ft_min_to_kW_m(f_btu_ft_min)

Convert fireline intensity from BTU/(ft*min) to kW/m.

Parameters:

Name Type Description Default
f_btu_ft_min float

Fireline intensity in BTU/(ft*min).

required

Returns:

Name Type Description
float float

Fireline intensity in kW/m.

Source code in embrs/utilities/unit_conversions.py
232
233
234
235
236
237
238
239
240
241
def BTU_ft_min_to_kW_m(f_btu_ft_min: float) -> float:
    """Convert fireline intensity from BTU/(ft*min) to kW/m.

    Args:
        f_btu_ft_min (float): Fireline intensity in BTU/(ft*min).

    Returns:
        float: Fireline intensity in kW/m.
    """
    return f_btu_ft_min * _BTU_FT_MIN_TO_KW_M

BTU_ft_min_to_kcal_s_m(f_btu_ft_min)

Convert fireline intensity from BTU/(ftmin) to kcal/(sm).

Parameters:

Name Type Description Default
f_btu_ft_min float

Fireline intensity in BTU/(ft*min).

required

Returns:

Name Type Description
float float

Fireline intensity in kcal/(s*m).

Source code in embrs/utilities/unit_conversions.py
244
245
246
247
248
249
250
251
252
253
def BTU_ft_min_to_kcal_s_m(f_btu_ft_min: float) -> float:
    """Convert fireline intensity from BTU/(ft*min) to kcal/(s*m).

    Args:
        f_btu_ft_min (float): Fireline intensity in BTU/(ft*min).

    Returns:
        float: Fireline intensity in kcal/(s*m).
    """
    return f_btu_ft_min * _BTU_FT_MIN_TO_KCAL_S_M

BTU_lb_to_cal_g(f_btu_lb)

Convert heat content from BTU/lb to cal/g.

Parameters:

Name Type Description Default
f_btu_lb float

Heat content in BTU/lb.

required

Returns:

Name Type Description
float float

Heat content in cal/g.

Source code in embrs/utilities/unit_conversions.py
272
273
274
275
276
277
278
279
280
281
def BTU_lb_to_cal_g(f_btu_lb: float) -> float:
    """Convert heat content from BTU/lb to cal/g.

    Args:
        f_btu_lb (float): Heat content in BTU/lb.

    Returns:
        float: Heat content in cal/g.
    """
    return f_btu_lb * _BTU_LB_TO_CAL_G

F_to_C(f_f)

Convert temperature from Fahrenheit to Celsius.

Parameters:

Name Type Description Default
f_f float

Temperature in degrees Fahrenheit.

required

Returns:

Name Type Description
float float

Temperature in degrees Celsius.

Source code in embrs/utilities/unit_conversions.py
48
49
50
51
52
53
54
55
56
57
def F_to_C(f_f: float) -> float:
    """Convert temperature from Fahrenheit to Celsius.

    Args:
        f_f (float): Temperature in degrees Fahrenheit.

    Returns:
        float: Temperature in degrees Celsius.
    """
    return (5.0 / 9.0) * (f_f - 32.0)

KiSq_to_Lbsft2(f_kisq)

Convert fuel loading from kg/m^2 to lb/ft^2.

Parameters:

Name Type Description Default
f_kisq float

Fuel loading in kg/m^2.

required

Returns:

Name Type Description
float float

Fuel loading in lb/ft^2.

Source code in embrs/utilities/unit_conversions.py
156
157
158
159
160
161
162
163
164
165
def KiSq_to_Lbsft2(f_kisq: float) -> float:
    """Convert fuel loading from kg/m^2 to lb/ft^2.

    Args:
        f_kisq (float): Fuel loading in kg/m^2.

    Returns:
        float: Fuel loading in lb/ft^2.
    """
    return f_kisq * _KISQ_TO_LBSFT2

KiSq_to_TPA(f_kisq)

Convert fuel loading from kg/m^2 to tons per acre.

Parameters:

Name Type Description Default
f_kisq float

Fuel loading in kg/m^2.

required

Returns:

Name Type Description
float float

Fuel loading in tons per acre.

Source code in embrs/utilities/unit_conversions.py
204
205
206
207
208
209
210
211
212
213
def KiSq_to_TPA(f_kisq: float) -> float:
    """Convert fuel loading from kg/m^2 to tons per acre.

    Args:
        f_kisq (float): Fuel loading in kg/m^2.

    Returns:
        float: Fuel loading in tons per acre.
    """
    return f_kisq * _KISQ_TO_TPA

Lbsft2_to_KiSq(f_libsft2)

Convert fuel loading from lb/ft^2 to kg/m^2.

Parameters:

Name Type Description Default
f_libsft2 float

Fuel loading in lb/ft^2.

required

Returns:

Name Type Description
float float

Fuel loading in kg/m^2.

Source code in embrs/utilities/unit_conversions.py
144
145
146
147
148
149
150
151
152
153
def Lbsft2_to_KiSq(f_libsft2: float) -> float:
    """Convert fuel loading from lb/ft^2 to kg/m^2.

    Args:
        f_libsft2 (float): Fuel loading in lb/ft^2.

    Returns:
        float: Fuel loading in kg/m^2.
    """
    return f_libsft2 * _LBSFT2_TO_KISQ

Lbsft2_to_TPA(f_lbsft2)

Convert fuel loading from lb/ft^2 to tons per acre.

Parameters:

Name Type Description Default
f_lbsft2 float

Fuel loading in lb/ft^2.

required

Returns:

Name Type Description
float float

Fuel loading in tons per acre.

Source code in embrs/utilities/unit_conversions.py
192
193
194
195
196
197
198
199
200
201
def Lbsft2_to_TPA(f_lbsft2: float) -> float:
    """Convert fuel loading from lb/ft^2 to tons per acre.

    Args:
        f_lbsft2 (float): Fuel loading in lb/ft^2.

    Returns:
        float: Fuel loading in tons per acre.
    """
    return f_lbsft2 * _LBSFT2_TO_TPA

TPA_to_KiSq(f_tpa)

Convert fuel loading from tons per acre to kg/m^2.

Parameters:

Name Type Description Default
f_tpa float

Fuel loading in tons per acre.

required

Returns:

Name Type Description
float float

Fuel loading in kg/m^2.

Source code in embrs/utilities/unit_conversions.py
168
169
170
171
172
173
174
175
176
177
def TPA_to_KiSq(f_tpa: float) -> float:
    """Convert fuel loading from tons per acre to kg/m^2.

    Args:
        f_tpa (float): Fuel loading in tons per acre.

    Returns:
        float: Fuel loading in kg/m^2.
    """
    return f_tpa / _TPA_TO_KISQ_DIVISOR

TPA_to_Lbsft2(f_tpa)

Convert fuel loading from tons per acre to lb/ft^2.

Parameters:

Name Type Description Default
f_tpa float

Fuel loading in tons per acre.

required

Returns:

Name Type Description
float float

Fuel loading in lb/ft^2.

Source code in embrs/utilities/unit_conversions.py
180
181
182
183
184
185
186
187
188
189
def TPA_to_Lbsft2(f_tpa: float) -> float:
    """Convert fuel loading from tons per acre to lb/ft^2.

    Args:
        f_tpa (float): Fuel loading in tons per acre.

    Returns:
        float: Fuel loading in lb/ft^2.
    """
    return f_tpa * _TPA_TO_LBSFT2

cal_g_to_BTU_lb(f_cal_g)

Convert heat content from cal/g to BTU/lb.

Parameters:

Name Type Description Default
f_cal_g float

Heat content in cal/g.

required

Returns:

Name Type Description
float float

Heat content in BTU/lb.

Source code in embrs/utilities/unit_conversions.py
260
261
262
263
264
265
266
267
268
269
def cal_g_to_BTU_lb(f_cal_g: float) -> float:
    """Convert heat content from cal/g to BTU/lb.

    Args:
        f_cal_g (float): Heat content in cal/g.

    Returns:
        float: Heat content in BTU/lb.
    """
    return f_cal_g * _CAL_G_TO_BTU_LB

ft_min_to_m_s(f_ft_min)

Convert speed from feet per minute to meters per second.

Parameters:

Name Type Description Default
f_ft_min float

Speed in ft/min.

required

Returns:

Name Type Description
float float

Speed in m/s.

Source code in embrs/utilities/unit_conversions.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def ft_min_to_m_s(f_ft_min: float) -> float:
    """Convert speed from feet per minute to meters per second.

    Args:
        f_ft_min (float): Speed in ft/min.

    Returns:
        float: Speed in m/s.
    """
    return f_ft_min * _FT_MIN_TO_M_S

ft_min_to_mph(f_ft_min)

Convert speed from feet per minute to miles per hour.

Parameters:

Name Type Description Default
f_ft_min float

Speed in ft/min.

required

Returns:

Name Type Description
float float

Speed in mph.

Source code in embrs/utilities/unit_conversions.py
116
117
118
119
120
121
122
123
124
125
def ft_min_to_mph(f_ft_min: float) -> float:
    """Convert speed from feet per minute to miles per hour.

    Args:
        f_ft_min (float): Speed in ft/min.

    Returns:
        float: Speed in mph.
    """
    return f_ft_min * _FT_MIN_TO_MPH

ft_to_m(f_ft)

Convert length from feet to meters.

Parameters:

Name Type Description Default
f_ft float

Length in feet.

required

Returns:

Name Type Description
float float

Length in meters.

Source code in embrs/utilities/unit_conversions.py
76
77
78
79
80
81
82
83
84
85
def ft_to_m(f_ft: float) -> float:
    """Convert length from feet to meters.

    Args:
        f_ft (float): Length in feet.

    Returns:
        float: Length in meters.
    """
    return f_ft * _FT_TO_M

m_s_to_ft_min(m_s)

Convert speed from meters per second to feet per minute.

Parameters:

Name Type Description Default
m_s float

Speed in m/s.

required

Returns:

Name Type Description
float float

Speed in ft/min.

Source code in embrs/utilities/unit_conversions.py
104
105
106
107
108
109
110
111
112
113
def m_s_to_ft_min(m_s: float) -> float:
    """Convert speed from meters per second to feet per minute.

    Args:
        m_s (float): Speed in m/s.

    Returns:
        float: Speed in ft/min.
    """
    return m_s * _M_S_TO_FT_MIN

m_to_ft(f_m)

Convert length from meters to feet.

Parameters:

Name Type Description Default
f_m float

Length in meters.

required

Returns:

Name Type Description
float float

Length in feet.

Source code in embrs/utilities/unit_conversions.py
64
65
66
67
68
69
70
71
72
73
def m_to_ft(f_m: float) -> float:
    """Convert length from meters to feet.

    Args:
        f_m (float): Length in meters.

    Returns:
        float: Length in feet.
    """
    return f_m * _M_TO_FT

mph_to_ft_min(f_mph)

Convert speed from miles per hour to feet per minute.

Parameters:

Name Type Description Default
f_mph float

Speed in mph.

required

Returns:

Name Type Description
float float

Speed in ft/min.

Source code in embrs/utilities/unit_conversions.py
128
129
130
131
132
133
134
135
136
137
def mph_to_ft_min(f_mph: float) -> float:
    """Convert speed from miles per hour to feet per minute.

    Args:
        f_mph (float): Speed in mph.

    Returns:
        float: Speed in ft/min.
    """
    return f_mph * _MPH_TO_FT_MIN

Numba Utilities

Numba JIT compilation utilities for EMBRS.

This module provides configuration and helper utilities for Numba JIT compilation used in performance-critical sections of the EMBRS codebase.

Environment Variables

EMBRS_DISABLE_JIT: Set to '1' to disable JIT compilation globally. Useful for debugging or testing without JIT overhead. NUMBA_DISABLE_JIT: Numba's built-in flag, also respected.

Usage

In modules that use JIT-compiled functions:

from embrs.utilities.numba_utils import jit_if_enabled, NUMBA_AVAILABLE

@jit_if_enabled(nopython=True, cache=True) def my_hot_function(x, y): # Numerical computation return x + y

Check if JIT is available:

if NUMBA_AVAILABLE: # Use JIT-optimized path pass else: # Fallback to pure Python pass

get_numba_status()

Get information about Numba availability and configuration.

Returns:

Name Type Description
dict dict

Dictionary containing: - available: bool, whether Numba is installed - version: str or None, Numba version if available - jit_enabled: bool, whether JIT compilation is enabled - disable_jit_env: bool, whether EMBRS_DISABLE_JIT is set

Source code in embrs/utilities/numba_utils.py
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
def get_numba_status() -> dict:
    """Get information about Numba availability and configuration.

    Returns:
        dict: Dictionary containing:
            - available: bool, whether Numba is installed
            - version: str or None, Numba version if available
            - jit_enabled: bool, whether JIT compilation is enabled
            - disable_jit_env: bool, whether EMBRS_DISABLE_JIT is set
    """
    return {
        'available': NUMBA_AVAILABLE,
        'version': NUMBA_VERSION,
        'jit_enabled': NUMBA_AVAILABLE and not DISABLE_JIT,
        'disable_jit_env': DISABLE_JIT,
    }

get_prange()

Get the appropriate parallel range function.

Returns:

Name Type Description
type type

numba.prange if available and JIT enabled, else range.

Source code in embrs/utilities/numba_utils.py
152
153
154
155
156
157
158
159
160
def get_prange() -> type:
    """Get the appropriate parallel range function.

    Returns:
        type: numba.prange if available and JIT enabled, else range.
    """
    if NUMBA_AVAILABLE and not DISABLE_JIT:
        return prange
    return range

jit_if_enabled(**jit_kwargs)

Decorator that applies Numba JIT if available and enabled.

This decorator wraps functions with Numba's @jit decorator when Numba is available and JIT is not disabled. If Numba is unavailable or JIT is disabled, the function is returned unchanged.

Parameters:

Name Type Description Default
**jit_kwargs Any

Keyword arguments to pass to numba.jit. Common options: - nopython=True: Compile in nopython mode (faster) - cache=True: Cache compiled functions to disk - parallel=True: Enable automatic parallelization - fastmath=True: Use fast math optimizations

{}

Returns:

Name Type Description
Callable Callable

Decorated function (JIT-compiled if enabled, else unchanged).

Example

@jit_if_enabled(nopython=True, cache=True) def compute_moisture(w, t, s, params): # Numerical computation result = 0.0 for i in range(len(w)): result += w[i] * t[i] return result

Source code in embrs/utilities/numba_utils.py
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
def jit_if_enabled(**jit_kwargs: Any) -> Callable:
    """Decorator that applies Numba JIT if available and enabled.

    This decorator wraps functions with Numba's @jit decorator when Numba
    is available and JIT is not disabled. If Numba is unavailable or JIT
    is disabled, the function is returned unchanged.

    Args:
        **jit_kwargs: Keyword arguments to pass to numba.jit.
                      Common options:
                      - nopython=True: Compile in nopython mode (faster)
                      - cache=True: Cache compiled functions to disk
                      - parallel=True: Enable automatic parallelization
                      - fastmath=True: Use fast math optimizations

    Returns:
        Callable: Decorated function (JIT-compiled if enabled, else unchanged).

    Example:
        @jit_if_enabled(nopython=True, cache=True)
        def compute_moisture(w, t, s, params):
            # Numerical computation
            result = 0.0
            for i in range(len(w)):
                result += w[i] * t[i]
            return result
    """
    def decorator(func: Callable) -> Callable:
        if NUMBA_AVAILABLE and not DISABLE_JIT:
            return jit(**jit_kwargs)(func)
        else:
            return func
    return decorator

njit_if_enabled(**jit_kwargs)

Decorator that applies Numba njit if available and enabled.

Equivalent to jit_if_enabled(nopython=True, **jit_kwargs). Use this for functions that must run in nopython mode.

Parameters:

Name Type Description Default
**jit_kwargs Any

Keyword arguments to pass to numba.njit.

{}

Returns:

Name Type Description
Callable Callable

Decorated function (JIT-compiled if enabled, else unchanged).

Source code in embrs/utilities/numba_utils.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
def njit_if_enabled(**jit_kwargs: Any) -> Callable:
    """Decorator that applies Numba njit if available and enabled.

    Equivalent to jit_if_enabled(nopython=True, **jit_kwargs).
    Use this for functions that must run in nopython mode.

    Args:
        **jit_kwargs: Keyword arguments to pass to numba.njit.

    Returns:
        Callable: Decorated function (JIT-compiled if enabled, else unchanged).
    """
    def decorator(func: Callable) -> Callable:
        if NUMBA_AVAILABLE and not DISABLE_JIT:
            return njit(**jit_kwargs)(func)
        else:
            return func
    return decorator

warmup_jit_cache()

Warm up JIT-compiled functions to avoid first-call latency.

This function can be called during application startup to pre-compile JIT-decorated functions. This moves the compilation overhead from the first simulation step to the initialization phase.

Call this after all JIT-decorated functions are defined.

Source code in embrs/utilities/numba_utils.py
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
def warmup_jit_cache() -> None:
    """Warm up JIT-compiled functions to avoid first-call latency.

    This function can be called during application startup to pre-compile
    JIT-decorated functions. This moves the compilation overhead from the
    first simulation step to the initialization phase.

    Call this after all JIT-decorated functions are defined.
    """
    if not NUMBA_AVAILABLE or DISABLE_JIT:
        return

    # Import modules that contain JIT-compiled functions
    # This triggers compilation if cache=True is not set
    try:
        from embrs.models import dead_fuel_moisture
        # Add other modules with JIT functions here as they are implemented
    except ImportError:
        pass