"""Chemical Engineering Design Library (ChEDL). Utilities for process modeling.
Copyright (C) 2016, Caleb Bell <Caleb.Andrew.Bell@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
This module contains functions for lookup the following properties for a
chemical:
* Short-term Exposure Limit (STEL)
* Time-Weighted Average Exposure Limit (TWA)
* Celing limit for working exposure
* Whether a chemicals is absorbed thorough human skin
* Whether a chemical is a carcinogen, suspected of being a carcinogen, or has
been identified as unlikely to be a carcinogen
* Flash point
* Auto ignition point
* Lower flammability limit
* Upper flammability limit
In addition, several estimation methods for chemicals without flammability
limits are provided and for calculating the flammability limits of mixtures.
This module also contains several utility functions.
For reporting bugs, adding feature requests, or submitting pull requests,
please use the `GitHub issue tracker <https://github.com/CalebBell/chemicals/>`_.
.. contents:: :local:
Short-term Exposure Limit
-------------------------
.. autofunction:: chemicals.safety.STEL
.. autofunction:: chemicals.safety.STEL_methods
.. autodata:: chemicals.safety.STEL_all_methods
Time-Weighted Average Exposure Limit
------------------------------------
.. autofunction:: chemicals.safety.TWA
.. autofunction:: chemicals.safety.TWA_methods
.. autodata:: chemicals.safety.TWA_all_methods
Ceiling Limit
-------------
.. autofunction:: chemicals.safety.Ceiling
.. autofunction:: chemicals.safety.Ceiling_methods
.. autodata:: chemicals.safety.Ceiling_all_methods
Skin Absorbance
---------------
.. autofunction:: chemicals.safety.Skin
.. autofunction:: chemicals.safety.Skin_methods
.. autodata:: chemicals.safety.Skin_all_methods
Carcinogenicity
---------------
.. autofunction:: chemicals.safety.Carcinogen
.. autofunction:: chemicals.safety.Carcinogen_methods
.. autodata:: chemicals.safety.Carcinogen_all_methods
Flash Point
-----------
.. autofunction:: chemicals.safety.T_flash
.. autofunction:: chemicals.safety.T_flash_methods
.. autodata:: chemicals.safety.T_flash_all_methods
Autoignition Point
------------------
.. autofunction:: chemicals.safety.T_autoignition
.. autofunction:: chemicals.safety.T_autoignition_methods
.. autodata:: chemicals.safety.T_autoignition_all_methods
Lower Flammability Limit
------------------------
.. autofunction:: chemicals.safety.LFL
.. autofunction:: chemicals.safety.LFL_methods
.. autodata:: chemicals.safety.LFL_all_methods
.. autofunction:: chemicals.safety.Suzuki_LFL
.. autofunction:: chemicals.safety.Crowl_Louvar_LFL
.. autofunction:: chemicals.safety.LFL_ISO_10156_2017
Upper Flammability Limit
------------------------
.. autofunction:: chemicals.safety.UFL
.. autofunction:: chemicals.safety.UFL_methods
.. autodata:: chemicals.safety.UFL_all_methods
.. autofunction:: chemicals.safety.Suzuki_UFL
.. autofunction:: chemicals.safety.Crowl_Louvar_UFL
Mixture Flammability Limit
--------------------------
.. autofunction:: chemicals.safety.fire_mixing
Utility Methods
---------------
.. autofunction:: chemicals.safety.ppmv_to_mgm3
.. autofunction:: chemicals.safety.mgm3_to_ppmv
.. autofunction:: chemicals.safety.NFPA_30_classification
"""
__all__ = ('ppmv_to_mgm3', 'mgm3_to_ppmv',
'NTP_codes', 'IARC_codes',
'Skin_all_methods', 'Ceiling_all_methods', 'STEL_all_methods',
'TWA_all_methods',
'TWA_methods', 'TWA', 'STEL', 'STEL_methods', 'Ceiling', 'Ceiling_methods',
'Skin', 'Skin_methods', 'Carcinogen_methods', 'Carcinogen_all_methods',
'Carcinogen', 'T_flash_all_methods', 'T_flash_methods',
'T_flash', 'T_autoignition_methods', 'T_autoignition_all_methods',
'T_autoignition', 'LFL_methods', 'LFL_all_methods',
'LFL', 'UFL_methods', 'UFL_all_methods', 'UFL', 'fire_mixing',
'Suzuki_LFL', 'Suzuki_UFL',
'Crowl_Louvar_LFL', 'Crowl_Louvar_UFL', 'LFL_ISO_10156_2017',
'NFPA_30_classification')
from chemicals import data_reader as dr
from chemicals import miscdata
from chemicals.data_reader import (
data_source,
database_constant_lookup,
list_available_methods_from_df_dict,
register_df_source,
retrieve_any_from_df_dict,
retrieve_from_df_dict,
)
from chemicals.utils import PY37, R, can_load_data, mark_numba_incompatible, normalize, os_path_join, source_path
### Utilities
[docs]def ppmv_to_mgm3(ppmv, MW, T=298.15, P=101325.0):
r'''
Converts a concentration in ppmv to units of mg/m^3. Used in
industrial toxicology.
.. math::
\frac{mg}{m^3} = \frac{ppmv\cdot P}{RT}\cdot \frac{MW}{1000}
Parameters
----------
ppmv : float
Concentration of a component in a gas mixure [parts per million,
volumetric]
MW : float
Molecular weight of the trace gas [g/mol]
T : float, optional
Temperature of the gas at which the ppmv is reported, [K]
P : float, optional
Pressure of the gas at which the ppmv is reported, [Pa]
Returns
-------
mgm3 : float
Concentration of a substance in an ideal gas mixture [mg/m^3]
Notes
-----
The term P/(RT)/1000 converts to 0.040874 at STP. Its inverse is reported
as 24.45 in [1]_.
Examples
--------
>>> ppmv_to_mgm3(1.0, 40.0)
1.6349617809430446
References
----------
.. [1] ACGIH. Industrial Ventilation: A Manual of Recommended Practice,
23rd Edition. American Conference of Governmental and Industrial
Hygenists, 2004.
'''
parts = ppmv*1E-6
n = parts*P/(R*T)
mgm3 = MW*n*1000 # mol toxin /m^3 * g/mol toxis * 1000 mg/g
return mgm3
[docs]def mgm3_to_ppmv(mgm3, MW, T=298.15, P=101325.):
r'''
Converts a concentration in mg/m^3 to units of ppmv. Used in
industrial toxicology.
.. math::
ppmv = \frac{1000RT}{MW\cdot P} \cdot \frac{mg}{m^3}
Parameters
----------
mgm3 : float
Concentration of a substance in an ideal gas mixture [mg/m^3]
MW : float
Molecular weight of the trace gas [g/mol]
T : float, optional
Temperature of the gas at which the ppmv is reported, [K]
P : float, optional
Pressure of the gas at which the ppmv is reported, [Pa]
Returns
-------
ppmv : float
Concentration of a component in a gas mixure [parts per million,
volumetric]
Notes
-----
The term P/(RT)/1000 converts to 0.040874 at STP. Its inverse is reported
as 24.45 in [1]_.
Examples
--------
>>> mgm3_to_ppmv(1.635, 40.0)
1.0000233761164334
References
----------
.. [1] ACGIH. Industrial Ventilation: A Manual of Recommended Practice,
23rd Edition. American Conference of Governmental and Industrial
Hygenists, 2004.
'''
n = mgm3/MW/1000.
parts = n*R*T/P
ppm = parts/1E-6
return ppm
### Data
NTP_codes = {1: 'Known', 2: 'Reasonably Anticipated'}
IARC_codes = {1: 'Carcinogenic to humans (1)',
11: 'Probably carcinogenic to humans (2A)', # 2A
12: 'Possibly carcinogenic to humans (2B)', # 2B
3: 'Not classifiable as to its carcinogenicity to humans (3)',
4: 'Probably not carcinogenic to humans (4)'}
folder = os_path_join(source_path, 'Safety')
register_df_source(folder, 'NFPA 497 2008.tsv')
register_df_source(folder, 'IS IEC 60079-20-1 2010.tsv')
register_df_source(folder, 'DIPPR T_flash Serat.csv')
register_df_source(folder, 'National Toxicology Program Carcinogens.tsv')
register_df_source(folder, 'IARC Carcinogen Database.tsv')
_safety_data_loaded = False
IEC = 'IEC 60079-20-1 (2010)'
NFPA = 'NFPA 497 (2008)'
SERAT = 'Serat DIPPR (2017)'
SUZUKI = 'Suzuki (1994)'
CROWLLOUVAR = 'Crowl and Louvar (2001)'
def _load_safety_data():
global Ontario_exposure_limits_dict, NFPA_2008_data, IEC_2010_data
global DIPPR_SERAT_data, NTP_data, IARC_data, Tflash_sources
global Tautoignition_sources, LFL_sources, UFL_sources, _safety_data_loaded
import json
file = os_path_join(folder, 'Ontario Exposure Limits.json')
with open(file) as stream:
Ontario_exposure_limits_dict = json.load(stream)
NFPA_2008_data = data_source('NFPA 497 2008.tsv')
IEC_2010_data = data_source('IS IEC 60079-20-1 2010.tsv')
DIPPR_SERAT_data = data_source('DIPPR T_flash Serat.csv')
NTP_data = data_source('National Toxicology Program Carcinogens.tsv')
IARC_data = data_source('IARC Carcinogen Database.tsv')
Tflash_sources = {IEC: IEC_2010_data,
NFPA: NFPA_2008_data,
SERAT: DIPPR_SERAT_data,
miscdata.WIKIDATA: miscdata.wikidata_data,
}
Tautoignition_sources = {IEC: IEC_2010_data,
NFPA: NFPA_2008_data,
miscdata.WIKIDATA: miscdata.wikidata_data}
LFL_sources = Tautoignition_sources.copy()
UFL_sources = Tautoignition_sources.copy()
_safety_data_loaded = True
if PY37:
def __getattr__(name):
if name in ('Ontario_exposure_limits_dict', 'NFPA_2008_data', 'IEC_2010_data',
'DIPPR_SERAT_data'):
_load_safety_data()
return globals()[name]
raise AttributeError(f"module {__name__} has no attribute {name}")
else: # pragma: no cover
if can_load_data:
_load_safety_data()
# # Used to read Ontario Expore Limits data from original file (DO NOT DELETE!)
# Ontario_exposure_limits_dict = {}
# def str_to_ppm_mgm3(line, MW): # pragma: no cover
# if not line:
# return None, None
# if 'ppm' in line:
# _ppm = float(line.split('ppm')[0])
# try:
# _mgm3 = ppmv_to_mgm3(_ppm, MW)
# except:
# _mgm3 = None
# elif 'mg/m3' in line:
# _mgm3 = float(line.split('mg/m3')[0])
# try:
# _ppm = mgm3_to_ppmv(_mgm3, MW)
# except:
# _ppm = None
# if not _ppm and not _mgm3:
# raise Exception('failure in function')
# return (_ppm, _mgm3)
# with open(os.path.join(folder, 'Ontario Exposure Limits.tsv'), encoding='utf-8') as f:
# '''Read in a dict of TWAs, STELs, and Ceiling Limits. The data source
# is the Ontario Labor Website. They have obtained their data in part from
# their own reviews, and also from ACGIH.
# Warning: The lowest value is taken, when multiple units or different forms
# of a compound are listed.
# Note that each province has a different set of values, but these serve
# as general values.
# '''
# next(f)
# for line in f:
# values = to_num(line.strip('\n').split('\t'))
# if values[0]:
# if type(values[6]) == str:
# MWs = [float(i) if i != '' else None for i in values[6].split(';')]
# elif values[6] is None:
# MWs = [None]
# elif type(values[6]) == float:
# MWs = [values[6]]
# else:
# MWs = [None]
# for i, CASRN in enumerate(values[0].split(';')):
# try:
# MWi = MWs[i]
# except IndexError:
# MWi = None
# _ppm_TWA, _mgm3_TWA = str_to_ppm_mgm3(values[2], MWi)
# _ppm_STEL, _mgm3_STEL = str_to_ppm_mgm3(values[3], MWi)
# _ppm_C, _mgm3_C = str_to_ppm_mgm3(values[4], MWi)
# if values[5] == 'Skin':
# _skin = True
# else:
# _skin = False
# Ontario_exposure_limits_dict[CASRN] = {"Name": values[1], "TWA (ppm)": _ppm_TWA,
# "TWA (mg/m^3)": _mgm3_TWA, "STEL (ppm)": _ppm_STEL,
# "STEL (mg/m^3)": _mgm3_STEL, "Ceiling (ppm)": _ppm_C,
# "Ceiling (mg/m^3)": _mgm3_C, "Skin":_skin, "MW": MWi}
#TODO: Add CRC exposure limits. Note that functions should be used.
#_CRCExposureLimits = {}
#with open(os.path.join(folder,'CRC Exposure Limits.csv')) as f:
# '''Read in a dict of TWAs and STELs. The data source
# is the CRC Handbook.. They have obtained their data from
# NIOSH, and OSHA Chemical Information Manual, and ACGIH.
# '''
# f.next()
# for line in f:
# values = to_num(line.strip('\n').split('\t'))
# _ppm_TWA, _mgm3_TWA = str_to_ppm_mgm3(values[2], CASRN.strip())
# _ppm_STEL, _mgm3_STEL = str_to_ppm_mgm3(values[3], CASRN.strip())
# _CRCExposureLimits[CASRN] = {"Name": values[1], "TWA (ppm)": _ppm_TWA,
# "TWA (mg/m^3)": _mgm3_TWA, "STEL (ppm)": _ppm_STEL,
# "STEL (mg/m^3)": _mgm3_STEL}
#del _ppm_TWA, _mgm3_TWA, _ppm_STEL, _mgm3_STEL, _ppm_C, _mgm3_C, status
#print Ontario_exposure_limits_dict['109-73-9']
##{'STEL (ppm)': None, 'Name': 'n-Butylamine [109-73-9]', 'Ceiling (mg/m^3)': 14.956408997955013, 'Ceiling (ppm)': 5.0, 'TWA (mg/m^3)': None, 'STEL (mg/m^3)': None, 'TWA (ppm)': None}
#print Ontario_exposure_limits_dict['34590-94-8']
#{'STEL (ppm)': 150.0, 'Name': '(2-Methoxymethylethoxy) propanol (DPGME) [34590-94-8]', 'Ceiling (mg/m^3)': None, 'Ceiling (ppm)': None, 'TWA (mg/m^3)': None, 'STEL (mg/m^3)': None, 'TWA (ppm)': 100.0}
# TODO: Add https://www.worksafebc.com/en/law-policy/occupational-health-safety/searchable-ohs-regulation/ohs-guidelines/guidelines-part-05#ExposureLimits
### OSHA exposure limit functions
ONTARIO = 'Ontario Limits'
TWA_all_methods = (ONTARIO,)
"""Tuple of method name keys. See the :obj:`TWA` for the actual references"""
STEL_all_methods = (ONTARIO,)
"""Tuple of method name keys. See the :obj:`STEL` for the actual references"""
Ceiling_all_methods = (ONTARIO,)
"""Tuple of method name keys. See the :obj:`Ceiling` for the actual references"""
Skin_all_methods = (ONTARIO,)
"""Tuple of method name keys. See the :obj:`Skin` for the actual references"""
[docs]@mark_numba_incompatible
def TWA_methods(CASRN):
"""Return all methods available to obtain the Time-Weighted Average exposure
limits (TWA) for the desired chemical.
Parameters
----------
CASRN : str
CASRN, [-]
Returns
-------
methods : list[str]
Methods which can be used to obtain TWA with the given inputs.
See Also
--------
TWA
Examples
--------
>>> TWA_methods('71-43-2')
['Ontario Limits']
"""
if not _safety_data_loaded: _load_safety_data()
if CASRN in Ontario_exposure_limits_dict:
data = Ontario_exposure_limits_dict[CASRN]
if (data["TWA (ppm)"] or data["TWA (mg/m^3)"]): return [ONTARIO]
return []
[docs]@mark_numba_incompatible
def TWA(CASRN, method=None):
"""Return the Time-Weighted Average exposure
limits (TWA) for the desired chemical if it is available.
Parameters
----------
CASRN : str
CASRN, [-]
method : str
Name of method to use, [-]
Returns
-------
TWA : float
Time-Weighted Average exposure, [ppm or mg/m^3]
units : str
One of ppm or mg/m^3, [-]
Notes
-----
The ppm value is preferentially returned if both are available. While they
can be converted in specific cases, it is better to work with the specified
units of the original source.
Examples
--------
>>> TWA('98-00-0')
(10.0, 'ppm')
>>> TWA('1303-00-0')
(5.0742430905659505e-05, 'ppm')
"""
if not _safety_data_loaded: _load_safety_data()
if not method or method == ONTARIO:
if CASRN in Ontario_exposure_limits_dict:
data = Ontario_exposure_limits_dict[CASRN]
value = data["TWA (ppm)"]
if value: return value, 'ppm'
value = data["TWA (mg/m^3)"]
if value: return value, 'mg/m^3'
else:
raise ValueError(f'Invalid method: {method}, allowed methods are {TWA_all_methods}')
[docs]@mark_numba_incompatible
def STEL_methods(CASRN):
"""Return all methods available to obtain STEL for the desired chemical.
Parameters
----------
CASRN : str
CASRN, [-]
Returns
-------
methods : list[str]
Methods which can be used to obtain STEL with the given inputs.
See Also
--------
STEL
"""
if not _safety_data_loaded: _load_safety_data()
if CASRN in Ontario_exposure_limits_dict:
data = Ontario_exposure_limits_dict[CASRN]
if (data["STEL (ppm)"] or data["STEL (mg/m^3)"]): return [ONTARIO]
return []
[docs]@mark_numba_incompatible
def STEL(CASRN, method=None):
"""This function handles the retrieval of Short-term Exposure Limit (STEL)
on worker exposure to dangerous chemicals.
Parameters
----------
CASRN : str
CASRN, [-]
method : str
Name of method to use, [-]
Returns
-------
STEL : float
Short-term Exposure Limit, [ppm or mg/m^3]
units : str
One of ppm or mg/m^3, [-]
Notes
-----
The ppm value is preferentially returned if both are available. While they
can be converted in specific cases, it is better to work with the specified
units of the original source.
Examples
--------
>>> STEL('67-64-1')
(750.0, 'ppm')
>>> STEL('7664-38-2')
(0.7489774978301237, 'ppm')
>>> STEL('55720-99-5')
(2.0, 'mg/m^3')
"""
if not _safety_data_loaded: _load_safety_data()
if not method or method == ONTARIO:
if CASRN in Ontario_exposure_limits_dict:
data = Ontario_exposure_limits_dict[CASRN]
value = data["STEL (ppm)"]
if value: return value, 'ppm'
value = data["STEL (mg/m^3)"]
if value: return value, 'mg/m^3'
else:
raise ValueError(f'Invalid method: {method}, allowed methods are {TWA_all_methods}')
[docs]@mark_numba_incompatible
def Ceiling_methods(CASRN):
"""Return all methods available to obtain Ceiling limits for the desired
chemical.
Parameters
----------
CASRN : str
CASRN, [-]
Returns
-------
methods : list[str]
Methods which can be used to obtain Ceiling limits with the given inputs.
See Also
--------
Ceiling
"""
if not _safety_data_loaded: _load_safety_data()
if CASRN in Ontario_exposure_limits_dict:
data = Ontario_exposure_limits_dict[CASRN]
if (data["Ceiling (ppm)"] or data["Ceiling (mg/m^3)"]): return [ONTARIO]
return []
[docs]@mark_numba_incompatible
def Ceiling(CASRN, method=None):
"""This function handles the retrieval of ceiling limits on worker exposure
to dangerous chemicals. Ceiling limits are not to be exceeded at any time.
Parameters
----------
CASRN : str
CASRN, [-]
method : str
Name of method to use, [-]
Returns
-------
Ceiling : float
Ceiling Limit, [ppm or mg/m^3]
units : str
One of ppm or mg/m^3, [-]
Examples
--------
>>> Ceiling('75-07-0')
(25.0, 'ppm')
>>> Ceiling('1395-21-7')
(6e-05, 'mg/m^3')
"""
if not _safety_data_loaded: _load_safety_data()
if not method or method == ONTARIO:
if CASRN in Ontario_exposure_limits_dict:
data = Ontario_exposure_limits_dict[CASRN]
value = data["Ceiling (ppm)"]
if value: return value, 'ppm'
value = data["Ceiling (mg/m^3)"]
if value: return value, 'mg/m^3'
else:
raise ValueError(f'Invalid method: {method}, allowed methods are {list(Ontario_exposure_limits_dict)}')
[docs]@mark_numba_incompatible
def Skin_methods(CASRN):
"""Return all methods available to obtain whether or not a chemical can be
absorbed through the skin.
Parameters
----------
CASRN : str
CASRN, [-]
Returns
-------
methods : list[str]
Methods which can be used to obtain whether or not a chemical can
be absorbed through the skin.
See Also
--------
Skin
"""
return [ONTARIO] if CASRN in Ontario_exposure_limits_dict else []
[docs]@mark_numba_incompatible
def Skin(CASRN, method=None):
"""This function handles the retrieval of whether or not a chemical can be
absorbed through the skin, relevant to chemical safety calculations.
Parameters
----------
CASRN : str
CASRN, [-]
method : str
Name of method to use, [-]
Returns
-------
skin : bool
Whether or not the substance is absorbed through human skin, [-]
Examples
--------
>>> Skin('108-94-1')
True
>>> Skin('1395-21-7')
False
"""
if not _safety_data_loaded: _load_safety_data()
if not method or method == ONTARIO:
if CASRN in Ontario_exposure_limits_dict:
return Ontario_exposure_limits_dict[CASRN]["Skin"]
else:
raise ValueError(f'Invalid method: {method}, allowed methods are {TWA_all_methods}')
### Carcinogen functions
IARC = 'International Agency for Research on Cancer'
NTP = 'National Toxicology Program 13th Report on Carcinogens'
UNLISTED = 'Unlisted'
COMBINED = 'Combined'
Carcinogen_all_methods = (IARC, NTP)
"""Tuple of method name keys. See the :obj:`Carcinogen` for the actual references"""
[docs]@mark_numba_incompatible
def Carcinogen_methods(CASRN):
"""Return all methods available to obtain Carcinogen listings for the
desired chemical.
Parameters
----------
CASRN : str
CASRN, [-]
Returns
-------
methods : list[str]
Methods which can be used to obtain Carcinogen listings with the given inputs.
See Also
--------
Carcinogen
"""
return list(Carcinogen_all_methods)
[docs]@mark_numba_incompatible
def Carcinogen(CASRN, method=None):
r'''Looks up if a chemical is listed as a carcinogen or not according to
either a specifc method or with all methods.
Returns either the status as a string for a specified method, or the
status of the chemical in all available data sources, in the format
{source: status}.
Parameters
----------
CASRN : str
CASRN [-]
Returns
-------
status : str or dict
Carcinogen status information [-].
Other Parameters
----------------
method : string, optional
A string for the method name to use, as defined in the variable,
`Carcinogen_all_methods`.
Notes
-----
Supported methods are:
* **IARC**: International Agency for Research on Cancer, [1]_. As
extracted with a last update of February 22, 2016. Has listing
information of 863 chemicals with CAS numbers. Chemicals without
CAS numbers not included here. If two listings for the same CAS
were available, the harshest rating was used. If two
listings were available published at different times, the latest
value was used. All else equal, the most pessimistic value was used.
* **NTP**: National Toxicology Program, [2]_. Has data on 228
chemicals.
Examples
--------
>>> Carcinogen('61-82-5')
{'International Agency for Research on Cancer': 'Not classifiable as to its carcinogenicity to humans (3)', 'National Toxicology Program 13th Report on Carcinogens': 'Reasonably Anticipated'}
References
----------
.. [1] International Agency for Research on Cancer. Agents Classified by
the IARC Monographs, Volumes 1-115. Lyon, France: IARC; 2020 Available
from: http://monographs.iarc.fr/ENG/Classification/
.. [2] NTP (National Toxicology Program). 2021. Report on Carcinogens,
Fifteenth Edition.; Research Triangle Park, NC: U.S. Department of
Health and Human Services, Public Health Service.
https://doi.org/10.22427/NTP-OTHER-1003
'''
if not _safety_data_loaded: _load_safety_data()
if not method:
return {
IARC: IARC_codes[IARC_data.at[CASRN, 'group']] if CASRN in IARC_data.index else UNLISTED,
NTP: NTP_codes[NTP_data.at[CASRN, 'Listing']] if CASRN in NTP_data.index else UNLISTED
}
if method == IARC:
if CASRN in IARC_data.index:
return IARC_codes[IARC_data.at[CASRN, 'group']]
elif method == NTP:
if CASRN in NTP_data.index:
return NTP_codes[NTP_data.at[CASRN, 'Listing']]
else:
raise ValueError(f'Invalid method: {method}, allowed methods are {Carcinogen_all_methods}')
return UNLISTED
### Fire-related functions
T_flash_all_methods = (IEC, NFPA, SERAT, miscdata.WIKIDATA)
"""Tuple of method name keys. See the :obj:`T_flash` for the actual references"""
[docs]@mark_numba_incompatible
def T_flash_methods(CASRN):
"""Return all methods available to obtain T_flash for the desired chemical.
Parameters
----------
CASRN : str
CASRN, [-]
Returns
-------
methods : list[str]
Methods which can be used to obtain T_flash with the given inputs.
See Also
--------
T_flash
"""
if not _safety_data_loaded: _load_safety_data()
return list_available_methods_from_df_dict(Tflash_sources, CASRN, 'T_flash')
[docs]@mark_numba_incompatible
def T_flash(CASRN, method=None):
r'''
This function handles the retrieval or calculation of a chemical's
flash point. Lookup is based on CASRNs. No predictive methods are currently
implemented. Will automatically select a data source to use if no method
is provided; returns None if the data is not available.
Examples
--------
>>> T_flash(CASRN='64-17-5')
285.15
>>> T_flash('111-69-3', method='WIKIDATA')
365.92778
Parameters
----------
CASRN : str
CASRN [-]
Returns
-------
T_flash : float
Flash point of the chemical, [K]
Other Parameters
----------------
method : string, optional
A string for the method name to use, as defined in the variable,
`T_flash_all_methods`,
Notes
-----
Preferred source is 'IEC 60079-20-1 (2010)' [1]_, with the secondary source
'NFPA 497 (2008)' [2]_ having very similar data. A third source
'Serat DIPPR (2017)' [3]_ provides third hand experimental but evaluated
data from the DIPPR database, version unspecified, for 870 compounds.
The predicted values from the DIPPR databank are also available in the
supporting material in [3]_, but are not included.
See Also
--------
T_flash_methods
References
----------
.. [1] IEC. "IEC 60079-20-1:2010 Explosive atmospheres - Part 20-1:
Material characteristics for gas and vapour classification - Test
methods and data." https://webstore.iec.ch/publication/635. See also
https://law.resource.org/pub/in/bis/S05/is.iec.60079.20.1.2010.pdf
.. [2] National Fire Protection Association. NFPA 497: Recommended
Practice for the Classification of Flammable Liquids, Gases, or Vapors
and of Hazardous. NFPA, 2008.
.. [3] Serat, Fatima Zohra, Ali Mustapha Benkouider, Ahmed Yahiaoui, and
Farid Bagui. "Nonlinear Group Contribution Model for the Prediction of
Flash Points Using Normal Boiling Points." Fluid Phase Equilibria 449
(October 15, 2017): 52-59. doi:10.1016/j.fluid.2017.06.008.
.. [4] Wikidata. Wikidata. Accessed via API. https://www.wikidata.org/
'''
if dr.USE_CONSTANTS_DATABASE and method is None:
val, found = database_constant_lookup(CASRN, 'T_flash')
if found: return val
if not _safety_data_loaded: _load_safety_data()
if method:
return retrieve_from_df_dict(Tflash_sources, CASRN, 'T_flash', method)
else:
return retrieve_any_from_df_dict(Tflash_sources, CASRN, 'T_flash')
T_autoignition_all_methods = (IEC, NFPA, miscdata.WIKIDATA)
"""Tuple of method name keys. See the :obj:`T_autoignition` for the actual references"""
[docs]@mark_numba_incompatible
def T_autoignition_methods(CASRN):
"""Return all methods available to obtain T_autoignition for the desired
chemical.
Parameters
----------
CASRN : str
CASRN, [-]
Returns
-------
methods : list[str]
Methods which can be used to obtain T_autoignition with the given inputs.
See Also
--------
T_autoignition
"""
if not _safety_data_loaded: _load_safety_data()
return list_available_methods_from_df_dict(Tautoignition_sources, CASRN, 'T_autoignition')
[docs]@mark_numba_incompatible
def T_autoignition(CASRN, method=None):
r'''
This function handles the retrieval or calculation of a chemical's
autoifnition temperature. Lookup is based on CASRNs. No predictive methods
are currently implemented. Will automatically select a data source to use
if no Method is provided; returns None if the data is not available.
Parameters
----------
CASRN : str
CASRN [-]
Returns
-------
Tautoignition : float
Autoignition point of the chemical, [K].
Other Parameters
----------------
method : string, optional
A string for the method name to use, as defined in the variable,
`T_autoignition_all_methods`.
Examples
--------
>>> T_autoignition(CASRN='71-43-2')
771.15
>>> T_autoignition('111-69-3', method='WIKIDATA')
823.15
Notes
-----
Preferred source is 'IEC 60079-20-1 (2010)' [1]_, with the secondary source
'NFPA 497 (2008)' [2]_ having very similar data.
See Also
--------
T_autoignition_methods
References
----------
.. [1] IEC. “IEC 60079-20-1:2010 Explosive atmospheres - Part 20-1:
Material characteristics for gas and vapour classification - Test
methods and data.” https://webstore.iec.ch/publication/635. See also
https://law.resource.org/pub/in/bis/S05/is.iec.60079.20.1.2010.pdf
.. [2] National Fire Protection Association. NFPA 497: Recommended
Practice for the Classification of Flammable Liquids, Gases, or Vapors
and of Hazardous. NFPA, 2008.
.. [3] Wikidata. Wikidata. Accessed via API. https://www.wikidata.org/
'''
if dr.USE_CONSTANTS_DATABASE and method is None:
val, found = database_constant_lookup(CASRN, 'T_autoignition')
if found: return val
if not _safety_data_loaded: _load_safety_data()
if method:
return retrieve_from_df_dict(Tautoignition_sources, CASRN, 'T_autoignition', method)
else:
return retrieve_any_from_df_dict(Tautoignition_sources, CASRN, 'T_autoignition')
LFL_all_methods = (IEC, NFPA, miscdata.WIKIDATA, SUZUKI, CROWLLOUVAR)
"""Tuple of method name keys. See the :obj:`LFL` for the actual references"""
[docs]@mark_numba_incompatible
def LFL_methods(Hc=None, atoms=None, CASRN=''):
"""Return all methods available to obtain LFL for the desired chemical.
Parameters
----------
Hc : float, optional
Heat of combustion of gas [J/mol].
atoms : dict, optional
Dictionary of atoms and atom counts.
CASRN : str, optional
CASRN, [-]
Returns
-------
methods : list[str]
Methods which can be used to obtain LFL with the given inputs.
See Also
--------
LFL
Examples
--------
Methane
>>> LFL_methods(Hc=-890590.0, atoms={'C': 1, 'H': 4}, CASRN='74-82-8')
['IEC 60079-20-1 (2010)', 'NFPA 497 (2008)', 'Suzuki (1994)', 'Crowl and Louvar (2001)']
"""
if not _safety_data_loaded: _load_safety_data()
methods = list_available_methods_from_df_dict(LFL_sources, CASRN, 'LFL')
if Hc is not None:
methods.append(SUZUKI)
if atoms is not None:
methods.append(CROWLLOUVAR)
return methods
[docs]@mark_numba_incompatible
def LFL(Hc=None, atoms=None, CASRN='', method=None):
r'''This function handles the retrieval or calculation of a chemical's
Lower Flammability Limit. Lookup is based on CASRNs. Will automatically
select a data source to use if no Method is provided; returns None if the
data is not available.
Parameters
----------
Hc : float, optional
Heat of combustion of gas [J/mol].
atoms : dict, optional
Dictionary of atoms and atom counts.
CASRN : str, optional
CASRN, [-]
Returns
-------
LFL : float
Lower flammability limit of the gas in an atmosphere at STP, [mole fraction].
Other Parameters
----------------
method : string, optional
A string for the method name to use, as defined in the variable,
`LFL_all_methods`.
Examples
--------
>>> LFL(CASRN='71-43-2')
0.012
>>> LFL(Hc=-890590.0, atoms={'C': 1, 'H': 4}, CASRN='74-82-8')
0.044
>>> LFL(CASRN='111-69-3', method='WIKIDATA')
0.017
Notes
-----
Preferred source is 'IEC 60079-20-1 (2010)' [1]_, with the secondary source
'NFPA 497 (2008)' [2]_ having very similar data. If the heat of combustion
is provided, the estimation method :obj:`Suzuki_LFL` can be used. If the atoms
of the molecule are available, the method :obj:`Crowl_Louvar_LFL` can be used.
References
----------
.. [1] IEC. “IEC 60079-20-1:2010 Explosive atmospheres - Part 20-1:
Material characteristics for gas and vapour classification - Test
methods and data.” https://webstore.iec.ch/publication/635. See also
https://law.resource.org/pub/in/bis/S05/is.iec.60079.20.1.2010.pdf
.. [2] National Fire Protection Association. NFPA 497: Recommended
Practice for the Classification of Flammable Liquids, Gases, or Vapors
and of Hazardous. NFPA, 2008.
.. [3] Wikidata. Wikidata. Accessed via API. https://www.wikidata.org/
'''
if dr.USE_CONSTANTS_DATABASE and method is None:
val, found = database_constant_lookup(CASRN, 'LFL')
if found: return val
if not _safety_data_loaded: _load_safety_data()
if not method:
LFL = retrieve_any_from_df_dict(LFL_sources, CASRN, 'LFL')
if not LFL:
if Hc == 0.0:
return None
if Hc: LFL = Suzuki_LFL(Hc)
elif atoms: LFL = Crowl_Louvar_LFL(atoms)
return LFL
elif method == SUZUKI:
return Suzuki_LFL(Hc)
elif method == CROWLLOUVAR:
return Crowl_Louvar_LFL(atoms)
else:
return retrieve_from_df_dict(LFL_sources, CASRN, 'LFL', method)
UFL_all_methods = (IEC, NFPA, miscdata.WIKIDATA, SUZUKI, CROWLLOUVAR)
"""Tuple of method name keys. See the :obj:`UFL` for the actual references"""
[docs]@mark_numba_incompatible
def UFL_methods(Hc=None, atoms=None, CASRN=''):
"""Return all methods available to obtain UFL for the desired chemical.
Parameters
----------
Hc : float, optional
Heat of combustion of gas [J/mol].
atoms : dict, optional
Dictionary of atoms and atom counts.
CASRN : str, optional
CASRN, [-]
Returns
-------
methods : list[str]
Methods which can be used to obtain UFL with the given inputs.
See Also
--------
UFL
Examples
--------
Methane
>>> UFL_methods(Hc=-890590.0, atoms={'C': 1, 'H': 4}, CASRN='74-82-8')
['IEC 60079-20-1 (2010)', 'NFPA 497 (2008)', 'Suzuki (1994)', 'Crowl and Louvar (2001)']
"""
if not _safety_data_loaded: _load_safety_data()
methods = list_available_methods_from_df_dict(UFL_sources, CASRN, 'UFL')
if Hc is not None:
methods.append(SUZUKI)
if atoms is not None:
methods.append(CROWLLOUVAR)
return methods
[docs]@mark_numba_incompatible
def UFL(Hc=None, atoms=None, CASRN='', method=None):
r'''This function handles the retrieval or calculation of a chemical's
Upper Flammability Limit. Lookup is based on CASRNs. Two predictive methods
are currently implemented. Will automatically select a data source to use
if no Method is provided; returns None if the data is not available.
Examples
--------
>>> UFL(CASRN='71-43-2')
0.086
Methane
>>> UFL(Hc=-890590.0, atoms={'C': 1, 'H': 4}, CASRN='74-82-8')
0.17
>>> UFL(CASRN='111-69-3', method='WIKIDATA')
0.05
Parameters
----------
Hc : float, optional
Heat of combustion of gas [J/mol]
atoms : dict, optional
Dictionary of atoms and atom counts
CASRN : str, optional
CASRN [-]
Returns
-------
UFL : float
Upper flammability limit of the gas in an atmosphere at STP, [mole fraction]
Other Parameters
----------------
method : string, optional
A string for the method name to use, as defined in the variable,
`UFL_all_methods`.
Notes
-----
Preferred source is 'IEC 60079-20-1 (2010)' [1]_, with the secondary source
'NFPA 497 (2008)' [2]_ having very similar data. If the heat of combustion
is provided, the estimation method :obj:`Suzuki_UFL` can be used. If the atoms
of the molecule are available, the method :obj:`Crowl_Louvar_UFL` can be used.
References
----------
.. [1] IEC. “IEC 60079-20-1:2010 Explosive atmospheres - Part 20-1:
Material characteristics for gas and vapour classification - Test
methods and data.” https://webstore.iec.ch/publication/635. See also
https://law.resource.org/pub/in/bis/S05/is.iec.60079.20.1.2010.pdf
.. [2] National Fire Protection Association. NFPA 497: Recommended
Practice for the Classification of Flammable Liquids, Gases, or Vapors
and of Hazardous. NFPA, 2008.
.. [3] Wikidata. Wikidata. Accessed via API. https://www.wikidata.org/
'''
if dr.USE_CONSTANTS_DATABASE and method is None:
val, found = database_constant_lookup(CASRN, 'UFL')
if found: return val
if not _safety_data_loaded: _load_safety_data()
if not method:
UFL = retrieve_any_from_df_dict(UFL_sources, CASRN, 'UFL')
if not UFL:
if Hc is not None: UFL = Suzuki_UFL(Hc)
elif atoms is not None: UFL = Crowl_Louvar_UFL(atoms)
return UFL
elif method == SUZUKI:
return Suzuki_UFL(Hc)
elif method == CROWLLOUVAR:
return Crowl_Louvar_UFL(atoms)
else:
return retrieve_from_df_dict(UFL_sources, CASRN, 'UFL', method)
ISO_10156_2017_Kks = {
'7782-44-7': 1.0, # O2,
'7727-37-9': 1.0, # N2
'124-38-9': 1.5, # CO2
'7440-59-7': 0.9, # He
'7440-37-1': 0.55, # Ar
'7440-01-9': 0.7, # Ne
'7439-90-9': 0.5, # Kr
'7440-63-3': 0.5, # Xe
'7446-09-5': 1.5, # SO2
'2551-62-4': 4.0, # SF6
'75-73-0': 2.0, # CF4
'76-19-7': 1.5, # C3F8
'354-33-6': 3.5, # C2HF5
}
[docs]@mark_numba_incompatible
def LFL_ISO_10156_2017(zs, LFLs, CASs):
r'''Calculate the lower flammability limit of a mixture of combustible gases
and inert gases according to ISO 10156 (2017) [1]_.
.. math::
\text{LFL} = \frac{1}{\sum_{i=1}^{n_{combustible}}\frac{A_i}{\text{LFL}_i'}}
.. math::
\text{LFL}_i' = \frac{1 - \text{LFL}_m' - (1 - K)
\frac{\sum_j^{n_{inert}} B_j}{\sum_j^{n_{combustible}} A_j} \text{LFL}_m'
}
{100 - \text{LFL}_m'}\text{LFL}_i
.. math::
K = \sum_i^{n_{inert}} z_i K_k
The `B` sum is the total mole fraction of all inert gas compounds;
and the `A` sum is the total mole fraction of all combustible compounds.
:math:`K_k` are the looked up inert gas coefficients.
:math:`\text{LFL}_m'` is calculated as the Le Chatelier's lower
flammability limit if there were no inert gases in the mixture.
Parameters
----------
zs : list[float]
Mole fractions of all components in a gas including inerts, [-]
LFLs : list[float]
Lower or upper flammability limits for each flammable component in a
gas, [-]
CASs : list[str]
CAS numbers of each compound; required to look up inert gas factors, [-]
Returns
-------
LFL : float
Lower or flammability limit of a gas mixture, [-]
Notes
-----
Inert gas parameters are available for O2, N2, CO2, He, Ar, Ne, Kr, Xe,
SO2, SF6, CF4, C3F8, and C2HF5.
Examples
--------
All the sample problems from [1]_ have been implemented as tests.
>>> zs = [.15, .15, .3, .35+.05*.79, .05*.21]
>>> LFLs = [.04, .044, None, None, None]
>>> CASs = ['1333-74-0', '74-82-8', '124-38-9', '7727-37-9', '7782-44-7']
>>> LFL_ISO_10156_2017(zs, LFLs, CASs)
0.1427372274
References
----------
.. [1] Standardization, International Organization for. ISO 10156: 2017 :
Gas Cylinders - Gases and Gas Mixtures - Determination of Fire Potential
and Oxidizing Ability for the Selection of Cylinder Valve Outlets, 2017.
'''
N = len(zs)
has_inerts = False
for CAS in CASs:
if CAS in ISO_10156_2017_Kks:
has_inerts = True
break
if has_inerts:
combustible_idxs = []
combustible_zs = []
for i, CAS in enumerate(CASs):
# Combustible
if CAS not in ISO_10156_2017_Kks:
combustible_idxs.append(i)
combustible_zs.append(zs[i])
combustible_zs_norm = normalize(combustible_zs)
Lm_prime = 0.0
for idx, zi in zip(combustible_idxs, combustible_zs_norm):
Lm_prime += zi/LFLs[idx]
Lm_prime = 1.0/Lm_prime
combustible_frac = sum(combustible_zs)
inert_frac = 1.0 - combustible_frac
K = 0.0
for i, CAS in enumerate(CASs):
if CAS in ISO_10156_2017_Kks:
K += ISO_10156_2017_Kks[CAS]*zs[i]
K /= inert_frac
factor = ((1.0 - Lm_prime - (1.0 - K)*inert_frac/combustible_frac*Lm_prime)
/(1.0 - Lm_prime))
Lm = 0.0
for idx, zi in zip(combustible_idxs, combustible_zs):
Lm += zi/(factor*LFLs[idx])
Lm = 1.0/Lm
return Lm
tot = 0.0
for i in range(len(zs)):
tot += zs[i]/LFLs[i]
return 1.0/tot
[docs]def fire_mixing(ys, FLs):
'''Le Chatelier's mixing rule for lower and upper flammability limits of
mixtures of gases.
Parameters
----------
ys : list[float]
Normalized mole fractions of all flammable components in a gas, [-]
FLs : list[float]
Lower or upper flammability limits for each flammable component in a
gas, [-]
Returns
-------
FL : float
Lower or upper flammability limit of a gas, [-]
Notes
-----
This equation has a higher accuracy for lower flammability limits than
upper flammability limits. Some sources recommend not using it for
upper flammability limits.
Examples
--------
Sample problems from [1]_ for the lower and upper flammability limit.
>>> fire_mixing(ys=normalize([0.0024, 0.0061, 0.0015]), FLs=[.012, .053, .031])
0.02751172136637642
>>> fire_mixing(ys=normalize([0.0024, 0.0061, 0.0015]), FLs=[.075, .15, .32])
0.12927551844869378
References
----------
.. [1] Crowl, Daniel A., and Joseph F. Louvar. Chemical Process Safety:
Fundamentals with Applications. 2E. Upper Saddle River, N.J: Prentice
Hall, 2001.
'''
tot = 0.0
for i in range(len(ys)):
tot += ys[i]/FLs[i]
return 1.0/tot
[docs]def Suzuki_LFL(Hc):
r'''Calculates lower flammability limit, using the Suzuki [1]_ correlation.
Uses heat of combustion only.
The lower flammability limit of a gas is air is:
.. math::
\text{LFL} = \frac{-3.42}{\Delta H_c^{\circ}} + 0.569
.. math::
\Delta H_c^{\circ} + 0.0538\Delta H_c^{\circ 2} + 1.80
Parameters
----------
Hc : float
Heat of combustion of gas [J/mol]
Returns
-------
LFL : float
Lower flammability limit, mole fraction [-]
Notes
-----
Fit performed with 112 compounds, r^2 was 0.977.
LFL in percent volume in air. Hc is at standard conditions, in MJ/mol.
11 compounds left out as they were outliers.
Equation does not apply for molecules with halogen atoms, only hydrocarbons
with oxygen or nitrogen or sulfur.
No sample calculation provided with the article. However, the equation is
straightforward.
Limits of equations's validity are -6135596 J where it predicts a
LFL of 0, and -48322129 J where it predicts a LFL of 1.
Examples
--------
Pentane, 1.5 % LFL in literature
>>> Suzuki_LFL(-3536600)
0.014276107095811815
References
----------
.. [1] Suzuki, Takahiro. "Note: Empirical Relationship between Lower
Flammability Limits and Standard Enthalpies of Combustion of Organic
Compounds." Fire and Materials 18, no. 5 (September 1, 1994): 333-36.
doi:10.1002/fam.810180509.
'''
Hc = Hc/1E6
LFL = -3.42/Hc + 0.569*Hc + 0.0538*Hc*Hc + 1.80
return LFL/100.
[docs]def Suzuki_UFL(Hc):
r'''Calculates upper flammability limit, using the Suzuki [1]_ correlation.
Uses heat of combustion only.
The upper flammability limit of a gas is air is:
.. math::
\text{UFL} = 6.3\Delta H_c^\circ + 0.567\Delta H_c^{\circ 2} + 23.5
Parameters
----------
Hc : float
Heat of combustion of gas [J/mol]
Returns
-------
UFL : float
Upper flammability limit, mole fraction
Notes
-----
UFL in percent volume in air according to original equation.
Hc is at standard conditions in the equation, in units of MJ/mol.
AAPD = 1.2% for 95 compounds used in fit.
Somewhat better results than the High and Danner method.
4.9% < UFL < 23.0%
-890.3 kJ/mol < dHc < -6380 kJ/mol
r^2 = 0.989
Sample calculations provided for all chemicals, both this method and
High and Danner. Examples are from the article.
Predicts a UFL of 1 at 7320190 J and a UFL of 0 at -5554160 J.
Examples
--------
Pentane, literature 7.8% UFL
>>> Suzuki_UFL(-3536600)
0.0831119493052
References
----------
.. [1] Suzuki, Takahiro, and Kozo Koide. "Short Communication: Correlation
between Upper Flammability Limits and Thermochemical Properties of
Organic Compounds." Fire and Materials 18, no. 6 (November 1, 1994):
393-97. doi:10.1002/fam.810180608.
'''
Hc = Hc/1E6
UFL = 6.3*Hc + 0.567*Hc*Hc + 23.5
return UFL/100.
[docs]@mark_numba_incompatible
def Crowl_Louvar_LFL(atoms):
r'''Calculates lower flammability limit, using the Crowl-Louvar [1]_
correlation. Uses molecular formula only.
The lower flammability limit of a gas is air is:
.. math::
C_mH_xO_y + zO_2 \to mCO_2 + \frac{x}{2}H_2O
.. math::
\text{LFL} = \frac{0.55}{4.76m + 1.19x - 2.38y + 1}
Parameters
----------
atoms : dict
Dictionary of atoms and atom counts
Returns
-------
LFL : float
Lower flammability limit, mole fraction
Notes
-----
Coefficient of 0.55 taken from [2]_
Examples
--------
Hexane, example from [1]_, lit. 1.2 %
>>> Crowl_Louvar_LFL({'H': 14, 'C': 6})
0.011899610558199915
References
----------
.. [1] Crowl, Daniel A., and Joseph F. Louvar. Chemical Process Safety:
Fundamentals with Applications. 2E. Upper Saddle River, N.J:
Prentice Hall, 2001.
.. [2] Jones, G. W. "Inflammation Limits and Their Practical Application
in Hazardous Industrial Operations." Chemical Reviews 22, no. 1
(February 1, 1938): 1-26. doi:10.1021/cr60071a001
'''
nC, nH, nO = 0, 0, 0
if atoms.get('C'):
nC = atoms['C']
else:
return None
if 'H' in atoms:
nH = atoms['H']
if 'O' in atoms:
nO = atoms['O']
return 0.55/(4.76*nC + 1.19*nH - 2.38*nO + 1.)
[docs]@mark_numba_incompatible
def Crowl_Louvar_UFL(atoms):
r'''Calculates upper flammability limit, using the Crowl-Louvar [1]_
correlation. Uses molecular formula only.
The upper flammability limit of a gas is air is:
.. math::
C_mH_xO_y + zO_2 \to mCO_2 + \frac{x}{2}H_2O
.. math::
\text{UFL} = \frac{3.5}{4.76m + 1.19x - 2.38y + 1}
Parameters
----------
atoms : dict
Dictionary of atoms and atom counts
Returns
-------
UFL : float
Upper flammability limit, mole fraction
Notes
-----
Coefficient of 3.5 taken from [2]_
Examples
--------
Hexane, example from [1]_, lit. 7.5 %
>>> Crowl_Louvar_UFL({'H': 14, 'C': 6})
0.07572479446127219
References
----------
.. [1] Crowl, Daniel A., and Joseph F. Louvar. Chemical Process Safety:
Fundamentals with Applications. 2E. Upper Saddle River, N.J:
Prentice Hall, 2001.
.. [2] Jones, G. W. "Inflammation Limits and Their Practical Application
in Hazardous Industrial Operations." Chemical Reviews 22, no. 1
(February 1, 1938): 1-26. doi:10.1021/cr60071a001
'''
nC, nH, nO = 0, 0, 0
if atoms.get('C'):
nC = atoms['C']
else:
return None
if 'H' in atoms:
nH = atoms['H']
if 'O' in atoms:
nO = atoms['O']
return 3.5/(4.76*nC + 1.19*nH - 2.38*nO + 1.)
[docs]def NFPA_30_classification(T_flash, Tb=None, Psat_100F=None):
r'''Classify a chemical's flammability/combustibility according
to the NFPA 30 standard Flammable and Combustible Liquids Code.
Class IA: Flash Point < 73°F; Boiling Point < 100°F
Class IB: Flash Point < 73°F; 100°F <= Boiling Point
Class IC: 73°F <= Flash Point < 100°F
Class II: 100°F <= Flash Point < 140°F
Class IIIA: 140°F <= Flash Point < 200°F
Class IIIB: 200°F <= Flash Point
Class I liquids are designated as flammable; class II and II
liquids are designated as combustible.
Parameters
----------
T_flash : float
Flash point (closed-cup method, adjusted for sea level), [K]
Tb : float, optional
Normal boiling point (needed to classify IA and IB liquids), [K]
Psat_100F : float, optional
Vapor pressure at 100°F (needed to classify IA and IB liquids), [K]
Returns
-------
classification : str
One of 'IA', 'IB', 'IC', 'II', 'IIIA', 'IIIB', [-]
Notes
-----
Only one of `Tb` or `Psat_100F` is needed.
Class 'IA' also includes unstable liquids.
Examples
--------
Ethylene oxide
>>> NFPA_30_classification(253.15, 283.55)
'IA'
Butyl alcohol
>>> NFPA_30_classification(308.15)
'IC'
References
----------
.. [1] NFPA (National Fire Prevention Association). NFPA 30: Flammable and
Combustible Liquids Code, 2008. National Fire Protection Association
(NFPA), 2007.
'''
F_100 = 310.92777777777777
F_73 = 295.92777777777775
F_140 = 333.15
F_200 = 366.4833333333333
Tb_above_100F = False # For numba only
if Tb is not None:
Tb_above_100F = Tb >= F_100
elif Psat_100F is not None:
Tb_above_100F = Psat_100F < 101325.0
elif T_flash < F_73:
raise ValueError("Tb or Psat_100F is required to classify the provided inputs")
if T_flash < F_100:
if T_flash < F_73 and not Tb_above_100F:
# Also unstable flammable liquids
# ethylene oxide, methyl chloride, pentane should go here
return 'IA'
elif T_flash < F_73 and Tb_above_100F:
# acetone, benzene, ethyl alcohol, and isopropyl alcohol.
return 'IB'
elif F_73 <= T_flash < F_100:
# butyl alcohol, diethyl glycol, styrene, and turpentine.
return 'IC'
if F_100 <= T_flash < F_140:
return 'II'
if F_140 <= T_flash < F_200:
return 'IIIA'
if F_200 <= T_flash:
return 'IIIB'