Source code for firebench.ros_models.surface_for_urban

import numpy as np
from pint import Quantity

from ..tools.check_data_quality import extract_magnitudes
from ..tools.input_info import ParameterType
from ..tools.namespace import StandardVariableNames as svn
from ..tools.rate_of_spread_model import RateOfSpreadModel
from ..tools.units import ureg


[docs] class Hamada_1(RateOfSpreadModel): """ A class to represent the Hamada's model for urban fire spread rate calculation in its version 1. This class provides metadata for various fuel properties and a static method to compute the rate of spread (ROS) of fire using the Hamada's model. The metadata includes descriptions, units, and acceptable ranges for each property. Metadata -------- The model uses the following fuel parameters: - ``side_length`` - Standard name: ``BUILDING_LENGTH_SIDE`` - Units: ``meter`` - Range: ``0 to inf`` - Type: ``input`` - ``separation`` - Standard name: ``BUILDING_LENGTH_SEPARATION`` - Units: ``meter`` - Range: ``0 to inf`` - Type: ``input`` - ``wind_u`` - Standard name: ``WIND_SPEED_U`` - Units: ``meter / second`` - Range: ``-inf to inf`` - Type: ``input`` - ``wind_v`` - Standard name: ``WIND_SPEED_V`` - Units: ``meter / second`` - Range: ``-inf to inf`` - Type: ``input`` - ``normal_vector_x`` - Standard name: ``NORMAL_SPREAD_DIR_X`` - Units: ``dimensionless`` - Range: ``-1 to 1`` - Type: ``input`` - ``normal_vector_y`` - Standard name: ``NORMAL_SPREAD_DIR_Y`` - Units: ``dimensionless`` - Range: ``-1 to 1`` - Type: ``input`` - ``fire_resistant_ratio`` - Standard name: ``BUILDING_RATIO_FIRE_RESISTANT`` - Units: ``dimensionless`` - Range: ``0 to 1`` - Type: ``optional`` - Default: ``0.6`` - ``rate_of_spread`` - Standard name: ``RATE_OF_SPREAD`` - Units: ``meter / second`` - Range: ``0 to inf`` - Type: ``output`` """ # pylint: disable=line-too-long metadata = { "side_length": { "std_name": svn.BUILDING_LENGTH_SIDE, "units": ureg.meter, "range": (0, np.inf), "type": ParameterType.input, }, "separation": { "std_name": svn.BUILDING_LENGTH_SEPARATION, "units": ureg.meter, "range": (0, np.inf), "type": ParameterType.input, }, "wind_u": { "std_name": svn.WIND_SPEED_U, "units": ureg.meter / ureg.second, "range": (-np.inf, np.inf), "type": ParameterType.input, }, "wind_v": { "std_name": svn.WIND_SPEED_V, "units": ureg.meter / ureg.second, "range": (-np.inf, np.inf), "type": ParameterType.input, }, "normal_vector_x": { "std_name": svn.NORMAL_SPREAD_DIR_X, "units": ureg.dimensionless, "range": (-1, 1), "type": ParameterType.input, }, "normal_vector_y": { "std_name": svn.NORMAL_SPREAD_DIR_Y, "units": ureg.dimensionless, "range": (-1, 1), "type": ParameterType.input, }, "fire_resistant_ratio": { "std_name": svn.BUILDING_RATIO_FIRE_RESISTANT, "units": ureg.dimensionless, "range": (0, 1), "type": ParameterType.optional, "default": 0.6, }, "rate_of_spread": { "std_name": svn.RATE_OF_SPREAD, "units": ureg.meter / ureg.second, "range": (0, np.inf), "type": ParameterType.output, }, }
[docs] @staticmethod def hamada_1( side_length: float, separation: float, wind_u: float, wind_v: float, normal_vector_x: float, normal_vector_y: float, fire_resistant_ratio: float, ) -> float: """ Compute the urban rate of spread using the Hamada model. Parameters ---------- side_length : float Building side length [m]. separation : float Buildings separation [m]. wind_u : float The U component of the wind speed [m s-1]. wind_v : float The V component of the wind speed [m s-1]. normal_vector_x : float The X component of the normalized spread direction vector [-]. wind_direction_y : float The Y component of the normalized spread direction vector [-]. fire_resistant_ratio : float The ratio of fire-resistant buildings [-]. Returns ------- float The computed urban rate of spread in meters per second. """ # norm of the wind wind = np.hypot(wind_u, wind_v) # rate of spread along specific directions t_d = ( (1 - fire_resistant_ratio) * (3 + 0.375 * side_length + 8 * separation / (25 + 2.5 * wind)) + fire_resistant_ratio * (5 + 0.625 * side_length + 16 * separation / (25 + 2.5 * wind)) ) / (1.5 * (1 + 0.1 * wind + 0.007 * wind**2)) t_o = ( (1 - fire_resistant_ratio) * (3 + 0.375 * side_length + 8 * separation / (5 + 0.25 * wind)) + fire_resistant_ratio * (5 + 0.625 * side_length + 16 * separation / (5 + 0.25 * wind)) ) / (1 + 0.005 * wind**2) t_u = ( (1 - fire_resistant_ratio) * (3 + 0.375 * side_length + 8 * separation / (5 + 0.2 * wind)) + fire_resistant_ratio * (5 + 0.625 * side_length + 16 * separation / (5 + 0.2 * wind)) ) / (1 + 0.002 * wind**2) # downwind ros ros_d = (side_length + separation) / t_d # orthogonal ros ros_o = (side_length + separation) / t_o # upwind ros ros_u = (side_length + separation) / t_u # ellipse parameters as a function of spread direction k = 1 if wind > 0: k = (normal_vector_x * wind_u + normal_vector_y * wind_v) / wind # check on which ellispe we are if k >= 0: eccentricity = (ros_d - ros_o) / ros_d a_ellipse = ros_d**2 / (2 * ros_d - ros_o) return a_ellipse * (1 - eccentricity**2) / (1 - eccentricity * k) / 60 return ros_o * ros_u / np.sqrt(ros_u**2 * (1 - k**2) + ros_o**2 * k**2) / 60
[docs] @staticmethod def compute_ros( input_dict: dict[str, float | int | list[float] | list[int]], fuel_cat: int = 0, **opt, ) -> float: """ Compute the rate of spread of fire using the `Hamada's` model. This function processes input fuel properties, optionally selects a specific fuel category, and calculates the rate of spread (ROS) of fire using the `hamada_1` method. Missing keys in the input dictionary are replaced with their default values, as specified in `Hamada_1.metadata`. Input data must be provided in standard units without `pint.Quantity` objects. For unit-aware calculations, use `compute_ros_with_units`. Parameters ---------- input_dict : dict Dictionary containing the input data for various fuel properties. The keys should match the standard variable names as defined in `Hamada_1.metadata`. Each value can be a single float/int or a list/array of floats/ints. fuel_cat : int, optional Fuel category index (one-based). If provided, fuel properties are expected to be lists or arrays, and the function will extract the properties corresponding to the specified fuel category. If not provided, fuel properties are expected to be scalar values. Returns ------- float The computed rate of spread of fire. Notes ----- - `fuel_cat` uses one-based indexing to align with natural fuel category numbering. When accessing lists or arrays in `input_dict`, the index is adjusted accordingly (i.e., `index = fuel_cat - 1`). - This function assumes `input_dict` contains values in standard units (e.g., no `pint.Quantity` objects), compliant with units specified in the metadata dictionary. """ # pylint: disable=line-too-long # Prepare fuel properties using the base class method fuel_properties = RateOfSpreadModel.prepare_fuel_properties( input_dict=input_dict, metadata=Hamada_1.metadata, fuel_cat=fuel_cat ) # Calculate the rate of spread return Hamada_1.hamada_1(**fuel_properties)
[docs] @staticmethod def compute_ros_with_units( input_dict: dict[str, float | int | list[float] | list[int] | Quantity], fuel_cat: int = 0, **opt, ) -> Quantity: """ Compute the rate of spread (ROS) of fire using modified Hamada's model with unit handling. This function extracts magnitudes from input data (removing `pint.Quantity` wrappers), computes the ROS using `compute_ros`, and attaches the appropriate unit to the result. Parameters ---------- input_dict : dict Dictionary containing input fuel properties as `pint.Quantity` objects or standard values. Keys should match the variable names defined in `Hamada_1.metadata`. fuel_cat : int, optional One-based index for selecting a specific fuel category from lists in `input_dict`. Defaults to 0, indicating scalar inputs. **opt : dict Additional optional parameters passed to `compute_ros`. Returns ------- ureg.Quantity Computed rate of spread (ROS) with units (e.g., meters per second). Notes ----- - Use this function when working with `pint.Quantity` objects in `input_dict`. - Units for the ROS are defined in `Hamada_1.metadata["rate_of_spread"]["units"]`. """ # pylint: disable=line-too-long input_dict_no_units = extract_magnitudes(input_dict) return ureg.Quantity( Hamada_1.compute_ros(input_dict_no_units, fuel_cat, **opt), Hamada_1.metadata["rate_of_spread"]["units"], )
[docs] class Hamada_2(RateOfSpreadModel): # pylint: disable=duplicate-code """ A class to represent the Hamada's model for urban fire spread rate calculation in its version 2. This class provides metadata for various fuel properties and a static method to compute the rate of spread (ROS) of fire using the Hamada's model. The metadata includes descriptions, units, and acceptable ranges for each property. Metadata -------- The model uses the following fuel parameters: - ``side_length`` - Standard name: ``BUILDING_LENGTH_SIDE`` - Units: ``meter`` - Range: ``0 to inf`` - Type: ``input`` - ``separation`` - Standard name: ``BUILDING_LENGTH_SEPARATION`` - Units: ``meter`` - Range: ``0 to inf`` - Type: ``input`` - ``wind_u`` - Standard name: ``WIND_SPEED_U`` - Units: ``meter / second`` - Range: ``-inf to inf`` - Type: ``input`` - ``wind_v`` - Standard name: ``WIND_SPEED_V`` - Units: ``meter / second`` - Range: ``-inf to inf`` - Type: ``input`` - ``normal_vector_x`` - Standard name: ``NORMAL_SPREAD_DIR_X`` - Units: ``dimensionless`` - Range: ``-1 to 1`` - Type: ``input`` - ``normal_vector_y`` - Standard name: ``NORMAL_SPREAD_DIR_Y`` - Units: ``dimensionless`` - Range: ``-1 to 1`` - Type: ``input`` - ``fire_resistant_ratio`` - Standard name: ``BUILDING_RATIO_FIRE_RESISTANT`` - Units: ``dimensionless`` - Range: ``0 to 1`` - Type: ``optional`` - Default: ``0.6`` - ``bare_structure_ratio`` - Standard name: ``BUILDING_RATIO_STRUCTURE_WOOD_BARE`` - Units: ``dimensionless`` - Range: ``0 to 1`` - Type: ``optional`` - Default: ``0.2`` - ``mortar_structure_ratio`` - Standard name: ``BUILDING_RATIO_STRUCTURE_WOOD_MORTAR`` - Units: ``dimensionless`` - Range: ``0 to 1`` - Type: ``optional`` - Default: ``0.2`` - ``beta`` - Standard name: ``BETA`` - Units: ``dimensionless`` - Range: ``2 to inf`` - Type: ``optional`` - Default: ``5`` - ``rate_of_spread`` - Standard name: ``RATE_OF_SPREAD`` - Units: ``meter / second`` - Range: ``0 to inf`` - Type: ``output`` """ # pylint: disable=line-too-long # pylint: enable=duplicate-code metadata = { "side_length": { "std_name": svn.BUILDING_LENGTH_SIDE, "units": ureg.meter, "range": (0, np.inf), "type": ParameterType.input, }, "separation": { "std_name": svn.BUILDING_LENGTH_SEPARATION, "units": ureg.meter, "range": (0, np.inf), "type": ParameterType.input, }, "wind_u": { "std_name": svn.WIND_SPEED_U, "units": ureg.meter / ureg.second, "range": (-np.inf, np.inf), "type": ParameterType.input, }, "wind_v": { "std_name": svn.WIND_SPEED_V, "units": ureg.meter / ureg.second, "range": (-np.inf, np.inf), "type": ParameterType.input, }, "normal_vector_x": { "std_name": svn.NORMAL_SPREAD_DIR_X, "units": ureg.dimensionless, "range": (-1, 1), "type": ParameterType.input, }, "normal_vector_y": { "std_name": svn.NORMAL_SPREAD_DIR_Y, "units": ureg.dimensionless, "range": (-1, 1), "type": ParameterType.input, }, "fire_resistant_ratio": { "std_name": svn.BUILDING_RATIO_FIRE_RESISTANT, "units": ureg.dimensionless, "range": (0, 1), "type": ParameterType.optional, "default": 0.6, }, "bare_structure_ratio": { "std_name": svn.BUILDING_RATIO_STRUCTURE_WOOD_BARE, "units": ureg.dimensionless, "range": (0, 1), "type": ParameterType.optional, "default": 0.2, }, "mortar_structure_ratio": { "std_name": svn.BUILDING_RATIO_STRUCTURE_WOOD_MORTAR, "units": ureg.dimensionless, "range": (0, 1), "type": ParameterType.optional, "default": 0.2, }, "beta": { "std_name": svn.BETA, "units": ureg.dimensionless, "range": (2, np.inf), "type": ParameterType.optional, "default": 5, }, "rate_of_spread": { "std_name": svn.RATE_OF_SPREAD, "units": ureg.meter / ureg.second, "range": (0, np.inf), "type": ParameterType.output, }, }
[docs] @staticmethod def hamada_2( side_length: float, separation: float, wind_u: float, wind_v: float, normal_vector_x: float, normal_vector_y: float, fire_resistant_ratio: float, bare_structure_ratio: float, mortar_structure_ratio: float, beta: float, ) -> float: """ Compute the urban rate of spread using the Hamada model. Parameters ---------- side_length : float Building side length [m]. separation : float Buildings separation distance [m]. wind_u : float The U component of the wind speed [m s-1]. wind_v : float The V component of the wind speed [m s-1]. normal_vector_x : float The X component of the normalized spread direction vector [-]. wind_direction_y : float The Y component of the normalized spread direction vector [-]. fire_resistant_ratio : float The ratio of fire-resistant buildings [-]. bare_structure_ratio : float The ratio of buildings with bare structural materials [-]. mortar_structure_ratio : float The ratio of buildings with mortar [-]. beta : float The beta parameter for the model (>2 for stability) [-]. Returns ------- float The computed urban rate of spread in meters per second. """ # pylint: disable=line-too-long # Calculate wind speed magnitude wind_speed = np.hypot(wind_u, wind_v) # Calculate downwind rate of spread downwind_ros = ( (bare_structure_ratio + mortar_structure_ratio) * (1 - fire_resistant_ratio) * (side_length + separation) * (1 + 0.1 * wind_speed + 0.007 * wind_speed**2) / ( (bare_structure_ratio + 5 * mortar_structure_ratio / 3) * (3 + 3 * side_length / 8 + 8 * separation / (1.15 * beta * (5 + 0.5 * wind_speed))) ) ) # Calculate orthogonal rate of spread orthogonal_ros = ( (bare_structure_ratio + mortar_structure_ratio) * (1 - fire_resistant_ratio) * (side_length + separation) * (1 + 0.002 * wind_speed**2) / ( (bare_structure_ratio + 5 * mortar_structure_ratio / 3) * (3 + 3 * side_length / 8 + 8 * separation / (1.15 * (5 + 0.5 * wind_speed))) ) ) cos_theta = 0 if wind_speed > 0: cos_theta = (normal_vector_x * wind_u + normal_vector_y * wind_v) / wind_speed eccentricity = (downwind_ros - orthogonal_ros) / downwind_ros a_ellipse = downwind_ros**2 / (2 * downwind_ros - orthogonal_ros) # c_ellipse = downwind_ros * (downwind_ros - orthogonal_ros) / (2 *downwind_ros - orthogonal_ros) return a_ellipse * (1 - eccentricity**2) / (1 - eccentricity * cos_theta) / 60
[docs] @staticmethod def compute_ros( input_dict: dict[str, float | int | list[float] | list[int]], fuel_cat: int = 0, **opt, ) -> float: """ Compute the rate of spread of fire using the `Hamada's` model. This function processes input fuel properties, optionally selects a specific fuel category, and calculates the rate of spread (ROS) of fire using the `hamada_2` method. Missing keys in the input dictionary are replaced with their default values, as specified in `Hamada_2.metadata`. Input data must be provided in standard units without `pint.Quantity` objects. For unit-aware calculations, use `compute_ros_with_units`. Parameters ---------- input_dict : dict Dictionary containing the input data for various fuel properties. The keys should match the standard variable names as defined in `Hamada_2.metadata`. Each value can be a single float/int or a list/array of floats/ints. fuel_cat : int, optional Fuel category index (one-based). If provided, fuel properties are expected to be lists or arrays, and the function will extract the properties corresponding to the specified fuel category. If not provided, fuel properties are expected to be scalar values. Returns ------- float The computed rate of spread of fire. Notes ----- - `fuel_cat` uses one-based indexing to align with natural fuel category numbering. When accessing lists or arrays in `input_dict`, the index is adjusted accordingly (i.e., `index = fuel_cat - 1`). - This function assumes `input_dict` contains values in standard units (e.g., no `pint.Quantity` objects), compliant with units specified in the metadata dictionary. """ # pylint: disable=line-too-long # Prepare fuel properties using the base class method fuel_properties = RateOfSpreadModel.prepare_fuel_properties( input_dict=input_dict, metadata=Hamada_2.metadata, fuel_cat=fuel_cat ) # Calculate the rate of spread return Hamada_2.hamada_2(**fuel_properties)
[docs] @staticmethod def compute_ros_with_units( input_dict: dict[str, float | int | list[float] | list[int] | Quantity], fuel_cat: int = 0, **opt, ) -> Quantity: """ Compute the rate of spread (ROS) of fire using modified Hamada's model with unit handling. This function extracts magnitudes from input data (removing `pint.Quantity` wrappers), computes the ROS using `compute_ros`, and attaches the appropriate unit to the result. Parameters ---------- input_dict : dict Dictionary containing input fuel properties as `pint.Quantity` objects or standard values. Keys should match the variable names defined in `Hamada_2.metadata`. fuel_cat : int, optional One-based index for selecting a specific fuel category from lists in `input_dict`. Defaults to 0, indicating scalar inputs. **opt : dict Additional optional parameters passed to `compute_ros`. Returns ------- ureg.Quantity Computed rate of spread (ROS) with units (e.g., meters per second). Notes ----- - Use this function when working with `pint.Quantity` objects in `input_dict`. - Units for the ROS are defined in `Hamada_2.metadata["rate_of_spread"]["units"]`. """ # pylint: disable=line-too-long input_dict_no_units = extract_magnitudes(input_dict) return ureg.Quantity( Hamada_2.compute_ros(input_dict_no_units, fuel_cat, **opt), Hamada_2.metadata["rate_of_spread"]["units"], )