01 Basic usage#

This example shows how to create a basic CFAST fire simulation model using PyCFAST. We’ll build a complete simulation with two compartments, ventilation, fire sources, and target devices.

Step 1: Import Required PyCFAST Components#

First, let’s import all the necessary PyCFAST components.

from pycfast import (
    CeilingFloorVents,
    CFASTModel,
    Compartments,
    Devices,
    Fires,
    MaterialProperties,
    MechanicalVents,
    SimulationEnvironment,
    SurfaceConnections,
    WallVents,
)

Step 2: Configure Simulation Environment#

The simulation environment defines the global parameters for our CFAST simulation. The SimulationEnvironment class is the equivalent of the CEdit simulation settings tab but programmatically defined.

../_images/cedit-simulation-tab.png
simulation_env = SimulationEnvironment(
    title="Simple example",
    time_simulation=7200,  # Total simulation time in seconds (2 hours)
    print=40,  # Print output every 40 seconds
    smokeview=10,  # Smokeview output every 10 seconds
    spreadsheet=10,  # Spreadsheet output every 10 seconds
    init_pressure=101325,  # Initial pressure in Pa (1 atm)
    relative_humidity=50,  # Relative humidity as percentage
    interior_temperature=20,  # Interior temperature in °C
    exterior_temperature=20,  # Exterior temperature in °C
    adiabatic=False,  # Allow heat transfer through surfaces
    lower_oxygen_limit=0.1,  # Lower oxygen limit for combustion
    max_time_step=10,  # Maximum time step in seconds
)

You can expand the simulation environment diagram below to see all the available parameters and their descriptions.

simulation_env
⚙️

Simulation Environment

Simple example

Duration: 120 min
Print interval: 40 s
Interior temp: 20°C
Exterior temp: 20°C
Pressure: 101325 Pa
Humidity: 50%
Advanced Settings
Smokeview: 10 s
Spreadsheet: 10 s
Max timestep: 10 s
O₂ limit: 0.1
Adiabatic: False


Step 3: Define Material Properties#

Material properties define the thermal characteristics of surfaces in our compartments. The MaterialProperties class is the equivalent of the CEdit simulation settings tab but programmatically defined.

CEdit Material Properties Tab

Here we define gypsum board, which is commonly used for walls and ceilings.

gypsum_board = MaterialProperties(
    id="Gypboard",  # Unique identifier for the material
    material="Gypsum Board",  # Descriptive name
    conductivity=0.16,  # Thermal conductivity in W/m·K (not in kW as CEdit shows)
    density=480,  # Density in kg/m³
    specific_heat=1,  # Specific heat in kJ/kg·K
    thickness=0.015,  # Default thickness in meters
    emissivity=0.9,  # Surface emissivity for radiation
)

You can see the properties of the gypsum board on the material card below.

gypsum_board
🧱

Material: Gypboard

Gypsum Board

Conductivity: 0.16 W/m·K
Density: 480 kg/m³
Specific Heat: 1 kJ/kg·K
Thickness: 0.015 m
Emissivity: 0.9


Step 4: Create Compartments#

Compartments represent the physical spaces in our building. The Compartments class is the equivalent of the CEdit compartment tab but programmatically defined.

CEdit Compartments Tab

We’ll create two 10×10×10 meter rooms stacked vertically.

ground_level = Compartments(
    id="Comp 1",
    depth=10.0,  # Depth in meters (Y-direction)
    height=10.0,  # Height in meters (Z-direction)
    width=10.0,  # Width in meters (X-direction)
    ceiling_mat_id="Gypboard",  # Material for ceiling
    ceiling_thickness=0.01,  # Ceiling thickness in meters
    wall_mat_id="Gypboard",  # Material for walls
    wall_thickness=0.01,  # Wall thickness in meters
    floor_mat_id="Gypboard",  # Material for floor
    floor_thickness=0.01,  # Floor thickness in meters
    origin_x=0,  # X-coordinate of origin
    origin_y=0,  # Y-coordinate of origin
    origin_z=0,  # Z-coordinate of origin
)

upper_level = Compartments(
    id="Comp 2",
    depth=10.0,
    height=10.0,
    width=10.0,
    ceiling_mat_id="Gypboard",
    ceiling_thickness=0.01,
    wall_mat_id="Gypboard",
    wall_thickness=0.01,
    floor_mat_id="Gypboard",
    floor_thickness=0.01,
    origin_x=0,
    origin_y=0,
    origin_z=10,  # Positioned above first compartment
)

You can see the properties of the compartments on the compartment cards below (we display only the first compartment as an example).

ground_level
🏠

Compartment: Comp 1

10.0×10.0×10.0 m • 1000.0 m³

Width: 10.0 m
Depth: 10.0 m
Height: 10.0 m
Volume: 1000.0 m³
Origin: (0, 0, 0) m
Materials & Construction
Ceiling: Gypboard (0.010m)
Walls: Gypboard (0.010m)
Floor: Gypboard (0.010m)


Step 5: Define Ventilation Systems#

As before, we’ll create three types of ventilation:

Wall vents

Ceiling/floor vents

Mechanical vents

Natural ventilation through openings in walls

Natural ventilation between compartments

Forced ventilation systems

CEdit Wall Vents Tab
CEdit Ceiling/Floor Vents Tab
CEdit Mechanical Ventilation Tab

We’ll use the MechanicalVents, CeilingFloorVents, and WallVents classes to define our vents.

# Wall vent connecting first compartment to outside

wall_vent = WallVents(
    id="WallVent_1",
    comps_ids=["Comp 1", "OUTSIDE"],  # Connect compartment 1 to outside
    bottom=0.02,  # Height of bottom of vent in meters
    height=0.3,  # Height of vent opening in meters
    width=0.2,  # Width of vent opening in meters
    face="FRONT",  # Wall face (FRONT, BACK, LEFT, RIGHT)
    offset=0.47,
)
ceiling_floor_vents = CeilingFloorVents(
    id="CeilFloorVent_1",
    comps_ids=["Comp 2", "Comp 1"],  # Connect compartment 2 to compartment 1
    area=0.01,  # Vent area in m²
    shape="SQUARE",  # Shape of the vent
    width=None,  # Width (calculated from area for square)
    offsets=[0.84, 0.86],
)

mechanical_vents = MechanicalVents(
    id="mech",
    comps_ids=["OUTSIDE", "Comp 1"],  # Connect outside to compartment 1
    area=[1.2, 10],  # Areas at each end in m²
    heights=[1, 1],  # Heights at each end in meters
    orientations=["HORIZONTAL", "HORIZONTAL"],  # Duct orientations
    flow=1,  # Flow rate in m³/s
    cutoffs=[250, 300],  # Begin Drop Off and Zero Flow Pressure in Pa
    offsets=[0, 0.6],
    filter_time=1.2,  # Filter time constant
    filter_efficiency=5,  # Filter efficiency percentage
)

You can see the properties of the wall vent on the wall vent card below (we display only the wall vent as an example).

wall_vent
🚪

Wall Vent: WallVent_1

Comp 1 ↔ OUTSIDE

Dimensions: 0.2×0.3 m
Area: 0.06 m²
Wall face: FRONT
Bottom height: 0.02 m
Offset: 0.47 m


Step 6: Define Fire Sources#

Fire sources represent the combustion processes in our simulation. The Fires class is the equivalent of the CEdit fires tab but programmatically defined.

CEdit Fires Tab

Here we define a propane fire with specific chemical composition and heat release characteristics.

propane_fire = Fires(
    id="Propane",
    comp_id="Comp 1",  # Location: first compartment
    fire_id="Propane_Fire",
    location=[0.3, 0.3],  # X,Y coordinates within compartment
    # Chemical composition (atoms per molecule)
    carbon=5,  # Carbon atoms
    chlorine=2,  # Chlorine atoms
    hydrogen=8,  # Hydrogen atoms
    nitrogen=1,  # Nitrogen atoms
    oxygen=0,  # Oxygen atoms
    heat_of_combustion=100,  # Heat of combustion in kJ/kg
    radiative_fraction=0.3,  # Fraction of energy released as radiation
    # Fire time-line data
    # [time, mdot, hight, area, CO_yield, soot_yield, HCN_yield, HCl_yield, trace_yield]
    # you can also use an numpy array or pandas DataFrame
    # as long as the shape of the table is (n row , 9 columns)
    data_table=[
        [0, 0, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],  # t=0s
        [30, 10, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],  # t=30s
        [60, 40, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],  # t=60s
        [90, 90, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],  # t=90s
        [120, 160, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],  # t=120s
        [150, 250, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],  # t=150s
        [180, 360, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],  # t=180s
        [210, 490, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],  # ...
        [240, 640, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
        [270, 810, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
        [300, 999.9999, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
        [600, 1000, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
        [601, 810, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
        [602, 640, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
        [603, 490, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
        [604, 360, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
        [605, 250, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
        [606, 160, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
        [607, 90, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
        [608, 40, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
        [609, 10, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
        [610, 0, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
        [620, 0, 0, 0.3, 0.008021683, 0.02, 0, 0, 0],
    ],
)

Step 7: Add Devices#

Devices allow us to monitor conditions at specific locations. The Devices class is the equivalent of the CEdit devices tab but programmatically defined.

CEdit Target Tab

The Devices class has classmethods to help create common device types: * create_target(): equivalent of target device * create_heat_detector(): equivalent of heat detector device * create_smoke_detector(): equivalent of smoke detector device * create_sprinkler(): equivalent of sprinkler device

Here we add a target device to measure thermal conditions.

target = Devices.create_target(
    id="Target_1",
    comp_id="Comp 1",  # Location: first compartment
    location=[0.5, 0.5, 0],  # X,Y,Z coordinates
    type="CYLINDER",  # Target geometry
    material_id="Gypboard",  # Target material
    surface_orientation="HORIZONTAL",  # Surface orientation
    thickness=0.01,  # Target thickness in meters
    temperature_depth=0.01,  # Depth for temperature measurement
    depth_units="M",  # Units for depth
)

You can see the properties of the target device on the device card below.

target
🎯

Device: Target_1

Target in Comp 1

Location: (0.5, 0.5, 0)
Type: Target
Material: Gypboard
Orientation: HORIZONTAL
Thickness: 0.01 m


Step 8: Configure Surface Connections#

Surface connections define thermal connections between compartments through shared surfaces. The SurfaceConnections class is the equivalent of the CEdit surface connections tab but programmatically defined.

CEdit Surface Connections

The SurfaceConnections class has 2 classmethods to help create common connection types ceiling_floor_connection(), and wall_connection(). Here we create a ceiling/floor connection between the two compartments to allow heat transfer and air flow between them.

ceiling_floor_connection = SurfaceConnections.ceiling_floor_connection(
    comp_id="Comp 1",  # Source compartment
    comp_ids="Comp 2",  # Target compartment
)

You can see the properties of the surface connection on the surface connection card below.

ceiling_floor_connection
🏗️

Surface Connection

Floor: Comp 1 → Comp 2

Type: Floor
From: Comp 1
To: Comp 2


Step 9: Create and Run the CFAST Model#

Now we’ll create a complete CFASTModel with all our components and run the simulation. After running, we’ll explore how to access and analyze the results.

model = CFASTModel(
    simulation_environment=simulation_env,
    material_properties=[gypsum_board],
    compartments=[ground_level, upper_level],
    wall_vents=[wall_vent],
    ceiling_floor_vents=[ceiling_floor_vents],
    mechanical_vents=[mechanical_vents],
    fires=[propane_fire],
    devices=[target],
    surface_connections=[ceiling_floor_connection],
    file_name="example_simulation.in",  # Output file name
    cfast_exe="cfast",  # Path to CFAST executable (adjust if needed)
    extra_arguments=["-f"],  # Optionnal command-line arguments
)

You can view the complete model with the card below

model
🔥

CFAST Model

example_simulation.in

Total Components: 9
Simulation: Simple example
Duration: 120 min
Compartments (2)
  • Comp 1: 10.0×10.0×10.0 m
  • Comp 2: 10.0×10.0×10.0 m
Fires (1)
  • Propane in Comp 1: Propane_Fire
Ventilation (3)
  • WallVent_1 (Wall): Comp 1 ↔ OUTSIDE
  • CeilFloorVent_1 (Ceiling/Floor): Comp 2 ↔ Comp 1
  • mech (Mechanical): OUTSIDE → Comp 1
Devices (1)
  • Target_1 in Comp 1: CYLINDER
Materials (1)
  • Gypboard: Gypsum Board


Or use the summary() method to print a summary of the model configuration.

model.summary()
Model: example_simulation.in
Simulation: 'Simple example' (7200s)

Components:
  Material Properties (1):
    Material 'Gypboard' (Gypsum Board): k=0.16, ρ=480, c=1, t=0.015, ε=0.9
  Compartments (2):
    Compartment 'Comp 1': 10.0x10.0x10.0 m, volume: 1000.00 m³ (ceiling: Gypboard, wall: Gypboard, floor: Gypboard)
    Compartment 'Comp 2': 10.0x10.0x10.0 m, volume: 1000.00 m³ (ceiling: Gypboard, wall: Gypboard, floor: Gypboard)
  Wall Vents (1):
    Wall Vent 'WallVent_1': Comp 1 ↔ OUTSIDE, 0.2x0.3 m, bottom: 0.02 m
  Ceiling/Floor Vents (1):
    Ceiling/Floor Vent 'CeilFloorVent_1': Comp 2 ↕ Comp 1, area: 0.01 m², shape: SQUARE
  Mechanical Vents (1):
    Mechanical Vent 'mech': OUTSIDE -> Comp 1, flow: 1 m³/s
  Fires (1):
    Fire 'Propane' (Propane_Fire) in 'Comp 1' at (0.3, 0.3) (peak: 1 kW, duration: 10min, χr: 0.3)
  Devices (1):
    Target 'Target_1' (CYLINDER) in 'Comp 1' at (0.5, 0.5, 0) (material: Gypboard, depth: 0.01m, thickness: 0.01m)
  Surface Connections (1):
    Surface Connection (FLOOR): Comp 1 -> Comp 2

You can also save to the disk the CFAST model input file with the save() method and view its contents with view_cfast_input_file() (not neccessary to run the simulation, as the model will be saved automatically when you run it, but useful if you want to inspect the generated input file or run it manually with CFAST).

model.save()

# View the saved input file (pretty printed)
input_file_contents = model.view_cfast_input_file(pretty_print=True)
print(input_file_contents)
 1: &HEAD VERSION = 7700 TITLE = 'Simple example' /
 2:
 3: !! Scenario Configuration
 4: &TIME SIMULATION = 7200 PRINT = 40 SMOKEVIEW = 10 SPREADSHEET = 10 /
 5: &INIT PRESSURE = 101325 RELATIVE_HUMIDITY = 50 INTERIOR_TEMPERATURE = 20 EXTERIOR_TEMPERATURE = 20 /
 6: &MISC ADIABATIC = .FALSE. MAX_TIME_STEP = 10 LOWER_OXYGEN_LIMIT = 0.1 /
 7:
 8: !! Material Properties
 9: &MATL ID = 'Gypboard' MATERIAL = 'Gypsum Board' CONDUCTIVITY = 0.16 DENSITY = 480 SPECIFIC_HEAT = 1 THICKNESS = 0.015 EMISSIVITY = 0.9 /
10:
11: !! Compartments
12: &COMP ID = 'Comp 1' DEPTH = 10.0 HEIGHT = 10.0 WIDTH = 10.0 CEILING_MATL_ID = 'Gypboard' CEILING_THICKNESS = 0.01 WALL_MATL_ID = 'Gypboard' WALL_THICKNESS = 0.01 FLOOR_MATL_ID = 'Gypboard' FLOOR_THICKNESS = 0.01 ORIGIN = 0, 0, 0 GRID = 50, 50, 50 /
13: &COMP ID = 'Comp 2' DEPTH = 10.0 HEIGHT = 10.0 WIDTH = 10.0 CEILING_MATL_ID = 'Gypboard' CEILING_THICKNESS = 0.01 WALL_MATL_ID = 'Gypboard' WALL_THICKNESS = 0.01 FLOOR_MATL_ID = 'Gypboard' FLOOR_THICKNESS = 0.01 ORIGIN = 0, 0, 10 GRID = 50, 50, 50 /
14:
15: !! Wall Vents
16: &VENT TYPE = 'WALL' ID = 'WallVent_1' COMP_IDS = 'Comp 1', 'OUTSIDE' BOTTOM = 0.02 HEIGHT = 0.3 WIDTH = 0.2 FACE = 'FRONT' OFFSET = 0.47 /
17:
18: !! Ceiling and Floor Vents
19: &VENT TYPE = 'FLOOR' ID = 'CeilFloorVent_1' COMP_IDS = 'Comp 2', 'Comp 1' AREA = 0.01 SHAPE = 'SQUARE' OFFSETS = 0.84, 0.86 /
20:
21: !! Mechanical Vents
22: &VENT TYPE = 'MECHANICAL' ID = 'mech' COMP_IDS = 'OUTSIDE', 'Comp 1' AREAS = 1.2, 10 HEIGHTS = 1, 1 ORIENTATIONS = 'HORIZONTAL', 'HORIZONTAL' FLOW = 1 CUTOFFS = 250, 300 OFFSETS = 0, 0.6 FILTER_TIME = 1.2 FILTER_EFFICIENCY = 5 /
23:
24: !! Fires
25: &FIRE ID = 'Propane' COMP_ID = 'Comp 1' FIRE_ID = 'Propane_Fire' LOCATION = 0.3, 0.3 /
26: &CHEM ID = 'Propane_Fire' CARBON = 5 CHLORINE = 2 HYDROGEN = 8 NITROGEN = 1 OXYGEN = 0 HEAT_OF_COMBUSTION = 100 RADIATIVE_FRACTION = 0.3 /
27: &TABL ID = 'Propane_Fire' LABELS = 'TIME', 'HRR', 'HEIGHT', 'AREA', 'CO_YIELD', 'SOOT_YIELD', 'HCN_YIELD', 'HCL_YIELD', 'TRACE_YIELD' /
28: &TABL ID = 'Propane_Fire' DATA = 0.0, 0.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
29: &TABL ID = 'Propane_Fire' DATA = 30.0, 10.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
30: &TABL ID = 'Propane_Fire' DATA = 60.0, 40.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
31: &TABL ID = 'Propane_Fire' DATA = 90.0, 90.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
32: &TABL ID = 'Propane_Fire' DATA = 120.0, 160.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
33: &TABL ID = 'Propane_Fire' DATA = 150.0, 250.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
34: &TABL ID = 'Propane_Fire' DATA = 180.0, 360.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
35: &TABL ID = 'Propane_Fire' DATA = 210.0, 490.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
36: &TABL ID = 'Propane_Fire' DATA = 240.0, 640.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
37: &TABL ID = 'Propane_Fire' DATA = 270.0, 810.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
38: &TABL ID = 'Propane_Fire' DATA = 300.0, 999.9999, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
39: &TABL ID = 'Propane_Fire' DATA = 600.0, 1000.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
40: &TABL ID = 'Propane_Fire' DATA = 601.0, 810.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
41: &TABL ID = 'Propane_Fire' DATA = 602.0, 640.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
42: &TABL ID = 'Propane_Fire' DATA = 603.0, 490.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
43: &TABL ID = 'Propane_Fire' DATA = 604.0, 360.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
44: &TABL ID = 'Propane_Fire' DATA = 605.0, 250.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
45: &TABL ID = 'Propane_Fire' DATA = 606.0, 160.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
46: &TABL ID = 'Propane_Fire' DATA = 607.0, 90.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
47: &TABL ID = 'Propane_Fire' DATA = 608.0, 40.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
48: &TABL ID = 'Propane_Fire' DATA = 609.0, 10.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
49: &TABL ID = 'Propane_Fire' DATA = 610.0, 0.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
50: &TABL ID = 'Propane_Fire' DATA = 620.0, 0.0, 0.0, 0.3, 0.008021683, 0.02, 0.0, 0.0, 0.0 /
51:
52: !! Devices
53: &DEVC ID = 'Target_1' COMP_ID = 'Comp 1' LOCATION = 0.5, 0.5, 0 TYPE = 'CYLINDER' MATL_ID = 'Gypboard' SURFACE_ORIENTATION = 'HORIZONTAL' THICKNESS = 0.01 TEMPERATURE_DEPTH = 0.01 DEPTH_UNITS = 'M' /
54:
55: !! Surface Connections
56: &CONN TYPE = 'FLOOR' COMP_ID = 'Comp 1' COMP_IDS = 'Comp 2' /
57:
58: &TAIL /

The run() method returns a dictionary containing pandas DataFrames for each CFAST output file. This makes it easy to analyze and visualize the simulation results using familiar pandas methods and matplotlib.

results = model.run(
    verbose=True,  # if True, print CFAST stdoutput and stderr
    timeout=None,  # You can set a timeout in seconds to stop the simulation but None means no timeout
)
CFAST stdout:
Total execution time =  0.976     seconds
Total time steps =       2277
Normal exit from CFAST

CFAST stderr:
Note: The following floating-point exceptions are signalling: IEEE_UNDERFLOW_FLAG

Step 10: Analyzing Simulation Results#

The run() method returns a dictionary containing pandas DataFrames for each CFAST output file. This makes it easy to analyze and visualize the simulation results using familiar pandas methods and matplotlib.

Available Output Files#

Each simulation generates several CSV files with different types of data:

  • `zone`: Complete zone data including temperatures, pressures, and fire parameters

  • `devices`: Target device responses (temperatures, heat fluxes)

  • `vents`: Ventilation mass flows through each vent

  • `compartments`: Detailed compartment conditions for all species

  • `walls`: Wall surface temperatures

  • `masses`: Species mass tracking over time

Below is a small example of comparing the Expected HRR and the Actual HRR using matplotlib and pandas, though you’re free to use any Python data analysis tools in the ecosystem!

import matplotlib.pyplot as plt

df = results["compartments"]

plt.figure(figsize=(10, 6))
plt.plot(df["Time"], df["HRR_1"], label="HRR Actual", color="tab:red", linewidth=2)
plt.plot(
    df["Time"],
    df["HRR_E1"],
    label="HRR Expected",
    color="tab:blue",
    linestyle="--",
    linewidth=2,
)
plt.title("Heat Release Rate in Compartment 1")
plt.xlabel("Time (s)")
plt.ylabel("Heat Release Rate (kW)")
plt.legend()
plt.xlim(0, 1500)
plt.grid(True, linestyle="--", alpha=0.7)
plt.tight_layout()
plt.show()
Heat Release Rate in Compartment 1

Step 11: Updating the model#

You can update any part of the model after its creation with the update_* methods (e.g., update_fire_params()). For example, to change the fire’s radiative fraction, you can do:

print(f"Original model: {model.fires}")

# After radiative fraction update
print(
    f"\nUpdated model: {model.update_fire_params(fire='Propane', radiative_fraction=0.4).fires}"
)
# You can also add additional components to an existing model using the ``add_*`` methods (e.g., :meth:`~pycfast.CFASTModel.add_device`). For example, you can add another target device:
Original model: [Fires(id='Propane', comp_id='Comp 1', fire_id='Propane_Fire', location=[0.3, 0.3], heat_of_combustion=100, radiative_fraction=0.3, data_rows=23)]

Updated model: [Fires(id='Propane', comp_id='Comp 1', fire_id='Propane_Fire', location=[0.3, 0.3], heat_of_combustion=100, radiative_fraction=0.4, data_rows=23)]
print("Original model devices:")
for device in model.devices:
    print(device)

# After adding a new device
new_device = Devices.create_target(
    id="Target_2",
    comp_id="Comp 2",  # Location: second compartment
    location=[0.5, 0.5, 0.5],  # X,Y,Z coordinates
    type="CYLINDER",  # Target geometry
    material_id="Gypboard",  # Target material
    surface_orientation="HORIZONTAL",  # Surface orientation
    thickness=0.01,  # Target thickness in meters
    temperature_depth=0.01,  # Depth for temperature measurement
    depth_units="M",  # Units for depth
)

updated_model = model.add_device(new_device)

print("\nAfter adding new device, updated model devices:")
for device in updated_model.devices:
    print(device)
Original model devices:
Target 'Target_1' (CYLINDER) in 'Comp 1' at (0.5, 0.5, 0) (material: Gypboard, depth: 0.01m, thickness: 0.01m)

After adding new device, updated model devices:
Target 'Target_1' (CYLINDER) in 'Comp 1' at (0.5, 0.5, 0) (material: Gypboard, depth: 0.01m, thickness: 0.01m)
Target 'Target_2' (CYLINDER) in 'Comp 2' at (0.5, 0.5, 0.5) (material: Gypboard, depth: 0.01m, thickness: 0.01m)

Cleanup#

Finally, we clean up the temporary files generated during the simulation.

import glob
import os

files_to_remove = glob.glob("example_simulation*")

for file in files_to_remove:
    if os.path.exists(file):
        os.remove(file)
        print(f"Removed {file}")

if files_to_remove:
    print("Cleanup completed!")
else:
    print("No files to clean up.")
Removed example_simulation_zone.csv
Removed example_simulation.log
Removed example_simulation_vents.csv
Removed example_simulation_walls.csv
Removed example_simulation_compartments.csv
Removed example_simulation_masses.csv
Removed example_simulation.smv
Removed example_simulation_devices.csv
Removed example_simulation.in
Removed example_simulation.out
Removed example_simulation.plt
Removed example_simulation.status
Cleanup completed!

Total running time of the script: (0 minutes 1.242 seconds)

Gallery generated by Sphinx-Gallery