
# **********************************************************************
# This file has been auto-generated by a code generation tool.
# Version:   "4.1.6"
# Date/time: 25 Jul 2024 12:00:25
# Template:  /python/entities.razor.
# **********************************************************************

# ================================================================================
# Python PWS entities.
# ================================================================================

from typing import Optional

from .enums import *


class EntityBase(object):
    """
    Base class for all entities.
    """
    def initialise_from_dictionary(self, data: dict):
        pass

    def __str__(self):
        pass


class LocalPosition(object):
    """
    Position with reference to some arbitrary local origin and axes.

    Attributes
    ----------
	x : float
		X. [m] (default value is 0)
	y : float
		Y. [m] (default value is 0)
	z : float
		Z. [m] (default value is 0)
    """
    
    def __init__(self, x: Optional[float]=0, y: Optional[float]=0, z: Optional[float]=0):
        """Initializes a new instance of the LocalPosition class"""
        super().__init__()
        self.x = x
        self.y = y
        self.z = z

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.x = float(data.get('x', self.x))
        self.y = float(data.get('y', self.y))
        self.z = float(data.get('z', self.z))

    def __str__(self):
        parts = [
            '* LocalPosition',
            f'X:    {self.x}',
            f'Y:    {self.y}',
            f'Z:    {self.z}',
        ]
        return '\n'.join(parts)


class Asset(EntityBase):
    """
    Any equipment to be modeled, vessels, pipelines.

    Attributes
    ----------
	location : LocalPosition
		Location of the asset. (default value is LocalPosition())
    """
    
    def __init__(self, location: Optional[LocalPosition]=LocalPosition()):
        """Initializes a new instance of the Asset class"""
        super().__init__()
        self.location = location

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        location_data = data.get('location')
        if location_data is not None:
            self.location.initialise_from_dictionary(location_data)

    def __str__(self):
        parts = [
            '* Asset',
            self.location.__str__(),
        ]
        return '\n'.join(parts)


class Scenario(EntityBase):
    """
    Base struct/class for all scenario types.

    Attributes
    ----------
		None
    """
    
    def __init__(self):
        """Initializes a new instance of the Scenario class"""
        super().__init__()
        pass

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        pass

    def __str__(self):
        parts = [
            '* Scenario',
        ]
        return '\n'.join(parts)


class Instantaneous(Scenario):
    """
    Base struct/class for instantaneous release scenarios.

    Attributes
    ----------
		None
    """
    
    def __init__(self):
        """Initializes a new instance of the Instantaneous class"""
        super().__init__()
        pass

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        pass

    def __str__(self):
        parts = [
            '* Instantaneous',
        ]
        return '\n'.join(parts)


class ReleaseOverTime(Scenario):
    """
    Scenario representing a release over time.

    Attributes
    ----------
	release_angle : float
		Angle above horizontal of release. [Radians] (default value is 0.0)
	time_varying_option : TimeVaryingOption
		Time-varying or steady-state modelling. (default value is TimeVaryingOption.INITIAL_RATE)
    """
    
    def __init__(self, release_angle: Optional[float]=0.0, time_varying_option: Optional[TimeVaryingOption]=TimeVaryingOption.INITIAL_RATE):
        """Initializes a new instance of the ReleaseOverTime class"""
        super().__init__()
        self.release_angle = release_angle
        self.time_varying_option = time_varying_option

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.release_angle = float(data.get('release_angle', self.release_angle))
        self.time_varying_option = TimeVaryingOption(data.get('time_varying_option', self.time_varying_option))

    def __str__(self):
        parts = [
            '* ReleaseOverTime',
            f'Release angle:    {self.release_angle}',
            f'Time varying option:    {self.time_varying_option}',
        ]
        return '\n'.join(parts)


class Transect(EntityBase):
    """
    Definition of transect (line segment).

    Attributes
    ----------
	transect_start_point : LocalPosition
		Cartesian coordinates of start point of transect. (default value is LocalPosition())
	transect_end_point : LocalPosition
		Cartesian coordinates of end point of transect. (default value is LocalPosition())
    """
    
    def __init__(self, transect_start_point: Optional[LocalPosition]=LocalPosition(), transect_end_point: Optional[LocalPosition]=LocalPosition()):
        """Initializes a new instance of the Transect class"""
        super().__init__()
        self.transect_start_point = transect_start_point
        self.transect_end_point = transect_end_point

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        transect_start_point_data = data.get('transect_start_point')
        if transect_start_point_data is not None:
            self.transect_start_point.initialise_from_dictionary(transect_start_point_data)
        transect_end_point_data = data.get('transect_end_point')
        if transect_end_point_data is not None:
            self.transect_end_point.initialise_from_dictionary(transect_end_point_data)

    def __str__(self):
        parts = [
            '* Transect',
            self.transect_start_point.__str__(),
            self.transect_end_point.__str__(),
        ]
        return '\n'.join(parts)


class FlammableOutputConfig(EntityBase):
    """
    Fire and radiation output configuration.

    Attributes
    ----------
	position : LocalPosition
		Position used for radiation calculations (including contours). (default value is LocalPosition())
	radiation_type : RadiationType
		Radiation type. (default value is RadiationType.INTENSITY)
	contour_type : ContourType
		Plane orientation for contouring. (default value is ContourType.FOOTPRINT_ELLIPSE)
	radiation_level : float
		Radiation level (could be dose, probit, intensity, etc). (default value is 4000)
	radiation_resolution : Resolution
		Spatial resolution for radiation calculations. (default value is Resolution.MEDIUM)
	transect : Transect
		Definition of line segment of interest for radiation transects. (default value is Transect())
	fixed_orientation : int
		If disabled orientation optimized to give maximum radiation. (default value is 0)
	orientation : float
		Horizontal angle with respect to the downwind direction. [Radians] (default value is 0)
	fixed_inclination : int
		If disabled inclination optimized to give maximum radiation. (default value is 0)
	inclination : float
		Angle between the normal to the surface and the horizontal plane. (default value is 0)
    """
    
    def __init__(self, position: Optional[LocalPosition]=LocalPosition(), radiation_type: Optional[RadiationType]=RadiationType.INTENSITY, contour_type: Optional[ContourType]=ContourType.FOOTPRINT_ELLIPSE, radiation_level: Optional[float]=4000, radiation_resolution: Optional[Resolution]=Resolution.MEDIUM, transect: Optional[Transect]=Transect(), fixed_orientation: Optional[int]=0, orientation: Optional[float]=0, fixed_inclination: Optional[int]=0, inclination: Optional[float]=0):
        """Initializes a new instance of the FlammableOutputConfig class"""
        super().__init__()
        self.position = position
        self.transect = transect
        self.radiation_type = radiation_type
        self.contour_type = contour_type
        self.radiation_level = radiation_level
        self.radiation_resolution = radiation_resolution
        self.fixed_orientation = fixed_orientation
        self.orientation = orientation
        self.fixed_inclination = fixed_inclination
        self.inclination = inclination

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        position_data = data.get('position')
        if position_data is not None:
            self.position.initialise_from_dictionary(position_data)
        transect_data = data.get('transect')
        if transect_data is not None:
            self.transect.initialise_from_dictionary(transect_data)
        self.radiation_type = RadiationType(data.get('radiation_type', self.radiation_type))
        self.contour_type = ContourType(data.get('contour_type', self.contour_type))
        self.radiation_level = float(data.get('radiation_level', self.radiation_level))
        self.radiation_resolution = Resolution(data.get('radiation_resolution', self.radiation_resolution))
        self.fixed_orientation = int(data.get('fixed_orientation', self.fixed_orientation))
        self.orientation = float(data.get('orientation', self.orientation))
        self.fixed_inclination = int(data.get('fixed_inclination', self.fixed_inclination))
        self.inclination = float(data.get('inclination', self.inclination))

    def __str__(self):
        parts = [
            '* FlammableOutputConfig',
            self.position.__str__(),
            self.transect.__str__(),
            f'Radiation type:    {self.radiation_type}',
            f'Contour type:    {self.contour_type}',
            f'Radiation level:    {self.radiation_level}',
            f'Radiation resolution:    {self.radiation_resolution}',
            f'Fixed orientation:    {self.fixed_orientation}',
            f'Orientation:    {self.orientation}',
            f'Fixed inclination:    {self.fixed_inclination}',
            f'Inclination:    {self.inclination}',
        ]
        return '\n'.join(parts)


class MaterialComponent(object):
    """
    Constituent component of a material.

    Attributes
    ----------
	name : str
		Name of the component. 
	mole_fraction : float
		Mole fraction of the component in the material. [fraction] (default value is 1)
    """
    
    def __init__(self, name: str, mole_fraction: Optional[float]=1):
        """Initializes a new instance of the MaterialComponent class"""
        super().__init__()
        self.name = name
        self.mole_fraction = mole_fraction

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.name = str(data.get('name', self.name))
        self.mole_fraction = float(data.get('mole_fraction', self.mole_fraction))

    def __str__(self):
        parts = [
            '* MaterialComponent',
            f'Name:    {self.name}',
            f'Mole fraction:    {self.mole_fraction}',
        ]
        return '\n'.join(parts)


class Material(EntityBase):
    """
    Material.

    Attributes
    ----------
	name : str
		Material name. 
	components : list[MaterialComponent]
		Constituent components. 
	component_count : int
		Number of components in the material. (default value is 1)
	property_template : PropertyTemplate
		Property used template for material. (default value is PropertyTemplate.PHAST_MC)
    """
    
    def __init__(self, name: str, components: list[MaterialComponent], component_count: Optional[int]=1, property_template: Optional[PropertyTemplate]=PropertyTemplate.PHAST_MC):
        """Initializes a new instance of the Material class"""
        super().__init__()
        self.name = name
        self.components = components
        self.component_count = component_count
        self.property_template = property_template

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.name = str(data.get('name', self.name))

        data_items = data.get('components', [])
        for item in data_items:
            init_item = MaterialComponent()
            init_item.initialise_from_dictionary(item)
            self.components.append(init_item)    
        self.component_count = int(data.get('component_count', self.component_count))
        self.property_template = PropertyTemplate(data.get('property_template', self.property_template))

    def __str__(self):
        parts = [
            '* Material',
            f'Name:    {self.name}',
            '\n'.join(item.__str__() for item in self.components),
            f'Component count:    {self.component_count}',
            f'Property template:    {self.property_template}',
        ]
        return '\n'.join(parts)


class State(object):
    """
    Description of the fluid state.

    Attributes
    ----------
	pressure : float
		Absolute pressure of the fluid. [Pa] 
	temperature : float
		Temperature of the fluid. [K] 
	liquid_fraction : float
		Mole fraction of liquid in the fluid. [fraction] 
	flash_flag : FluidSpec
		How fluid equilibrium is specified. (default value is FluidSpec.TP)
	mixture_modelling : MixtureModelling
		Mixture modelling: Pseudo-component (=0), MC single aerosol (=1), MC multiple aerosol (=3). (default value is MixtureModelling.PC)
    """
    
    def __init__(self, pressure: float, temperature: float, liquid_fraction: float, flash_flag: Optional[FluidSpec]=FluidSpec.TP, mixture_modelling: Optional[MixtureModelling]=MixtureModelling.PC):
        """Initializes a new instance of the State class"""
        super().__init__()
        self.pressure = pressure
        self.temperature = temperature
        self.liquid_fraction = liquid_fraction
        self.flash_flag = flash_flag
        self.mixture_modelling = mixture_modelling

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.pressure = float(data.get('pressure', self.pressure))
        self.temperature = float(data.get('temperature', self.temperature))
        self.liquid_fraction = float(data.get('liquid_fraction', self.liquid_fraction))
        self.flash_flag = FluidSpec(data.get('flash_flag', self.flash_flag))
        self.mixture_modelling = MixtureModelling(data.get('mixture_modelling', self.mixture_modelling))

    def __str__(self):
        parts = [
            '* State',
            f'Pressure:    {self.pressure}',
            f'Temperature:    {self.temperature}',
            f'Liquid fraction:    {self.liquid_fraction}',
            f'Flash flag:    {self.flash_flag}',
            f'Mixture modelling:    {self.mixture_modelling}',
        ]
        return '\n'.join(parts)


class Vessel(Asset):
    """
    All vessel types.

    Attributes
    ----------
	state : State
		Fluid specification (at liquid surface). 
	material : Material
		Material. 
	diameter : float
		Internal diameter of the vessel. [m] (default value is 2)
	height : float
		Internal height of the vessel. [m] (default value is 4)
	length : float
		Internal length of the vessel. [m] (default value is 4)
	width : float
		Internal width of the vessel. [m] (default value is 0.0)
	shape : VesselShape
		Shape. (default value is VesselShape.HORIZONTAL_CYLINDER)
	vessel_conditions : VesselConditions
		Vessel conditions. (default value is VesselConditions.UNSET)
	liquid_fill_fraction_by_volume : float
		The liquid fill fraction in the vessel by volume. [fraction] (default value is 0.0)
	location : LocalPosition
		Location of the asset. (default value is LocalPosition())
    """
    
    def __init__(self, state: State, material: Material, diameter: Optional[float]=2, height: Optional[float]=4, length: Optional[float]=4, width: Optional[float]=0.0, shape: Optional[VesselShape]=VesselShape.HORIZONTAL_CYLINDER, vessel_conditions: Optional[VesselConditions]=VesselConditions.UNSET, liquid_fill_fraction_by_volume: Optional[float]=0.0, location: Optional[LocalPosition]=LocalPosition()):
        """Initializes a new instance of the Vessel class"""
        super().__init__(location)
        self.state = state
        self.material = material
        self.diameter = diameter
        self.height = height
        self.length = length
        self.width = width
        self.shape = shape
        self.vessel_conditions = vessel_conditions
        self.liquid_fill_fraction_by_volume = liquid_fill_fraction_by_volume

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        state_data = data.get('state')
        if state_data is not None:
            self.state.initialise_from_dictionary(state_data)
        material_data = data.get('material')
        if material_data is not None:
            self.material.initialise_from_dictionary(material_data)
        self.diameter = float(data.get('diameter', self.diameter))
        self.height = float(data.get('height', self.height))
        self.length = float(data.get('length', self.length))
        self.width = float(data.get('width', self.width))
        self.shape = VesselShape(data.get('shape', self.shape))
        self.vessel_conditions = VesselConditions(data.get('vessel_conditions', self.vessel_conditions))
        self.liquid_fill_fraction_by_volume = float(data.get('liquid_fill_fraction_by_volume', self.liquid_fill_fraction_by_volume))

    def __str__(self):
        parts = [
            '* Vessel',
            self.state.__str__(),
            self.material.__str__(),
            f'Diameter:    {self.diameter}',
            f'Height:    {self.height}',
            f'Length:    {self.length}',
            f'Width:    {self.width}',
            f'Shape:    {self.shape}',
            f'Vessel conditions:    {self.vessel_conditions}',
            f'Liquid fill fraction by volume:    {self.liquid_fill_fraction_by_volume}',
        ]
        return '\n'.join(parts)


class PropertiesDipprPT3(object):
    """
    Properties DIPPR part 3.

    Attributes
    ----------
	svap_sat : list[float]
		Saturated vapour entropy. 
	sliq_sat : list[float]
		Saturated liquid entropy. 
	rho_vap_sat : list[float]
		Saturated vapour density. 
	hvap_sat : list[float]
		Saturated vapour enthalpy. 
	rho_vap_atm : list[float]
		Vapour density at 1 atm. 
	tvap_sat : list[float]
		Saturated vapour temperature. [K] 
	surface_tension : list[float]
		Surface tension. 
	rho_liq : list[float]
		Liquid density. 
	hliq : list[float]
		Liquid enthalpy. 
	sliq : list[float]
		Liquid entropy. 
	rho_vap : list[float]
		Vapour density. 
	hvap : list[float]
		Vapour enthalpy. 
	svap : list[float]
		Vapour entropy. 
	zvap : list[float]
		Vapour compressibility. 
	sonic_vel_vap : list[float]
		Vapour sonic velocity. 
    """
    
    def __init__(self, svap_sat: list[float], sliq_sat: list[float], rho_vap_sat: list[float], hvap_sat: list[float], rho_vap_atm: list[float], tvap_sat: list[float], surface_tension: list[float], rho_liq: list[float], hliq: list[float], sliq: list[float], rho_vap: list[float], hvap: list[float], svap: list[float], zvap: list[float], sonic_vel_vap: list[float]):
        """Initializes a new instance of the PropertiesDipprPT3 class"""
        super().__init__()
        self.svap_sat = svap_sat
        self.sliq_sat = sliq_sat
        self.rho_vap_sat = rho_vap_sat
        self.hvap_sat = hvap_sat
        self.rho_vap_atm = rho_vap_atm
        self.tvap_sat = tvap_sat
        self.surface_tension = surface_tension
        self.rho_liq = rho_liq
        self.hliq = hliq
        self.sliq = sliq
        self.rho_vap = rho_vap
        self.hvap = hvap
        self.svap = svap
        self.zvap = zvap
        self.sonic_vel_vap = sonic_vel_vap

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""

        data_items = data.get('svap_sat', [])
        for item in data_items:
            self.svap_sat.append(float(item))    

        data_items = data.get('sliq_sat', [])
        for item in data_items:
            self.sliq_sat.append(float(item))    

        data_items = data.get('rho_vap_sat', [])
        for item in data_items:
            self.rho_vap_sat.append(float(item))    

        data_items = data.get('hvap_sat', [])
        for item in data_items:
            self.hvap_sat.append(float(item))    

        data_items = data.get('rho_vap_atm', [])
        for item in data_items:
            self.rho_vap_atm.append(float(item))    

        data_items = data.get('tvap_sat', [])
        for item in data_items:
            self.tvap_sat.append(float(item))    

        data_items = data.get('surface_tension', [])
        for item in data_items:
            self.surface_tension.append(float(item))    

        data_items = data.get('rho_liq', [])
        for item in data_items:
            self.rho_liq.append(float(item))    

        data_items = data.get('hliq', [])
        for item in data_items:
            self.hliq.append(float(item))    

        data_items = data.get('sliq', [])
        for item in data_items:
            self.sliq.append(float(item))    

        data_items = data.get('rho_vap', [])
        for item in data_items:
            self.rho_vap.append(float(item))    

        data_items = data.get('hvap', [])
        for item in data_items:
            self.hvap.append(float(item))    

        data_items = data.get('svap', [])
        for item in data_items:
            self.svap.append(float(item))    

        data_items = data.get('zvap', [])
        for item in data_items:
            self.zvap.append(float(item))    

        data_items = data.get('sonic_vel_vap', [])
        for item in data_items:
            self.sonic_vel_vap.append(float(item))    

    def __str__(self):
        parts = [
            '* PropertiesDipprPT3',
            f'S vap sat:    {self.svap_sat}',
            f'S liq sat:    {self.sliq_sat}',
            f'Rho vap sat:    {self.rho_vap_sat}',
            f'H vap sat:    {self.hvap_sat}',
            f'Rho vap atm:    {self.rho_vap_atm}',
            f'T vap sat:    {self.tvap_sat}',
            f'Surface tension:    {self.surface_tension}',
            f'Rho liq:    {self.rho_liq}',
            f'H liq:    {self.hliq}',
            f'S liq:    {self.sliq}',
            f'Rho vap:    {self.rho_vap}',
            f'H vap:    {self.hvap}',
            f'S vap:    {self.svap}',
            f'Z vap:    {self.zvap}',
            f'Sonic vel vap:    {self.sonic_vel_vap}',
        ]
        return '\n'.join(parts)


class RadiationRecord(object):
    """
    Radiation type and level at specific point (x,y,z).

    Attributes
    ----------
	position : LocalPosition
		Cartesian coordinates of a specific point. 
	radiation_result : float
		Radiation level. 
	radiation_type : RadiationType
		Type of radiation result. (default value is RadiationType.UNSET)
    """
    
    def __init__(self, position: LocalPosition, radiation_result: float, radiation_type: Optional[RadiationType]=RadiationType.UNSET):
        """Initializes a new instance of the RadiationRecord class"""
        super().__init__()
        self.position = position
        self.radiation_result = radiation_result
        self.radiation_type = radiation_type

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        position_data = data.get('position')
        if position_data is not None:
            self.position.initialise_from_dictionary(position_data)
        self.radiation_result = float(data.get('radiation_result', self.radiation_result))
        self.radiation_type = RadiationType(data.get('radiation_type', self.radiation_type))

    def __str__(self):
        parts = [
            '* RadiationRecord',
            self.position.__str__(),
            f'Radiation result:    {self.radiation_result}',
            f'Radiation type:    {self.radiation_type}',
        ]
        return '\n'.join(parts)


class Leak(ReleaseOverTime):
    """
    Leak scenario.

    Attributes
    ----------
	hole_diameter : float
		Diameter of the hole. [m] 
	hole_height_fraction : float
		Location of the hole above the base of the vessel as a fraction of vessel height. [fraction] (default value is 0.5)
	release_angle : float
		Angle above horizontal of release. [Radians] (default value is 0.0)
	time_varying_option : TimeVaryingOption
		Time-varying or steady-state modelling. (default value is TimeVaryingOption.INITIAL_RATE)
    """
    
    def __init__(self, hole_diameter: float, hole_height_fraction: Optional[float]=0.5, release_angle: Optional[float]=0.0, time_varying_option: Optional[TimeVaryingOption]=TimeVaryingOption.INITIAL_RATE):
        """Initializes a new instance of the Leak class"""
        super().__init__(release_angle, time_varying_option)
        self.hole_diameter = hole_diameter
        self.hole_height_fraction = hole_height_fraction

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.hole_diameter = float(data.get('hole_diameter', self.hole_diameter))
        self.hole_height_fraction = float(data.get('hole_height_fraction', self.hole_height_fraction))

    def __str__(self):
        parts = [
            '* Leak',
            f'Hole diameter:    {self.hole_diameter}',
            f'Hole height fraction:    {self.hole_height_fraction}',
        ]
        return '\n'.join(parts)


class Bund(object):
    """
    Bund.

    Attributes
    ----------
	bund_height : float
		Bund height. [m] (default value is 0.0)
	bund_diameter : float
		Bund diameter. [m] (default value is 0.0)
	specify_bund : bool
		Specify a bund. (default value is False)
    """
    
    def __init__(self, bund_height: Optional[float]=0.0, bund_diameter: Optional[float]=0.0, specify_bund: Optional[bool]=False):
        """Initializes a new instance of the Bund class"""
        super().__init__()
        self.bund_height = bund_height
        self.bund_diameter = bund_diameter
        self.specify_bund = specify_bund

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.bund_height = float(data.get('bund_height', self.bund_height))
        self.bund_diameter = float(data.get('bund_diameter', self.bund_diameter))
        self.specify_bund = bool(data.get('specify_bund', self.specify_bund))

    def __str__(self):
        parts = [
            '* Bund',
            f'Bund height:    {self.bund_height}',
            f'Bund diameter:    {self.bund_diameter}',
            f'Specify bund:    {self.specify_bund}',
        ]
        return '\n'.join(parts)


class Substrate(EntityBase):
    """
    The ground over which a release is taking place.

    Attributes
    ----------
	surface_roughness : float
		Surface roughness length. [m] (default value is 0.183)
	surface_type : SurfaceType
		Dispersing surface type. (default value is SurfaceType.LAND)
	pool_surface_type : PoolSurfaceType
		Pool or bund surface type. (default value is PoolSurfaceType.CONCRETE)
	bund : Bund
		Bund data. (default value is Bund())
    """
    
    def __init__(self, surface_roughness: Optional[float]=0.183, surface_type: Optional[SurfaceType]=SurfaceType.LAND, pool_surface_type: Optional[PoolSurfaceType]=PoolSurfaceType.CONCRETE, bund: Optional[Bund]=Bund()):
        """Initializes a new instance of the Substrate class"""
        super().__init__()
        self.bund = bund
        self.surface_roughness = surface_roughness
        self.surface_type = surface_type
        self.pool_surface_type = pool_surface_type

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        bund_data = data.get('bund')
        if bund_data is not None:
            self.bund.initialise_from_dictionary(bund_data)
        self.surface_roughness = float(data.get('surface_roughness', self.surface_roughness))
        self.surface_type = SurfaceType(data.get('surface_type', self.surface_type))
        self.pool_surface_type = PoolSurfaceType(data.get('pool_surface_type', self.pool_surface_type))

    def __str__(self):
        parts = [
            '* Substrate',
            self.bund.__str__(),
            f'Surface roughness:    {self.surface_roughness}',
            f'Surface type:    {self.surface_type}',
            f'Pool surface type:    {self.pool_surface_type}',
        ]
        return '\n'.join(parts)


class ReliefValve(ReleaseOverTime):
    """
    Relief valve scenario.

    Attributes
    ----------
	relief_valve_constriction_diameter : float
		Constriction at the upstream end of the pipe. [m] 
	pipe_diameter : float
		Internal diameter of the short pipe. [m] 
	pipe_length : float
		Length of the short pipe. [m] 
	pipe_roughness : float
		Roughness of the short pipe. [m] (default value is 0.000045)
	pipe_height_fraction : float
		Location of the pipe connection above the base of the vessel. [fraction] (default value is 0.5)
	release_angle : float
		Angle above horizontal of release. [Radians] (default value is 0.0)
	time_varying_option : TimeVaryingOption
		Time-varying or steady-state modelling. (default value is TimeVaryingOption.INITIAL_RATE)
    """
    
    def __init__(self, relief_valve_constriction_diameter: float, pipe_diameter: float, pipe_length: float, pipe_roughness: Optional[float]=0.000045, pipe_height_fraction: Optional[float]=0.5, release_angle: Optional[float]=0.0, time_varying_option: Optional[TimeVaryingOption]=TimeVaryingOption.INITIAL_RATE):
        """Initializes a new instance of the ReliefValve class"""
        super().__init__(release_angle, time_varying_option)
        self.relief_valve_constriction_diameter = relief_valve_constriction_diameter
        self.pipe_diameter = pipe_diameter
        self.pipe_length = pipe_length
        self.pipe_roughness = pipe_roughness
        self.pipe_height_fraction = pipe_height_fraction

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.relief_valve_constriction_diameter = float(data.get('relief_valve_constriction_diameter', self.relief_valve_constriction_diameter))
        self.pipe_diameter = float(data.get('pipe_diameter', self.pipe_diameter))
        self.pipe_length = float(data.get('pipe_length', self.pipe_length))
        self.pipe_roughness = float(data.get('pipe_roughness', self.pipe_roughness))
        self.pipe_height_fraction = float(data.get('pipe_height_fraction', self.pipe_height_fraction))

    def __str__(self):
        parts = [
            '* ReliefValve',
            f'Relief valve constriction diameter:    {self.relief_valve_constriction_diameter}',
            f'Pipe diameter:    {self.pipe_diameter}',
            f'Pipe length:    {self.pipe_length}',
            f'Pipe roughness:    {self.pipe_roughness}',
            f'Pipe height fraction:    {self.pipe_height_fraction}',
        ]
        return '\n'.join(parts)


class ToxicRecord(object):
    """
    Toxic result: dose, probit or lethality.

    Attributes
    ----------
	position : LocalPosition
		Cartesian coordinates of a specific point. 
	toxic_result : float
		Dose, probit or lethality level. 
	toxic_result_type : ToxicResultType
		Type of toxic result. (default value is ToxicResultType.UNSET)
    """
    
    def __init__(self, position: LocalPosition, toxic_result: float, toxic_result_type: Optional[ToxicResultType]=ToxicResultType.UNSET):
        """Initializes a new instance of the ToxicRecord class"""
        super().__init__()
        self.position = position
        self.toxic_result = toxic_result
        self.toxic_result_type = toxic_result_type

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        position_data = data.get('position')
        if position_data is not None:
            self.position.initialise_from_dictionary(position_data)
        self.toxic_result = float(data.get('toxic_result', self.toxic_result))
        self.toxic_result_type = ToxicResultType(data.get('toxic_result_type', self.toxic_result_type))

    def __str__(self):
        parts = [
            '* ToxicRecord',
            self.position.__str__(),
            f'Toxic result:    {self.toxic_result}',
            f'Toxic result type:    {self.toxic_result_type}',
        ]
        return '\n'.join(parts)


class CatastrophicRupture(Instantaneous):
    """
    Catastrophic rupture of a vessel scenario.

    Attributes
    ----------
		None
    """
    
    def __init__(self):
        """Initializes a new instance of the CatastrophicRupture class"""
        super().__init__()
        pass

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        pass

    def __str__(self):
        parts = [
            '* CatastrophicRupture',
        ]
        return '\n'.join(parts)


class DischargeResult(EntityBase):
    """
    Scalar discharge results.

    Attributes
    ----------
	expansion_energy : float
		Specific expansion energy (instantaneous releases only). [J] 
	release_mass : float
		Released mass. [kg] 
	height : float
		Release height above ground. [m] 
	angle : float
		Release angle (non-instantaneous releases only). [Radians] 
	hole_diameter : float
		Diameter of the hole. [m] 
	release_type : DynamicType
		Instantaneous, continuous or time-varying. (default value is DynamicType.UNSET)
	pre_dilution_air_rate : float
		Pre-dilution air rate. [kg/s] (default value is 0)
    """
    
    def __init__(self, expansion_energy: float, release_mass: float, height: float, angle: float, hole_diameter: float, release_type: Optional[DynamicType]=DynamicType.UNSET, pre_dilution_air_rate: Optional[float]=0):
        """Initializes a new instance of the DischargeResult class"""
        super().__init__()
        self.expansion_energy = expansion_energy
        self.release_mass = release_mass
        self.height = height
        self.angle = angle
        self.hole_diameter = hole_diameter
        self.release_type = release_type
        self.pre_dilution_air_rate = pre_dilution_air_rate

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.expansion_energy = float(data.get('expansion_energy', self.expansion_energy))
        self.release_mass = float(data.get('release_mass', self.release_mass))
        self.height = float(data.get('height', self.height))
        self.angle = float(data.get('angle', self.angle))
        self.hole_diameter = float(data.get('hole_diameter', self.hole_diameter))
        self.release_type = DynamicType(data.get('release_type', self.release_type))
        self.pre_dilution_air_rate = float(data.get('pre_dilution_air_rate', self.pre_dilution_air_rate))

    def __str__(self):
        parts = [
            '* DischargeResult',
            f'Expansion energy:    {self.expansion_energy}',
            f'Release mass:    {self.release_mass}',
            f'Height:    {self.height}',
            f'Angle:    {self.angle}',
            f'Hole diameter:    {self.hole_diameter}',
            f'Release type:    {self.release_type}',
            f'Pre dilution air rate:    {self.pre_dilution_air_rate}',
        ]
        return '\n'.join(parts)


class PropertiesDnvPT2(object):
    """
    Properties DNV part 2.

    Attributes
    ----------
	toxic_n : list[float]
		Toxic property N. 
	toxic_a : list[float]
		Toxic property A. 
	toxic_b : list[float]
		Toxic property B. 
	hint_range : list[float]
		Enthalpy interpolation range. [K] 
	liq_water_surf_ten : list[float]
		Liquid water surface tension. 
	solubility_water : list[float]
		Solubility in water. 
	heat_solution : list[float]
		Heat of solution. 
	water_reaction_flag : list[float]
		Reaction with water flag. 
	alpha_water : list[float]
		Water heat transfer coefficient. 
	prob_delayed_exp_cont : list[float]
		Probability of delayed explosion (continuous). 
	prob_delayed_exp_inst : list[float]
		Probability of delayed explosion (instantaneous & QI). 
	prob_delayed_flash_fire_cont : list[float]
		Probability of delayed flash fire (continuous). 
	prob_delayed_flash_fire_inst : list[float]
		Probability of delayed flash fire (instantaneous & QI). 
	prob_delayed_ignition : list[float]
		Probability of delayed ignition (cont., inst. & QI). 
	prob_early_ignition_cont : list[float]
		Probability of early ignition (continuous). 
    """
    
    def __init__(self, toxic_n: list[float], toxic_a: list[float], toxic_b: list[float], hint_range: list[float], liq_water_surf_ten: list[float], solubility_water: list[float], heat_solution: list[float], water_reaction_flag: list[float], alpha_water: list[float], prob_delayed_exp_cont: list[float], prob_delayed_exp_inst: list[float], prob_delayed_flash_fire_cont: list[float], prob_delayed_flash_fire_inst: list[float], prob_delayed_ignition: list[float], prob_early_ignition_cont: list[float]):
        """Initializes a new instance of the PropertiesDnvPT2 class"""
        super().__init__()
        self.toxic_n = toxic_n
        self.toxic_a = toxic_a
        self.toxic_b = toxic_b
        self.hint_range = hint_range
        self.liq_water_surf_ten = liq_water_surf_ten
        self.solubility_water = solubility_water
        self.heat_solution = heat_solution
        self.water_reaction_flag = water_reaction_flag
        self.alpha_water = alpha_water
        self.prob_delayed_exp_cont = prob_delayed_exp_cont
        self.prob_delayed_exp_inst = prob_delayed_exp_inst
        self.prob_delayed_flash_fire_cont = prob_delayed_flash_fire_cont
        self.prob_delayed_flash_fire_inst = prob_delayed_flash_fire_inst
        self.prob_delayed_ignition = prob_delayed_ignition
        self.prob_early_ignition_cont = prob_early_ignition_cont

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""

        data_items = data.get('toxic_n', [])
        for item in data_items:
            self.toxic_n.append(float(item))    

        data_items = data.get('toxic_a', [])
        for item in data_items:
            self.toxic_a.append(float(item))    

        data_items = data.get('toxic_b', [])
        for item in data_items:
            self.toxic_b.append(float(item))    

        data_items = data.get('hint_range', [])
        for item in data_items:
            self.hint_range.append(float(item))    

        data_items = data.get('liq_water_surf_ten', [])
        for item in data_items:
            self.liq_water_surf_ten.append(float(item))    

        data_items = data.get('solubility_water', [])
        for item in data_items:
            self.solubility_water.append(float(item))    

        data_items = data.get('heat_solution', [])
        for item in data_items:
            self.heat_solution.append(float(item))    

        data_items = data.get('water_reaction_flag', [])
        for item in data_items:
            self.water_reaction_flag.append(float(item))    

        data_items = data.get('alpha_water', [])
        for item in data_items:
            self.alpha_water.append(float(item))    

        data_items = data.get('prob_delayed_exp_cont', [])
        for item in data_items:
            self.prob_delayed_exp_cont.append(float(item))    

        data_items = data.get('prob_delayed_exp_inst', [])
        for item in data_items:
            self.prob_delayed_exp_inst.append(float(item))    

        data_items = data.get('prob_delayed_flash_fire_cont', [])
        for item in data_items:
            self.prob_delayed_flash_fire_cont.append(float(item))    

        data_items = data.get('prob_delayed_flash_fire_inst', [])
        for item in data_items:
            self.prob_delayed_flash_fire_inst.append(float(item))    

        data_items = data.get('prob_delayed_ignition', [])
        for item in data_items:
            self.prob_delayed_ignition.append(float(item))    

        data_items = data.get('prob_early_ignition_cont', [])
        for item in data_items:
            self.prob_early_ignition_cont.append(float(item))    

    def __str__(self):
        parts = [
            '* PropertiesDnvPT2',
            f'Toxic n:    {self.toxic_n}',
            f'Toxic a:    {self.toxic_a}',
            f'Toxic b:    {self.toxic_b}',
            f'H int range:    {self.hint_range}',
            f'Liq water surf ten:    {self.liq_water_surf_ten}',
            f'Solubility water:    {self.solubility_water}',
            f'Heat solution:    {self.heat_solution}',
            f'Water reaction flag:    {self.water_reaction_flag}',
            f'Alpha water:    {self.alpha_water}',
            f'Prob delayed exp cont:    {self.prob_delayed_exp_cont}',
            f'Prob delayed exp inst:    {self.prob_delayed_exp_inst}',
            f'Prob delayed flash fire cont:    {self.prob_delayed_flash_fire_cont}',
            f'Prob delayed flash fire inst:    {self.prob_delayed_flash_fire_inst}',
            f'Prob delayed ignition:    {self.prob_delayed_ignition}',
            f'Prob early ignition cont:    {self.prob_early_ignition_cont}',
        ]
        return '\n'.join(parts)


class MaterialComponentDataItem(object):
    """
    Material component data item.

    Attributes
    ----------
	description : str
		Material component data item description. 
	equation_number : int
		Equation number. 
	equation_string : str
		Equation string. 
	equation_coefficients : list[float]
		Equation coefficients. 
	calculation_limits : list[float]
		Calculation limits. 
	supercritical_extrapolation : float
		Super critical extrapolation flag. (default value is 0)
	fraction_tc : float
		Fraction of critical temperature. (default value is 1)
    """
    
    def __init__(self, description: str, equation_number: int, equation_string: str, equation_coefficients: list[float], calculation_limits: list[float], supercritical_extrapolation: Optional[float]=0, fraction_tc: Optional[float]=1):
        """Initializes a new instance of the MaterialComponentDataItem class"""
        super().__init__()
        self.description = description
        self.equation_number = equation_number
        self.equation_string = equation_string
        self.equation_coefficients = equation_coefficients
        self.calculation_limits = calculation_limits
        self.supercritical_extrapolation = supercritical_extrapolation
        self.fraction_tc = fraction_tc

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.description = str(data.get('description', self.description))
        self.equation_number = int(data.get('equation_number', self.equation_number))
        self.equation_string = str(data.get('equation_string', self.equation_string))

        data_items = data.get('equation_coefficients', [])
        for item in data_items:
            self.equation_coefficients.append(float(item))    

        data_items = data.get('calculation_limits', [])
        for item in data_items:
            self.calculation_limits.append(float(item))    
        self.supercritical_extrapolation = float(data.get('supercritical_extrapolation', self.supercritical_extrapolation))
        self.fraction_tc = float(data.get('fraction_tc', self.fraction_tc))

    def __str__(self):
        parts = [
            '* MaterialComponentDataItem',
            f'Description:    {self.description}',
            f'Equation number:    {self.equation_number}',
            f'Equation string:    {self.equation_string}',
            f'Equation coefficients:    {self.equation_coefficients}',
            f'Calculation limits:    {self.calculation_limits}',
            f'Supercritical extrapolation:    {self.supercritical_extrapolation}',
            f'Fraction tc:    {self.fraction_tc}',
        ]
        return '\n'.join(parts)


class MaterialComponentData(EntityBase):
    """
    Material component data.

    Attributes
    ----------
	name : str
		Name of the material component data. 
	dippr_version : int
		DIPPR version number. 
	cas_id : int
		CAS id. 
	data_item : list[MaterialComponentDataItem]
		List of data items defining the material component data. 
    """
    
    def __init__(self, name: str, dippr_version: int, cas_id: int, data_item: list[MaterialComponentDataItem]):
        """Initializes a new instance of the MaterialComponentData class"""
        super().__init__()
        self.name = name
        self.dippr_version = dippr_version
        self.cas_id = cas_id
        self.data_item = data_item

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.name = str(data.get('name', self.name))
        self.dippr_version = int(data.get('dippr_version', self.dippr_version))
        self.cas_id = int(data.get('cas_id', self.cas_id))

        data_items = data.get('data_item', [])
        for item in data_items:
            init_item = MaterialComponentDataItem()
            init_item.initialise_from_dictionary(item)
            self.data_item.append(init_item)    

    def __str__(self):
        parts = [
            '* MaterialComponentData',
            f'Name:    {self.name}',
            f'Dippr version:    {self.dippr_version}',
            f'Cas id:    {self.cas_id}',
            '\n'.join(item.__str__() for item in self.data_item),
        ]
        return '\n'.join(parts)


class AtmosphericStorageTank(Asset):
    """
    Atmospheric storage tank.

    Attributes
    ----------
	state : State
		State (temperature). 
	diameter : float
		Diameter of the tank. [m] 
	height : float
		Height of the tank. [m] 
	material : Material
		Material. 
	liquid_fill_fraction_by_volume : float
		Liquid fill fraction by volume. [fraction] (default value is 0.9)
	location : LocalPosition
		Location of the asset. (default value is LocalPosition())
    """
    
    def __init__(self, state: State, diameter: float, height: float, material: Material, liquid_fill_fraction_by_volume: Optional[float]=0.9, location: Optional[LocalPosition]=LocalPosition()):
        """Initializes a new instance of the AtmosphericStorageTank class"""
        super().__init__(location)
        self.state = state
        self.diameter = diameter
        self.height = height
        self.material = material
        self.liquid_fill_fraction_by_volume = liquid_fill_fraction_by_volume

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        state_data = data.get('state')
        if state_data is not None:
            self.state.initialise_from_dictionary(state_data)
        self.diameter = float(data.get('diameter', self.diameter))
        self.height = float(data.get('height', self.height))
        material_data = data.get('material')
        if material_data is not None:
            self.material.initialise_from_dictionary(material_data)
        self.liquid_fill_fraction_by_volume = float(data.get('liquid_fill_fraction_by_volume', self.liquid_fill_fraction_by_volume))

    def __str__(self):
        parts = [
            '* AtmosphericStorageTank',
            self.state.__str__(),
            f'Diameter:    {self.diameter}',
            f'Height:    {self.height}',
            self.material.__str__(),
            f'Liquid fill fraction by volume:    {self.liquid_fill_fraction_by_volume}',
        ]
        return '\n'.join(parts)


class FlammableParameters(EntityBase):
    """
    Fire and radiation parameters.

    Attributes
    ----------
	max_exposure_duration : float
		Maximum exposure duration to radiation effects. [s] (default value is 20)
	radiation_relative_tolerance : float
		Relative tolerance for radiation calculations. [fraction] (default value is 0.01)
	pool_fire_type : PoolFireType
		Type of pool fire modelling. (default value is PoolFireType.LATE)
	jet_fire_auto_select : bool
		Option to automatically select jet fire modelling. (default value is False)
	time_averaging : bool
		Average between 0 s and the time of interest?. (default value is True)
	time_of_interest : float
		Time of interest. (default value is 20)
    """
    
    def __init__(self, max_exposure_duration: Optional[float]=20, radiation_relative_tolerance: Optional[float]=0.01, pool_fire_type: Optional[PoolFireType]=PoolFireType.LATE, jet_fire_auto_select: Optional[bool]=False, time_averaging: Optional[bool]=True, time_of_interest: Optional[float]=20):
        """Initializes a new instance of the FlammableParameters class"""
        super().__init__()
        self.max_exposure_duration = max_exposure_duration
        self.radiation_relative_tolerance = radiation_relative_tolerance
        self.pool_fire_type = pool_fire_type
        self.jet_fire_auto_select = jet_fire_auto_select
        self.time_averaging = time_averaging
        self.time_of_interest = time_of_interest

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.max_exposure_duration = float(data.get('max_exposure_duration', self.max_exposure_duration))
        self.radiation_relative_tolerance = float(data.get('radiation_relative_tolerance', self.radiation_relative_tolerance))
        self.pool_fire_type = PoolFireType(data.get('pool_fire_type', self.pool_fire_type))
        self.jet_fire_auto_select = bool(data.get('jet_fire_auto_select', self.jet_fire_auto_select))
        self.time_averaging = bool(data.get('time_averaging', self.time_averaging))
        self.time_of_interest = float(data.get('time_of_interest', self.time_of_interest))

    def __str__(self):
        parts = [
            '* FlammableParameters',
            f'Max exposure duration:    {self.max_exposure_duration}',
            f'Radiation relative tolerance:    {self.radiation_relative_tolerance}',
            f'Pool fire type:    {self.pool_fire_type}',
            f'Jet fire auto select:    {self.jet_fire_auto_select}',
            f'Time averaging:    {self.time_averaging}',
            f'Time of interest:    {self.time_of_interest}',
        ]
        return '\n'.join(parts)


class FlameResult(object):
    """
    Fire results.

    Attributes
    ----------
	time : float
		Time of fire, or duration if initial rate. [s] 
	surface_emissive_power : float
		Surface emissive power of flame. [W/m2] 
	flame_length : float
		Length of the flame. [m] 
	flame_diameter : float
		Diameter of the flame. [m] 
	fire_type : FireType
		Fire type  (Fireball, pool, cone jet, API jet, Multi point source jet). (default value is FireType.NO_FIRE)
    """
    
    def __init__(self, time: float, surface_emissive_power: float, flame_length: float, flame_diameter: float, fire_type: Optional[FireType]=FireType.NO_FIRE):
        """Initializes a new instance of the FlameResult class"""
        super().__init__()
        self.time = time
        self.surface_emissive_power = surface_emissive_power
        self.flame_length = flame_length
        self.flame_diameter = flame_diameter
        self.fire_type = fire_type

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.time = float(data.get('time', self.time))
        self.surface_emissive_power = float(data.get('surface_emissive_power', self.surface_emissive_power))
        self.flame_length = float(data.get('flame_length', self.flame_length))
        self.flame_diameter = float(data.get('flame_diameter', self.flame_diameter))
        self.fire_type = FireType(data.get('fire_type', self.fire_type))

    def __str__(self):
        parts = [
            '* FlameResult',
            f'Time:    {self.time}',
            f'Surface emissive power:    {self.surface_emissive_power}',
            f'Flame length:    {self.flame_length}',
            f'Flame diameter:    {self.flame_diameter}',
            f'Fire type:    {self.fire_type}',
        ]
        return '\n'.join(parts)


class PoolFireFlameResult(FlameResult):
    """
    Pool fire flame result.

    Attributes
    ----------
	pool_zone_sep : list[float]
		Surface emissive power from each of the two pool fire zones. [W/m2] 
	time : float
		Time of fire, or duration if initial rate. [s] 
	surface_emissive_power : float
		Surface emissive power of flame. [W/m2] 
	flame_length : float
		Length of the flame. [m] 
	flame_diameter : float
		Diameter of the flame. [m] 
	fire_type : FireType
		Fire type  (Fireball, pool, cone jet, API jet, Multi point source jet). (default value is FireType.NO_FIRE)
    """
    
    def __init__(self, pool_zone_sep: list[float], time: float, surface_emissive_power: float, flame_length: float, flame_diameter: float, fire_type: Optional[FireType]=FireType.NO_FIRE):
        """Initializes a new instance of the PoolFireFlameResult class"""
        super().__init__(time, surface_emissive_power, flame_length, flame_diameter, fire_type)
        self.pool_zone_sep = pool_zone_sep

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)

        data_items = data.get('pool_zone_sep', [])
        for item in data_items:
            self.pool_zone_sep.append(float(item))    

    def __str__(self):
        parts = [
            '* PoolFireFlameResult',
            f'Pool zone SEP:    {self.pool_zone_sep}',
        ]
        return '\n'.join(parts)


class PropertiesDipprPT1(object):
    """
    Properties DIPPR part 1.

    Attributes
    ----------
	total_steps_used : int
		Description of new property. 
	pressure : list[float]
		Array of pressure values. [Pa] 
	temperature : list[float]
		Array of temperatures. [K] 
	mass_comp : list[float]
		Mass of the composition. 
	mw_comp : list[float]
		Description of new property. 
	dangerous_toxic_load : list[float]
		Dangerous Toxic Load. 
	pcrit : list[float]
		Critical pressure . [Pa] 
	tcrit : list[float]
		Description of new property. [K] 
	tmelt : list[float]
		Melting point. [K] 
	tboil : list[float]
		Boiling point. [K] 
	tflash : list[float]
		Flash point. [K] 
	hcomb : list[float]
		Heat of combustion. 
	lfl : list[float]
		Lower flammability limit - vol%. 
	ufl : list[float]
		upper flammability limit. 
	comb_at : list[float]
		Combustion coefficient At. 
	comb_ct : list[float]
		Combustion coefficient Ct. 
    """
    
    def __init__(self, total_steps_used: int, pressure: list[float], temperature: list[float], mass_comp: list[float], mw_comp: list[float], dangerous_toxic_load: list[float], pcrit: list[float], tcrit: list[float], tmelt: list[float], tboil: list[float], tflash: list[float], hcomb: list[float], lfl: list[float], ufl: list[float], comb_at: list[float], comb_ct: list[float]):
        """Initializes a new instance of the PropertiesDipprPT1 class"""
        super().__init__()
        self.total_steps_used = total_steps_used
        self.pressure = pressure
        self.temperature = temperature
        self.mass_comp = mass_comp
        self.mw_comp = mw_comp
        self.dangerous_toxic_load = dangerous_toxic_load
        self.pcrit = pcrit
        self.tcrit = tcrit
        self.tmelt = tmelt
        self.tboil = tboil
        self.tflash = tflash
        self.hcomb = hcomb
        self.lfl = lfl
        self.ufl = ufl
        self.comb_at = comb_at
        self.comb_ct = comb_ct

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.total_steps_used = int(data.get('total_steps_used', self.total_steps_used))

        data_items = data.get('pressure', [])
        for item in data_items:
            self.pressure.append(float(item))    

        data_items = data.get('temperature', [])
        for item in data_items:
            self.temperature.append(float(item))    

        data_items = data.get('mass_comp', [])
        for item in data_items:
            self.mass_comp.append(float(item))    

        data_items = data.get('mw_comp', [])
        for item in data_items:
            self.mw_comp.append(float(item))    

        data_items = data.get('dangerous_toxic_load', [])
        for item in data_items:
            self.dangerous_toxic_load.append(float(item))    

        data_items = data.get('pcrit', [])
        for item in data_items:
            self.pcrit.append(float(item))    

        data_items = data.get('tcrit', [])
        for item in data_items:
            self.tcrit.append(float(item))    

        data_items = data.get('tmelt', [])
        for item in data_items:
            self.tmelt.append(float(item))    

        data_items = data.get('tboil', [])
        for item in data_items:
            self.tboil.append(float(item))    

        data_items = data.get('tflash', [])
        for item in data_items:
            self.tflash.append(float(item))    

        data_items = data.get('hcomb', [])
        for item in data_items:
            self.hcomb.append(float(item))    

        data_items = data.get('lfl', [])
        for item in data_items:
            self.lfl.append(float(item))    

        data_items = data.get('ufl', [])
        for item in data_items:
            self.ufl.append(float(item))    

        data_items = data.get('comb_at', [])
        for item in data_items:
            self.comb_at.append(float(item))    

        data_items = data.get('comb_ct', [])
        for item in data_items:
            self.comb_ct.append(float(item))    

    def __str__(self):
        parts = [
            '* PropertiesDipprPT1',
            f'Total steps used:    {self.total_steps_used}',
            f'Pressure:    {self.pressure}',
            f'Temperature:    {self.temperature}',
            f'Mass comp:    {self.mass_comp}',
            f'MW comp:    {self.mw_comp}',
            f'Dangerous toxic load:    {self.dangerous_toxic_load}',
            f'P crit:    {self.pcrit}',
            f'T crit:    {self.tcrit}',
            f'T melt:    {self.tmelt}',
            f'T boil:    {self.tboil}',
            f'T flash:    {self.tflash}',
            f'H comb:    {self.hcomb}',
            f'LFL:    {self.lfl}',
            f'UFL:    {self.ufl}',
            f'Comb at:    {self.comb_at}',
            f'Comb ct:    {self.comb_ct}',
        ]
        return '\n'.join(parts)


class ConcentrationRecord(object):
    """
    Concentration record.

    Attributes
    ----------
	concentration : float
		Cloud concentration at an x, y, z position. [fraction] 
	position : LocalPosition
		x, y, z position. 
    """
    
    def __init__(self, concentration: float, position: LocalPosition):
        """Initializes a new instance of the ConcentrationRecord class"""
        super().__init__()
        self.concentration = concentration
        self.position = position

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.concentration = float(data.get('concentration', self.concentration))
        position_data = data.get('position')
        if position_data is not None:
            self.position.initialise_from_dictionary(position_data)

    def __str__(self):
        parts = [
            '* ConcentrationRecord',
            f'Concentration:    {self.concentration}',
            self.position.__str__(),
        ]
        return '\n'.join(parts)


class Pipe(Asset):
    """
    All pipe types.

    Attributes
    ----------
	nodes : list[LocalPosition]
		Pipeline nodes. 
	node_count : int
		Number of nodes. 
	diameter : float
		Pipe diameter. [m] 
	material : Material
		Material. 
	state : State
		Fluid state. 
	roughness : float
		Pipe roughness. [m] (default value is 4.5e-5)
	pumped_inflow : float
		Upstream pumped inflow. [kg/s] (default value is 0)
	location : LocalPosition
		Location of the asset. (default value is LocalPosition())
    """
    
    def __init__(self, nodes: list[LocalPosition], node_count: int, diameter: float, material: Material, state: State, roughness: Optional[float]=4.5e-5, pumped_inflow: Optional[float]=0, location: Optional[LocalPosition]=LocalPosition()):
        """Initializes a new instance of the Pipe class"""
        super().__init__(location)
        self.nodes = nodes
        self.node_count = node_count
        self.diameter = diameter
        self.material = material
        self.state = state
        self.roughness = roughness
        self.pumped_inflow = pumped_inflow

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)

        data_items = data.get('nodes', [])
        for item in data_items:
            init_item = LocalPosition()
            init_item.initialise_from_dictionary(item)
            self.nodes.append(init_item)    
        self.node_count = int(data.get('node_count', self.node_count))
        self.diameter = float(data.get('diameter', self.diameter))
        material_data = data.get('material')
        if material_data is not None:
            self.material.initialise_from_dictionary(material_data)
        state_data = data.get('state')
        if state_data is not None:
            self.state.initialise_from_dictionary(state_data)
        self.roughness = float(data.get('roughness', self.roughness))
        self.pumped_inflow = float(data.get('pumped_inflow', self.pumped_inflow))

    def __str__(self):
        parts = [
            '* Pipe',
            '\n'.join(item.__str__() for item in self.nodes),
            f'Node count:    {self.node_count}',
            f'Diameter:    {self.diameter}',
            self.material.__str__(),
            self.state.__str__(),
            f'Roughness:    {self.roughness}',
            f'Pumped inflow:    {self.pumped_inflow}',
        ]
        return '\n'.join(parts)


class Interval(object):
    """
    A range of permitted values for the design variable when carrying out a design optimization workflow.

    Attributes
    ----------
	lower_boundary : float
		The lower boundary of the interval. 
	upper_boundary : float
		The upper boundary of the interval. 
    """
    
    def __init__(self, lower_boundary: float, upper_boundary: float):
        """Initializes a new instance of the Interval class"""
        super().__init__()
        self.lower_boundary = lower_boundary
        self.upper_boundary = upper_boundary

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.lower_boundary = float(data.get('lower_boundary', self.lower_boundary))
        self.upper_boundary = float(data.get('upper_boundary', self.upper_boundary))

    def __str__(self):
        parts = [
            '* Interval',
            f'Lower boundary:    {self.lower_boundary}',
            f'Upper boundary:    {self.upper_boundary}',
        ]
        return '\n'.join(parts)


class Constraint(object):
    """
    A set of data describing a design constraint. This includes the result target of interest  (e.g. mass flow) and the design variable (e.g. stack diameter).

    Attributes
    ----------
	target_variable_value : float
		User-defined target value for the chosen result type. 
	permitted_design_variable_interval : Interval
		An interval of permitted values for the design variable. 
	target_variable : TargetVariable
		The result type to be prescribed as a design target. (default value is TargetVariable.MASS_FLOW_RATE)
	design_variable : DesignVariable
		The input type to vary to achieve the design target. (default value is DesignVariable.PIPE_DIAMETER)
    """
    
    def __init__(self, target_variable_value: float, permitted_design_variable_interval: Interval, target_variable: Optional[TargetVariable]=TargetVariable.MASS_FLOW_RATE, design_variable: Optional[DesignVariable]=DesignVariable.PIPE_DIAMETER):
        """Initializes a new instance of the Constraint class"""
        super().__init__()
        self.target_variable_value = target_variable_value
        self.permitted_design_variable_interval = permitted_design_variable_interval
        self.target_variable = target_variable
        self.design_variable = design_variable

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.target_variable_value = float(data.get('target_variable_value', self.target_variable_value))
        permitted_design_variable_interval_data = data.get('permitted_design_variable_interval')
        if permitted_design_variable_interval_data is not None:
            self.permitted_design_variable_interval.initialise_from_dictionary(permitted_design_variable_interval_data)
        self.target_variable = TargetVariable(data.get('target_variable', self.target_variable))
        self.design_variable = DesignVariable(data.get('design_variable', self.design_variable))

    def __str__(self):
        parts = [
            '* Constraint',
            f'Target variable value:    {self.target_variable_value}',
            self.permitted_design_variable_interval.__str__(),
            f'Target variable:    {self.target_variable}',
            f'Design variable:    {self.design_variable}',
        ]
        return '\n'.join(parts)


class VesselRuleSet(EntityBase):
    """
    Rule set for generating scenarios from a vessel.

    Attributes
    ----------
	hole_diameters : list[float]
		Hole diameters for leaks. [m] 
	use_time_varying : bool
		Use time-varying leaks. (default value is False)
	include_catastrophic_rupture : bool
		Include catastrophic rupture scenarios. (default value is False)
	number_of_diameters : int
		Number of hole diameters (<= 5). (default value is 3)
    """
    
    def __init__(self, hole_diameters: list[float], use_time_varying: Optional[bool]=False, include_catastrophic_rupture: Optional[bool]=False, number_of_diameters: Optional[int]=3):
        """Initializes a new instance of the VesselRuleSet class"""
        super().__init__()
        self.hole_diameters = hole_diameters
        self.use_time_varying = use_time_varying
        self.include_catastrophic_rupture = include_catastrophic_rupture
        self.number_of_diameters = number_of_diameters

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)

        data_items = data.get('hole_diameters', [])
        for item in data_items:
            self.hole_diameters.append(float(item))    
        self.use_time_varying = bool(data.get('use_time_varying', self.use_time_varying))
        self.include_catastrophic_rupture = bool(data.get('include_catastrophic_rupture', self.include_catastrophic_rupture))
        self.number_of_diameters = int(data.get('number_of_diameters', self.number_of_diameters))

    def __str__(self):
        parts = [
            '* VesselRuleSet',
            f'Hole diameters:    {self.hole_diameters}',
            f'Use time varying:    {self.use_time_varying}',
            f'Include catastrophic rupture:    {self.include_catastrophic_rupture}',
            f'Number of diameters:    {self.number_of_diameters}',
        ]
        return '\n'.join(parts)


class ExplosionConfinedVolume(EntityBase):
    """
    Confined explosion volume data.

    Attributes
    ----------
	confined_strength : float
		Explosion strength of confined volume. (default value is 7)
	confined_volume : float
		Explosion volume of confined source. [m3] (default value is 1)
    """
    
    def __init__(self, confined_strength: Optional[float]=7, confined_volume: Optional[float]=1):
        """Initializes a new instance of the ExplosionConfinedVolume class"""
        super().__init__()
        self.confined_strength = confined_strength
        self.confined_volume = confined_volume

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.confined_strength = float(data.get('confined_strength', self.confined_strength))
        self.confined_volume = float(data.get('confined_volume', self.confined_volume))

    def __str__(self):
        parts = [
            '* ExplosionConfinedVolume',
            f'Confined strength:    {self.confined_strength}',
            f'Confined volume:    {self.confined_volume}',
        ]
        return '\n'.join(parts)


class Structure(EntityBase):
    """
    A building or process plant structure.

    Attributes
    ----------
	explosion_confined_volume : ExplosionConfinedVolume
		Explosion confined volume. 
	location : LocalPosition
		Location of the structure. (default value is LocalPosition())
    """
    
    def __init__(self, explosion_confined_volume: ExplosionConfinedVolume, location: Optional[LocalPosition]=LocalPosition()):
        """Initializes a new instance of the Structure class"""
        super().__init__()
        self.explosion_confined_volume = explosion_confined_volume
        self.location = location

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        explosion_confined_volume_data = data.get('explosion_confined_volume')
        if explosion_confined_volume_data is not None:
            self.explosion_confined_volume.initialise_from_dictionary(explosion_confined_volume_data)
        location_data = data.get('location')
        if location_data is not None:
            self.location.initialise_from_dictionary(location_data)

    def __str__(self):
        parts = [
            '* Structure',
            self.explosion_confined_volume.__str__(),
            self.location.__str__(),
        ]
        return '\n'.join(parts)


class PropertiesDnvPT3(object):
    """
    Properties DNV part 3.

    Attributes
    ----------
	prob_early_ignition_inst : list[float]
		Probability of early ignition (instantaneous & QI). 
	prob_early_pool_fire : list[float]
		Probability of early pool fire. 
	prob_fireball : list[float]
		Probability of fireball. 
	prob_free_jet_exp : list[float]
		Probability of free jet explosion. 
	prob_free_jet_fire : list[float]
		Probability of free jet fire. 
	prob_late_pool_fire : list[float]
		Probability of late pool fire. 
	dimer_coeff : list[float]
		Dimer coefficient. 
	trimer_coeff : list[float]
		Trimer coefficient. 
	hexamer_coeff : list[float]
		Hexamer coefficient. 
	octamer_coeff : list[float]
		Octamer coefficient. 
	hliq_water : list[float]
		Liquid water enthalpy . 
	pvap_sat_ln : list[float]
		Natural log of the saturated vap. pressure. 
	dp_vap_sat_ln_dt : list[float]
		First derivative of the natural log of sat.vap.pres. w.r.t. temp. 
	d2pvap_sat_ln_dt_2 : list[float]
		Second der. of the natural log. of sat.vap.pres. w.r.t. temp. 
    """
    
    def __init__(self, prob_early_ignition_inst: list[float], prob_early_pool_fire: list[float], prob_fireball: list[float], prob_free_jet_exp: list[float], prob_free_jet_fire: list[float], prob_late_pool_fire: list[float], dimer_coeff: list[float], trimer_coeff: list[float], hexamer_coeff: list[float], octamer_coeff: list[float], hliq_water: list[float], pvap_sat_ln: list[float], dp_vap_sat_ln_dt: list[float], d2pvap_sat_ln_dt_2: list[float]):
        """Initializes a new instance of the PropertiesDnvPT3 class"""
        super().__init__()
        self.prob_early_ignition_inst = prob_early_ignition_inst
        self.prob_early_pool_fire = prob_early_pool_fire
        self.prob_fireball = prob_fireball
        self.prob_free_jet_exp = prob_free_jet_exp
        self.prob_free_jet_fire = prob_free_jet_fire
        self.prob_late_pool_fire = prob_late_pool_fire
        self.dimer_coeff = dimer_coeff
        self.trimer_coeff = trimer_coeff
        self.hexamer_coeff = hexamer_coeff
        self.octamer_coeff = octamer_coeff
        self.hliq_water = hliq_water
        self.pvap_sat_ln = pvap_sat_ln
        self.dp_vap_sat_ln_dt = dp_vap_sat_ln_dt
        self.d2pvap_sat_ln_dt_2 = d2pvap_sat_ln_dt_2

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""

        data_items = data.get('prob_early_ignition_inst', [])
        for item in data_items:
            self.prob_early_ignition_inst.append(float(item))    

        data_items = data.get('prob_early_pool_fire', [])
        for item in data_items:
            self.prob_early_pool_fire.append(float(item))    

        data_items = data.get('prob_fireball', [])
        for item in data_items:
            self.prob_fireball.append(float(item))    

        data_items = data.get('prob_free_jet_exp', [])
        for item in data_items:
            self.prob_free_jet_exp.append(float(item))    

        data_items = data.get('prob_free_jet_fire', [])
        for item in data_items:
            self.prob_free_jet_fire.append(float(item))    

        data_items = data.get('prob_late_pool_fire', [])
        for item in data_items:
            self.prob_late_pool_fire.append(float(item))    

        data_items = data.get('dimer_coeff', [])
        for item in data_items:
            self.dimer_coeff.append(float(item))    

        data_items = data.get('trimer_coeff', [])
        for item in data_items:
            self.trimer_coeff.append(float(item))    

        data_items = data.get('hexamer_coeff', [])
        for item in data_items:
            self.hexamer_coeff.append(float(item))    

        data_items = data.get('octamer_coeff', [])
        for item in data_items:
            self.octamer_coeff.append(float(item))    

        data_items = data.get('hliq_water', [])
        for item in data_items:
            self.hliq_water.append(float(item))    

        data_items = data.get('pvap_sat_ln', [])
        for item in data_items:
            self.pvap_sat_ln.append(float(item))    

        data_items = data.get('dp_vap_sat_ln_dt', [])
        for item in data_items:
            self.dp_vap_sat_ln_dt.append(float(item))    

        data_items = data.get('d2pvap_sat_ln_dt_2', [])
        for item in data_items:
            self.d2pvap_sat_ln_dt_2.append(float(item))    

    def __str__(self):
        parts = [
            '* PropertiesDnvPT3',
            f'Prob early ignition inst:    {self.prob_early_ignition_inst}',
            f'Prob early pool fire:    {self.prob_early_pool_fire}',
            f'Prob fireball:    {self.prob_fireball}',
            f'Prob free jet exp:    {self.prob_free_jet_exp}',
            f'Prob free jet fire:    {self.prob_free_jet_fire}',
            f'Prob late pool fire:    {self.prob_late_pool_fire}',
            f'Dimer coeff:    {self.dimer_coeff}',
            f'Trimer coeff:    {self.trimer_coeff}',
            f'Hexamer coeff:    {self.hexamer_coeff}',
            f'Octamer coeff:    {self.octamer_coeff}',
            f'H liq water:    {self.hliq_water}',
            f'P vap sat ln:    {self.pvap_sat_ln}',
            f'DP vap sat ln DT:    {self.dp_vap_sat_ln_dt}',
            f'D2P vap sat ln DT2:    {self.d2pvap_sat_ln_dt_2}',
        ]
        return '\n'.join(parts)


class Weather(EntityBase):
    """
    A sum of the meteorological conditions at the time.

    Attributes
    ----------
	wind_speed : float
		Wind speed at reference height. [m/s] (default value is 5)
	stability_class : AtmosphericStabilityClass
		Stability class. (default value is AtmosphericStabilityClass.STABILITY_D)
	temperature : float
		Ambient temperature. [K] (default value is 283)
	relative_humidity : float
		Relative humidity. [fraction] (default value is 0.7)
	mixing_layer_height : float
		Mixing layer height. [m] (default value is 800)
	solar_radiation : float
		Solar radiation flux. [W/m2] (default value is 500)
    """
    
    def __init__(self, wind_speed: Optional[float]=5, stability_class: Optional[AtmosphericStabilityClass]=AtmosphericStabilityClass.STABILITY_D, temperature: Optional[float]=283, relative_humidity: Optional[float]=0.7, mixing_layer_height: Optional[float]=800, solar_radiation: Optional[float]=500):
        """Initializes a new instance of the Weather class"""
        super().__init__()
        self.wind_speed = wind_speed
        self.stability_class = stability_class
        self.temperature = temperature
        self.relative_humidity = relative_humidity
        self.mixing_layer_height = mixing_layer_height
        self.solar_radiation = solar_radiation

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.wind_speed = float(data.get('wind_speed', self.wind_speed))
        self.stability_class = AtmosphericStabilityClass(data.get('stability_class', self.stability_class))
        self.temperature = float(data.get('temperature', self.temperature))
        self.relative_humidity = float(data.get('relative_humidity', self.relative_humidity))
        self.mixing_layer_height = float(data.get('mixing_layer_height', self.mixing_layer_height))
        self.solar_radiation = float(data.get('solar_radiation', self.solar_radiation))

    def __str__(self):
        parts = [
            '* Weather',
            f'Wind speed:    {self.wind_speed}',
            f'Stability class:    {self.stability_class}',
            f'Temperature:    {self.temperature}',
            f'Relative humidity:    {self.relative_humidity}',
            f'Mixing layer height:    {self.mixing_layer_height}',
            f'Solar radiation:    {self.solar_radiation}',
        ]
        return '\n'.join(parts)


class ExplosionOutputConfig(EntityBase):
    """
    Explosion output configuration.

    Attributes
    ----------
	overpressure_level : float
		Overpressure of interest for explosions. [Pa] (default value is 2068)
	me_confined_method : MEConfinedMethod
		Explosion ME confined method where Uniform Confined = 3, User Defined = 1. (default value is MEConfinedMethod.UNIFORM_CONFINED)
    """
    
    def __init__(self, overpressure_level: Optional[float]=2068, me_confined_method: Optional[MEConfinedMethod]=MEConfinedMethod.UNIFORM_CONFINED):
        """Initializes a new instance of the ExplosionOutputConfig class"""
        super().__init__()
        self.overpressure_level = overpressure_level
        self.me_confined_method = me_confined_method

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.overpressure_level = float(data.get('overpressure_level', self.overpressure_level))
        self.me_confined_method = MEConfinedMethod(data.get('me_confined_method', self.me_confined_method))

    def __str__(self):
        parts = [
            '* ExplosionOutputConfig',
            f'Overpressure level:    {self.overpressure_level}',
            f'ME confined method:    {self.me_confined_method}',
        ]
        return '\n'.join(parts)


class FlashResult(object):
    """
    Physical properties for a material generated at a particular pressure and temperature.

    Attributes
    ----------
	pressure : float
		Pressure. [Pa] 
	temperature : float
		Temperature. [K] 
	liquid_mole_fraction : float
		Liquid fraction (mole). [fraction] 
	liquid_density : float
		Density of liquid phase. [kg/m3] 
	vapour_density : float
		Density of vapour phase. [kg/m3] 
	liquid_entropy : float
		Entropy of liquid phase. [J/kg.K] 
	vapour_entropy : float
		Entropy of vapour phase. [J/kg.K] 
	liquid_enthalpy : float
		Enthalpy of liquid phase. [J/kg] 
	vapour_enthalpy : float
		Enthalpy of vapour phase. [J/kg] 
	bubble_point_pressure : float
		Mixture bubble point pressure at given temperature. [Pa] 
	bubble_point_temperature : float
		Mixture bubble point temperature at given pressure. [K] 
	dew_point_pressure : float
		Mixture dew point pressure at given temperature. [Pa] 
	dew_point_temperature : float
		Mixture dew point temperature at given pressure. [K] 
	total_fluid_density : float
		Total fluid density (mass-based). [kg/m3] 
	liquid_mass_fraction : float
		Liquid mass fraction. [fraction] 
	fluid_phase : Phase
		Vapour, liquid or two-phase. (default value is Phase.UNSET)
    """
    
    def __init__(self, pressure: float, temperature: float, liquid_mole_fraction: float, liquid_density: float, vapour_density: float, liquid_entropy: float, vapour_entropy: float, liquid_enthalpy: float, vapour_enthalpy: float, bubble_point_pressure: float, bubble_point_temperature: float, dew_point_pressure: float, dew_point_temperature: float, total_fluid_density: float, liquid_mass_fraction: float, fluid_phase: Optional[Phase]=Phase.UNSET):
        """Initializes a new instance of the FlashResult class"""
        super().__init__()
        self.pressure = pressure
        self.temperature = temperature
        self.liquid_mole_fraction = liquid_mole_fraction
        self.liquid_density = liquid_density
        self.vapour_density = vapour_density
        self.liquid_entropy = liquid_entropy
        self.vapour_entropy = vapour_entropy
        self.liquid_enthalpy = liquid_enthalpy
        self.vapour_enthalpy = vapour_enthalpy
        self.bubble_point_pressure = bubble_point_pressure
        self.bubble_point_temperature = bubble_point_temperature
        self.dew_point_pressure = dew_point_pressure
        self.dew_point_temperature = dew_point_temperature
        self.total_fluid_density = total_fluid_density
        self.liquid_mass_fraction = liquid_mass_fraction
        self.fluid_phase = fluid_phase

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.pressure = float(data.get('pressure', self.pressure))
        self.temperature = float(data.get('temperature', self.temperature))
        self.liquid_mole_fraction = float(data.get('liquid_mole_fraction', self.liquid_mole_fraction))
        self.liquid_density = float(data.get('liquid_density', self.liquid_density))
        self.vapour_density = float(data.get('vapour_density', self.vapour_density))
        self.liquid_entropy = float(data.get('liquid_entropy', self.liquid_entropy))
        self.vapour_entropy = float(data.get('vapour_entropy', self.vapour_entropy))
        self.liquid_enthalpy = float(data.get('liquid_enthalpy', self.liquid_enthalpy))
        self.vapour_enthalpy = float(data.get('vapour_enthalpy', self.vapour_enthalpy))
        self.bubble_point_pressure = float(data.get('bubble_point_pressure', self.bubble_point_pressure))
        self.bubble_point_temperature = float(data.get('bubble_point_temperature', self.bubble_point_temperature))
        self.dew_point_pressure = float(data.get('dew_point_pressure', self.dew_point_pressure))
        self.dew_point_temperature = float(data.get('dew_point_temperature', self.dew_point_temperature))
        self.total_fluid_density = float(data.get('total_fluid_density', self.total_fluid_density))
        self.liquid_mass_fraction = float(data.get('liquid_mass_fraction', self.liquid_mass_fraction))
        self.fluid_phase = Phase(data.get('fluid_phase', self.fluid_phase))

    def __str__(self):
        parts = [
            '* FlashResult',
            f'Pressure:    {self.pressure}',
            f'Temperature:    {self.temperature}',
            f'Liquid mole fraction:    {self.liquid_mole_fraction}',
            f'Liquid density:    {self.liquid_density}',
            f'Vapour density:    {self.vapour_density}',
            f'Liquid entropy:    {self.liquid_entropy}',
            f'Vapour entropy:    {self.vapour_entropy}',
            f'Liquid enthalpy:    {self.liquid_enthalpy}',
            f'Vapour enthalpy:    {self.vapour_enthalpy}',
            f'Bubble point pressure:    {self.bubble_point_pressure}',
            f'Bubble point temperature:    {self.bubble_point_temperature}',
            f'Dew point pressure:    {self.dew_point_pressure}',
            f'Dew point temperature:    {self.dew_point_temperature}',
            f'Total fluid density:    {self.total_fluid_density}',
            f'Liquid mass fraction:    {self.liquid_mass_fraction}',
            f'Fluid phase:    {self.fluid_phase}',
        ]
        return '\n'.join(parts)


class ScalarUdmOutputs(object):
    """
    Scalar UDM output values required for post processing dispersion results.

    Attributes
    ----------
	observer_count : int
		Number of observers. 
	record_count : int
		Number of records. 
	minimum_concentration : float
		Minimum concentration. [fraction] 
	wind_power : float
		Wind power. 
	friction_velocity : float
		Friction velocity. [m/s] 
	dispersion_release_duration : float
		When is the last release observer released?. [s] 
	cloud_type : DynamicType
		Cloud type. (default value is DynamicType.UNSET)
    """
    
    def __init__(self, observer_count: int, record_count: int, minimum_concentration: float, wind_power: float, friction_velocity: float, dispersion_release_duration: float, cloud_type: Optional[DynamicType]=DynamicType.UNSET):
        """Initializes a new instance of the ScalarUdmOutputs class"""
        super().__init__()
        self.observer_count = observer_count
        self.record_count = record_count
        self.minimum_concentration = minimum_concentration
        self.wind_power = wind_power
        self.friction_velocity = friction_velocity
        self.dispersion_release_duration = dispersion_release_duration
        self.cloud_type = cloud_type

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.observer_count = int(data.get('observer_count', self.observer_count))
        self.record_count = int(data.get('record_count', self.record_count))
        self.minimum_concentration = float(data.get('minimum_concentration', self.minimum_concentration))
        self.wind_power = float(data.get('wind_power', self.wind_power))
        self.friction_velocity = float(data.get('friction_velocity', self.friction_velocity))
        self.dispersion_release_duration = float(data.get('dispersion_release_duration', self.dispersion_release_duration))
        self.cloud_type = DynamicType(data.get('cloud_type', self.cloud_type))

    def __str__(self):
        parts = [
            '* ScalarUdmOutputs',
            f'Observer count:    {self.observer_count}',
            f'Record count:    {self.record_count}',
            f'Minimum concentration:    {self.minimum_concentration}',
            f'Wind power:    {self.wind_power}',
            f'Friction velocity:    {self.friction_velocity}',
            f'Dispersion release duration:    {self.dispersion_release_duration}',
            f'Cloud type:    {self.cloud_type}',
        ]
        return '\n'.join(parts)


class PTRange(object):
    """
    Range of pressure and temperature.

    Attributes
    ----------
	pressure_low : float
		Start value of pressure range. [Pa] 
	pressure_high : float
		End value of pressure range. [Pa] 
	temp_low : float
		Start value of temperature range. [K] 
	temp_high : float
		End value of temperature range. [K] 
	steps_per_variable : int
		Description of new property. (default value is 20)
    """
    
    def __init__(self, pressure_low: float, pressure_high: float, temp_low: float, temp_high: float, steps_per_variable: Optional[int]=20):
        """Initializes a new instance of the PTRange class"""
        super().__init__()
        self.pressure_low = pressure_low
        self.pressure_high = pressure_high
        self.temp_low = temp_low
        self.temp_high = temp_high
        self.steps_per_variable = steps_per_variable

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.pressure_low = float(data.get('pressure_low', self.pressure_low))
        self.pressure_high = float(data.get('pressure_high', self.pressure_high))
        self.temp_low = float(data.get('temp_low', self.temp_low))
        self.temp_high = float(data.get('temp_high', self.temp_high))
        self.steps_per_variable = int(data.get('steps_per_variable', self.steps_per_variable))

    def __str__(self):
        parts = [
            '* PTRange',
            f'Pressure low:    {self.pressure_low}',
            f'Pressure high:    {self.pressure_high}',
            f'Temp low:    {self.temp_low}',
            f'Temp high:    {self.temp_high}',
            f'Steps per variable:    {self.steps_per_variable}',
        ]
        return '\n'.join(parts)


class ShortPipeRupture(ReleaseOverTime):
    """
    Short pipe rupture scenario.

    Attributes
    ----------
	pipe_length : float
		Length of short pipe. [m] 
	pipe_diameter : float
		Inner diameter of the short pipe. [m] 
	pipe_roughness : float
		Roughness of the short pipe. [m] (default value is 0.000045)
	pipe_height_fraction : float
		Location of the pipe connection above the base of the vessel. [fraction] (default value is 0.5)
	release_angle : float
		Angle above horizontal of release. [Radians] (default value is 0.0)
	time_varying_option : TimeVaryingOption
		Time-varying or steady-state modelling. (default value is TimeVaryingOption.INITIAL_RATE)
    """
    
    def __init__(self, pipe_length: float, pipe_diameter: float, pipe_roughness: Optional[float]=0.000045, pipe_height_fraction: Optional[float]=0.5, release_angle: Optional[float]=0.0, time_varying_option: Optional[TimeVaryingOption]=TimeVaryingOption.INITIAL_RATE):
        """Initializes a new instance of the ShortPipeRupture class"""
        super().__init__(release_angle, time_varying_option)
        self.pipe_length = pipe_length
        self.pipe_diameter = pipe_diameter
        self.pipe_roughness = pipe_roughness
        self.pipe_height_fraction = pipe_height_fraction

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.pipe_length = float(data.get('pipe_length', self.pipe_length))
        self.pipe_diameter = float(data.get('pipe_diameter', self.pipe_diameter))
        self.pipe_roughness = float(data.get('pipe_roughness', self.pipe_roughness))
        self.pipe_height_fraction = float(data.get('pipe_height_fraction', self.pipe_height_fraction))

    def __str__(self):
        parts = [
            '* ShortPipeRupture',
            f'Pipe length:    {self.pipe_length}',
            f'Pipe diameter:    {self.pipe_diameter}',
            f'Pipe roughness:    {self.pipe_roughness}',
            f'Pipe height fraction:    {self.pipe_height_fraction}',
        ]
        return '\n'.join(parts)


class PipeBreach(ReleaseOverTime):
    """
    Breach in a long pipe (runs GSPP / PBRK).

    Attributes
    ----------
	distance_downstream : float
		Distance downstream. [m] 
	relative_aperture : float
		Breach relative aperture. [fraction] (default value is 1)
	release_angle : float
		Angle above horizontal of release. [Radians] (default value is 0.0)
	time_varying_option : TimeVaryingOption
		Time-varying or steady-state modelling. (default value is TimeVaryingOption.INITIAL_RATE)
    """
    
    def __init__(self, distance_downstream: float, relative_aperture: Optional[float]=1, release_angle: Optional[float]=0.0, time_varying_option: Optional[TimeVaryingOption]=TimeVaryingOption.INITIAL_RATE):
        """Initializes a new instance of the PipeBreach class"""
        super().__init__(release_angle, time_varying_option)
        self.distance_downstream = distance_downstream
        self.relative_aperture = relative_aperture

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.distance_downstream = float(data.get('distance_downstream', self.distance_downstream))
        self.relative_aperture = float(data.get('relative_aperture', self.relative_aperture))

    def __str__(self):
        parts = [
            '* PipeBreach',
            f'Distance downstream:    {self.distance_downstream}',
            f'Relative aperture:    {self.relative_aperture}',
        ]
        return '\n'.join(parts)


class MixtureConstantPropertiesResult(object):
    """
    Mixture constant properties.

    Attributes
    ----------
	lower_flammability_limit : float
		Description of new property. [fraction] 
	upper_flammability_limit : float
		Description of new property. [fraction] 
	critical_pressure : float
		Critical pressure. [Pa] 
	critical_temperature : float
		Critical temperature. [K] 
	flash_point : float
		Flash point. [K] 
	heat_combustion : float
		Heat of combustion. 
	maximum_burn_rate : float
		Maximum burn rate. 
	maximum_sep : float
		Maximum surface emissive power. 
	molecular_weight : float
		Molecular weight. [kg/kmol] 
	bubble_point : float
		Bubble point at atmospheric pressure. [K] 
	pool_fire_burn_rate_length : float
		Pool fire burn rate length. [m] 
	dew_point : float
		Dew point at atmospheric pressure. [K] 
	emissive_power_length_scale : float
		Emissive power length scale. [m] 
	laminar_burning_velocity : float
		Laminar burning velocity of mixture. [m/s] 
	flammable_toxic_flag : FlammableToxic
		Flammable or toxic flag. (default value is FlammableToxic.INERT)
	luminous_smoky_flame : LuminousSmokyFlame
		Luminous or smoky flame. (default value is LuminousSmokyFlame.GENERAL)
    """
    
    def __init__(self, lower_flammability_limit: float, upper_flammability_limit: float, critical_pressure: float, critical_temperature: float, flash_point: float, heat_combustion: float, maximum_burn_rate: float, maximum_sep: float, molecular_weight: float, bubble_point: float, pool_fire_burn_rate_length: float, dew_point: float, emissive_power_length_scale: float, laminar_burning_velocity: float, flammable_toxic_flag: Optional[FlammableToxic]=FlammableToxic.INERT, luminous_smoky_flame: Optional[LuminousSmokyFlame]=LuminousSmokyFlame.GENERAL):
        """Initializes a new instance of the MixtureConstantPropertiesResult class"""
        super().__init__()
        self.lower_flammability_limit = lower_flammability_limit
        self.upper_flammability_limit = upper_flammability_limit
        self.critical_pressure = critical_pressure
        self.critical_temperature = critical_temperature
        self.flash_point = flash_point
        self.heat_combustion = heat_combustion
        self.maximum_burn_rate = maximum_burn_rate
        self.maximum_sep = maximum_sep
        self.molecular_weight = molecular_weight
        self.bubble_point = bubble_point
        self.pool_fire_burn_rate_length = pool_fire_burn_rate_length
        self.dew_point = dew_point
        self.emissive_power_length_scale = emissive_power_length_scale
        self.laminar_burning_velocity = laminar_burning_velocity
        self.flammable_toxic_flag = flammable_toxic_flag
        self.luminous_smoky_flame = luminous_smoky_flame

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.lower_flammability_limit = float(data.get('lower_flammability_limit', self.lower_flammability_limit))
        self.upper_flammability_limit = float(data.get('upper_flammability_limit', self.upper_flammability_limit))
        self.critical_pressure = float(data.get('critical_pressure', self.critical_pressure))
        self.critical_temperature = float(data.get('critical_temperature', self.critical_temperature))
        self.flash_point = float(data.get('flash_point', self.flash_point))
        self.heat_combustion = float(data.get('heat_combustion', self.heat_combustion))
        self.maximum_burn_rate = float(data.get('maximum_burn_rate', self.maximum_burn_rate))
        self.maximum_sep = float(data.get('maximum_sep', self.maximum_sep))
        self.molecular_weight = float(data.get('molecular_weight', self.molecular_weight))
        self.bubble_point = float(data.get('bubble_point', self.bubble_point))
        self.pool_fire_burn_rate_length = float(data.get('pool_fire_burn_rate_length', self.pool_fire_burn_rate_length))
        self.dew_point = float(data.get('dew_point', self.dew_point))
        self.emissive_power_length_scale = float(data.get('emissive_power_length_scale', self.emissive_power_length_scale))
        self.laminar_burning_velocity = float(data.get('laminar_burning_velocity', self.laminar_burning_velocity))
        self.flammable_toxic_flag = FlammableToxic(data.get('flammable_toxic_flag', self.flammable_toxic_flag))
        self.luminous_smoky_flame = LuminousSmokyFlame(data.get('luminous_smoky_flame', self.luminous_smoky_flame))

    def __str__(self):
        parts = [
            '* MixtureConstantPropertiesResult',
            f'Lower flammability limit:    {self.lower_flammability_limit}',
            f'Upper flammability limit:    {self.upper_flammability_limit}',
            f'Critical pressure:    {self.critical_pressure}',
            f'Critical temperature:    {self.critical_temperature}',
            f'Flash point:    {self.flash_point}',
            f'Heat combustion:    {self.heat_combustion}',
            f'Maximum burn rate:    {self.maximum_burn_rate}',
            f'Maximum SEP:    {self.maximum_sep}',
            f'Molecular weight:    {self.molecular_weight}',
            f'Bubble point:    {self.bubble_point}',
            f'Pool fire burn rate length:    {self.pool_fire_burn_rate_length}',
            f'Dew point:    {self.dew_point}',
            f'Emissive power length scale:    {self.emissive_power_length_scale}',
            f'Laminar burning velocity:    {self.laminar_burning_velocity}',
            f'Flammable toxic flag:    {self.flammable_toxic_flag}',
            f'Luminous smoky flame:    {self.luminous_smoky_flame}',
        ]
        return '\n'.join(parts)


class FlareStack(Asset):
    """
    Contains inputs required for running a flare stack calculation.

    Attributes
    ----------
	flare_stack_material : Material
		Material being flared. 
	flare_stack_fluid_state : State
		Fluid state in flare stack (driving the outflow). 
	flare_stack_height : float
		Flare stack tip height above ground level. [m] 
	flare_stack_tip_diameter : float
		Diameter of flare stack tip. [m] 
	flare_stack_conditions : VesselConditions
		Phase of the stored material. (default value is VesselConditions.PURE_GAS)
	location : LocalPosition
		Location of the asset. (default value is LocalPosition())
    """
    
    def __init__(self, flare_stack_material: Material, flare_stack_fluid_state: State, flare_stack_height: float, flare_stack_tip_diameter: float, flare_stack_conditions: Optional[VesselConditions]=VesselConditions.PURE_GAS, location: Optional[LocalPosition]=LocalPosition()):
        """Initializes a new instance of the FlareStack class"""
        super().__init__(location)
        self.flare_stack_material = flare_stack_material
        self.flare_stack_fluid_state = flare_stack_fluid_state
        self.flare_stack_height = flare_stack_height
        self.flare_stack_tip_diameter = flare_stack_tip_diameter
        self.flare_stack_conditions = flare_stack_conditions

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        flare_stack_material_data = data.get('flare_stack_material')
        if flare_stack_material_data is not None:
            self.flare_stack_material.initialise_from_dictionary(flare_stack_material_data)
        flare_stack_fluid_state_data = data.get('flare_stack_fluid_state')
        if flare_stack_fluid_state_data is not None:
            self.flare_stack_fluid_state.initialise_from_dictionary(flare_stack_fluid_state_data)
        self.flare_stack_height = float(data.get('flare_stack_height', self.flare_stack_height))
        self.flare_stack_tip_diameter = float(data.get('flare_stack_tip_diameter', self.flare_stack_tip_diameter))
        self.flare_stack_conditions = VesselConditions(data.get('flare_stack_conditions', self.flare_stack_conditions))

    def __str__(self):
        parts = [
            '* FlareStack',
            self.flare_stack_material.__str__(),
            self.flare_stack_fluid_state.__str__(),
            f'Flare stack height:    {self.flare_stack_height}',
            f'Flare stack tip diameter:    {self.flare_stack_tip_diameter}',
            f'Flare stack conditions:    {self.flare_stack_conditions}',
        ]
        return '\n'.join(parts)


class DispersionRecord(object):
    """
    Observer dispersion record at a given time.

    Attributes
    ----------
	observer_index : int
		Id of the observer associated with this record. 
	centreline_concentration : float
		Centreline concentraton (molar). [fraction] 
	downwind_distance : float
		Distance downwind. [m] 
	time : float
		Time after the start of the release. [s] 
	centreline_concentration_uncorrected : float
		Uncorrected centreline concentraton (molar). [fraction] 
	crosswind_radius : float
		Crosswind radius. [m] 
	vertical_radius : float
		Vertical radius. [m] 
	crosswind_exponent : float
		Crosswind exponent. 
	vertical_exponent : float
		Vertical exponent. 
	theta : float
		Centreline angle from horizontal. [Radians] 
	centreline_height : float
		Centreline height. [m] 
	liquid_fraction : float
		Liquid mass fraction. [fraction] 
	vapour_temperature : float
		Vapour temperature. [K] 
	mass_conc : float
		Mass concentration. [kg/m3] 
	velocity : float
		Velocity. [m/s] 
	mass_flow : float
		Mass flow rate (non-instantaneous). [kg/s] 
	profile_flag : int
		Profile flag. 
	elev_flag : int
		Elevation flag. 
	rho_cloud : float
		Cloud density. [kg/m3] 
	liq_temp : float
		Liquid temperature. [K] 
	effective_width : float
		Effective width. [m] 
	effective_height : float
		Effective height. [m] 
	pass_tran_dist : float
		Passive transition distance. [m] 
	downwind_radius : float
		Downwind radius. [m] 
	droplet_diameter : float
		Droplet diameter. [m] 
	droplet_height : float
		Droplet height. [m] 
	droplet_distance : float
		Droplet downwind distance. [m] 
	mass : float
		Mass (instantaneous). [kg] 
	inst_con : DynamicType
		Instantanous or continuous (time-varying not permitted). (default value is DynamicType.UNSET)
    """
    
    def __init__(self, observer_index: int, centreline_concentration: float, downwind_distance: float, time: float, centreline_concentration_uncorrected: float, crosswind_radius: float, vertical_radius: float, crosswind_exponent: float, vertical_exponent: float, theta: float, centreline_height: float, liquid_fraction: float, vapour_temperature: float, mass_conc: float, velocity: float, mass_flow: float, profile_flag: int, elev_flag: int, rho_cloud: float, liq_temp: float, effective_width: float, effective_height: float, pass_tran_dist: float, downwind_radius: float, droplet_diameter: float, droplet_height: float, droplet_distance: float, mass: float, inst_con: Optional[DynamicType]=DynamicType.UNSET):
        """Initializes a new instance of the DispersionRecord class"""
        super().__init__()
        self.observer_index = observer_index
        self.centreline_concentration = centreline_concentration
        self.downwind_distance = downwind_distance
        self.time = time
        self.centreline_concentration_uncorrected = centreline_concentration_uncorrected
        self.crosswind_radius = crosswind_radius
        self.vertical_radius = vertical_radius
        self.crosswind_exponent = crosswind_exponent
        self.vertical_exponent = vertical_exponent
        self.theta = theta
        self.centreline_height = centreline_height
        self.liquid_fraction = liquid_fraction
        self.vapour_temperature = vapour_temperature
        self.mass_conc = mass_conc
        self.velocity = velocity
        self.mass_flow = mass_flow
        self.profile_flag = profile_flag
        self.elev_flag = elev_flag
        self.rho_cloud = rho_cloud
        self.liq_temp = liq_temp
        self.effective_width = effective_width
        self.effective_height = effective_height
        self.pass_tran_dist = pass_tran_dist
        self.downwind_radius = downwind_radius
        self.droplet_diameter = droplet_diameter
        self.droplet_height = droplet_height
        self.droplet_distance = droplet_distance
        self.mass = mass
        self.inst_con = inst_con

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.observer_index = int(data.get('observer_index', self.observer_index))
        self.centreline_concentration = float(data.get('centreline_concentration', self.centreline_concentration))
        self.downwind_distance = float(data.get('downwind_distance', self.downwind_distance))
        self.time = float(data.get('time', self.time))
        self.centreline_concentration_uncorrected = float(data.get('centreline_concentration_uncorrected', self.centreline_concentration_uncorrected))
        self.crosswind_radius = float(data.get('crosswind_radius', self.crosswind_radius))
        self.vertical_radius = float(data.get('vertical_radius', self.vertical_radius))
        self.crosswind_exponent = float(data.get('crosswind_exponent', self.crosswind_exponent))
        self.vertical_exponent = float(data.get('vertical_exponent', self.vertical_exponent))
        self.theta = float(data.get('theta', self.theta))
        self.centreline_height = float(data.get('centreline_height', self.centreline_height))
        self.liquid_fraction = float(data.get('liquid_fraction', self.liquid_fraction))
        self.vapour_temperature = float(data.get('vapour_temperature', self.vapour_temperature))
        self.mass_conc = float(data.get('mass_conc', self.mass_conc))
        self.velocity = float(data.get('velocity', self.velocity))
        self.mass_flow = float(data.get('mass_flow', self.mass_flow))
        self.profile_flag = int(data.get('profile_flag', self.profile_flag))
        self.elev_flag = int(data.get('elev_flag', self.elev_flag))
        self.rho_cloud = float(data.get('rho_cloud', self.rho_cloud))
        self.liq_temp = float(data.get('liq_temp', self.liq_temp))
        self.effective_width = float(data.get('effective_width', self.effective_width))
        self.effective_height = float(data.get('effective_height', self.effective_height))
        self.pass_tran_dist = float(data.get('pass_tran_dist', self.pass_tran_dist))
        self.downwind_radius = float(data.get('downwind_radius', self.downwind_radius))
        self.droplet_diameter = float(data.get('droplet_diameter', self.droplet_diameter))
        self.droplet_height = float(data.get('droplet_height', self.droplet_height))
        self.droplet_distance = float(data.get('droplet_distance', self.droplet_distance))
        self.mass = float(data.get('mass', self.mass))
        self.inst_con = DynamicType(data.get('inst_con', self.inst_con))

    def __str__(self):
        parts = [
            '* DispersionRecord',
            f'Observer index:    {self.observer_index}',
            f'Centreline concentration:    {self.centreline_concentration}',
            f'Downwind distance:    {self.downwind_distance}',
            f'Time:    {self.time}',
            f'Centreline concentration uncorrected:    {self.centreline_concentration_uncorrected}',
            f'Crosswind radius:    {self.crosswind_radius}',
            f'Vertical radius:    {self.vertical_radius}',
            f'Crosswind exponent:    {self.crosswind_exponent}',
            f'Vertical exponent:    {self.vertical_exponent}',
            f'Theta:    {self.theta}',
            f'Centreline height:    {self.centreline_height}',
            f'Liquid fraction:    {self.liquid_fraction}',
            f'Vapour temperature:    {self.vapour_temperature}',
            f'Mass conc:    {self.mass_conc}',
            f'Velocity:    {self.velocity}',
            f'Mass flow:    {self.mass_flow}',
            f'Profile flag:    {self.profile_flag}',
            f'Elev flag:    {self.elev_flag}',
            f'Rho cloud:    {self.rho_cloud}',
            f'Liq temp:    {self.liq_temp}',
            f'Effective width:    {self.effective_width}',
            f'Effective height:    {self.effective_height}',
            f'Pass tran dist:    {self.pass_tran_dist}',
            f'Downwind radius:    {self.downwind_radius}',
            f'Droplet diameter:    {self.droplet_diameter}',
            f'Droplet height:    {self.droplet_height}',
            f'Droplet distance:    {self.droplet_distance}',
            f'Mass:    {self.mass}',
            f'Inst con:    {self.inst_con}',
        ]
        return '\n'.join(parts)


class VesselSphere(Asset):
    """
    Vessel sphere.

    Attributes
    ----------
	state : State
		The thermodynamic state of the fluid. 
	material : Material
		Material. 
	mass_inventory : float
		Mass inventory. [kg] 
	location : LocalPosition
		Location of the asset. (default value is LocalPosition())
    """
    
    def __init__(self, state: State, material: Material, mass_inventory: float, location: Optional[LocalPosition]=LocalPosition()):
        """Initializes a new instance of the VesselSphere class"""
        super().__init__(location)
        self.state = state
        self.material = material
        self.mass_inventory = mass_inventory

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        state_data = data.get('state')
        if state_data is not None:
            self.state.initialise_from_dictionary(state_data)
        material_data = data.get('material')
        if material_data is not None:
            self.material.initialise_from_dictionary(material_data)
        self.mass_inventory = float(data.get('mass_inventory', self.mass_inventory))

    def __str__(self):
        parts = [
            '* VesselSphere',
            self.state.__str__(),
            self.material.__str__(),
            f'Mass inventory:    {self.mass_inventory}',
        ]
        return '\n'.join(parts)


class ThermoPathRecord(object):
    """
    Contains a point on the thermodynamic depressurization trajectory for each of isothermal, isentropic and isenthalpic assumptions.

    Attributes
    ----------
	pressure : float
		Absolute pressure value at specific point on the thermodynamic path. [Pa] 
	bubble_temperature : float
		Bubble point temperature at given pressure. [K] 
	dew_temperature : float
		Dew point temperature at given pressure. [K] 
	isentropic_temperature : float
		Temperature at given pressure following isentropic depressurization. [K] 
	isenthalpic_temperature : float
		Temperature at given pressure following isenthalpic depressurization. [K] 
	isothermal_temperature : float
		Temperature at given pressure following isothermal depressurization. [K] 
    """
    
    def __init__(self, pressure: float, bubble_temperature: float, dew_temperature: float, isentropic_temperature: float, isenthalpic_temperature: float, isothermal_temperature: float):
        """Initializes a new instance of the ThermoPathRecord class"""
        super().__init__()
        self.pressure = pressure
        self.bubble_temperature = bubble_temperature
        self.dew_temperature = dew_temperature
        self.isentropic_temperature = isentropic_temperature
        self.isenthalpic_temperature = isenthalpic_temperature
        self.isothermal_temperature = isothermal_temperature

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.pressure = float(data.get('pressure', self.pressure))
        self.bubble_temperature = float(data.get('bubble_temperature', self.bubble_temperature))
        self.dew_temperature = float(data.get('dew_temperature', self.dew_temperature))
        self.isentropic_temperature = float(data.get('isentropic_temperature', self.isentropic_temperature))
        self.isenthalpic_temperature = float(data.get('isenthalpic_temperature', self.isenthalpic_temperature))
        self.isothermal_temperature = float(data.get('isothermal_temperature', self.isothermal_temperature))

    def __str__(self):
        parts = [
            '* ThermoPathRecord',
            f'Pressure:    {self.pressure}',
            f'Bubble temperature:    {self.bubble_temperature}',
            f'Dew temperature:    {self.dew_temperature}',
            f'Isentropic temperature:    {self.isentropic_temperature}',
            f'Isenthalpic temperature:    {self.isenthalpic_temperature}',
            f'Isothermal temperature:    {self.isothermal_temperature}',
        ]
        return '\n'.join(parts)


class DispersionParameters(EntityBase):
    """
    Dispersion Parameters.

    Attributes
    ----------
	relative_tolerance : float
		Relative tolerance. [fraction] (default value is 0.001)
	rainout_thermo_flag : RainoutThermoFlag
		Rainout and equilibrium method. (default value is RainoutThermoFlag.RAINOUT_NON_EQUILIBRIUM)
	fixed_step_size : float
		Fixed step size. [s] (default value is 0.01)
	output_step_multiplier : float
		Ratio to increase step size. (default value is 1.2)
	max_dispersion_distance : float
		Absolute maximum distance for dispersion calculations. [m] (default value is 50000)
	max_dispersion_height : float
		Absolute maximum height for dispersion calculations. [m] (default value is 1000)
	number_of_release_observers : int
		Number of release observers for time-varying releases. (default value is 5)
	number_of_pool_observers : int
		Number of pool observers for rainout cases. (default value is 10)
	averaging_time : float
		Core averaging time. [s] (default value is 18.75)
	lfl_fraction_to_stop : float
		The lowest LFL fraction of interest. [fraction] (default value is 0.5)
    """
    
    def __init__(self, relative_tolerance: Optional[float]=0.001, rainout_thermo_flag: Optional[RainoutThermoFlag]=RainoutThermoFlag.RAINOUT_NON_EQUILIBRIUM, fixed_step_size: Optional[float]=0.01, output_step_multiplier: Optional[float]=1.2, max_dispersion_distance: Optional[float]=50000, max_dispersion_height: Optional[float]=1000, number_of_release_observers: Optional[int]=5, number_of_pool_observers: Optional[int]=10, averaging_time: Optional[float]=18.75, lfl_fraction_to_stop: Optional[float]=0.5):
        """Initializes a new instance of the DispersionParameters class"""
        super().__init__()
        self.relative_tolerance = relative_tolerance
        self.rainout_thermo_flag = rainout_thermo_flag
        self.fixed_step_size = fixed_step_size
        self.output_step_multiplier = output_step_multiplier
        self.max_dispersion_distance = max_dispersion_distance
        self.max_dispersion_height = max_dispersion_height
        self.number_of_release_observers = number_of_release_observers
        self.number_of_pool_observers = number_of_pool_observers
        self.averaging_time = averaging_time
        self.lfl_fraction_to_stop = lfl_fraction_to_stop

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.relative_tolerance = float(data.get('relative_tolerance', self.relative_tolerance))
        self.rainout_thermo_flag = RainoutThermoFlag(data.get('rainout_thermo_flag', self.rainout_thermo_flag))
        self.fixed_step_size = float(data.get('fixed_step_size', self.fixed_step_size))
        self.output_step_multiplier = float(data.get('output_step_multiplier', self.output_step_multiplier))
        self.max_dispersion_distance = float(data.get('max_dispersion_distance', self.max_dispersion_distance))
        self.max_dispersion_height = float(data.get('max_dispersion_height', self.max_dispersion_height))
        self.number_of_release_observers = int(data.get('number_of_release_observers', self.number_of_release_observers))
        self.number_of_pool_observers = int(data.get('number_of_pool_observers', self.number_of_pool_observers))
        self.averaging_time = float(data.get('averaging_time', self.averaging_time))
        self.lfl_fraction_to_stop = float(data.get('lfl_fraction_to_stop', self.lfl_fraction_to_stop))

    def __str__(self):
        parts = [
            '* DispersionParameters',
            f'Relative tolerance:    {self.relative_tolerance}',
            f'Rainout thermo flag:    {self.rainout_thermo_flag}',
            f'Fixed step size:    {self.fixed_step_size}',
            f'Output step multiplier:    {self.output_step_multiplier}',
            f'Max dispersion distance:    {self.max_dispersion_distance}',
            f'Max dispersion height:    {self.max_dispersion_height}',
            f'Number of release observers:    {self.number_of_release_observers}',
            f'Number of pool observers:    {self.number_of_pool_observers}',
            f'Averaging time:    {self.averaging_time}',
            f'LFL fraction to stop:    {self.lfl_fraction_to_stop}',
        ]
        return '\n'.join(parts)


class LineRupture(ReleaseOverTime):
    """
    Line rupture scenario.

    Attributes
    ----------
	pipe_diameter : float
		Internal diameter of the short pipe. [m] 
	pipe_length : float
		Length of the short pipe. [m] 
	pipe_roughness : float
		Roughness of the short pipe. [m] (default value is 0.000045)
	pipe_height_fraction : float
		Location of the pipe connection above the base of the vessel. [fraction] (default value is 0.5)
	release_angle : float
		Angle above horizontal of release. [Radians] (default value is 0.0)
	time_varying_option : TimeVaryingOption
		Time-varying or steady-state modelling. (default value is TimeVaryingOption.INITIAL_RATE)
    """
    
    def __init__(self, pipe_diameter: float, pipe_length: float, pipe_roughness: Optional[float]=0.000045, pipe_height_fraction: Optional[float]=0.5, release_angle: Optional[float]=0.0, time_varying_option: Optional[TimeVaryingOption]=TimeVaryingOption.INITIAL_RATE):
        """Initializes a new instance of the LineRupture class"""
        super().__init__(release_angle, time_varying_option)
        self.pipe_diameter = pipe_diameter
        self.pipe_length = pipe_length
        self.pipe_roughness = pipe_roughness
        self.pipe_height_fraction = pipe_height_fraction

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.pipe_diameter = float(data.get('pipe_diameter', self.pipe_diameter))
        self.pipe_length = float(data.get('pipe_length', self.pipe_length))
        self.pipe_roughness = float(data.get('pipe_roughness', self.pipe_roughness))
        self.pipe_height_fraction = float(data.get('pipe_height_fraction', self.pipe_height_fraction))

    def __str__(self):
        parts = [
            '* LineRupture',
            f'Pipe diameter:    {self.pipe_diameter}',
            f'Pipe length:    {self.pipe_length}',
            f'Pipe roughness:    {self.pipe_roughness}',
            f'Pipe height fraction:    {self.pipe_height_fraction}',
        ]
        return '\n'.join(parts)


class ConstantMaterialResult(object):
    """
    Constant material properties, i.e. critical pressure, temperature, mole weight.

    Attributes
    ----------
	critical_pressure : float
		The critical pressure of the material. [Pa] 
	critical_temperature : float
		The critical temperature of the material. [K] 
	total_molecular_weight : float
		The total molecular weight of the material. [kg/kmol] 
    """
    
    def __init__(self, critical_pressure: float, critical_temperature: float, total_molecular_weight: float):
        """Initializes a new instance of the ConstantMaterialResult class"""
        super().__init__()
        self.critical_pressure = critical_pressure
        self.critical_temperature = critical_temperature
        self.total_molecular_weight = total_molecular_weight

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.critical_pressure = float(data.get('critical_pressure', self.critical_pressure))
        self.critical_temperature = float(data.get('critical_temperature', self.critical_temperature))
        self.total_molecular_weight = float(data.get('total_molecular_weight', self.total_molecular_weight))

    def __str__(self):
        parts = [
            '* ConstantMaterialResult',
            f'Critical pressure:    {self.critical_pressure}',
            f'Critical temperature:    {self.critical_temperature}',
            f'Total molecular weight:    {self.total_molecular_weight}',
        ]
        return '\n'.join(parts)


class FlameRecord(object):
    """
    Flame geometry description.

    Attributes
    ----------
	x_coordinate : float
		Distance downwind. [m] 
	z_coordinate : float
		Height above ground. [m] 
	r_coordinate : float
		Flame radius. [m] 
	phi_coordinate : float
		Inclination from vertical. [Radians] 
    """
    
    def __init__(self, x_coordinate: float, z_coordinate: float, r_coordinate: float, phi_coordinate: float):
        """Initializes a new instance of the FlameRecord class"""
        super().__init__()
        self.x_coordinate = x_coordinate
        self.z_coordinate = z_coordinate
        self.r_coordinate = r_coordinate
        self.phi_coordinate = phi_coordinate

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.x_coordinate = float(data.get('x_coordinate', self.x_coordinate))
        self.z_coordinate = float(data.get('z_coordinate', self.z_coordinate))
        self.r_coordinate = float(data.get('r_coordinate', self.r_coordinate))
        self.phi_coordinate = float(data.get('phi_coordinate', self.phi_coordinate))

    def __str__(self):
        parts = [
            '* FlameRecord',
            f'X coordinate:    {self.x_coordinate}',
            f'Z coordinate:    {self.z_coordinate}',
            f'R coordinate:    {self.r_coordinate}',
            f'Phi coordinate:    {self.phi_coordinate}',
        ]
        return '\n'.join(parts)


class DispersionOutputConfig(EntityBase):
    """
    Dispersion plotting and reporting control parameters.

    Attributes
    ----------
	downwind_distance : float
		Downwind distance. [m] (default value is 100)
	time : float
		Time since start of the release. [s] (default value is 60)
	resolution : Resolution
		Output resolution of results and gird. (default value is Resolution.MEDIUM)
	elevation : float
		Height of interest above ground level. [m] (default value is 1)
	special_concentration : SpecialConcentration
		Pre-defined concentration. (default value is SpecialConcentration.MIN)
	concentration : float
		Concentration (vol fraction). Not used unless SpecialConcentration is undefined. [fraction] (default value is 0)
	crosswind_distance : float
		Crosswind distance. [m] (default value is 0)
	contour_type : ContourType
		List of view types. (default value is ContourType.FOOTPRINT)
	lfl_fraction_value : float
		Value of the lower flammable limit fraction. [fraction] (default value is 0.5)
	component_to_track_index : int
		Index of the component to track. (default value is -1)
	component_to_track_name : str
		Name of the property to track. 
    """
    
    def __init__(self, downwind_distance: Optional[float]=100, time: Optional[float]=60, resolution: Optional[Resolution]=Resolution.MEDIUM, elevation: Optional[float]=1, special_concentration: Optional[SpecialConcentration]=SpecialConcentration.MIN, concentration: Optional[float]=0, crosswind_distance: Optional[float]=0, contour_type: Optional[ContourType]=ContourType.FOOTPRINT, lfl_fraction_value: Optional[float]=0.5, component_to_track_index: Optional[int]=-1, component_to_track_name: Optional[str]= ''):
        """Initializes a new instance of the DispersionOutputConfig class"""
        super().__init__()
        self.downwind_distance = downwind_distance
        self.time = time
        self.resolution = resolution
        self.elevation = elevation
        self.special_concentration = special_concentration
        self.concentration = concentration
        self.crosswind_distance = crosswind_distance
        self.contour_type = contour_type
        self.lfl_fraction_value = lfl_fraction_value
        self.component_to_track_index = component_to_track_index
        self.component_to_track_name = component_to_track_name

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.downwind_distance = float(data.get('downwind_distance', self.downwind_distance))
        self.time = float(data.get('time', self.time))
        self.resolution = Resolution(data.get('resolution', self.resolution))
        self.elevation = float(data.get('elevation', self.elevation))
        self.special_concentration = SpecialConcentration(data.get('special_concentration', self.special_concentration))
        self.concentration = float(data.get('concentration', self.concentration))
        self.crosswind_distance = float(data.get('crosswind_distance', self.crosswind_distance))
        self.contour_type = ContourType(data.get('contour_type', self.contour_type))
        self.lfl_fraction_value = float(data.get('lfl_fraction_value', self.lfl_fraction_value))
        self.component_to_track_index = int(data.get('component_to_track_index', self.component_to_track_index))
        self.component_to_track_name = str(data.get('component_to_track_name', self.component_to_track_name))

    def __str__(self):
        parts = [
            '* DispersionOutputConfig',
            f'Downwind distance:    {self.downwind_distance}',
            f'Time:    {self.time}',
            f'Resolution:    {self.resolution}',
            f'Elevation:    {self.elevation}',
            f'Special concentration:    {self.special_concentration}',
            f'Concentration:    {self.concentration}',
            f'Crosswind distance:    {self.crosswind_distance}',
            f'Contour type:    {self.contour_type}',
            f'LFL fraction value:    {self.lfl_fraction_value}',
            f'Component to track index:    {self.component_to_track_index}',
            f'Component to track name:    {self.component_to_track_name}',
        ]
        return '\n'.join(parts)


class PropertiesDipprPT2(object):
    """
    Properties DIPPR part 2.

    Attributes
    ----------
	ignition_category : list[float]
		Ignotion category. 
	lam_burn_velocity : list[float]
		Laminar burn velocity. [m/s] 
	rho_liq_sat : list[float]
		Saturated liquid density. 
	pvap : list[float]
		Vapour pressure. 
	cp_ideal : list[float]
		Ideal gas heat capacity. 
	cp_liq : list[float]
		Liquid heat capacity. 
	cp_ratio : list[float]
		Ratio of specific heat capacities. 
	virial2 : list[float]
		Second virial coefficient. 
	mu_vap : list[float]
		Vapour viscosity. 
	mu_liq : list[float]
		Liquid viscosity. 
	kvap : list[float]
		Vapour thermal conductivity. 
	kliq : list[float]
		Liquid thermal conductivity. 
	heat_vap : list[float]
		Heat of vaporisation. 
	hvap_ideal : list[float]
		Ideal gas enthalpy. 
	hliq_sat : list[float]
		Saturated liquid enthalpy. 
    """
    
    def __init__(self, ignition_category: list[float], lam_burn_velocity: list[float], rho_liq_sat: list[float], pvap: list[float], cp_ideal: list[float], cp_liq: list[float], cp_ratio: list[float], virial2: list[float], mu_vap: list[float], mu_liq: list[float], kvap: list[float], kliq: list[float], heat_vap: list[float], hvap_ideal: list[float], hliq_sat: list[float]):
        """Initializes a new instance of the PropertiesDipprPT2 class"""
        super().__init__()
        self.ignition_category = ignition_category
        self.lam_burn_velocity = lam_burn_velocity
        self.rho_liq_sat = rho_liq_sat
        self.pvap = pvap
        self.cp_ideal = cp_ideal
        self.cp_liq = cp_liq
        self.cp_ratio = cp_ratio
        self.virial2 = virial2
        self.mu_vap = mu_vap
        self.mu_liq = mu_liq
        self.kvap = kvap
        self.kliq = kliq
        self.heat_vap = heat_vap
        self.hvap_ideal = hvap_ideal
        self.hliq_sat = hliq_sat

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""

        data_items = data.get('ignition_category', [])
        for item in data_items:
            self.ignition_category.append(float(item))    

        data_items = data.get('lam_burn_velocity', [])
        for item in data_items:
            self.lam_burn_velocity.append(float(item))    

        data_items = data.get('rho_liq_sat', [])
        for item in data_items:
            self.rho_liq_sat.append(float(item))    

        data_items = data.get('pvap', [])
        for item in data_items:
            self.pvap.append(float(item))    

        data_items = data.get('cp_ideal', [])
        for item in data_items:
            self.cp_ideal.append(float(item))    

        data_items = data.get('cp_liq', [])
        for item in data_items:
            self.cp_liq.append(float(item))    

        data_items = data.get('cp_ratio', [])
        for item in data_items:
            self.cp_ratio.append(float(item))    

        data_items = data.get('virial2', [])
        for item in data_items:
            self.virial2.append(float(item))    

        data_items = data.get('mu_vap', [])
        for item in data_items:
            self.mu_vap.append(float(item))    

        data_items = data.get('mu_liq', [])
        for item in data_items:
            self.mu_liq.append(float(item))    

        data_items = data.get('kvap', [])
        for item in data_items:
            self.kvap.append(float(item))    

        data_items = data.get('kliq', [])
        for item in data_items:
            self.kliq.append(float(item))    

        data_items = data.get('heat_vap', [])
        for item in data_items:
            self.heat_vap.append(float(item))    

        data_items = data.get('hvap_ideal', [])
        for item in data_items:
            self.hvap_ideal.append(float(item))    

        data_items = data.get('hliq_sat', [])
        for item in data_items:
            self.hliq_sat.append(float(item))    

    def __str__(self):
        parts = [
            '* PropertiesDipprPT2',
            f'Ignition category:    {self.ignition_category}',
            f'Lam burn velocity:    {self.lam_burn_velocity}',
            f'Rho liq sat:    {self.rho_liq_sat}',
            f'P vap:    {self.pvap}',
            f'Cp ideal:    {self.cp_ideal}',
            f'Cp liq:    {self.cp_liq}',
            f'Cp ratio:    {self.cp_ratio}',
            f'Virial2:    {self.virial2}',
            f'Mu vap:    {self.mu_vap}',
            f'Mu liq:    {self.mu_liq}',
            f'K vap:    {self.kvap}',
            f'K liq:    {self.kliq}',
            f'Heat vap:    {self.heat_vap}',
            f'H vap ideal:    {self.hvap_ideal}',
            f'H liq sat:    {self.hliq_sat}',
        ]
        return '\n'.join(parts)


class PoolVapourisationParameters(EntityBase):
    """
    Pool vapourisation parameters.

    Attributes
    ----------
	toxics_cutoff_rate : float
		Cutoff rate for toxic materials. [kg/s] (default value is 0.001)
	flammable_cutoff_rate : float
		Cutoff rate for flammable materials. [kg/s] (default value is 0.1)
	relative_tolerance : float
		Relative tolerance. [fraction] (default value is 0.001)
    """
    
    def __init__(self, toxics_cutoff_rate: Optional[float]=0.001, flammable_cutoff_rate: Optional[float]=0.1, relative_tolerance: Optional[float]=0.001):
        """Initializes a new instance of the PoolVapourisationParameters class"""
        super().__init__()
        self.toxics_cutoff_rate = toxics_cutoff_rate
        self.flammable_cutoff_rate = flammable_cutoff_rate
        self.relative_tolerance = relative_tolerance

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.toxics_cutoff_rate = float(data.get('toxics_cutoff_rate', self.toxics_cutoff_rate))
        self.flammable_cutoff_rate = float(data.get('flammable_cutoff_rate', self.flammable_cutoff_rate))
        self.relative_tolerance = float(data.get('relative_tolerance', self.relative_tolerance))

    def __str__(self):
        parts = [
            '* PoolVapourisationParameters',
            f'Toxics cutoff rate:    {self.toxics_cutoff_rate}',
            f'Flammable cutoff rate:    {self.flammable_cutoff_rate}',
            f'Relative tolerance:    {self.relative_tolerance}',
        ]
        return '\n'.join(parts)


class PoolRecord(object):
    """
    Pool results at a given time.

    Attributes
    ----------
	time : float
		Time since rainout. [s] 
	mass_spilt : float
		Mass spilled. [kg] 
	mass_vaporised : float
		Mass vaporised. [kg] 
	mass_dissolved : float
		Mass dissolved. [kg] 
	mass_remaining : float
		Mass remaining. [kg] 
	vapourisation_rate : float
		Vapourisation rate. [kg/s] 
	solution_rate : float
		Solution rate. [kg/s] 
	effective_radius : float
		Effective radius. [m] 
	depth : float
		Pool depth. [m] 
	temperature : float
		Pool temperature. [K] 
	spill_rate : float
		Spill rate. [kg/s] 
	actual_radius : float
		Actual pool radius. [m] 
	pool_centre : float
		Pool centre. [m] 
    """
    
    def __init__(self, time: float, mass_spilt: float, mass_vaporised: float, mass_dissolved: float, mass_remaining: float, vapourisation_rate: float, solution_rate: float, effective_radius: float, depth: float, temperature: float, spill_rate: float, actual_radius: float, pool_centre: float):
        """Initializes a new instance of the PoolRecord class"""
        super().__init__()
        self.time = time
        self.mass_spilt = mass_spilt
        self.mass_vaporised = mass_vaporised
        self.mass_dissolved = mass_dissolved
        self.mass_remaining = mass_remaining
        self.vapourisation_rate = vapourisation_rate
        self.solution_rate = solution_rate
        self.effective_radius = effective_radius
        self.depth = depth
        self.temperature = temperature
        self.spill_rate = spill_rate
        self.actual_radius = actual_radius
        self.pool_centre = pool_centre

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.time = float(data.get('time', self.time))
        self.mass_spilt = float(data.get('mass_spilt', self.mass_spilt))
        self.mass_vaporised = float(data.get('mass_vaporised', self.mass_vaporised))
        self.mass_dissolved = float(data.get('mass_dissolved', self.mass_dissolved))
        self.mass_remaining = float(data.get('mass_remaining', self.mass_remaining))
        self.vapourisation_rate = float(data.get('vapourisation_rate', self.vapourisation_rate))
        self.solution_rate = float(data.get('solution_rate', self.solution_rate))
        self.effective_radius = float(data.get('effective_radius', self.effective_radius))
        self.depth = float(data.get('depth', self.depth))
        self.temperature = float(data.get('temperature', self.temperature))
        self.spill_rate = float(data.get('spill_rate', self.spill_rate))
        self.actual_radius = float(data.get('actual_radius', self.actual_radius))
        self.pool_centre = float(data.get('pool_centre', self.pool_centre))

    def __str__(self):
        parts = [
            '* PoolRecord',
            f'Time:    {self.time}',
            f'Mass spilt:    {self.mass_spilt}',
            f'Mass vaporised:    {self.mass_vaporised}',
            f'Mass dissolved:    {self.mass_dissolved}',
            f'Mass remaining:    {self.mass_remaining}',
            f'Vapourisation rate:    {self.vapourisation_rate}',
            f'Solution rate:    {self.solution_rate}',
            f'Effective radius:    {self.effective_radius}',
            f'Depth:    {self.depth}',
            f'Temperature:    {self.temperature}',
            f'Spill rate:    {self.spill_rate}',
            f'Actual radius:    {self.actual_radius}',
            f'Pool centre:    {self.pool_centre}',
        ]
        return '\n'.join(parts)


class ExplosionOverpressureResult(object):
    """
    Worst case explosion summary results for a given overpressure.

    Attributes
    ----------
	overpressure : float
		Overpressure for this result. [Pa] 
	explosion_centre : float
		Centre of the explosion (distance downwind). [m] 
	maximum_distance : float
		Maximum distance to overpressure (downwind edge). [m] 
	exploded_mass : float
		Flammable mass used in the explosion. [kg] 
	ignition_time : float
		Time of ignition. [s] 
	radius : float
		Radius of the explosion at the explosion centre. [m] 
    """
    
    def __init__(self, overpressure: float, explosion_centre: float, maximum_distance: float, exploded_mass: float, ignition_time: float, radius: float):
        """Initializes a new instance of the ExplosionOverpressureResult class"""
        super().__init__()
        self.overpressure = overpressure
        self.explosion_centre = explosion_centre
        self.maximum_distance = maximum_distance
        self.exploded_mass = exploded_mass
        self.ignition_time = ignition_time
        self.radius = radius

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.overpressure = float(data.get('overpressure', self.overpressure))
        self.explosion_centre = float(data.get('explosion_centre', self.explosion_centre))
        self.maximum_distance = float(data.get('maximum_distance', self.maximum_distance))
        self.exploded_mass = float(data.get('exploded_mass', self.exploded_mass))
        self.ignition_time = float(data.get('ignition_time', self.ignition_time))
        self.radius = float(data.get('radius', self.radius))

    def __str__(self):
        parts = [
            '* ExplosionOverpressureResult',
            f'Overpressure:    {self.overpressure}',
            f'Explosion centre:    {self.explosion_centre}',
            f'Maximum distance:    {self.maximum_distance}',
            f'Exploded mass:    {self.exploded_mass}',
            f'Ignition time:    {self.ignition_time}',
            f'Radius:    {self.radius}',
        ]
        return '\n'.join(parts)


class VesselLeakMaxFlammableCloudResults(object):
    """
    Results for a linked run of vessel leak followed by dispersion and views from the cloud.

    Attributes
    ----------
	discharge_rate : float
		Leak discharge mass rate. [kg/s] 
	expanded_temperature : float
		Post atmospheric expansion temperature. [K] 
	lfl_extent : float
		Maximum downwind distance to LFL. [m] 
	lfl_area : float
		Horizontal area within LFL envelope. [m2] 
	lfl_height : float
		Height of maximum LFL extent. [m] 
	phase : Phase
		Post atmospheric expansion fluid phase. (default value is Phase.UNSET)
    """
    
    def __init__(self, discharge_rate: float, expanded_temperature: float, lfl_extent: float, lfl_area: float, lfl_height: float, phase: Optional[Phase]=Phase.UNSET):
        """Initializes a new instance of the VesselLeakMaxFlammableCloudResults class"""
        super().__init__()
        self.discharge_rate = discharge_rate
        self.expanded_temperature = expanded_temperature
        self.lfl_extent = lfl_extent
        self.lfl_area = lfl_area
        self.lfl_height = lfl_height
        self.phase = phase

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.discharge_rate = float(data.get('discharge_rate', self.discharge_rate))
        self.expanded_temperature = float(data.get('expanded_temperature', self.expanded_temperature))
        self.lfl_extent = float(data.get('lfl_extent', self.lfl_extent))
        self.lfl_area = float(data.get('lfl_area', self.lfl_area))
        self.lfl_height = float(data.get('lfl_height', self.lfl_height))
        self.phase = Phase(data.get('phase', self.phase))

    def __str__(self):
        parts = [
            '* VesselLeakMaxFlammableCloudResults',
            f'Discharge rate:    {self.discharge_rate}',
            f'Expanded temperature:    {self.expanded_temperature}',
            f'LFL extent:    {self.lfl_extent}',
            f'LFL area:    {self.lfl_area}',
            f'LFL height:    {self.lfl_height}',
            f'Phase:    {self.phase}',
        ]
        return '\n'.join(parts)


class DischargeRecord(EntityBase):
    """
    Discharge results at a given time.

    Attributes
    ----------
	time : float
		Time. [s] 
	mass_flow : float
		Mass flow rate (continuous and time-varying). [kg/s] 
	final_state : State
		Final fluid state. 
	final_velocity : float
		Final velocity. [m/s] 
	orifice_state : State
		Orifice fluid state. 
	orifice_velocity : float
		Orifice velocity. [m/s] 
	storage_state : State
		Storage fluid state. 
	droplet_diameter : float
		Representative droplet size. [m] 
	expanded_diameter : float
		Expanded diameter. [m] (default value is 0.0)
    """
    
    def __init__(self, time: float, mass_flow: float, final_state: State, final_velocity: float, orifice_state: State, orifice_velocity: float, storage_state: State, droplet_diameter: float, expanded_diameter: Optional[float]=0.0):
        """Initializes a new instance of the DischargeRecord class"""
        super().__init__()
        self.time = time
        self.mass_flow = mass_flow
        self.final_state = final_state
        self.final_velocity = final_velocity
        self.orifice_state = orifice_state
        self.orifice_velocity = orifice_velocity
        self.storage_state = storage_state
        self.droplet_diameter = droplet_diameter
        self.expanded_diameter = expanded_diameter

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.time = float(data.get('time', self.time))
        self.mass_flow = float(data.get('mass_flow', self.mass_flow))
        final_state_data = data.get('final_state')
        if final_state_data is not None:
            self.final_state.initialise_from_dictionary(final_state_data)
        self.final_velocity = float(data.get('final_velocity', self.final_velocity))
        orifice_state_data = data.get('orifice_state')
        if orifice_state_data is not None:
            self.orifice_state.initialise_from_dictionary(orifice_state_data)
        self.orifice_velocity = float(data.get('orifice_velocity', self.orifice_velocity))
        storage_state_data = data.get('storage_state')
        if storage_state_data is not None:
            self.storage_state.initialise_from_dictionary(storage_state_data)
        self.droplet_diameter = float(data.get('droplet_diameter', self.droplet_diameter))
        self.expanded_diameter = float(data.get('expanded_diameter', self.expanded_diameter))

    def __str__(self):
        parts = [
            '* DischargeRecord',
            f'Time:    {self.time}',
            f'Mass flow:    {self.mass_flow}',
            self.final_state.__str__(),
            f'Final velocity:    {self.final_velocity}',
            self.orifice_state.__str__(),
            f'Orifice velocity:    {self.orifice_velocity}',
            self.storage_state.__str__(),
            f'Droplet diameter:    {self.droplet_diameter}',
            f'Expanded diameter:    {self.expanded_diameter}',
        ]
        return '\n'.join(parts)


class ExplosionParameters(EntityBase):
    """
    Explosion parameters.

    Attributes
    ----------
	explosion_uniform_strength : float
		Explosion strength for uniform unconfined (Multi-energy method). (default value is 10.0)
    """
    
    def __init__(self, explosion_uniform_strength: Optional[float]=10.0):
        """Initializes a new instance of the ExplosionParameters class"""
        super().__init__()
        self.explosion_uniform_strength = explosion_uniform_strength

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.explosion_uniform_strength = float(data.get('explosion_uniform_strength', self.explosion_uniform_strength))

    def __str__(self):
        parts = [
            '* ExplosionParameters',
            f'Explosion uniform strength:    {self.explosion_uniform_strength}',
        ]
        return '\n'.join(parts)


class PropertiesDnvPT1(object):
    """
    Properties DNV part 1.

    Attributes
    ----------
	total_steps_used : int
		Total PT steps. 
	pressure : list[float]
		Pressure. [Pa] 
	temperature : list[float]
		Temperature. [K] 
	mass_comp : list[float]
		Composition. 
	flam_tox : list[float]
		 Flammable/toxic flag. 
	lum_smoky : list[float]
		Luminous smoky flame flag. 
	sep_max : list[float]
		Maximum surface emissive power. 
	sep_length : list[float]
		Emissive power length scale. 
	pool_fire_burn_rate : list[float]
		Pool fire burn rate length. [m] 
	burn_rate_max : list[float]
		Maximum burn rate. 
	tnt_efficiency : list[float]
		TNT explosion efficiency. 
	erpg_1 : list[float]
		ERPG1 concentration. 
	erpg_2 : list[float]
		ERPG2 concentration. 
	erpg_3 : list[float]
		ERPG3 concentration. 
	idlh : list[float]
		IDLH concentration. 
	stel : list[float]
		STEL concentration. 
    """
    
    def __init__(self, total_steps_used: int, pressure: list[float], temperature: list[float], mass_comp: list[float], flam_tox: list[float], lum_smoky: list[float], sep_max: list[float], sep_length: list[float], pool_fire_burn_rate: list[float], burn_rate_max: list[float], tnt_efficiency: list[float], erpg_1: list[float], erpg_2: list[float], erpg_3: list[float], idlh: list[float], stel: list[float]):
        """Initializes a new instance of the PropertiesDnvPT1 class"""
        super().__init__()
        self.total_steps_used = total_steps_used
        self.pressure = pressure
        self.temperature = temperature
        self.mass_comp = mass_comp
        self.flam_tox = flam_tox
        self.lum_smoky = lum_smoky
        self.sep_max = sep_max
        self.sep_length = sep_length
        self.pool_fire_burn_rate = pool_fire_burn_rate
        self.burn_rate_max = burn_rate_max
        self.tnt_efficiency = tnt_efficiency
        self.erpg_1 = erpg_1
        self.erpg_2 = erpg_2
        self.erpg_3 = erpg_3
        self.idlh = idlh
        self.stel = stel

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.total_steps_used = int(data.get('total_steps_used', self.total_steps_used))

        data_items = data.get('pressure', [])
        for item in data_items:
            self.pressure.append(float(item))    

        data_items = data.get('temperature', [])
        for item in data_items:
            self.temperature.append(float(item))    

        data_items = data.get('mass_comp', [])
        for item in data_items:
            self.mass_comp.append(float(item))    

        data_items = data.get('flam_tox', [])
        for item in data_items:
            self.flam_tox.append(float(item))    

        data_items = data.get('lum_smoky', [])
        for item in data_items:
            self.lum_smoky.append(float(item))    

        data_items = data.get('sep_max', [])
        for item in data_items:
            self.sep_max.append(float(item))    

        data_items = data.get('sep_length', [])
        for item in data_items:
            self.sep_length.append(float(item))    

        data_items = data.get('pool_fire_burn_rate', [])
        for item in data_items:
            self.pool_fire_burn_rate.append(float(item))    

        data_items = data.get('burn_rate_max', [])
        for item in data_items:
            self.burn_rate_max.append(float(item))    

        data_items = data.get('tnt_efficiency', [])
        for item in data_items:
            self.tnt_efficiency.append(float(item))    

        data_items = data.get('erpg_1', [])
        for item in data_items:
            self.erpg_1.append(float(item))    

        data_items = data.get('erpg_2', [])
        for item in data_items:
            self.erpg_2.append(float(item))    

        data_items = data.get('erpg_3', [])
        for item in data_items:
            self.erpg_3.append(float(item))    

        data_items = data.get('idlh', [])
        for item in data_items:
            self.idlh.append(float(item))    

        data_items = data.get('stel', [])
        for item in data_items:
            self.stel.append(float(item))    

    def __str__(self):
        parts = [
            '* PropertiesDnvPT1',
            f'Total steps used:    {self.total_steps_used}',
            f'Pressure:    {self.pressure}',
            f'Temperature:    {self.temperature}',
            f'Mass comp:    {self.mass_comp}',
            f'Flam tox:    {self.flam_tox}',
            f'Lum smoky:    {self.lum_smoky}',
            f'Sep max:    {self.sep_max}',
            f'Sep length:    {self.sep_length}',
            f'Pool fire burn rate:    {self.pool_fire_burn_rate}',
            f'Burn rate max:    {self.burn_rate_max}',
            f'TNT efficiency:    {self.tnt_efficiency}',
            f'ERPG1:    {self.erpg_1}',
            f'ERPG2:    {self.erpg_2}',
            f'ERPG3:    {self.erpg_3}',
            f'IDLH:    {self.idlh}',
            f'STEL:    {self.stel}',
        ]
        return '\n'.join(parts)


class WeatherStationData(object):
    """
    Compiled data from weather live service.

    Attributes
    ----------
	cloudiness : float
		Cloud coverage in percentage. 
	wind_speed : float
		Wind speed at reference height. [m/s] 
	temperature : float
		Ambient temperature. [K] 
	relative_humidity : float
		Relative humidity. [fraction] 
	latitude : float
		Latitude measured in degrees. [Radians] (default value is 0.0)
	longitude : float
		Longitude coordinate in degrees. [Radians] (default value is 0.0)
	day_night_option : DayNight
		Indicates if it is day or night. (default value is DayNight.UNSET)
	solar_radiation : float
		Solar radiation flux. [W/m2] (default value is 500)
    """
    
    def __init__(self, cloudiness: float, wind_speed: float, temperature: float, relative_humidity: float, latitude: Optional[float]=0.0, longitude: Optional[float]=0.0, day_night_option: Optional[DayNight]=DayNight.UNSET, solar_radiation: Optional[float]=500):
        """Initializes a new instance of the WeatherStationData class"""
        super().__init__()
        self.cloudiness = cloudiness
        self.wind_speed = wind_speed
        self.temperature = temperature
        self.relative_humidity = relative_humidity
        self.latitude = latitude
        self.longitude = longitude
        self.day_night_option = day_night_option
        self.solar_radiation = solar_radiation

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        self.cloudiness = float(data.get('cloudiness', self.cloudiness))
        self.wind_speed = float(data.get('wind_speed', self.wind_speed))
        self.temperature = float(data.get('temperature', self.temperature))
        self.relative_humidity = float(data.get('relative_humidity', self.relative_humidity))
        self.latitude = float(data.get('latitude', self.latitude))
        self.longitude = float(data.get('longitude', self.longitude))
        self.day_night_option = DayNight(data.get('day_night_option', self.day_night_option))
        self.solar_radiation = float(data.get('solar_radiation', self.solar_radiation))

    def __str__(self):
        parts = [
            '* WeatherStationData',
            f'Cloudiness:    {self.cloudiness}',
            f'Wind speed:    {self.wind_speed}',
            f'Temperature:    {self.temperature}',
            f'Relative humidity:    {self.relative_humidity}',
            f'Latitude:    {self.latitude}',
            f'Longitude:    {self.longitude}',
            f'Day night option:    {self.day_night_option}',
            f'Solar radiation:    {self.solar_radiation}',
        ]
        return '\n'.join(parts)


class DischargeParameters(EntityBase):
    """
    Discharge parameters.

    Attributes
    ----------
	flash_at_orifice : FlashAtOrifice
		Flashing at orifice. (default value is FlashAtOrifice.DISALLOW_LIQUID_FLASH)
    """
    
    def __init__(self, flash_at_orifice: Optional[FlashAtOrifice]=FlashAtOrifice.DISALLOW_LIQUID_FLASH):
        """Initializes a new instance of the DischargeParameters class"""
        super().__init__()
        self.flash_at_orifice = flash_at_orifice

    def initialise_from_dictionary(self, data: dict):
        """Initialise the entity with data from a dictionary."""
        super().initialise_from_dictionary(data)
        self.flash_at_orifice = FlashAtOrifice(data.get('flash_at_orifice', self.flash_at_orifice))

    def __str__(self):
        parts = [
            '* DischargeParameters',
            f'Flash at orifice:    {self.flash_at_orifice}',
        ]
        return '\n'.join(parts)