
# **********************************************************************
# This file has been auto-generated by a code generation tool.
# Version:   4.2.0
# Date/time: 22 Nov 2024 12:56:21
# Template:  templates/pythonpws/entities.razor.
# **********************************************************************

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

import uuid
from typing import List, 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 coordinate. (default value is 0)
	y : float
		y coordinate. (default value is 0)
	z : float
		z coordinate. (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. 
    """
    
    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',
            f'Location:           {self.location.__str__()}',
        ]
        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. (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):
    """
    The material to use in calculations.

    Attributes
    ----------
	name : str
		Name of the material. 
	components : List[MaterialComponent]
		Constituent components. 
	component_count : int
		Number of components in the material. (default value is 1)
	property_template : PropertyTemplate
		The template to be used for the selection of calculation methods for material properties. (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. 
	temperature : float
		Temperature of the fluid. 
	liquid_fraction : float
		Mole fraction of liquid in the fluid. 
	flash_flag : FluidSpec
		Specification of the fluid equilibrium. (default value is FluidSpec.TP)
	mixture_modelling : MixtureModelling
		Method for modelling a mixture. (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 AtmosphericStorageTank(Asset):
    """
    An atmospheric storage tank asset to model events that involve releases from unpressurised containment.

    Attributes
    ----------
	state : State
		The fluid state within the tank. 
	diameter : float
		Diameter of the tank. 
	height : float
		Height of the tank. 
	material : Material
		Material within the tank. 
	location : LocalPosition
		Location of the asset. 
	liquid_fill_fraction_by_volume : float
		The proportion of the tank occupied by liquid. (default value is 0.9)
    """
    
    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',
            f'State:              {self.state.__str__()}',
            f'Diameter:           {self.diameter}',
            f'Height:             {self.height}',
            f'Material:           {self.material.__str__()}',
            f'Liquid Fill Fraction By Volume:{self.liquid_fill_fraction_by_volume}',
        ]
        return '\n'.join(parts)


class Bund(object):
    """
    A bund entity used in the modelling of pool spreading and vaporisation.

    Attributes
    ----------
	bund_height : float
		Used in calculating the volume of the bund and in modelling bund failure and the location of rainout. (default value is 0.0)
	bund_diameter : float
		The diameter of the (circular) bund. (default value is 0.0)
	specify_bund : bool
		Whether to model the effect of a bund on the spreading of a liquid pool. (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 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 CatastrophicRupture(Instantaneous):
    """
    An instanaeous release of the entire inventory of an associated vessel, intended to model an incident in which the vessel is destroyed by an impact, a crack, or some other failure which propagates very quickly.

    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 ConcentrationRecord(object):
    """
    A record containing the cloud concentration at a specified x, y, z position.

    Attributes
    ----------
	concentration : float
		Cloud concentration at an x, y, z position. 
	position : LocalPosition
		x, y, z position. 
    """
    
    def __init__(self, concentration: float, position: Optional[LocalPosition]=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}',
            f'Position:           {self.position.__str__()}',
        ]
        return '\n'.join(parts)


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

    Attributes
    ----------
	critical_pressure : float
		The critical pressure of the material. 
	critical_temperature : float
		The critical temperature of the material. 
	total_molecular_weight : float
		The total molecular weight of the material. 
    """
    
    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 DischargeParameters(EntityBase):
    """
    A set of parameters used in discharge calculations.

    Attributes
    ----------
	flash_at_orifice : FlashAtOrifice
		Whether discharge calculations should allow the phase to change between storage and orifice conditions. (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)


class DischargeRecord(EntityBase):
    """
    A record containing discharge results at a given time.

    Attributes
    ----------
	time : float
		The time elapsed since the start of the discharge. 
	mass_flow : float
		The mass flow rate at the specified time. 
	final_state : State
		The fluid state after expansion to atmosphere at the specified time. 
	final_velocity : float
		The velocity after expansion to atmosphere at the specified time. 
	orifice_state : State
		The fluid state at the orifice at the specified time. 
	orifice_velocity : float
		The velocity at the orifice at the specified time. 
	storage_state : State
		The fluid state of the storage at the specified time. 
	droplet_diameter : float
		A representative size of entrained liquid droplets. 
	expanded_diameter : float
		The diameter of the assumed circular cross-sectional flow at the point where the fluid has depressurised to ambient pressure. (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}',
            f'Final State:        {self.final_state.__str__()}',
            f'Final Velocity:     {self.final_velocity}',
            f'Orifice State:      {self.orifice_state.__str__()}',
            f'Orifice Velocity:   {self.orifice_velocity}',
            f'Storage State:      {self.storage_state.__str__()}',
            f'Droplet Diameter:   {self.droplet_diameter}',
            f'Expanded Diameter:  {self.expanded_diameter}',
        ]
        return '\n'.join(parts)


class DischargeResult(EntityBase):
    """
    A set of discharge results that do not vary with time.

    Attributes
    ----------
	expansion_energy : float
		The energy released when a pressurized substance, such as a liquid or vapor, is released following an instantaneous rupture. 
	release_mass : float
		Amount of mass released during the discharge. 
	height : float
		Release height above ground. 
	angle : float
		Release angle (non-instantaneous releases only). 
	hole_diameter : float
		Diameter of the hole. 
	release_type : DynamicType
		Instantaneous, continuous or time-varying. (default value is DynamicType.UNSET)
	pre_dilution_air_rate : float
		The rate at which air at ambient conditions mixes with the released material before the cloud starts to move away from the point of release. (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 DispersionOutputConfig(EntityBase):
    """
    Dispersion plotting and reporting parameters.

    Attributes
    ----------
	downwind_distance : float
		The distance downwind at which concentration at a point is provided. (default value is 100)
	time : float
		The time of interest, measured from the start of the release. (default value is 60)
	resolution : Resolution
		Output resolution of results. (default value is Resolution.MEDIUM)
	elevation : float
		The distance that an XY plane of interest is offset from the ground level. (default value is 1)
	special_concentration : SpecialConcentration
		The method used to determine the concentration of interest when post processing dispersion calculations. (default value is SpecialConcentration.MIN)
	concentration : float
		Concentration of interest (vol fraction). Not used unless SpecialConcentration is NotDefined. (default value is 0)
	crosswind_distance : float
		The distance that an XZ plane of interest is offset from the downwind direction (x-axis). (default value is 0)
	contour_type : ContourType
		The type of contour on which the contour points will be based. (default value is ContourType.FOOTPRINT)
	lfl_fraction_value : float
		Value of the lower flammable limit fraction, used when SpecialConcentration is set to Min or LflFraction. (default value is 0.5)
	component_to_track_index : int
		Index of a component that you want to track within a mixture. (default value is -1)
	component_to_track_name : str
		Name of the component 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 DispersionParameters(EntityBase):
    """
    A set of parameters used in dispersion calculations.

    Attributes
    ----------
	relative_tolerance : float
		Controls the step size used in the core dispersion calculations for integrations of the differential equations for the cloud dynamics and droplet dynamics so as to maximize computational efficiency while minimising the errors involved. (default value is 0.001)
	rainout_thermo_flag : RainoutThermoFlag
		Sets the model for droplet evaporation calculations. (default value is RainoutThermoFlag.RAINOUT_NON_EQUILIBRIUM)
	fixed_step_size : float
		The size of steps within the core dispersion calculations. (default value is 0.01)
	output_step_multiplier : float
		Multiplier to increase each step size after the initial fixed steps. (default value is 1.2)
	max_dispersion_distance : float
		The maximum dispersion distance that will be modelled. Modelling will stop at this distance even if the lowest concentration of interest has not been reached. (default value is 50000)
	max_dispersion_height : float
		The dispersion calculation will stop when this height is exceeded. This provides a means of preventing the calculation of dispersion of buoyant releases going too far above the ground. (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
		The core averaging time, used to take into account the effects of changes in the wind direction over the course of the release. (default value is 18.75)
	lfl_fraction_to_stop : float
		The LFL multipler, which determines the minimum concentration of interest for a flammable release. If the concentration of interest determined from the DispersionOutputConfig is lowest than this value, an error will occur. (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 DispersionRecord(object):
    """
    A record containing observer dispersion results at a given time.

    Attributes
    ----------
	observer_index : int
		Id of the observer associated with the record. 
	centreline_concentration : float
		The (molar) concentraton of the centreline of the cloud, calculated using the averaging time set in the DispersionParameters and taking into account gravity spreading. 
	downwind_distance : float
		The downwind distance reached by the observer, measured from the release location. 
	time : float
		Elapsed time since the start of the release. 
	centreline_concentration_uncorrected : float
		The uncorrected (molar) concentraton of the centreline of the cloud, which does not take into account gravity spreading. 
	crosswind_radius : float
		A measure of the standard deviation of the concentration profile in the crosswind direction. 
	vertical_radius : float
		A measure of the standard deviation of the concentration profile in the vertical direction. 
	crosswind_exponent : float
		Describe the sharpness or smoothness of the concentration profile in the crosswind direction. 
	vertical_exponent : float
		Describe the sharpness or smoothness of the concentration profile in the vertical direction. 
	theta : float
		Centreline angle from horizontal. 
	centreline_height : float
		The height of the centreline of the cloud, measured from ground level. 
	liquid_fraction : float
		The liquid fraction in the cloud. If there is liquid in the cloud at the start of the release, the fraction will usually drop gradually during the dispersion as the liquid droplets evaporate, and then drop to zero at the end of the segment when the droplets reach the ground and rain out of the cloud to form a pool. 
	vapour_temperature : float
		The temperature of the vapour portion of the cloud, including entrained air and any entrained water vapour. 
	mass_conc : float
		The mass concentration of release material, given as the mass in a given volume of cloud. The concentration is calculated using the Averaging Time set in the Dispersion Parameters. At the beginning of the release, this will be the same as the Cloud density, and it then drops below the density as air is entrained into the cloud. 
	velocity : float
		The velocity of the cloud at the centroid. 
	mass_flow : float
		Mass flow rate of material in the cloud (non-instantaneous releases) . The value will be constant for a given segment, but can be useful when you are investigating the effects of rainout and evaporation, and the segments that model these phenomena. 
	profile_flag : int
		This shows the type of dispersion modelling being used for the current step. 
	elev_flag : int
		A flag to indicate whether the release is elevated, touching down, grounded or capped (by the mixing layer height). 
	rho_cloud : float
		The density of the cloud at the centreline. 
	liq_temp : float
		The temperature of the liquid droplets in the cloud. 
	effective_width : float
		The width of an equivalent cloud that contains the same mass as the real cloud but that has a uniform concentration throughout. 
	effective_height : float
		The height of an equivalent cloud that contains the same mass as the real cloud but that has a uniform concentration throughout. 
	pass_tran_dist : float
		The distance at which the observer has made the transition to passive dispersion. 
	downwind_radius : float
		A measure of the standard deviation of the concentration profile in the downwind direction. 
	droplet_diameter : float
		The representative diameter for liquid droplets in the cloud. 
	droplet_height : float
		The representative height for liquid droplets in the cloud, measured above ground level. 
	droplet_distance : float
		The downwind distance of droplets in the cloud. 
	mass : float
		The mass of released material in the cloud (instantaneous releases). 
	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 ExplosionConfinedVolume(EntityBase):
    """
    Confined explosion volume data.

    Attributes
    ----------
	confined_strength : float
		The degree of confinement in the area or source, described by an integer between 3 (lowest) and 10 (highest). (default value is 7)
	confined_volume : float
		The volume of the cloud that is contained in the area of confinement. (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 ExplosionOutputConfig(EntityBase):
    """
    Explosion plotting and reporting parameters.

    Attributes
    ----------
	overpressure_level : float
		Overpressure of interest for explosions. (default value is 2068)
	me_confined_method : MEConfinedMethod
		The multi energy confined method for modelling the effects of explosions. (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'MeConfined Method:  {self.me_confined_method}',
        ]
        return '\n'.join(parts)


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

    Attributes
    ----------
	overpressure : float
		The target overpressure level for the worst-case explosion. 
	explosion_centre : float
		The distance downwind from the release source to the centre of the explosion. 
	maximum_distance : float
		The maximum downwind distance reached by the effect zone for the overpressure level of interest. 
	exploded_mass : float
		The flammable mass used in the explosion. 
	ignition_time : float
		The time that the cloud is ignited, measured from the start of the release. 
	radius : float
		The radius of the effect zone for the overpressure level of interest. 
    """
    
    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 ExplosionParameters(EntityBase):
    """
    A set of parameters used in explosion calculations.

    Attributes
    ----------
	explosion_uniform_strength : float
		The confined strength in the multi-energy uniform confined 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 FlameRecord(object):
    """
    A record containing flame geometry data.

    Attributes
    ----------
	x_coordinate : float
		The distance downwind from the release source to the centre of a circle describing the frustum base or tip. 
	z_coordinate : float
		The height above the ground of the centre of a circle describing the frustum base or tip. 
	r_coordinate : float
		The radius of the frustum base or tip. 
	phi_coordinate : float
		Inclination of the frustum base or tip from the vertical. 
    """
    
    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 FlameResult(object):
    """
    A set of flame results.

    Attributes
    ----------
	time : float
		Time of interest for time varying releases, or duration for initial rate releases. 
	surface_emissive_power : float
		The rate at which thermal radiation is emitted from the surface of a flame per unit area. 
	flame_length : float
		Length of the flame. 
	flame_diameter : float
		Diameter of the flame. 
	fire_type : FireType
		Type of fire. (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 Transect(EntityBase):
    """
    A line segment, along which results are provided.

    Attributes
    ----------
	transect_start_point : LocalPosition
		Cartesian coordinates of the start point of the transect. 
	transect_end_point : LocalPosition
		Cartesian coordinates of the end point of the transect. 
    """
    
    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',
            f'Transect Start Point:{self.transect_start_point.__str__()}',
            f'Transect End Point: {self.transect_end_point.__str__()}',
        ]
        return '\n'.join(parts)


class FlammableOutputConfig(EntityBase):
    """
    Fire and radiation plotting and reporting parameters.

    Attributes
    ----------
	position : LocalPosition
		Position used for radiation calculations (except Transect). 
	transect : Transect
		A line segment, along which results are provided. 
	radiation_type : RadiationType
		The type of radiation result of interest. (default value is RadiationType.INTENSITY)
	contour_type : ContourType
		The type of contour plot. (default value is ContourType.FOOTPRINT_ELLIPSE)
	radiation_level : float
		The radiation level of interest for the RadiationType. (default value is 4000)
	radiation_resolution : Resolution
		Spatial resolution for radiation calculations. (default value is Resolution.MEDIUM)
	fixed_orientation : int
		Whether to specify the orientation of a flat surface on which an observer lies with respect to the flame. (default value is 0)
	orientation : float
		Angle between the projection of the observer normal onto the horizontal plane and the y axis. (default value is 0)
	fixed_inclination : int
		Whether to specify the inclination of a flat surface on which an observer lies with respect to the flame. (default value is 0)
	inclination : float
		Angle between the observer normal 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',
            f'Position:           {self.position.__str__()}',
            f'Transect:           {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 FlammableParameters(EntityBase):
    """
    A set of parameters used in fire and radiation calculations.

    Attributes
    ----------
	max_exposure_duration : float
		The time that someone will remain in range of the radiation before attempting to escape. It is used in the calculations of dose and lethality. (default value is 20)
	radiation_relative_tolerance : float
		Controls the precision of the numerical integration over the visible surface of the flame when calculating the view factor of the flame as seen by an observer at a specific position. (default value is 0.01)
	pool_fire_type : PoolFireType
		Type of pool fire modelling. (default value is PoolFireType.LATE)
	jet_fire_auto_select : bool
		Whether to have the calculations automatically select the type of jet fire modelling. (default value is 0)
	time_averaging : bool
		Whether to base the jet fire calculations on a discharge rate averaged between 0 seconds and a TimeOfInterest. (default value is True)
	time_of_interest : float
		The time of interest in the jet fire calculations. The jet fire will be based on the discharge results either at the TimeOfInterest or averaged between 0 seconds and the TimeOfInterest, depending on the TimeAveraging option. (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]=0, 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 FlashResult(object):
    """
    Physical properties for a material generated at a particular pressure and temperature.

    Attributes
    ----------
	pressure : float
		Pressure. 
	temperature : float
		Temperature. 
	liquid_mole_fraction : float
		Liquid fraction (mole). 
	liquid_density : float
		Density of liquid phase. 
	vapour_density : float
		Density of vapour phase. 
	liquid_entropy : float
		Entropy of liquid phase. 
	vapour_entropy : float
		Entropy of vapour phase. 
	liquid_enthalpy : float
		Enthalpy of liquid phase. 
	vapour_enthalpy : float
		Enthalpy of vapour phase. 
	bubble_point_pressure : float
		Mixture bubble point pressure at given temperature. 
	bubble_point_temperature : float
		Mixture bubble point temperature at given pressure. 
	dew_point_pressure : float
		Mixture dew point pressure at given temperature. 
	dew_point_temperature : float
		Mixture dew point temperature at given pressure. 
	total_fluid_density : float
		Total fluid density (mass-based). 
	liquid_mass_fraction : float
		Liquid mass 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 ReleaseOverTime(Scenario):
    """
    Scenario representing a release over time.

    Attributes
    ----------
	release_angle : float
		Angle of release above a horizontal plane. (default value is 0.0)
	time_varying_option : TimeVaryingOption
		Whether the release is a time-varying release or a steady state release using the initial rate. (default value is TimeVaryingOption.INITIAL_RATE)
	release_angle_from_mde : float
		Release angle returned from MDE LoadMassInventory model call. (default value is 0.0)
    """
    
    def __init__(self, release_angle: Optional[float]=0.0, time_varying_option: Optional[TimeVaryingOption]=TimeVaryingOption.INITIAL_RATE, release_angle_from_mde: Optional[float]=0.0):
        """Initializes a new instance of the ReleaseOverTime class"""
        super().__init__()
        self.release_angle = release_angle
        self.time_varying_option = time_varying_option
        self.release_angle_from_mde = release_angle_from_mde

    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))
        self.release_angle_from_mde = float(data.get('release_angle_from_mde', self.release_angle_from_mde))

    def __str__(self):
        parts = [
            '* ReleaseOverTime',
            f'Release Angle:      {self.release_angle}',
            f'Time Varying Option:{self.time_varying_option}',
            f'Release Angle From MdE:{self.release_angle_from_mde}',
        ]
        return '\n'.join(parts)


class Leak(ReleaseOverTime):
    """
    A storage scenario which models a release of material through a hole in a vessel or pipe.

    Attributes
    ----------
	hole_diameter : float
		The diameter of the equivalent circular orifice with the same area as the area of the leak. 
	hole_height_fraction : float
		Location of the hole above the base of a vessel as a fraction of the vessel's vertical dimension. (default value is 0.5)
	release_elevation : float
		The elevation of the release. (default value is 1)
	release_angle : float
		Angle of release above a horizontal plane. (default value is 0.0)
	time_varying_option : TimeVaryingOption
		Whether the release is a time-varying release or a steady state release using the initial rate. (default value is TimeVaryingOption.INITIAL_RATE)
	release_angle_from_mde : float
		Release angle returned from MDE LoadMassInventory model call. (default value is 0.0)
    """
    
    def __init__(self, hole_diameter: float, hole_height_fraction: Optional[float]=0.5, release_elevation: Optional[float]=1, release_angle: Optional[float]=0.0, time_varying_option: Optional[TimeVaryingOption]=TimeVaryingOption.INITIAL_RATE, release_angle_from_mde: Optional[float]=0.0):
        """Initializes a new instance of the Leak class"""
        super().__init__(release_angle, time_varying_option, release_angle_from_mde)
        self.hole_diameter = hole_diameter
        self.hole_height_fraction = hole_height_fraction
        self.release_elevation = release_elevation

    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))
        self.release_elevation = float(data.get('release_elevation', self.release_elevation))

    def __str__(self):
        parts = [
            '* Leak',
            f'Hole Diameter:      {self.hole_diameter}',
            f'Hole Height Fraction:{self.hole_height_fraction}',
            f'Release Elevation:  {self.release_elevation}',
        ]
        return '\n'.join(parts)


class LineRupture(ReleaseOverTime):
    """
    A storage scenario which models a release of material due to rupture of a short length of pipework attached to a vessel or any kind of pressure reservoir.

    Attributes
    ----------
	pipe_diameter : float
		Internal diameter of the short pipe. 
	pipe_length : float
		Length of the short pipe. 
	pipe_roughness : float
		Roughness of the short pipe. (default value is 0.000045)
	pipe_height_fraction : float
		Height of the pipe connection measured from the base of the vessel. (default value is 0.5)
	release_angle : float
		Angle of release above a horizontal plane. (default value is 0.0)
	time_varying_option : TimeVaryingOption
		Whether the release is a time-varying release or a steady state release using the initial rate. (default value is TimeVaryingOption.INITIAL_RATE)
	release_angle_from_mde : float
		Release angle returned from MDE LoadMassInventory model call. (default value is 0.0)
    """
    
    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, release_angle_from_mde: Optional[float]=0.0):
        """Initializes a new instance of the LineRupture class"""
        super().__init__(release_angle, time_varying_option, release_angle_from_mde)
        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 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):
    """
    Data related to a MaterialComponent.

    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. 
	non_standard : bool
		Description of new property. 
    """
    
    def __init__(self, name: str, dippr_version: int, cas_id: int, data_item: List[MaterialComponentDataItem], non_standard: bool):
        """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
        self.non_standard = non_standard

    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)    
        self.non_standard = bool(data.get('non_standard', self.non_standard))

    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),
            f'Non Standard:       {self.non_standard}',
        ]
        return '\n'.join(parts)


class MixtureConstantPropertiesResult(object):
    """
    Constant properties of a mixture.

    Attributes
    ----------
	lower_flammability_limit : float
		The minimum concentration of vapour in air that is capable of propagating a flame through a homogeneous mixture of air and the vapour. 
	upper_flammability_limit : float
		The maximum concentration of vapour in air that is capable of propagating a flame through a homogeneous mixture of air and the vapour. 
	critical_pressure : float
		The pressure above which liquid and gas cannot coexist at any temperature. 
	critical_temperature : float
		The temperature above which the gas cannot become liquid, regardless of the applied pressure. 
	flash_point : float
		The lowest temperature at which a liquid can create enough vapour to ignite when exposed to an external heat source. 
	heat_combustion : float
		The amount of energy released in the form of heat when one mole of a substance is burned. 
	maximum_burn_rate : float
		The maximum mass rate at which a material burns per unit area, used in pool fire modelling. 
	maximum_sep : float
		The maximum surface emissive power of a material. 
	molecular_weight : float
		The sum of the atomic masses of all atoms in a molecule. 
	bubble_point : float
		The temperature where the first bubble of vapor is formed when heating a liquid at atmospheric pressure. 
	pool_fire_burn_rate_length : float
		A characteristic pool fire burn rate length. 
	dew_point : float
		The temperature at which the first liquid drop will form when cooling a gas at atmospheric pressure. 
	emissive_power_length_scale : float
		Used in pool fire modelling for calculating the emissive power for a fire with a given diameter. 
	laminar_burning_velocity : float
		The flame speed, used in the Multi-Energy explosion modelling to calculate the peak overpressure, and can also be used in the pool fire calculations to calculate the MaximumBurnRate. 
	flammable_toxic_flag : FlammableToxic
		Whether a material is flammable, toxic, both or inert. (default value is FlammableToxic.INERT)
	luminous_smoky_flame : LuminousSmokyFlame
		A flag to indicate whether a flame is luminous or smoky. (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 Pipe(Asset):
    """
    An asset to model events that involve releases from pressurised pipelines.

    Attributes
    ----------
	nodes : List[LocalPosition]
		A set of points along the pipe. 
	node_count : int
		The number of nodes along the pipe. 
	diameter : float
		Diameter of the pipe. 
	material : Material
		Material. 
	state : State
		Fluid state in the pipe. 
	location : LocalPosition
		Location of the asset. 
	roughness : float
		A measure of the roughness of internal surfaces of the pipe. (default value is 4.5e-5)
	pumped_inflow : float
		Flowrate along the pipeline under normal operating conditions. (default value is 0)
    """
    
    def __init__(self, node_count: int, diameter: float, material: Material, state: State, nodes: Optional[List[LocalPosition]]=LocalPosition(), 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}',
            f'Material:           {self.material.__str__()}',
            f'State:              {self.state.__str__()}',
            f'Roughness:          {self.roughness}',
            f'Pumped Inflow:      {self.pumped_inflow}',
        ]
        return '\n'.join(parts)


class PipeBreach(ReleaseOverTime):
    """
    A storage scenario which models a time-dependent release of material from its process or transport conditions in a pipeline.

    Attributes
    ----------
	distance_downstream : float
		The distance of the pipe breach, measured along the pipeline from the upstream end. 
	relative_aperture : float
		The size of the outflow area as a fraction of the total potential outflow area for the breach location. (default value is 1)
	release_angle : float
		Angle of release above a horizontal plane. (default value is 0.0)
	time_varying_option : TimeVaryingOption
		Whether the release is a time-varying release or a steady state release using the initial rate. (default value is TimeVaryingOption.INITIAL_RATE)
	release_angle_from_mde : float
		Release angle returned from MDE LoadMassInventory model call. (default value is 0.0)
    """
    
    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, release_angle_from_mde: Optional[float]=0.0):
        """Initializes a new instance of the PipeBreach class"""
        super().__init__(release_angle, time_varying_option, release_angle_from_mde)
        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 PoolFireFlameResult(FlameResult):
    """
    Flame results for a pool fire.

    Attributes
    ----------
	pool_zone_sep : List[float]
		Surface emissive power from each of the two pool fire zones. 
	time : float
		Time of interest for time varying releases, or duration for initial rate releases. 
	surface_emissive_power : float
		The rate at which thermal radiation is emitted from the surface of a flame per unit area. 
	flame_length : float
		Length of the flame. 
	flame_diameter : float
		Diameter of the flame. 
	fire_type : FireType
		Type of fire. (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 PoolRecord(object):
    """
    A record containing pool results at a given time.

    Attributes
    ----------
	time : float
		Time since rainout occurred. 
	mass_spilt : float
		The mass that rains out and forms a pool. 
	mass_vaporised : float
		Mass vaporised from the pool. 
	mass_dissolved : float
		The mass of the pool dissolved in water. 
	mass_remaining : float
		Mass remaining in the pool. 
	vapourisation_rate : float
		The rate of vapourisation from the pool. 
	solution_rate : float
		The rate at which the pool will dissolve in water. 
	effective_radius : float
		The radius of the area of the pool which is taking into account the amount of mass re-evaporated into the cloud. 
	depth : float
		Depth of the pool. 
	temperature : float
		Temperature of the material in the pool. 
	spill_rate : float
		The mass rate at which the cloud is raining out and forming a pool. 
	actual_radius : float
		The radius of the pool formed. 
	pool_centre : float
		The downwind distance at which rainout occurs and a pool is formed. 
    """
    
    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 PoolVapourisationParameters(EntityBase):
    """
    Pool vapourisation parameters.

    Attributes
    ----------
	toxics_cutoff_rate : float
		The rate below which pool vaporisation calculations for toxic releases stop and any remaining mass in the pool no longer contributes to toxic effects. (default value is 0.001)
	flammable_cutoff_rate : float
		The rate below which pool vaporisation calculations for flammable releases stop and any remaining mass in the pool contributes to pool fire effects only. (default value is 0.1)
	relative_tolerance : float
		Controls the step size used by the pool modelling in the integrations of the differential equations for the pool behaviour so as to maximize computational efficiency while minimising the errors involved. (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 RadiationRecord(object):
    """
    A record of the radiation type and level at a specific point (x,y,z).

    Attributes
    ----------
	position : LocalPosition
		Cartesian coordinates of a point of interest. 
	radiation_result : float
		The value for the RadiationType at the specified position. 
	radiation_type : RadiationType
		The type of radiation result of interest. (default value is RadiationType.UNSET)
    """
    
    def __init__(self, radiation_result: float, position: Optional[LocalPosition]=LocalPosition(), 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',
            f'Position:           {self.position.__str__()}',
            f'Radiation Result:   {self.radiation_result}',
            f'Radiation Type:     {self.radiation_type}',
        ]
        return '\n'.join(parts)


class ReliefValve(ReleaseOverTime):
    """
    A storage scenario which models a release of material from the vapour side of a vessel due to the lifting of a relief valve.

    Attributes
    ----------
	relief_valve_constriction_diameter : float
		Constriction at the upstream end of the pipe. 
	pipe_diameter : float
		Internal diameter of the short pipe. 
	pipe_length : float
		Length of the short pipe. 
	pipe_roughness : float
		Roughness of the short pipe. (default value is 0.000045)
	pipe_height_fraction : float
		Location of the pipe connection above the base of the vessel. (default value is 0.5)
	release_angle : float
		Angle of release above a horizontal plane. (default value is 0.0)
	time_varying_option : TimeVaryingOption
		Whether the release is a time-varying release or a steady state release using the initial rate. (default value is TimeVaryingOption.INITIAL_RATE)
	release_angle_from_mde : float
		Release angle returned from MDE LoadMassInventory model call. (default value is 0.0)
    """
    
    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, release_angle_from_mde: Optional[float]=0.0):
        """Initializes a new instance of the ReliefValve class"""
        super().__init__(release_angle, time_varying_option, release_angle_from_mde)
        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 ScalarUdmOutputs(object):
    """
    Scalar UDM output values required for post processing dispersion results.

    Attributes
    ----------
	observer_count : int
		Number of observers either from the release or from the pool. 
	record_count : int
		Number of total dispersion records from all observers. 
	minimum_concentration : float
		Minimum concentration to which dispersion calculations have been performed. 
	wind_power : float
		A wind profile exponent describing how wind changes with height. 
	friction_velocity : float
		The shear stress between the air and the ground. 
	dispersion_release_duration : float
		The time at which the last observer is released. 
	cloud_type : DynamicType
		Type of release or cloud. (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 ShortPipeRupture(ReleaseOverTime):
    """
    Short pipe rupture scenario.

    Attributes
    ----------
	pipe_length : float
		Length of short pipe. 
	pipe_diameter : float
		Inner diameter of the short pipe. 
	pipe_roughness : float
		Roughness of the short pipe. (default value is 0.000045)
	pipe_height_fraction : float
		Location of the pipe connection above the base of the vessel. (default value is 0.5)
	release_angle : float
		Angle of release above a horizontal plane. (default value is 0.0)
	time_varying_option : TimeVaryingOption
		Whether the release is a time-varying release or a steady state release using the initial rate. (default value is TimeVaryingOption.INITIAL_RATE)
	release_angle_from_mde : float
		Release angle returned from MDE LoadMassInventory model call. (default value is 0.0)
    """
    
    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, release_angle_from_mde: Optional[float]=0.0):
        """Initializes a new instance of the ShortPipeRupture class"""
        super().__init__(release_angle, time_varying_option, release_angle_from_mde)
        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 Structure(EntityBase):
    """
    A building or process plant structure.

    Attributes
    ----------
	explosion_confined_volume : ExplosionConfinedVolume
		Confined explosion volume data. 
	location : LocalPosition
		Location of the structure. 
    """
    
    def __init__(self, explosion_confined_volume: Optional[ExplosionConfinedVolume]=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',
            f'Explosion Confined Volume:{self.explosion_confined_volume.__str__()}',
            f'Location:           {self.location.__str__()}',
        ]
        return '\n'.join(parts)


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

    Attributes
    ----------
	bund : Bund
		A bund entity used in the modelling of pool spreading and vaporisation. 
	surface_roughness : float
		The height above the ground below which the wind speed is theoretically zero due to friction from the surface. (default value is 0.183)
	surface_type : SurfaceType
		Surface over which the dispersion occurs. (default value is SurfaceType.LAND)
	pool_surface_type : PoolSurfaceType
		Surface onto which the liquid which rains out will spread. (default value is PoolSurfaceType.CONCRETE)
    """
    
    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',
            f'Bund:               {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 ToxicRecord(object):
    """
    A record of the toxic result type and level at a specific point (x,y,z).

    Attributes
    ----------
	position : LocalPosition
		Cartesian coordinates of a point of interest. 
	toxic_result : float
		The value for the ToxicResultType at the specified position. 
	toxic_result_type : ToxicResultType
		The type of toxic result. (default value is ToxicResultType.UNSET)
    """
    
    def __init__(self, toxic_result: float, position: Optional[LocalPosition]=LocalPosition(), 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',
            f'Position:           {self.position.__str__()}',
            f'Toxic Result:       {self.toxic_result}',
            f'Toxic Result Type:  {self.toxic_result_type}',
        ]
        return '\n'.join(parts)


class Vessel(Asset):
    """
    A pressue vessel asset to represent pressurised containment.

    Attributes
    ----------
	state : State
		Fluid state in the vessel. 
	material : Material
		Material in the vessel. 
	location : LocalPosition
		Location of the asset. 
	diameter : float
		Internal diameter of the vessel. (default value is 2)
	height : float
		Internal height of a VerticalCylinder or VesselCuboid. (default value is 4)
	length : float
		Internal length of HorizontalCylinder or VesselCuboid. (default value is 4)
	width : float
		Internal width of a VesselCuboid. (default value is 0.0)
	shape : VesselShape
		Shape of the vessel. (default value is VesselShape.HORIZONTAL_CYLINDER)
	vessel_conditions : VesselConditions
		The conditions inside the vessel. (default value is VesselConditions.UNSET)
	liquid_fill_fraction_by_volume : float
		The proportion of the vessel occupied by liquid. Used when the VesselConditions are two-phase or pressurized liquid. (default value is 0.0)
    """
    
    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',
            f'State:              {self.state.__str__()}',
            f'Material:           {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 VesselLeakMaxFlammableCloudResults(object):
    """
    Results for a linked run of vessel leak followed by dispersion and views from the cloud.

    Attributes
    ----------
	discharge_rate : float
		Mass flow rate from the leak. 
	expanded_temperature : float
		Post atmospheric expansion temperature. 
	lfl_extent : float
		Maximum downwind distance to LFL. 
	lfl_area : float
		Horizontal area of the LFL envelope. 
	lfl_height : float
		Height of the maximum LFL extent. 
	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 VesselSphere(Asset):
    """
    A spherical pressue vessel asset to represent pressurised containment.

    Attributes
    ----------
	state : State
		Fluid state in the vessel. 
	material : Material
		Material in the vessel. 
	mass_inventory : float
		Mass of the material in the vessel. 
	location : LocalPosition
		Location of the asset. 
    """
    
    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',
            f'State:              {self.state.__str__()}',
            f'Material:           {self.material.__str__()}',
            f'Mass Inventory:     {self.mass_inventory}',
        ]
        return '\n'.join(parts)


class Weather(EntityBase):
    """
    A set of weather conditions for use in the modelling of a release and its effects.

    Attributes
    ----------
	wind_speed : float
		Wind speed at a reference height. (default value is 5)
	stability_class : AtmosphericStabilityClass
		The Pasquill atmospheric stability class. (default value is AtmosphericStabilityClass.STABILITY_D)
	temperature : float
		The atmospheric temperature. (default value is 283)
	relative_humidity : float
		The amount of water vapour present in the air compared to the maximum amount the air can hold at a given temperature. (default value is 0.7)
	mixing_layer_height : float
		The height of the atmospheric boundary layer which caps the centreline of the plume. (default value is 800)
	solar_radiation : float
		The radiation received from the sun, which contributes to pool evaporation. (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)