def get_settings(self):
        """Returns the settings of the index."""
        try:
            logger.info('GET SETTINGS ON %s', self.index_name)
            return self.__index.get_settings()
        except AlgoliaException as e:
            if DEBUG:
                raise e
            else:
                logger.warning('ERROR DURING GET_SETTINGS ON %s: %s',
                               self.model, e)

def
get_settings
(
self
)
:
try
:
logger
.
info
(
'GET SETTINGS ON %s'
,
self
.
index_name
)
return
self
.
__index
.
get_settings
(
)
except
AlgoliaException
as
e
:
if
DEBUG
:
raise
e
else
:
logger
.
warning
(
'ERROR DURING GET_SETTINGS ON %s: %s'
,
self
.
model
,
e
)


def set_settings(self):
        """Applies the settings to the index."""
        if not self.settings:
            return

        try:
            self.__index.set_settings(self.settings)
            logger.info('APPLY SETTINGS ON %s', self.index_name)
        except AlgoliaException as e:
            if DEBUG:
                raise e
            else:
                logger.warning('SETTINGS NOT APPLIED ON %s: %s',
                               self.model, e)

def
set_settings
(
self
)
:
if
not
self
.
settings
:
return
try
:
self
.
__index
.
set_settings
(
self
.
settings
)
logger
.
info
(
'APPLY SETTINGS ON %s'
,
self
.
index_name
)
except
AlgoliaException
as
e
:
if
DEBUG
:
raise
e
else
:
logger
.
warning
(
'SETTINGS NOT APPLIED ON %s: %s'
,
self
.
model
,
e
)


def register(self, model, index_cls=AlgoliaIndex, auto_indexing=None):
        """
        Registers the given model with Algolia engine.

        If the given model is already registered with Algolia engine, a
        RegistrationError will be raised.
        """
        # Check for existing registration.
        if self.is_registered(model):
            raise RegistrationError(
                '{} is already registered with Algolia engine'.format(model))

        # Perform the registration.
        if not issubclass(index_cls, AlgoliaIndex):
            raise RegistrationError(
                '{} should be a subclass of AlgoliaIndex'.format(index_cls))
        index_obj = index_cls(model, self.client, self.__settings)
        self.__registered_models[model] = index_obj

        if (isinstance(auto_indexing, bool) and
                auto_indexing) or self.__auto_indexing:
            # Connect to the signalling framework.
            post_save.connect(self.__post_save_receiver, model)
            pre_delete.connect(self.__pre_delete_receiver, model)
            logger.info('REGISTER %s', model)

Registers the given model with Algolia engine .


def unregister(self, model):
        """
        Unregisters the given model with Algolia engine.

        If the given model is not registered with Algolia engine, a
        RegistrationError will be raised.
        """
        if not self.is_registered(model):
            raise RegistrationError(
                '{} is not registered with Algolia engine'.format(model))
        # Perform the unregistration.
        del self.__registered_models[model]

        # Disconnect from the signalling framework.
        post_save.disconnect(self.__post_save_receiver, model)
        pre_delete.disconnect(self.__pre_delete_receiver, model)
        logger.info('UNREGISTER %s', model)

Unregisters the given model with Algolia engine .


def get_adapter(self, model):
        """Returns the adapter associated with the given model."""
        if not self.is_registered(model):
            raise RegistrationError(
                '{} is not registered with Algolia engine'.format(model))

        return self.__registered_models[model]

Returns the adapter associated with the given model .


def __post_save_receiver(self, instance, **kwargs):
        """Signal handler for when a registered model has been saved."""
        logger.debug('RECEIVE post_save FOR %s', instance.__class__)
        self.save_record(instance, **kwargs)

def
__post_save_receiver
(
self
,
instance
,
**
kwargs
)
:
logger
.
debug
(
'RECEIVE post_save FOR %s'
,
instance
.
__class__
)
self
.
save_record
(
instance
,
**
kwargs
)

Signal handler for when a registered model has been saved .


def __pre_delete_receiver(self, instance, **kwargs):
        """Signal handler for when a registered model has been deleted."""
        logger.debug('RECEIVE pre_delete FOR %s', instance.__class__)
        self.delete_record(instance)

def
__pre_delete_receiver
(
self
,
instance
,
**
kwargs
)
:
logger
.
debug
(
'RECEIVE pre_delete FOR %s'
,
instance
.
__class__
)
self
.
delete_record
(
instance
)

Signal handler for when a registered model has been deleted .


def decode(geohash):
    """
    Decode geohash, returning two strings with latitude and longitude
    containing only relevant digits and with trailing zeroes removed.
    """
    lat, lon, lat_err, lon_err = decode_exactly(geohash)
    # Format to the number of decimals that are known
    lats = "%.*f" % (max(1, int(round(-log10(lat_err)))) - 1, lat)
    lons = "%.*f" % (max(1, int(round(-log10(lon_err)))) - 1, lon)
    if '.' in lats: lats = lats.rstrip('0')
    if '.' in lons: lons = lons.rstrip('0')
    return lats, lons

def decode ( geohash ) : lat , lon , lat_err , lon_err = decode_exactly ( geohash ) lats = "%.*f" % ( max ( 1 , int ( round ( - log10 ( lat_err ) ) ) ) - 1 , lat ) lons = "%.*f" % ( max ( 1 , int ( round ( - log10 ( lon_err ) ) ) ) - 1 , lon ) if '.' in lats : lats = lats . rstrip ( '0' ) if '.' in lons : lons = lons . rstrip ( '0' ) return lats , lons

Decode geohash returning two strings with latitude and longitude containing only relevant digits and with trailing zeroes removed .


def encode(latitude, longitude, precision=12):
    """
    Encode a position given in float arguments latitude, longitude to
    a geohash which will have the character count precision.
    """
    lat_interval, lon_interval = (-90.0, 90.0), (-180.0, 180.0)
    geohash = []
    bits = [ 16, 8, 4, 2, 1 ]
    bit = 0
    ch = 0
    even = True
    while len(geohash) < precision:
        if even:
            mid = (lon_interval[0] + lon_interval[1]) / 2
            if longitude > mid:
                ch |= bits[bit]
                lon_interval = (mid, lon_interval[1])
            else:
                lon_interval = (lon_interval[0], mid)
        else:
            mid = (lat_interval[0] + lat_interval[1]) / 2
            if latitude > mid:
                ch |= bits[bit]
                lat_interval = (mid, lat_interval[1])
            else:
                lat_interval = (lat_interval[0], mid)
        even = not even
        if bit < 4:
            bit += 1
        else:
            geohash += __base32[ch]
            bit = 0
            ch = 0
    return ''.join(geohash)

def encode ( latitude , longitude , precision = 12 ) : lat_interval , lon_interval = ( - 90.0 , 90.0 ) , ( - 180.0 , 180.0 ) geohash = [ ] bits = [ 16 , 8 , 4 , 2 , 1 ] bit = 0 ch = 0 even = True while len ( geohash ) < precision : if even : mid = ( lon_interval [ 0 ] + lon_interval [ 1 ] ) / 2 if longitude > mid : ch |= bits [ bit ] lon_interval = ( mid , lon_interval [ 1 ] ) else : lon_interval = ( lon_interval [ 0 ] , mid ) else : mid = ( lat_interval [ 0 ] + lat_interval [ 1 ] ) / 2 if latitude > mid : ch |= bits [ bit ] lat_interval = ( mid , lat_interval [ 1 ] ) else : lat_interval = ( lat_interval [ 0 ] , mid ) even = not even if bit < 4 : bit += 1 else : geohash += __base32 [ ch ] bit = 0 ch = 0 return '' . join ( geohash )

Encode a position given in float arguments latitude longitude to a geohash which will have the character count precision .


def pad_to(unpadded, target_len):
    """
    Pad a string to the target length in characters, or return the original
    string if it's longer than the target length.
    """
    under = target_len - len(unpadded)
    if under <= 0:
        return unpadded
    return unpadded + (' ' * under)

def
pad_to
(
unpadded
,
target_len
)
:
under
=
target_len
len
(
unpadded
)
if
under
<=
0
:
return
unpadded
return
unpadded
+
(
' '
*
under
)

Pad a string to the target length in characters or return the original string if it s longer than the target length .


def normalize_cols(table):
    """
    Pad short rows to the length of the longest row to help render "jagged"
    CSV files
    """
    longest_row_len = max([len(row) for row in table])
    for row in table:
        while len(row) < longest_row_len:
            row.append('')
    return table

def normalize_cols ( table ) : longest_row_len = max ( [ len ( row ) for row in table ] ) for row in table : while len ( row ) < longest_row_len : row . append ( '' ) return table

Pad short rows to the length of the longest row to help render jagged CSV files


def pad_cells(table):
    """Pad each cell to the size of the largest cell in its column."""
    col_sizes = [max(map(len, col)) for col in zip(*table)]
    for row in table:
        for cell_num, cell in enumerate(row):
            row[cell_num] = pad_to(cell, col_sizes[cell_num])
    return table

def pad_cells ( table ) : col_sizes = [ max ( map ( len , col ) ) for col in zip ( * table ) ] for row in table : for cell_num , cell in enumerate ( row ) : row [ cell_num ] = pad_to ( cell , col_sizes [ cell_num ] ) return table

Pad each cell to the size of the largest cell in its column .


def horiz_div(col_widths, horiz, vert, padding):
    """
    Create the column dividers for a table with given column widths.

    col_widths: list of column widths
    horiz: the character to use for a horizontal divider
    vert: the character to use for a vertical divider
    padding: amount of padding to add to each side of a column
    """
    horizs = [horiz * w for w in col_widths]
    div = ''.join([padding * horiz, vert, padding * horiz])
    return div.join(horizs)

def horiz_div ( col_widths , horiz , vert , padding ) : horizs = [ horiz * w for w in col_widths ] div = '' . join ( [ padding * horiz , vert , padding * horiz ] ) return div . join ( horizs )

Create the column dividers for a table with given column widths .


def add_dividers(row, divider, padding):
    """Add dividers and padding to a row of cells and return a string."""
    div = ''.join([padding * ' ', divider, padding * ' '])
    return div.join(row)

def
add_dividers
(
row
,
divider
,
padding
)
:
div
=
''
.
join
(
[
padding
*
' '
,
divider
,
padding
*
' '
]
)
return
div
.
join
(
row
)

Add dividers and padding to a row of cells and return a string .


def md_table(table, *, padding=DEFAULT_PADDING, divider='|', header_div='-'):
    """
    Convert a 2D array of items into a Markdown table.

    padding: the number of padding spaces on either side of each divider
    divider: the vertical divider to place between columns
    header_div: the horizontal divider to place between the header row and
        body cells
    """
    table = normalize_cols(table)
    table = pad_cells(table)
    header = table[0]
    body = table[1:]

    col_widths = [len(cell) for cell in header]
    horiz = horiz_div(col_widths, header_div, divider, padding)

    header = add_dividers(header, divider, padding)
    body = [add_dividers(row, divider, padding) for row in body]

    table = [header, horiz]
    table.extend(body)
    table = [row.rstrip() for row in table]
    return '\n'.join(table)

def md_table ( table , * , padding = DEFAULT_PADDING , divider = '|' , header_div = '-' ) : table = normalize_cols ( table ) table = pad_cells ( table ) header = table [ 0 ] body = table [ 1 : ] col_widths = [ len ( cell ) for cell in header ] horiz = horiz_div ( col_widths , header_div , divider , padding ) header = add_dividers ( header , divider , padding ) body = [ add_dividers ( row , divider , padding ) for row in body ] table = [ header , horiz ] table . extend ( body ) table = [ row . rstrip ( ) for row in table ] return '\n' . join ( table )

Convert a 2D array of items into a Markdown table .


def baseId(resource_id, return_version=False):
    """Calculate base id and version from a resource id.

    :params resource_id: Resource id.
    :params return_version: (optional) True if You need version, returns (resource_id, version).
    """
    version = 0
    resource_id = resource_id + 0xC4000000  # 3288334336
    # TODO: version is broken due ^^, needs refactoring

    while resource_id > 0x01000000:  # 16777216
        version += 1
        if version == 1:
            resource_id -= 0x80000000  # 2147483648  # 0x50000000  # 1342177280 ?  || 0x2000000  # 33554432
        elif version == 2:
            resource_id -= 0x03000000  # 50331648
        else:
            resource_id -= 0x01000000  # 16777216

    if return_version:
        return resource_id, version - 67  # just correct "magic number"

    return resource_id

Calculate base id and version from a resource id .


def cardInfo(self, resource_id):
        """Return card info.

        :params resource_id: Resource id.
        """
        # TODO: add referer to headers (futweb)
        base_id = baseId(resource_id)
        if base_id in self.players:
            return self.players[base_id]
        else:  # not a player?
            url = '{0}{1}.json'.format(card_info_url, base_id)
            return requests.get(url, timeout=self.timeout).json()

def cardInfo ( self , resource_id ) : base_id = baseId ( resource_id ) if base_id in self . players : return self . players [ base_id ] else : url = '{0}{1}.json' . format ( card_info_url , base_id ) return requests . get ( url , timeout = self . timeout ) . json ( )


def search(self, ctype, level=None, category=None, assetId=None, defId=None,
               min_price=None, max_price=None, min_buy=None, max_buy=None,
               league=None, club=None, position=None, zone=None, nationality=None,
               rare=False, playStyle=None, start=0, page_size=itemsPerPage['transferMarket'],
               fast=False):
        """Prepare search request, send and return parsed data as a dict.

        :param ctype: [development / ? / ?] Card type.
        :param level: (optional) [?/?/gold] Card level.
        :param category: (optional) [fitness/?/?] Card category.
        :param assetId: (optional) Asset id.
        :param defId: (optional) Definition id.
        :param min_price: (optional) Minimal price.
        :param max_price: (optional) Maximum price.
        :param min_buy: (optional) Minimal buy now price.
        :param max_buy: (optional) Maximum buy now price.
        :param league: (optional) League id.
        :param club: (optional) Club id.
        :param position: (optional) Position.
        :param nationality: (optional) Nation id.
        :param rare: (optional) [boolean] True for searching special cards.
        :param playStyle: (optional) Play style.
        :param start: (optional) Start page sent to server so it supposed to be 12/15, 24/30 etc. (default platform page_size*n)
        :param page_size: (optional) Page size (items per page).
        """
        # TODO: add "search" alias
        # TODO: generator
        method = 'GET'
        url = 'transfermarket'

        # pinEvents
        if start == 0:
            events = [self.pin.event('page_view', 'Hub - Transfers'), self.pin.event('page_view', 'Transfer Market Search')]
            self.pin.send(events, fast=fast)

        params = {
            'start': start,
            'num': page_size,
            'type': ctype,  # "type" namespace is reserved in python
        }
        if level:
            params['lev'] = level
        if category:
            params['cat'] = category
        if assetId:
            params['maskedDefId'] = assetId
        if defId:
            params['definitionId'] = defId
        if min_price:
            params['micr'] = min_price
        if max_price:
            params['macr'] = max_price
        if min_buy:
            params['minb'] = min_buy
        if max_buy:
            params['maxb'] = max_buy
        if league:
            params['leag'] = league
        if club:
            params['team'] = club
        if position:
            params['pos'] = position
        if zone:
            params['zone'] = zone
        if nationality:
            params['nat'] = nationality
        if rare:
            params['rare'] = 'SP'
        if playStyle:
            params['playStyle'] = playStyle

        rc = self.__request__(method, url, params=params, fast=fast)

        # pinEvents
        if start == 0:
            events = [self.pin.event('page_view', 'Transfer Market Results - List View'), self.pin.event('page_view', 'Item - Detail View')]
            self.pin.send(events, fast=fast)

        return [itemParse(i) for i in rc.get('auctionInfo', ())]

def
search
(
self
,
ctype
,
level
=
,
category
=
,
assetId
=
,
defId
=
,
min_price
=
,
max_price
=
,
min_buy
=
,
max_buy
=
,
league
=
,
club
=
,
position
=
,
zone
=
,
nationality
=
,
rare
=
False
,
playStyle
=
,
start
=
0
,
page_size
=
itemsPerPage
[
'transferMarket'
]
,
fast
=
False
)
:
method
=
'GET'
url
=
'transfermarket'
if
start
==
0
:
events
=
[
self
.
pin
.
event
(
'page_view'
,
'Hub - Transfers'
)
,
self
.
pin
.
event
(
'page_view'
,
'Transfer Market Search'
)
]
self
.
pin
.
send
(
events
,
fast
=
fast
)
params
=
{
'start'
:
start
,
'num'
:
page_size
,
'type'
:
ctype
,
}
if
level
:
params
[
'lev'
]
=
level
if
category
:
params
[
'cat'
]
=
category
if
assetId
:
params
[
'maskedDefId'
]
=
assetId
if
defId
:
params
[
'definitionId'
]
=
defId
if
min_price
:
params
[
'micr'
]
=
min_price
if
max_price
:
params
[
'macr'
]
=
max_price
if
min_buy
:
params
[
'minb'
]
=
min_buy
if
max_buy
:
params
[
'maxb'
]
=
max_buy
if
league
:
params
[
'leag'
]
=
league
if
club
:
params
[
'team'
]
=
club
if
position
:
params
[
'pos'
]
=
position
if
zone
:
params
[
'zone'
]
=
zone
if
nationality
:
params
[
'nat'
]
=
nationality
if
rare
:
params
[
'rare'
]
=
'SP'
if
playStyle
:
params
[
'playStyle'
]
=
playStyle
rc
=
self
.
__request__
(
method
,
url
,
params
=
params
,
fast
=
fast
)
if
start
==
0
:
events
=
[
self
.
pin
.
event
(
'page_view'
,
'Transfer Market Results - List View'
)
,
self
.
pin
.
event
(
'page_view'
,
'Item - Detail View'
)
]
self
.
pin
.
send
(
events
,
fast
=
fast
)
return
[
itemParse
(
i
)
for
i
in
rc
.
get
(
'auctionInfo'
,
(
)
)
]

Prepare search request send and return parsed data as a dict .


def bid(self, trade_id, bid, fast=False):
        """Make a bid.

        :params trade_id: Trade id.
        :params bid: Amount of credits You want to spend.
        :params fast: True for fastest bidding (skips trade status & credits check).
        """
        method = 'PUT'
        url = 'trade/%s/bid' % trade_id

        if not fast:
            rc = self.tradeStatus(trade_id)[0]
            # don't bid if current bid is equal or greater than our max bid
            if rc['currentBid'] >= bid or self.credits < bid:
                return False  # TODO: add exceptions
        data = {'bid': bid}
        try:
            rc = self.__request__(method, url, data=json.dumps(data), params={'sku_b': self.sku_b}, fast=fast)[
                'auctionInfo'][0]
        except PermissionDenied:  # too slow, somebody took it already :-(
            return False
        if rc['bidState'] == 'highest' or (
                rc['tradeState'] == 'closed' and rc['bidState'] == 'buyNow'):  # checking 'tradeState' is required?
            return True
        else:
            return False

def bid ( self , trade_id , bid , fast = False ) : method = 'PUT' url = 'trade/%s/bid' % trade_id if not fast : rc = self . tradeStatus ( trade_id ) [ 0 ] if rc [ 'currentBid' ] >= bid or self . credits < bid : return False data = { 'bid' : bid } try : rc = self . __request__ ( method , url , data = json . dumps ( data ) , params = { 'sku_b' : self . sku_b } , fast = fast ) [ 'auctionInfo' ] [ 0 ] except PermissionDenied : return False if rc [ 'bidState' ] == 'highest' or ( rc [ 'tradeState' ] == 'closed' and rc [ 'bidState' ] == 'buyNow' ) : return True else : return False


def club(self, sort='desc', ctype='player', defId='', start=0, count=None, page_size=itemsPerPage['club'],
             level=None, category=None, assetId=None, league=None, club=None,
             position=None, zone=None, nationality=None, rare=False, playStyle=None):
        """Return items in your club, excluding consumables.

        :param ctype: [development / ? / ?] Card type.
        :param level: (optional) [?/?/gold] Card level.
        :param category: (optional) [fitness/?/?] Card category.
        :param assetId: (optional) Asset id.
        :param defId: (optional) Definition id.
        :param min_price: (optional) Minimal price.
        :param max_price: (optional) Maximum price.
        :param min_buy: (optional) Minimal buy now price.
        :param max_buy: (optional) Maximum buy now price.
        :param league: (optional) League id.
        :param club: (optional) Club id.
        :param position: (optional) Position.
        :param nationality: (optional) Nation id.
        :param rare: (optional) [boolean] True for searching special cards.
        :param playStyle: (optional) Play style.
        :param start: (optional) Start page sent to server so it supposed to be 12/15, 24/30 etc. (default platform page_size*n)
        :param page_size: (optional) Page size (items per page)
        """
        method = 'GET'
        url = 'club'

        if count:  # backward compatibility, will be removed in future
            page_size = count

        params = {'sort': sort, 'type': ctype, 'defId': defId, 'start': start, 'count': page_size}
        if level:
            params['level'] = level
        if category:
            params['cat'] = category
        if assetId:
            params['maskedDefId'] = assetId
        if league:
            params['leag'] = league
        if club:
            params['team'] = club
        if position:
            params['pos'] = position
        if zone:
            params['zone'] = zone
        if nationality:
            params['nat'] = nationality
        if rare:
            params['rare'] = 'SP'
        if playStyle:
            params['playStyle'] = playStyle
        rc = self.__request__(method, url, params=params)

        # pinEvent
        if start == 0:
            if ctype == 'player':
                pgid = 'Club - Players - List View'
            elif ctype == 'staff':
                pgid = 'Club - Staff - List View'
            elif ctype in ('item', 'kit', 'ball', 'badge', 'stadium'):
                pgid = 'Club - Club Items - List View'
            # else:  # TODO: THIS IS probably WRONG, detect all ctypes
            #     pgid = 'Club - Club Items - List View'
            events = [self.pin.event('page_view', 'Hub - Club'), self.pin.event('page_view', pgid)]
            if rc['itemData']:
                events.append(self.pin.event('page_view', 'Item - Detail View'))
            self.pin.send(events)

        return [itemParse({'itemData': i}) for i in rc['itemData']]

def
club
(
self
,
sort
=
'desc'
,
ctype
=
'player'
,
defId
=
''
,
start
=
0
,
count
=
,
page_size
=
itemsPerPage
[
'club'
]
,
level
=
,
category
=
,
assetId
=
,
league
=
,
club
=
,
position
=
,
zone
=
,
nationality
=
,
rare
=
False
,
playStyle
=
)
:
method
=
'GET'
url
=
'club'
if
count
:
page_size
=
count
params
=
{
'sort'
:
sort
,
'type'
:
ctype
,
'defId'
:
defId
,
'start'
:
start
,
'count'
:
page_size
}
if
level
:
params
[
'level'
]
=
level
if
category
:
params
[
'cat'
]
=
category
if
assetId
:
params
[
'maskedDefId'
]
=
assetId
if
league
:
params
[
'leag'
]
=
league
if
club
:
params
[
'team'
]
=
club
if
position
:
params
[
'pos'
]
=
position
if
zone
:
params
[
'zone'
]
=
zone
if
nationality
:
params
[
'nat'
]
=
nationality
if
rare
:
params
[
'rare'
]
=
'SP'
if
playStyle
:
params
[
'playStyle'
]
=
playStyle
rc
=
self
.
__request__
(
method
,
url
,
params
=
params
)
if
start
==
0
:
if
ctype
==
'player'
:
pgid
=
'Club - Players - List View'
elif
ctype
==
'staff'
:
pgid
=
'Club - Staff - List View'
elif
ctype
in
(
'item'
,
'kit'
,
'ball'
,
'badge'
,
'stadium'
)
:
pgid
=
'Club - Club Items - List View'
events
=
[
self
.
pin
.
event
(
'page_view'
,
'Hub - Club'
)
,
self
.
pin
.
event
(
'page_view'
,
pgid
)
]
if
rc
[
'itemData'
]
:
events
.
append
(
self
.
pin
.
event
(
'page_view'
,
'Item - Detail View'
)
)
self
.
pin
.
send
(
events
)
return
[
itemParse
(
{
'itemData'
:
i
}
)
for
i
in
rc
[
'itemData'
]
]

Return items in your club excluding consumables .


def clubStaff(self):
        """Return staff in your club."""
        method = 'GET'
        url = 'club/stats/staff'

        rc = self.__request__(method, url)
        return rc

def clubStaff ( self ) : method = 'GET' url = 'club/stats/staff' rc = self . __request__ ( method , url ) return rc


def clubConsumables(self, fast=False):
        """Return all consumables from club."""
        method = 'GET'
        url = 'club/consumables/development'

        rc = self.__request__(method, url)

        events = [self.pin.event('page_view', 'Hub - Club')]
        self.pin.send(events, fast=fast)
        events = [self.pin.event('page_view', 'Club - Consumables')]
        self.pin.send(events, fast=fast)
        events = [self.pin.event('page_view', 'Club - Consumables - List View')]
        self.pin.send(events, fast=fast)

        return [itemParse(i) for i in rc.get('itemData', ())]

def
clubConsumables
(
self
,
fast
=
False
)
:
method
=
'GET'
url
=
'club/consumables/development'
rc
=
self
.
__request__
(
method
,
url
)
events
=
[
self
.
pin
.
event
(
'page_view'
,
'Hub - Club'
)
]
self
.
pin
.
send
(
events
,
fast
=
fast
)
events
=
[
self
.
pin
.
event
(
'page_view'
,
'Club - Consumables'
)
]
self
.
pin
.
send
(
events
,
fast
=
fast
)
events
=
[
self
.
pin
.
event
(
'page_view'
,
'Club - Consumables - List View'
)
]
self
.
pin
.
send
(
events
,
fast
=
fast
)
return
[
itemParse
(
i
)
for
i
in
rc
.
get
(
'itemData'
,
(
)
)
]


def squad(self, squad_id=0, persona_id=None):
        """Return a squad.

        :params squad_id: Squad id.
        """
        method = 'GET'
        url = 'squad/%s/user/%s' % (squad_id, persona_id or self.persona_id)

        # pinEvents
        events = [self.pin.event('page_view', 'Hub - Squads')]
        self.pin.send(events)

        # TODO: ability to return other info than players only
        rc = self.__request__(method, url)

        # pinEvents
        events = [self.pin.event('page_view', 'Squad Details'), self.pin.event('page_view', 'Squads - Squad Overview')]
        self.pin.send(events)

        return [itemParse(i) for i in rc.get('players', ())]

def
squad
(
self
,
squad_id
=
0
,
persona_id
=
)
:
method
=
'GET'
url
=
'squad/%s/user/%s'
%
(
squad_id
,
persona_id
or
self
.
persona_id
)
events
=
[
self
.
pin
.
event
(
'page_view'
,
'Hub - Squads'
)
]
self
.
pin
.
send
(
events
)
rc
=
self
.
__request__
(
method
,
url
)
events
=
[
self
.
pin
.
event
(
'page_view'
,
'Squad Details'
)
,
self
.
pin
.
event
(
'page_view'
,
'Squads - Squad Overview'
)
]
self
.
pin
.
send
(
events
)
return
[
itemParse
(
i
)
for
i
in
rc
.
get
(
'players'
,
(
)
)
]


def tradeStatus(self, trade_id):
        """Return trade status.

        :params trade_id: Trade id.
        """
        method = 'GET'
        url = 'trade/status'

        if not isinstance(trade_id, (list, tuple)):
            trade_id = (trade_id,)
        trade_id = (str(i) for i in trade_id)
        params = {'tradeIds': ','.join(trade_id)}  # multiple trade_ids not tested
        rc = self.__request__(method, url, params=params)
        return [itemParse(i, full=False) for i in rc['auctionInfo']]

def tradeStatus ( self , trade_id ) : method = 'GET' url = 'trade/status' if not isinstance ( trade_id , ( list , tuple ) ) : trade_id = ( trade_id , ) trade_id = ( str ( i ) for i in trade_id ) params = { 'tradeIds' : ',' . join ( trade_id ) } rc = self . __request__ ( method , url , params = params ) return [ itemParse ( i , full = False ) for i in rc [ 'auctionInfo' ] ]


def tradepile(self):
        """Return items in tradepile."""
        method = 'GET'
        url = 'tradepile'

        rc = self.__request__(method, url)

        # pinEvents
        events = [self.pin.event('page_view', 'Hub - Transfers'), self.pin.event('page_view', 'Transfer List - List View')]
        if rc.get('auctionInfo'):
            events.append(self.pin.event('page_view', 'Item - Detail View'))
        self.pin.send(events)

        return [itemParse(i) for i in rc.get('auctionInfo', ())]

def
tradepile
(
self
)
:
method
=
'GET'
url
=
'tradepile'
rc
=
self
.
__request__
(
method
,
url
)
events
=
[
self
.
pin
.
event
(
'page_view'
,
'Hub - Transfers'
)
,
self
.
pin
.
event
(
'page_view'
,
'Transfer List - List View'
)
]
if
rc
.
get
(
'auctionInfo'
)
:
events
.
append
(
self
.
pin
.
event
(
'page_view'
,
'Item - Detail View'
)
)
self
.
pin
.
send
(
events
)
return
[
itemParse
(
i
)
for
i
in
rc
.
get
(
'auctionInfo'
,
(
)
)
]


def sell(self, item_id, bid, buy_now, duration=3600, fast=False):
        """Start auction. Returns trade_id.

        :params item_id: Item id.
        :params bid: Stard bid.
        :params buy_now: Buy now price.
        :params duration: Auction duration in seconds (Default: 3600).
        """
        method = 'POST'
        url = 'auctionhouse'

        # TODO: auto send to tradepile
        data = {'buyNowPrice': buy_now, 'startingBid': bid, 'duration': duration, 'itemData': {'id': item_id}}
        rc = self.__request__(method, url, data=json.dumps(data), params={'sku_b': self.sku_b})
        if not fast:  # tradeStatus check like webapp do
            self.tradeStatus(rc['id'])
        return rc['id']

def sell ( self , item_id , bid , buy_now , duration = 3600 , fast = False ) : method = 'POST' url = 'auctionhouse' data = { 'buyNowPrice' : buy_now , 'startingBid' : bid , 'duration' : duration , 'itemData' : { 'id' : item_id } } rc = self . __request__ ( method , url , data = json . dumps ( data ) , params = { 'sku_b' : self . sku_b } ) if not fast : self . tradeStatus ( rc [ 'id' ] ) return rc [ 'id' ]


def quickSell(self, item_id):
        """Quick sell.

        :params item_id: Item id.
        """
        method = 'DELETE'
        url = 'item'

        if not isinstance(item_id, (list, tuple)):
            item_id = (item_id,)
        item_id = (str(i) for i in item_id)
        params = {'itemIds': ','.join(item_id)}
        self.__request__(method, url, params=params)  # {"items":[{"id":280607437106}],"totalCredits":18136}
        return True

def quickSell ( self , item_id ) : method = 'DELETE' url = 'item' if not isinstance ( item_id , ( list , tuple ) ) : item_id = ( item_id , ) item_id = ( str ( i ) for i in item_id ) params = { 'itemIds' : ',' . join ( item_id ) } self . __request__ ( method , url , params = params ) return True

Quick sell.

        :params item_id: Item id.


def watchlistDelete(self, trade_id):
        """Remove cards from watchlist.

        :params trade_id: Trade id.
        """
        method = 'DELETE'
        url = 'watchlist'

        if not isinstance(trade_id, (list, tuple)):
            trade_id = (trade_id,)
        trade_id = (str(i) for i in trade_id)
        params = {'tradeId': ','.join(trade_id)}
        self.__request__(method, url, params=params)  # returns nothing
        return True

def watchlistDelete ( self , trade_id ) : method = 'DELETE' url = 'watchlist' if not isinstance ( trade_id , ( list , tuple ) ) : trade_id = ( trade_id , ) trade_id = ( str ( i ) for i in trade_id ) params = { 'tradeId' : ',' . join ( trade_id ) } self . __request__ ( method , url , params = params ) return True


def tradepileDelete(self, trade_id):  # item_id instead of trade_id?
        """Remove card from tradepile.

        :params trade_id: Trade id.
        """
        method = 'DELETE'
        url = 'trade/%s' % trade_id

        self.__request__(method, url)  # returns nothing
        # TODO: validate status code
        return True

def tradepileDelete ( self , trade_id ) : method = 'DELETE' url = 'trade/%s' % trade_id self . __request__ ( method , url ) return True


def sendToWatchlist(self, trade_id):
        """Send to watchlist.

        :params trade_id: Trade id.
        """
        method = 'PUT'
        url = 'watchlist'

        data = {'auctionInfo': [{'id': trade_id}]}
        return self.__request__(method, url, data=json.dumps(data))

def sendToWatchlist ( self , trade_id ) : method = 'PUT' url = 'watchlist' data = { 'auctionInfo' : [ { 'id' : trade_id } ] } return self . __request__ ( method , url , data = json . dumps ( data ) )


def sendToSbs(self, challenge_id, item_id):
        """Send card FROM CLUB to first free slot in sbs squad."""
        # TODO?: multiple item_ids
        method = 'PUT'
        url = 'sbs/challenge/%s/squad' % challenge_id

        squad = self.sbsSquad(challenge_id)
        players = []
        moved = False
        n = 0
        for i in squad['squad']['players']:
            if i['itemData']['id'] == item_id:  # item already in sbs  # TODO?: report reason
                return False
            if i['itemData']['id'] == 0 and not moved:
                i['itemData']['id'] = item_id
                moved = True
            players.append({"index": n,
                            "itemData": {"id": i['itemData']['id'],
                                         "dream": False}})
            n += 1
        data = {'players': players}

        if not moved:
            return False
        else:
            self.__request__(method, url, data=json.dumps(data))
            return True

def sendToSbs ( self , challenge_id , item_id ) : method = 'PUT' url = 'sbs/challenge/%s/squad' % challenge_id squad = self . sbsSquad ( challenge_id ) players = [ ] moved = False n = 0 for i in squad [ 'squad' ] [ 'players' ] : if i [ 'itemData' ] [ 'id' ] == item_id : return False if i [ 'itemData' ] [ 'id' ] == 0 and not moved : i [ 'itemData' ] [ 'id' ] = item_id moved = True players . append ( { "index" : n , "itemData" : { "id" : i [ 'itemData' ] [ 'id' ] , "dream" : False } } ) n += 1 data = { 'players' : players } if not moved : return False else : self . __request__ ( method , url , data = json . dumps ( data ) ) return True

Send card FROM CLUB to first free slot in sbs squad .


def applyConsumable(self, item_id, resource_id):
        """Apply consumable on player.

        :params item_id: Item id of player.
        :params resource_id: Resource id of consumable.
        """
        # TODO: catch exception when consumable is not found etc.
        # TODO: multiple players like in quickSell
        method = 'POST'
        url = 'item/resource/%s' % resource_id

        data = {'apply': [{'id': item_id}]}
        self.__request__(method, url, data=json.dumps(data))

def applyConsumable ( self , item_id , resource_id ) : method = 'POST' url = 'item/resource/%s' % resource_id data = { 'apply' : [ { 'id' : item_id } ] } self . __request__ ( method , url , data = json . dumps ( data ) )


def messages(self):
        """Return active messages."""
        method = 'GET'
        url = 'activeMessage'

        rc = self.__request__(method, url)
        # try:
        #     return rc['activeMessage']
        # except:
        #     raise UnknownError('Invalid activeMessage response')  # is it even possible?
        return rc['activeMessage']

def messages ( self ) : method = 'GET' url = 'activeMessage' rc = self . __request__ ( method , url ) return rc [ 'activeMessage' ]


def num2hex(self, num):
        '''
            Convert a decimal number to hexadecimal
        '''
        temp = ''
        for i in range(0, 4):
            x = self.hexChars[ ( num >> (i * 8 + 4) ) & 0x0F ]
            y = self.hexChars[ ( num >> (i * 8) ) & 0x0F ]
            temp += (x + y)

        return temp

def num2hex ( self , num ) : temp = '' for i in range ( 0 , 4 ) : x = self . hexChars [ ( num >> ( i * 8 + 4 ) ) & 0x0F ] y = self . hexChars [ ( num >> ( i * 8 ) ) & 0x0F ] temp += ( x + y ) return temp


def logger(name=None, save=False):
    """Init and configure logger."""
    logger = logging.getLogger(name)

    if save:
        logformat = '%(asctime)s [%(levelname)s] [%(name)s] %(funcName)s: %(message)s (line %(lineno)d)'
        log_file_path = 'fut.log'  # TODO: define logpath
        open(log_file_path, 'w').write('')  # remove old logs
        logger.setLevel(logging.DEBUG)
        logger_handler = logging.FileHandler(log_file_path)
        logger_handler.setFormatter(logging.Formatter(logformat))
    else:
        logger_handler = NullHandler()

    logger.addHandler(logger_handler)

    return logger


def run(self):
        """
        Runs its worker method.

        This method will be terminated once its parent's is_running
        property turns False.
        """
        while self._base.is_running:
            if self._worker:
                self._worker()
                time.sleep(self._sleep_duration)

def run ( self ) : while self . _base . is_running : if self . _worker : self . _worker ( ) time . sleep ( self . _sleep_duration )


def represent_pixel_location(self):
        """
        Returns a NumPy array that represents the 2D pixel location,
        which is defined by PFNC, of the original image data.

        You may use the returned NumPy array for a calculation to map the
        original image to another format.

        :return: A NumPy array that represents the 2D pixel location.
        """
        if self.data is None:
            return None

        #
        return self._data.reshape(
            self.height + self.y_padding,
            int(self.width * self._num_components_per_pixel + self.x_padding)
        )

def represent_pixel_location ( self ) : if self . data is None : return None return self . _data . reshape ( self . height + self . y_padding , int ( self . width * self . _num_components_per_pixel + self . x_padding ) )

Returns a NumPy array that represents the 2D pixel location which is defined by PFNC of the original image data .


def start_image_acquisition(self):
        """
        Starts image acquisition.

        :return: None.
        """
        if not self._create_ds_at_connection:
            self._setup_data_streams()

        #
        num_required_buffers = self._num_buffers
        for data_stream in self._data_streams:
            try:
                num_buffers = data_stream.buffer_announce_min
                if num_buffers < num_required_buffers:
                    num_buffers = num_required_buffers
            except InvalidParameterException as e:
                num_buffers = num_required_buffers
                self._logger.debug(e, exc_info=True)

            if data_stream.defines_payload_size():
                buffer_size = data_stream.payload_size
            else:
                buffer_size = self.device.node_map.PayloadSize.value

            raw_buffers = self._create_raw_buffers(
                num_buffers, buffer_size
            )

            buffer_tokens = self._create_buffer_tokens(
                raw_buffers
            )

            self._announced_buffers = self._announce_buffers(
                data_stream=data_stream, _buffer_tokens=buffer_tokens
            )

            self._queue_announced_buffers(
                data_stream=data_stream, buffers=self._announced_buffers
            )

        # Reset the number of images to acquire.
        try:
            acq_mode = self.device.node_map.AcquisitionMode.value
            if acq_mode == 'Continuous':
                num_images_to_acquire = -1
            elif acq_mode == 'SingleFrame':
                num_images_to_acquire = 1
            elif acq_mode == 'MultiFrame':
                num_images_to_acquire = self.device.node_map.AcquisitionFrameCount.value
            else:
                num_images_to_acquire = -1
        except LogicalErrorException as e:
            # The node doesn't exist.
            num_images_to_acquire = -1
            self._logger.debug(e, exc_info=True)

        self._num_images_to_acquire = num_images_to_acquire

        try:
            # We're ready to start image acquisition. Lock the device's
            # transport layer related features:
            self.device.node_map.TLParamsLocked.value = 1
        except LogicalErrorException:
            # SFNC < 2.0
            pass

        # Start image acquisition.
        self._is_acquiring_images = True

        for data_stream in self._data_streams:
            data_stream.start_acquisition(
                ACQ_START_FLAGS_LIST.ACQ_START_FLAGS_DEFAULT,
                self._num_images_to_acquire
            )

        #
        if self.thread_image_acquisition:
            self.thread_image_acquisition.start()

        #
        self.device.node_map.AcquisitionStart.execute()

        self._logger.info(
            '{0} started image acquisition.'.format(self._device.id_)
        )

        if self._profiler:
            self._profiler.print_diff()

def
start_image_acquisition
(
self
)
:
if
not
self
.
_create_ds_at_connection
:
self
.
_setup_data_streams
(
)
num_required_buffers
=
self
.
_num_buffers
for
data_stream
in
self
.
_data_streams
:
try
:
num_buffers
=
data_stream
.
buffer_announce_min
if
num_buffers
<
num_required_buffers
:
num_buffers
=
num_required_buffers
except
InvalidParameterException
as
e
:
num_buffers
=
num_required_buffers
self
.
_logger
.
debug
(
e
,
exc_info
=
True
)
if
data_stream
.
defines_payload_size
(
)
:
buffer_size
=
data_stream
.
payload_size
else
:
buffer_size
=
self
.
device
.
node_map
.
PayloadSize
.
value
raw_buffers
=
self
.
_create_raw_buffers
(
num_buffers
,
buffer_size
)
buffer_tokens
=
self
.
_create_buffer_tokens
(
raw_buffers
)
self
.
_announced_buffers
=
self
.
_announce_buffers
(
data_stream
=
data_stream
,
_buffer_tokens
=
buffer_tokens
)
self
.
_queue_announced_buffers
(
data_stream
=
data_stream
,
buffers
=
self
.
_announced_buffers
)
try
:
acq_mode
=
self
.
device
.
node_map
.
AcquisitionMode
.
value
if
acq_mode
==
'Continuous'
:
num_images_to_acquire
=
1
elif
acq_mode
==
'SingleFrame'
:
num_images_to_acquire
=
1
elif
acq_mode
==
'MultiFrame'
:
num_images_to_acquire
=
self
.
device
.
node_map
.
AcquisitionFrameCount
.
value
else
:
num_images_to_acquire
=
1
except
LogicalErrorException
as
e
:
num_images_to_acquire
=
1
self
.
_logger
.
debug
(
e
,
exc_info
=
True
)
self
.
_num_images_to_acquire
=
num_images_to_acquire
try
:
self
.
device
.
node_map
.
TLParamsLocked
.
value
=
1
except
LogicalErrorException
:
pass
self
.
_is_acquiring_images
=
True
for
data_stream
in
self
.
_data_streams
:
data_stream
.
start_acquisition
(
ACQ_START_FLAGS_LIST
.
ACQ_START_FLAGS_DEFAULT
,
self
.
_num_images_to_acquire
)
if
self
.
thread_image_acquisition
:
self
.
thread_image_acquisition
.
start
(
)
self
.
device
.
node_map
.
AcquisitionStart
.
execute
(
)
self
.
_logger
.
info
(
'{0} started image acquisition.'
.
format
(
self
.
_device
.
id_
)
)
if
self
.
_profiler
:
self
.
_profiler
.
print_diff
(
)


def stop_image_acquisition(self):
        """
        Stops image acquisition.

        :return: None.
        """
        if self.is_acquiring_images:
            #
            self._is_acquiring_images = False

            #
            if self.thread_image_acquisition.is_running:  # TODO
                self.thread_image_acquisition.stop()

            with MutexLocker(self.thread_image_acquisition):
                #
                self.device.node_map.AcquisitionStop.execute()

                try:
                    # Unlock TLParamsLocked in order to allow full device
                    # configuration:
                    self.device.node_map.TLParamsLocked.value = 0
                except LogicalErrorException:
                    # SFNC < 2.0
                    pass

                for data_stream in self._data_streams:
                    # Stop image acquisition.
                    try:
                        data_stream.stop_acquisition(
                            ACQ_STOP_FLAGS_LIST.ACQ_STOP_FLAGS_KILL
                        )
                    except (ResourceInUseException, TimeoutException) as e:
                        self._logger.error(e, exc_info=True)

                    # Flash the queue for image acquisition process.
                    data_stream.flush_buffer_queue(
                        ACQ_QUEUE_TYPE_LIST.ACQ_QUEUE_ALL_DISCARD
                    )

                for event_manager in self._event_new_buffer_managers:
                    event_manager.flush_event_queue()

                if self._create_ds_at_connection:
                    self._release_buffers()
                else:
                    self._release_data_streams()

            #
            self._has_acquired_1st_image = False

            #
            self._chunk_adapter.detach_buffer()

            #
            self._logger.info(
                '{0} stopped image acquisition.'.format(self._device.id_)
            )

        if self._profiler:
            self._profiler.print_diff()

def
stop_image_acquisition
(
self
)
:
if
self
.
is_acquiring_images
:
self
.
_is_acquiring_images
=
False
if
self
.
thread_image_acquisition
.
is_running
:
self
.
thread_image_acquisition
.
stop
(
)
with
MutexLocker
(
self
.
thread_image_acquisition
)
:
self
.
device
.
node_map
.
AcquisitionStop
.
execute
(
)
try
:
self
.
device
.
node_map
.
TLParamsLocked
.
value
=
0
except
LogicalErrorException
:
pass
for
data_stream
in
self
.
_data_streams
:
try
:
data_stream
.
stop_acquisition
(
ACQ_STOP_FLAGS_LIST
.
ACQ_STOP_FLAGS_KILL
)
except
(
ResourceInUseException
,
TimeoutException
)
as
e
:
self
.
_logger
.
error
(
e
,
exc_info
=
True
)
data_stream
.
flush_buffer_queue
(
ACQ_QUEUE_TYPE_LIST
.
ACQ_QUEUE_ALL_DISCARD
)
for
event_manager
in
self
.
_event_new_buffer_managers
:
event_manager
.
flush_event_queue
(
)
if
self
.
_create_ds_at_connection
:
self
.
_release_buffers
(
)
else
:
self
.
_release_data_streams
(
)
self
.
_has_acquired_1st_image
=
False
self
.
_chunk_adapter
.
detach_buffer
(
)
self
.
_logger
.
info
(
'{0} stopped image acquisition.'
.
format
(
self
.
_device
.
id_
)
)
if
self
.
_profiler
:
self
.
_profiler
.
print_diff
(
)

Stops image acquisition.

        :return: None.


def add_cti_file(self, file_path: str):
        """
        Adds a CTI file to work with to the CTI file list.

        :param file_path: Set a file path to the target CTI file.

        :return: None.
        """
        if not os.path.exists(file_path):
            self._logger.warning(
                'Attempted to add {0} which does not exist.'.format(file_path)
            )

        if file_path not in self._cti_files:
            self._cti_files.append(file_path)
            self._logger.info(
                'Added {0} to the CTI file list.'.format(file_path)
            )

Adds a CTI file to work with to the CTI file list .


def remove_cti_file(self, file_path: str):
        """
        Removes the specified CTI file from the CTI file list.

        :param file_path: Set a file path to the target CTI file.

        :return: None.
        """
        if file_path in self._cti_files:
            self._cti_files.remove(file_path)
            self._logger.info(
                'Removed {0} from the CTI file list.'.format(file_path)
            )

def
remove_cti_file
(
self
,
file_path
:
str
)
:
if
file_path
in
self
.
_cti_files
:
self
.
_cti_files
.
remove
(
file_path
)
self
.
_logger
.
info
(
'Removed {0} from the CTI file list.'
.
format
(
file_path
)
)

Removes the specified CTI file from the CTI file list .


def _destroy_image_acquirer(self, ia):
        """
        Releases all external resources including the controlling device.
        """

        id_ = None
        if ia.device:
            #
            ia.stop_image_acquisition()

            #
            ia._release_data_streams()

            #
            id_ = ia._device.id_

            #
            if ia.device.node_map:
                #
                if ia._chunk_adapter:
                    ia._chunk_adapter.detach_buffer()
                    ia._chunk_adapter = None
                    self._logger.info(
                        'Detached a buffer from the chunk adapter of {0}.'.format(
                            id_
                        )
                    )

                ia.device.node_map.disconnect()
                self._logger.info(
                    'Disconnected the port from the NodeMap of {0}.'.format(
                        id_
                    )
                )

            #
            if ia._device.is_open():
                ia._device.close()
                self._logger.info(
                    'Closed Device module, {0}.'.format(id_)
                )

        ia._device = None

        #
        if id_:
            self._logger.info(
                'Destroyed the ImageAcquirer object which {0} '
                'had belonged to.'.format(id_)
            )
        else:
            self._logger.info(
                'Destroyed an ImageAcquirer.'
            )

        if self._profiler:
            self._profiler.print_diff()

        self._ias.remove(ia)

Releases all external resources including the controlling device .


def add_coeffs(self, Tmin, Tmax, coeffs):
        '''Called internally during the parsing of the Zabransky database, to
        add coefficients as they are read one per line'''
        self.n += 1
        if not self.Ts:
            self.Ts = [Tmin, Tmax]
            self.coeff_sets = [coeffs]
        else:
            for ind, T in enumerate(self.Ts):
                if Tmin < T:
                    # Under an existing coefficient set - assume Tmax will come from another set
                    self.Ts.insert(ind, Tmin)
                    self.coeff_sets.insert(ind, coeffs)
                    return
            # Must be appended to end instead
            self.Ts.append(Tmax)
            self.coeff_sets.append(coeffs)

def add_coeffs ( self , Tmin , Tmax , coeffs ) : self . n += 1 if not self . Ts : self . Ts = [ Tmin , Tmax ] self . coeff_sets = [ coeffs ] else : for ind , T in enumerate ( self . Ts ) : if Tmin < T : self . Ts . insert ( ind , Tmin ) self . coeff_sets . insert ( ind , coeffs ) return self . Ts . append ( Tmax ) self . coeff_sets . append ( coeffs )

Called internally during the parsing of the Zabransky database to add coefficients as they are read one per line


def _coeff_ind_from_T(self, T):
        '''Determines the index at which the coefficients for the current
        temperature are stored in `coeff_sets`.
        '''
        # DO NOT CHANGE
        if self.n == 1:
            return 0
        for i in range(self.n):
            if T <= self.Ts[i+1]:
                return i
        return self.n - 1

def _coeff_ind_from_T ( self , T ) : if self . n == 1 : return 0 for i in range ( self . n ) : if T <= self . Ts [ i + 1 ] : return i return self . n - 1

Determines the index at which the coefficients for the current temperature are stored in coeff_sets .


def calculate(self, T, method):
        r'''Method to calculate heat capacity of a liquid at temperature `T`
        with a given method.

        This method has no exception handling; see `T_dependent_property`
        for that.

        Parameters
        ----------
        T : float
            Temperature at which to calculate heat capacity, [K]
        method : str
            Name of the method to use

        Returns
        -------
        Cp : float
            Heat capacity of the liquid at T, [J/mol/K]
        '''
        if method == ZABRANSKY_SPLINE:
            return self.Zabransky_spline.calculate(T)
        elif method == ZABRANSKY_QUASIPOLYNOMIAL:
            return self.Zabransky_quasipolynomial.calculate(T)
        elif method == ZABRANSKY_SPLINE_C:
            return self.Zabransky_spline_iso.calculate(T)
        elif method == ZABRANSKY_QUASIPOLYNOMIAL_C:
            return self.Zabransky_quasipolynomial_iso.calculate(T)
        elif method == ZABRANSKY_SPLINE_SAT:
            return self.Zabransky_spline_sat.calculate(T)
        elif method == ZABRANSKY_QUASIPOLYNOMIAL_SAT:
            return self.Zabransky_quasipolynomial_sat.calculate(T)
        elif method == COOLPROP:
            return CoolProp_T_dependent_property(T, self.CASRN , 'CPMOLAR', 'l')
        elif method == POLING_CONST:
            return self.POLING_constant
        elif method == CRCSTD:
            return self.CRCSTD_constant
        elif method == ROWLINSON_POLING:
            Cpgm = self.Cpgm(T) if hasattr(self.Cpgm, '__call__') else self.Cpgm
            return Rowlinson_Poling(T, self.Tc, self.omega, Cpgm)
        elif method == ROWLINSON_BONDI:
            Cpgm = self.Cpgm(T) if hasattr(self.Cpgm, '__call__') else self.Cpgm
            return Rowlinson_Bondi(T, self.Tc, self.omega, Cpgm)
        elif method == DADGOSTAR_SHAW:
            Cp = Dadgostar_Shaw(T, self.similarity_variable)
            return property_mass_to_molar(Cp, self.MW)
        elif method in self.tabular_data:
            return self.interpolate(T, method)
        else:
            raise Exception('Method not valid')

def
calculate
(
self
,
T
,
method
)
:
r
if
method
==
ZABRANSKY_SPLINE
:
return
self
.
Zabransky_spline
.
calculate
(
T
)
elif
method
==
ZABRANSKY_QUASIPOLYNOMIAL
:
return
self
.
Zabransky_quasipolynomial
.
calculate
(
T
)
elif
method
==
ZABRANSKY_SPLINE_C
:
return
self
.
Zabransky_spline_iso
.
calculate
(
T
)
elif
method
==
ZABRANSKY_QUASIPOLYNOMIAL_C
:
return
self
.
Zabransky_quasipolynomial_iso
.
calculate
(
T
)
elif
method
==
ZABRANSKY_SPLINE_SAT
:
return
self
.
Zabransky_spline_sat
.
calculate
(
T
)
elif
method
==
ZABRANSKY_QUASIPOLYNOMIAL_SAT
:
return
self
.
Zabransky_quasipolynomial_sat
.
calculate
(
T
)
elif
method
==
COOLPROP
:
return
CoolProp_T_dependent_property
(
T
,
self
.
CASRN
,
'CPMOLAR'
,
'l'
)
elif
method
==
POLING_CONST
:
return
self
.
POLING_constant
elif
method
==
CRCSTD
:
return
self
.
CRCSTD_constant
elif
method
==
ROWLINSON_POLING
:
Cpgm
=
self
.
Cpgm
(
T
)
if
hasattr
(
self
.
Cpgm
,
'__call__'
)
else
self
.
Cpgm
return
Rowlinson_Poling
(
T
,
self
.
Tc
,
self
.
omega
,
Cpgm
)
elif
method
==
ROWLINSON_BONDI
:
Cpgm
=
self
.
Cpgm
(
T
)
if
hasattr
(
self
.
Cpgm
,
'__call__'
)
else
self
.
Cpgm
return
Rowlinson_Bondi
(
T
,
self
.
Tc
,
self
.
omega
,
Cpgm
)
elif
method
==
DADGOSTAR_SHAW
:
Cp
=
Dadgostar_Shaw
(
T
,
self
.
similarity_variable
)
return
property_mass_to_molar
(
Cp
,
self
.
MW
)
elif
method
in
self
.
tabular_data
:
return
self
.
interpolate
(
T
,
method
)
else
:
raise
Exception
(
'Method not valid'
)

r Method to calculate heat capacity of a liquid at temperature T with a given method .


def calculate_integral(self, T1, T2, method):
        r'''Method to calculate the integral of a property with respect to
        temperature, using a specified method.  Implements the
        analytical integrals of all available methods except for tabular data,
        the case of multiple coefficient sets needed to encompass the temperature
        range of any of the ZABRANSKY methods, and the CSP methods using the
        vapor phase properties.

        Parameters
        ----------
        T1 : float
            Lower limit of integration, [K]
        T2 : float
            Upper limit of integration, [K]
        method : str
            Method for which to find the integral

        Returns
        -------
        integral : float
            Calculated integral of the property over the given range,
            [`units*K`]
        '''
        if method == ZABRANSKY_SPLINE:
            return self.Zabransky_spline.calculate_integral(T1, T2)
        elif method == ZABRANSKY_SPLINE_C:
            return self.Zabransky_spline_iso.calculate_integral(T1, T2)
        elif method == ZABRANSKY_SPLINE_SAT:
            return self.Zabransky_spline_sat.calculate_integral(T1, T2)
        elif method == ZABRANSKY_QUASIPOLYNOMIAL:
            return self.Zabransky_quasipolynomial.calculate_integral(T1, T2)
        elif method == ZABRANSKY_QUASIPOLYNOMIAL_C:
            return self.Zabransky_quasipolynomial_iso.calculate_integral(T1, T2)
        elif method == ZABRANSKY_QUASIPOLYNOMIAL_SAT:
            return self.Zabransky_quasipolynomial_sat.calculate_integral(T1, T2)
        elif method == POLING_CONST:
            return (T2 - T1)*self.POLING_constant
        elif method == CRCSTD:
            return (T2 - T1)*self.CRCSTD_constant
        elif method == DADGOSTAR_SHAW:
            dH = (Dadgostar_Shaw_integral(T2, self.similarity_variable)
                    - Dadgostar_Shaw_integral(T1, self.similarity_variable))
            return property_mass_to_molar(dH, self.MW)
        elif method in self.tabular_data or method == COOLPROP or method in [ROWLINSON_POLING, ROWLINSON_BONDI]:
            return float(quad(self.calculate, T1, T2, args=(method))[0])
        else:
            raise Exception('Method not valid')

def
calculate_integral
(
self
,
T1
,
T2
,
method
)
:
r
if
method
==
ZABRANSKY_SPLINE
:
return
self
.
Zabransky_spline
.
calculate_integral
(
T1
,
T2
)
elif
method
==
ZABRANSKY_SPLINE_C
:
return
self
.
Zabransky_spline_iso
.
calculate_integral
(
T1
,
T2
)
elif
method
==
ZABRANSKY_SPLINE_SAT
:
return
self
.
Zabransky_spline_sat
.
calculate_integral
(
T1
,
T2
)
elif
method
==
ZABRANSKY_QUASIPOLYNOMIAL
:
return
self
.
Zabransky_quasipolynomial
.
calculate_integral
(
T1
,
T2
)
elif
method
==
ZABRANSKY_QUASIPOLYNOMIAL_C
:
return
self
.
Zabransky_quasipolynomial_iso
.
calculate_integral
(
T1
,
T2
)
elif
method
==
ZABRANSKY_QUASIPOLYNOMIAL_SAT
:
return
self
.
Zabransky_quasipolynomial_sat
.
calculate_integral
(
T1
,
T2
)
elif
method
==
POLING_CONST
:
return
(
T2
T1
)
*
self
.
POLING_constant
elif
method
==
CRCSTD
:
return
(
T2
T1
)
*
self
.
CRCSTD_constant
elif
method
==
DADGOSTAR_SHAW
:
dH
=
(
Dadgostar_Shaw_integral
(
T2
,
self
.
similarity_variable
)
Dadgostar_Shaw_integral
(
T1
,
self
.
similarity_variable
)
)
return
property_mass_to_molar
(
dH
,
self
.
MW
)
elif
method
in
self
.
tabular_data
or
method
==
COOLPROP
or
method
in
[
ROWLINSON_POLING
,
ROWLINSON_BONDI
]
:
return
float
(
quad
(
self
.
calculate
,
T1
,
T2
,
args
=
(
method
)
)
[
0
]
)
else
:
raise
Exception
(
'Method not valid'
)

r Method to calculate the integral of a property with respect to temperature using a specified method . Implements the analytical integrals of all available methods except for tabular data the case of multiple coefficient sets needed to encompass the temperature range of any of the ZABRANSKY methods and the CSP methods using the vapor phase properties .


def calculate_integral_over_T(self, T1, T2, method):
        r'''Method to calculate the integral of a property over temperature
        with respect to temperature, using a specified method.   Implements the
        analytical integrals of all available methods except for tabular data,
        the case of multiple coefficient sets needed to encompass the temperature
        range of any of the ZABRANSKY methods, and the CSP methods using the
        vapor phase properties.

        Parameters
        ----------
        T1 : float
            Lower limit of integration, [K]
        T2 : float
            Upper limit of integration, [K]
        method : str
            Method for which to find the integral

        Returns
        -------
        integral : float
            Calculated integral of the property over the given range,
            [`units`]
        '''
        if method == ZABRANSKY_SPLINE:
            return self.Zabransky_spline.calculate_integral_over_T(T1, T2)
        elif method == ZABRANSKY_SPLINE_C:
            return self.Zabransky_spline_iso.calculate_integral_over_T(T1, T2)
        elif method == ZABRANSKY_SPLINE_SAT:
            return self.Zabransky_spline_sat.calculate_integral_over_T(T1, T2)
        elif method == ZABRANSKY_QUASIPOLYNOMIAL:
            return self.Zabransky_quasipolynomial.calculate_integral_over_T(T1, T2)
        elif method == ZABRANSKY_QUASIPOLYNOMIAL_C:
            return self.Zabransky_quasipolynomial_iso.calculate_integral_over_T(T1, T2)
        elif method == ZABRANSKY_QUASIPOLYNOMIAL_SAT:
            return self.Zabransky_quasipolynomial_sat.calculate_integral_over_T(T1, T2)
        elif method == POLING_CONST:
            return self.POLING_constant*log(T2/T1)
        elif method == CRCSTD:
            return self.CRCSTD_constant*log(T2/T1)
        elif method == DADGOSTAR_SHAW:
            dS = (Dadgostar_Shaw_integral_over_T(T2, self.similarity_variable)
                    - Dadgostar_Shaw_integral_over_T(T1, self.similarity_variable))
            return property_mass_to_molar(dS, self.MW)
        elif method in self.tabular_data or method == COOLPROP or method in [ROWLINSON_POLING, ROWLINSON_BONDI]:
            return float(quad(lambda T: self.calculate(T, method)/T, T1, T2)[0])
        else:
            raise Exception('Method not valid')

def
calculate_integral_over_T
(
self
,
T1
,
T2
,
method
)
:
r
if
method
==
ZABRANSKY_SPLINE
:
return
self
.
Zabransky_spline
.
calculate_integral_over_T
(
T1
,
T2
)
elif
method
==
ZABRANSKY_SPLINE_C
:
return
self
.
Zabransky_spline_iso
.
calculate_integral_over_T
(
T1
,
T2
)
elif
method
==
ZABRANSKY_SPLINE_SAT
:
return
self
.
Zabransky_spline_sat
.
calculate_integral_over_T
(
T1
,
T2
)
elif
method
==
ZABRANSKY_QUASIPOLYNOMIAL
:
return
self
.
Zabransky_quasipolynomial
.
calculate_integral_over_T
(
T1
,
T2
)
elif
method
==
ZABRANSKY_QUASIPOLYNOMIAL_C
:
return
self
.
Zabransky_quasipolynomial_iso
.
calculate_integral_over_T
(
T1
,
T2
)
elif
method
==
ZABRANSKY_QUASIPOLYNOMIAL_SAT
:
return
self
.
Zabransky_quasipolynomial_sat
.
calculate_integral_over_T
(
T1
,
T2
)
elif
method
==
POLING_CONST
:
return
self
.
POLING_constant
*
log
(
T2
/
T1
)
elif
method
==
CRCSTD
:
return
self
.
CRCSTD_constant
*
log
(
T2
/
T1
)
elif
method
==
DADGOSTAR_SHAW
:
dS
=
(
Dadgostar_Shaw_integral_over_T
(
T2
,
self
.
similarity_variable
)
Dadgostar_Shaw_integral_over_T
(
T1
,
self
.
similarity_variable
)
)
return
property_mass_to_molar
(
dS
,
self
.
MW
)
elif
method
in
self
.
tabular_data
or
method
==
COOLPROP
or
method
in
[
ROWLINSON_POLING
,
ROWLINSON_BONDI
]
:
return
float
(
quad
(
lambda
T
:
self
.
calculate
(
T
,
method
)
/
T
,
T1
,
T2
)
[
0
]
)
else
:
raise
Exception
(
'Method not valid'
)

r Method to calculate the integral of a property over temperature with respect to temperature using a specified method . Implements the analytical integrals of all available methods except for tabular data the case of multiple coefficient sets needed to encompass the temperature range of any of the ZABRANSKY methods and the CSP methods using the vapor phase properties .


def calculate(self, T, method):
        r'''Method to calculate heat capacity of a solid at temperature `T`
        with a given method.

        This method has no exception handling; see `T_dependent_property`
        for that.

        Parameters
        ----------
        T : float
            Temperature at which to calculate heat capacity, [K]
        method : str
            Name of the method to use

        Returns
        -------
        Cp : float
            Heat capacity of the solid at T, [J/mol/K]
        '''
        if method == PERRY151:
            Cp = (self.PERRY151_const + self.PERRY151_lin*T
            + self.PERRY151_quadinv/T**2 + self.PERRY151_quad*T**2)*calorie
        elif method == CRCSTD:
            Cp = self.CRCSTD_Cp
        elif method == LASTOVKA_S:
            Cp = Lastovka_solid(T, self.similarity_variable)
            Cp = property_mass_to_molar(Cp, self.MW)
        elif method in self.tabular_data:
            Cp = self.interpolate(T, method)
        return Cp

def calculate ( self , T , method ) : r if method == PERRY151 : Cp = ( self . PERRY151_const + self . PERRY151_lin * T + self . PERRY151_quadinv / T ** 2 + self . PERRY151_quad * T ** 2 ) * calorie elif method == CRCSTD : Cp = self . CRCSTD_Cp elif method == LASTOVKA_S : Cp = Lastovka_solid ( T , self . similarity_variable ) Cp = property_mass_to_molar ( Cp , self . MW ) elif method in self . tabular_data : Cp = self . interpolate ( T , method ) return Cp

r Method to calculate heat capacity of a solid at temperature T with a given method .


def calculate(self, T, P, zs, ws, method):
        r'''Method to calculate heat capacity of a liquid mixture at
        temperature `T`, pressure `P`, mole fractions `zs` and weight fractions
        `ws` with a given method.

        This method has no exception handling; see `mixture_property`
        for that.

        Parameters
        ----------
        T : float
            Temperature at which to calculate the property, [K]
        P : float
            Pressure at which to calculate the property, [Pa]
        zs : list[float]
            Mole fractions of all species in the mixture, [-]
        ws : list[float]
            Weight fractions of all species in the mixture, [-]
        method : str
            Name of the method to use

        Returns
        -------
        Cplm : float
            Molar heat capacity of the liquid mixture at the given conditions,
            [J/mol]
        '''
        if method == SIMPLE:
            Cplms = [i(T) for i in self.HeatCapacityLiquids]
            return mixing_simple(zs, Cplms)
        elif method == LALIBERTE:
            ws = list(ws) ; ws.pop(self.index_w)
            Cpl = Laliberte_heat_capacity(T, ws, self.wCASs)
            MW = mixing_simple(zs, self.MWs)
            return property_mass_to_molar(Cpl, MW)
        else:
            raise Exception('Method not valid')

def
calculate
(
self
,
T
,
P
,
zs
,
ws
,
method
)
:
r
if
method
==
SIMPLE
:
Cplms
=
[
i
(
T
)
for
i
in
self
.
HeatCapacityLiquids
]
return
mixing_simple
(
zs
,
Cplms
)
elif
method
==
LALIBERTE
:
ws
=
list
(
ws
)
ws
.
pop
(
self
.
index_w
)
Cpl
=
Laliberte_heat_capacity
(
T
,
ws
,
self
.
wCASs
)
MW
=
mixing_simple
(
zs
,
self
.
MWs
)
return
property_mass_to_molar
(
Cpl
,
MW
)
else
:
raise
Exception
(
'Method not valid'
)

r Method to calculate heat capacity of a liquid mixture at temperature T pressure P mole fractions zs and weight fractions ws with a given method .


def calculate(self, T, P, zs, ws, method):
        r'''Method to calculate heat capacity of a solid mixture at
        temperature `T`, pressure `P`, mole fractions `zs` and weight fractions
        `ws` with a given method.

        This method has no exception handling; see `mixture_property`
        for that.

        Parameters
        ----------
        T : float
            Temperature at which to calculate the property, [K]
        P : float
            Pressure at which to calculate the property, [Pa]
        zs : list[float]
            Mole fractions of all species in the mixture, [-]
        ws : list[float]
            Weight fractions of all species in the mixture, [-]
        method : str
            Name of the method to use

        Returns
        -------
        Cpsm : float
            Molar heat capacity of the solid mixture at the given conditions, [J/mol]
        '''
        if method == SIMPLE:
            Cpsms = [i(T) for i in self.HeatCapacitySolids]
            return mixing_simple(zs, Cpsms)
        else:
            raise Exception('Method not valid')

def
calculate
(
self
,
T
,
P
,
zs
,
ws
,
method
)
:
r
if
method
==
SIMPLE
:
Cpsms
=
[
i
(
T
)
for
i
in
self
.
HeatCapacitySolids
]
return
mixing_simple
(
zs
,
Cpsms
)
else
:
raise
Exception
(
'Method not valid'
)

r Method to calculate heat capacity of a solid mixture at temperature T pressure P mole fractions zs and weight fractions ws with a given method .


def calculate(self, T, P, zs, ws, method):
        r'''Method to calculate heat capacity of a gas mixture at
        temperature `T`, pressure `P`, mole fractions `zs` and weight fractions
        `ws` with a given method.

        This method has no exception handling; see `mixture_property`
        for that.

        Parameters
        ----------
        T : float
            Temperature at which to calculate the property, [K]
        P : float
            Pressure at which to calculate the property, [Pa]
        zs : list[float]
            Mole fractions of all species in the mixture, [-]
        ws : list[float]
            Weight fractions of all species in the mixture, [-]
        method : str
            Name of the method to use

        Returns
        -------
        Cpgm : float
            Molar heat capacity of the gas mixture at the given conditions,
            [J/mol]
        '''
        if method == SIMPLE:
            Cpgms = [i(T) for i in self.HeatCapacityGases]
            return mixing_simple(zs, Cpgms)
        else:
            raise Exception('Method not valid')

def
calculate
(
self
,
T
,
P
,
zs
,
ws
,
method
)
:
r
if
method
==
SIMPLE
:
Cpgms
=
[
i
(
T
)
for
i
in
self
.
HeatCapacityGases
]
return
mixing_simple
(
zs
,
Cpgms
)
else
:
raise
Exception
(
'Method not valid'
)

r Method to calculate heat capacity of a gas mixture at temperature T pressure P mole fractions zs and weight fractions ws with a given method .


def K_value(P=None, Psat=None, phi_l=None, phi_g=None, gamma=None, Poynting=1):
    r'''Calculates the equilibrium K-value assuming Raoult's law,
    or an equation of state model, or an activity coefficient model,
    or a combined equation of state-activity model.

    The calculation procedure will use the most advanced approach with the
    provided inputs:

        * If `P`, `Psat`, `phi_l`, `phi_g`, and `gamma` are provided, use the
          combined approach.
        * If `P`, `Psat`, and `gamma` are provided, use the modified Raoult's
          law.
        * If `phi_l` and `phi_g` are provided, use the EOS only method.
        * If `P` and `Psat` are provided, use Raoult's law.

    Definitions:

    .. math::
        K_i=\frac{y_i}{x_i}

    Raoult's law:

    .. math::
        K_i = \frac{P_{i}^{sat}}{P}

    Activity coefficient, no EOS (modified Raoult's law):

    .. math::
        K_i = \frac{\gamma_i P_{i}^{sat}}{P}

    Equation of state only:

    .. math::
        K_i = \frac{\phi_i^l}{\phi_i^v} = \frac{f_i^l}{f_i^v}

    Combined approach (liquid reference fugacity coefficient is normally
    calculated the saturation pressure for it as a pure species; vapor fugacity
    coefficient calculated normally):

    .. math::
        K_i = \frac{\gamma_i P_i^{sat} \phi_i^{l,ref}}{\phi_i^v P}

    Combined approach, with Poynting Correction Factor (liquid molar volume in
    the integral is for i as a pure species only):

    .. math::
        K_i = \frac{\gamma_i P_i^{sat} \phi_i^{l, ref} \exp\left[\frac{
        \int_{P_i^{sat}}^P V_i^l dP}{RT}\right]}{\phi_i^v P}

    Parameters
    ----------
    P : float
        System pressure, optional
    Psat : float
        Vapor pressure of species i, [Pa]
    phi_l : float
        Fugacity coefficient of species i in the liquid phase, either
        at the system conditions (EOS-only case) or at the saturation pressure
        of species i as a pure species (reference condition for the combined
        approach), optional [-]
    phi_g : float
        Fugacity coefficient of species i in the vapor phase at the system
        conditions, optional [-]
    gamma : float
        Activity coefficient of species i in the liquid phase, optional [-]
    Poynting : float
        Poynting correction factor, optional [-]

    Returns
    -------
    K : float
        Equilibrium K value of component i, calculated with an approach
        depending on the provided inputs [-]

    Notes
    -----
    The Poynting correction factor is normally simplified as follows, due to
    a liquid's low pressure dependency:

    .. math::
        K_i = \frac{\gamma_i P_i^{sat} \phi_i^{l, ref} \exp\left[\frac{V_l
        (P-P_i^{sat})}{RT}\right]}{\phi_i^v P}

    Examples
    --------
    Raoult's law:

    >>> K_value(101325, 3000.)
    0.029607698001480384

    Modified Raoult's law:

    >>> K_value(P=101325, Psat=3000, gamma=0.9)
    0.026646928201332347

    EOS-only approach:

    >>> K_value(phi_l=1.6356, phi_g=0.88427)
    1.8496613025433408

    Gamma-phi combined approach:

    >>> K_value(P=1E6, Psat=1938800, phi_l=1.4356, phi_g=0.88427, gamma=0.92)
    2.8958055544121137

    Gamma-phi combined approach with a Poynting factor:

    >>> K_value(P=1E6, Psat=1938800, phi_l=1.4356, phi_g=0.88427, gamma=0.92,
    ... Poynting=0.999)
    2.8929097488577016

    References
    ----------
    .. [1] Gmehling, Jurgen, Barbel Kolbe, Michael Kleiber, and Jurgen Rarey.
       Chemical Thermodynamics for Process Simulation. 1st edition. Weinheim:
       Wiley-VCH, 2012.
    .. [2] Skogestad, Sigurd. Chemical and Energy Process Engineering. 1st
       edition. Boca Raton, FL: CRC Press, 2008.
    '''
    try:
        if gamma:
            if phi_l:
                return gamma*Psat*phi_l*Poynting/(phi_g*P)
            return gamma*Psat*Poynting/P
        elif phi_l:
            return phi_l/phi_g
        return Psat/P
    except TypeError:
        raise Exception('Input must consist of one set from (P, Psat, phi_l, \
phi_g, gamma), (P, Psat, gamma), (phi_l, phi_g), (P, Psat)')

'Input must consist of one set from (P, Psat, phi_l, \phi_g, gamma), (P, Psat, gamma), (phi_l, phi_g), (P, Psat)'

r Calculates the equilibrium K - value assuming Raoult s law or an equation of state model or an activity coefficient model or a combined equation of state - activity model .


def Rachford_Rice_flash_error(V_over_F, zs, Ks):
    r'''Calculates the objective function of the Rachford-Rice flash equation.
    This function should be called by a solver seeking a solution to a flash
    calculation. The unknown variable is `V_over_F`, for which a solution
    must be between 0 and 1.

    .. math::
        \sum_i \frac{z_i(K_i-1)}{1 + \frac{V}{F}(K_i-1)} = 0

    Parameters
    ----------
    V_over_F : float
        Vapor fraction guess [-]
    zs : list[float]
        Overall mole fractions of all species, [-]
    Ks : list[float]
        Equilibrium K-values, [-]

    Returns
    -------
    error : float
        Deviation between the objective function at the correct V_over_F
        and the attempted V_over_F, [-]

    Notes
    -----
    The derivation is as follows:

    .. math::
        F z_i = L x_i + V y_i

        x_i = \frac{z_i}{1 + \frac{V}{F}(K_i-1)}

        \sum_i y_i = \sum_i K_i x_i = 1

        \sum_i(y_i - x_i)=0

        \sum_i \frac{z_i(K_i-1)}{1 + \frac{V}{F}(K_i-1)} = 0

    Examples
    --------
    >>> Rachford_Rice_flash_error(0.5, zs=[0.5, 0.3, 0.2],
    ... Ks=[1.685, 0.742, 0.532])
    0.04406445591174976

    References
    ----------
    .. [1] Rachford, H. H. Jr, and J. D. Rice. "Procedure for Use of Electronic
       Digital Computers in Calculating Flash Vaporization Hydrocarbon
       Equilibrium." Journal of Petroleum Technology 4, no. 10 (October 1,
       1952): 19-3. doi:10.2118/952327-G.
    '''
    return sum([zi*(Ki-1.)/(1.+V_over_F*(Ki-1.)) for Ki, zi in zip(Ks, zs)])

def Rachford_Rice_flash_error ( V_over_F , zs , Ks ) : r return sum ( [ zi * ( Ki - 1. ) / ( 1. + V_over_F * ( Ki - 1. ) ) for Ki , zi in zip ( Ks , zs ) ] )

r Calculates the objective function of the Rachford - Rice flash equation . This function should be called by a solver seeking a solution to a flash calculation . The unknown variable is V_over_F for which a solution must be between 0 and 1 .


def Wilson(xs, params):
    r'''Calculates the activity coefficients of each species in a mixture
    using the Wilson method, given their mole fractions, and
    dimensionless interaction parameters. Those are normally correlated with
    temperature, and need to be calculated separately.

    .. math::
        \ln \gamma_i = 1 - \ln \left(\sum_j^N \Lambda_{ij} x_j\right)
        -\sum_j^N \frac{\Lambda_{ji}x_j}{\displaystyle\sum_k^N \Lambda_{jk}x_k}

    Parameters
    ----------
    xs : list[float]
        Liquid mole fractions of each species, [-]
    params : list[list[float]]
        Dimensionless interaction parameters of each compound with each other,
        [-]

    Returns
    -------
    gammas : list[float]
        Activity coefficient for each species in the liquid mixture, [-]

    Notes
    -----
    This model needs N^2 parameters.

    The original model correlated the interaction parameters using the standard
    pure-component molar volumes of each species at 25°C, in the following form:

    .. math::
        \Lambda_{ij} = \frac{V_j}{V_i} \exp\left(\frac{-\lambda_{i,j}}{RT}\right)

    However, that form has less flexibility and offered no advantage over
    using only regressed parameters.

    Most correlations for the interaction parameters include some of the terms
    shown in the following form:

    .. math::
        \ln \Lambda_{ij} =a_{ij}+\frac{b_{ij}}{T}+c_{ij}\ln T + d_{ij}T
        + \frac{e_{ij}}{T^2} + h_{ij}{T^2}

    The Wilson model is not applicable to liquid-liquid systems.

    Examples
    --------
    Ethanol-water example, at 343.15 K and 1 MPa:

    >>> Wilson([0.252, 0.748], [[1, 0.154], [0.888, 1]])
    [1.8814926087178843, 1.1655774931125487]

    References
    ----------
    .. [1] Wilson, Grant M. "Vapor-Liquid Equilibrium. XI. A New Expression for
       the Excess Free Energy of Mixing." Journal of the American Chemical
       Society 86, no. 2 (January 1, 1964): 127-130. doi:10.1021/ja01056a002.
    .. [2] Gmehling, Jurgen, Barbel Kolbe, Michael Kleiber, and Jurgen Rarey.
       Chemical Thermodynamics for Process Simulation. 1st edition. Weinheim:
       Wiley-VCH, 2012.
    '''
    gammas = []
    cmps = range(len(xs))
    for i in cmps:
        tot1 = log(sum([params[i][j]*xs[j] for j in cmps]))
        tot2 = 0.
        for j in cmps:
            tot2 += params[j][i]*xs[j]/sum([params[j][k]*xs[k] for k in cmps])

        gamma = exp(1. - tot1 - tot2)
        gammas.append(gamma)
    return gammas

def Wilson ( xs , params ) : r gammas = [ ] cmps = range ( len ( xs ) ) for i in cmps : tot1 = log ( sum ( [ params [ i ] [ j ] * xs [ j ] for j in cmps ] ) ) tot2 = 0. for j in cmps : tot2 += params [ j ] [ i ] * xs [ j ] / sum ( [ params [ j ] [ k ] * xs [ k ] for k in cmps ] ) gamma = exp ( 1. - tot1 - tot2 ) gammas . append ( gamma ) return gammas

r Calculates the activity coefficients of each species in a mixture using the Wilson method given their mole fractions and dimensionless interaction parameters . Those are normally correlated with temperature and need to be calculated separately .


def identify_phase(T, P, Tm=None, Tb=None, Tc=None, Psat=None):
    r'''Determines the phase of a one-species chemical system according to
    basic rules, using whatever information is available. Considers only the
    phases liquid, solid, and gas; does not consider two-phase
    scenarios, as should occurs between phase boundaries.

    * If the melting temperature is known and the temperature is under or equal
      to it, consider it a solid.
    * If the critical temperature is known and the temperature is greater or
      equal to it, consider it a gas.
    * If the vapor pressure at `T` is known and the pressure is under or equal
      to it, consider it a gas. If the pressure is greater than the vapor
      pressure, consider it a liquid.
    * If the melting temperature, critical temperature, and vapor pressure are
      not known, attempt to use the boiling point to provide phase information.
      If the pressure is between 90 kPa and 110 kPa (approximately normal),
      consider it a liquid if it is under the boiling temperature and a gas if
      above the boiling temperature.
    * If the pressure is above 110 kPa and the boiling temperature is known,
      consider it a liquid if the temperature is under the boiling temperature.
    * Return None otherwise.

    Parameters
    ----------
    T : float
        Temperature, [K]
    P : float
        Pressure, [Pa]
    Tm : float, optional
        Normal melting temperature, [K]
    Tb : float, optional
        Normal boiling point, [K]
    Tc : float, optional
        Critical temperature, [K]
    Psat : float, optional
        Vapor pressure of the fluid at `T`, [Pa]

    Returns
    -------
    phase : str
        Either 's', 'l', 'g', or None if the phase cannot be determined

    Notes
    -----
    No special attential is paid to any phase transition. For the case where
    the melting point is not provided, the possibility of the fluid being solid
    is simply ignored.

    Examples
    --------
    >>> identify_phase(T=280, P=101325, Tm=273.15, Psat=991)
    'l'
    '''
    if Tm and T <= Tm:
        return 's'
    elif Tc and T >= Tc:
        # No special return value for the critical point
        return 'g'
    elif Psat:
        # Do not allow co-existence of phases; transition to 'l' directly under
        if P <= Psat:
            return 'g'
        elif P > Psat:
            return 'l'
    elif Tb:
        # Crude attempt to model phases without Psat
        # Treat Tb as holding from 90 kPa to 110 kPa
        if 9E4 < P < 1.1E5:
            if T < Tb:
                return  'l'
            else:
                return 'g'
        elif P > 1.1E5 and T <= Tb:
            # For the higher-pressure case, it is definitely liquid if under Tb
            # Above the normal boiling point, impossible to say - return None
            return 'l'
        else:
            return None
    else:
        return None

def identify_phase ( T , P , Tm = None , Tb = None , Tc = None , Psat = None ) : r if Tm and T <= Tm : return 's' elif Tc and T >= Tc : return 'g' elif Psat : if P <= Psat : return 'g' elif P > Psat : return 'l' elif Tb : if 9E4 < P < 1.1E5 : if T < Tb : return 'l' else : return 'g' elif P > 1.1E5 and T <= Tb : return 'l' else : return None else : return None

r Determines the phase of a one - species chemical system according to basic rules using whatever information is available . Considers only the phases liquid solid and gas ; does not consider two - phase scenarios as should occurs between phase boundaries .


def bubble_at_P(P, zs, vapor_pressure_eqns, fugacities=None, gammas=None):
    '''Calculates bubble point for a given pressure

    Parameters
    ----------
    P : float
        Pressure, [Pa]
    zs : list[float]
        Overall mole fractions of all species, [-]
    vapor_pressure_eqns : list[functions]
        Temperature dependent function for each specie, Returns Psat, [Pa]
    fugacities : list[float], optional
        fugacities of each species, defaults to list of ones, [-]
    gammas : list[float], optional
        gammas of each species, defaults to list of ones, [-]

    Returns
    -------
    Tbubble : float, optional
        Temperature of bubble point at pressure `P`, [K]

    '''

    def bubble_P_error(T):
        Psats = [VP(T) for VP in vapor_pressure_eqns]
        Pcalc = bubble_at_T(zs, Psats, fugacities, gammas)

        return P - Pcalc

    T_bubble = newton(bubble_P_error, 300)

    return T_bubble

def bubble_at_P ( P , zs , vapor_pressure_eqns , fugacities = None , gammas = None ) : def bubble_P_error ( T ) : Psats = [ VP ( T ) for VP in vapor_pressure_eqns ] Pcalc = bubble_at_T ( zs , Psats , fugacities , gammas ) return P - Pcalc T_bubble = newton ( bubble_P_error , 300 ) return T_bubble


def draw_2d(self, width=300, height=300, Hs=False): # pragma: no cover
        r'''Interface for drawing a 2D image of the molecule.
        Requires an HTML5 browser, and the libraries RDKit and
        IPython. An exception is raised if either of these libraries is
        absent.

        Parameters
        ----------
        width : int
            Number of pixels wide for the view
        height : int
            Number of pixels tall for the view
        Hs : bool
            Whether or not to show hydrogen

        Examples
        --------
        >>> Chemical('decane').draw_2d() # doctest: +ELLIPSIS
        <PIL.Image.Image image mode=RGBA size=300x300 at 0x...>
        '''
        try:
            from rdkit.Chem import Draw
            from rdkit.Chem.Draw import IPythonConsole
            if Hs:
                mol = self.rdkitmol_Hs
            else:
                mol = self.rdkitmol
            return Draw.MolToImage(mol, size=(width, height))
        except:
            return 'Rdkit is required for this feature.'

def
draw_2d
(
self
,
width
=
300
,
height
=
300
,
Hs
=
False
)
:
r
try
:
from
rdkit
.
Chem
import
Draw
from
rdkit
.
Chem
.
Draw
import
IPythonConsole
if
Hs
:
mol
=
self
.
rdkitmol_Hs
else
:
mol
=
self
.
rdkitmol
return
Draw
.
MolToImage
(
mol
,
size
=
(
width
,
height
)
)
except
:
return
'Rdkit is required for this feature.'

r Interface for drawing a 2D image of the molecule . Requires an HTML5 browser and the libraries RDKit and IPython . An exception is raised if either of these libraries is absent .


def draw_3d(self, width=300, height=500, style='stick', Hs=True): # pragma: no cover
        r'''Interface for drawing an interactive 3D view of the molecule.
        Requires an HTML5 browser, and the libraries RDKit, pymol3D, and
        IPython. An exception is raised if all three of these libraries are
        not installed.

        Parameters
        ----------
        width : int
            Number of pixels wide for the view
        height : int
            Number of pixels tall for the view
        style : str
            One of 'stick', 'line', 'cross', or 'sphere'
        Hs : bool
            Whether or not to show hydrogen

        Examples
        --------
        >>> Chemical('cubane').draw_3d()
        <IPython.core.display.HTML object>
        '''
        try:
            import py3Dmol
            from IPython.display import display
            if Hs:
                mol = self.rdkitmol_Hs
            else:
                mol = self.rdkitmol
            AllChem.EmbedMultipleConfs(mol)
            mb = Chem.MolToMolBlock(mol)
            p = py3Dmol.view(width=width,height=height)
            p.addModel(mb,'sdf')
            p.setStyle({style:{}})
            p.zoomTo()
            display(p.show())
        except:
            return 'py3Dmol, RDKit, and IPython are required for this feature.'

r Interface for drawing an interactive 3D view of the molecule . Requires an HTML5 browser and the libraries RDKit pymol3D and IPython . An exception is raised if all three of these libraries are not installed .


def charge(self):
        r'''Charge of a chemical, computed with RDKit from a chemical's SMILES.
        If RDKit is not available, holds None.

        Examples
        --------
        >>> Chemical('sodium ion').charge
        1
        '''
        try:
            if not self.rdkitmol:
                return charge_from_formula(self.formula)
            else:
                return Chem.GetFormalCharge(self.rdkitmol)
        except:
            return charge_from_formula(self.formula)

def charge ( self ) : r try : if not self . rdkitmol : return charge_from_formula ( self . formula ) else : return Chem . GetFormalCharge ( self . rdkitmol ) except : return charge_from_formula ( self . formula )

r Charge of a chemical computed with RDKit from a chemical s SMILES . If RDKit is not available holds None .


def rdkitmol(self):
        r'''RDKit object of the chemical, without hydrogen. If RDKit is not
        available, holds None.

        For examples of what can be done with RDKit, see
        `their website <http://www.rdkit.org/docs/GettingStartedInPython.html>`_.
        '''
        if self.__rdkitmol:
            return self.__rdkitmol
        else:
            try:
                self.__rdkitmol = Chem.MolFromSmiles(self.smiles)
                return self.__rdkitmol
            except:
                return None

def rdkitmol ( self ) : r if self . __rdkitmol : return self . __rdkitmol else : try : self . __rdkitmol = Chem . MolFromSmiles ( self . smiles ) return self . __rdkitmol except : return None

r RDKit object of the chemical without hydrogen . If RDKit is not available holds None .


def rdkitmol_Hs(self):
        r'''RDKit object of the chemical, with hydrogen. If RDKit is not
        available, holds None.

        For examples of what can be done with RDKit, see
        `their website <http://www.rdkit.org/docs/GettingStartedInPython.html>`_.
        '''
        if self.__rdkitmol_Hs:
            return self.__rdkitmol_Hs
        else:
            try:
                self.__rdkitmol_Hs = Chem.AddHs(self.rdkitmol)
                return self.__rdkitmol_Hs
            except:
                return None

def rdkitmol_Hs ( self ) : r if self . __rdkitmol_Hs : return self . __rdkitmol_Hs else : try : self . __rdkitmol_Hs = Chem . AddHs ( self . rdkitmol ) return self . __rdkitmol_Hs except : return None

r RDKit object of the chemical with hydrogen . If RDKit is not available holds None .


def legal_status(self):
        r'''Dictionary of legal status indicators for the chemical.

        Examples
        --------
        >>> pprint(Chemical('benzene').legal_status)
        {'DSL': 'LISTED',
         'EINECS': 'LISTED',
         'NLP': 'UNLISTED',
         'SPIN': 'LISTED',
         'TSCA': 'LISTED'}
        '''
        if self.__legal_status:
            return self.__legal_status
        else:
            self.__legal_status = legal_status(self.CAS, Method='COMBINED')
            return self.__legal_status

def legal_status ( self ) : r if self . __legal_status : return self . __legal_status else : self . __legal_status = legal_status ( self . CAS , Method = 'COMBINED' ) return self . __legal_status

r Dictionary of legal status indicators for the chemical .


def economic_status(self):
        r'''Dictionary of economic status indicators for the chemical.

        Examples
        --------
        >>> pprint(Chemical('benzene').economic_status)
        ["US public: {'Manufactured': 6165232.1, 'Imported': 463146.474, 'Exported': 271908.252}",
         u'1,000,000 - 10,000,000 tonnes per annum',
         u'Intermediate Use Only',
         'OECD HPV Chemicals']
        '''
        if self.__economic_status:
            return self.__economic_status
        else:
            self.__economic_status = economic_status(self.CAS, Method='Combined')
            return self.__economic_status

def economic_status ( self ) : r if self . __economic_status : return self . __economic_status else : self . __economic_status = economic_status ( self . CAS , Method = 'Combined' ) return self . __economic_status

r Dictionary of economic status indicators for the chemical .


def T_converter(T, current, desired):
    r'''Converts the a temperature reading made in any of the scales
    'ITS-90', 'ITS-68','ITS-48', 'ITS-76', or 'ITS-27' to any of the other
    scales. Not all temperature ranges can be converted to other ranges; for
    instance, 'ITS-76' is purely for low temperatures, and 5 K on it has no
    conversion to 'ITS-90' or any other scale. Both a conversion to ITS-90 and
    to the desired scale must be possible for the conversion to occur.
    The conversion uses cubic spline interpolation.

    ITS-68 conversion is valid from 14 K to 4300 K.
    ITS-48 conversion is valid from 93.15 K to 4273.15 K
    ITS-76 conversion is valid from 5 K to 27 K.
    ITS-27 is valid from 903.15 K to 4273.15 k.

    Parameters
    ----------
    T : float
        Temperature, on `current` scale [K]
    current : str
        String representing the scale T is in, 'ITS-90', 'ITS-68',
        'ITS-48', 'ITS-76', or 'ITS-27'.
    desired : str
        String representing the scale T will be returned in, 'ITS-90',
        'ITS-68', 'ITS-48', 'ITS-76', or 'ITS-27'.

    Returns
    -------
    T : float
        Temperature, on scale `desired` [K]

    Notes
    -----
    Because the conversion is performed by spline functions, a re-conversion
    of a value will not yield exactly the original value. However, it is quite
    close.

    The use of splines is quite quick (20 micro seconds/calculation). While
    just a spline for one-way conversion could be used, a numerical solver
    would have to be used to obtain an exact result for the reverse conversion.
    This was found to take approximately 1 ms/calculation, depending on the
    region.

    Examples
    --------
    >>> T_converter(500, 'ITS-68', 'ITS-48')
    499.9470092992346

    References
    ----------
    .. [1] Wier, Ron D., and Robert N. Goldberg. "On the Conversion of
       Thermodynamic Properties to the Basis of the International Temperature
       Scale of 1990." The Journal of Chemical Thermodynamics 28, no. 3
       (March 1996): 261-76. doi:10.1006/jcht.1996.0026.
    .. [2] Goldberg, Robert N., and R. D. Weir. "Conversion of Temperatures
       and Thermodynamic Properties to the Basis of the International
       Temperature Scale of 1990 (Technical Report)." Pure and Applied
       Chemistry 64, no. 10 (1992): 1545-1562. doi:10.1351/pac199264101545.
    '''
    def range_check(T, Tmin, Tmax):
        if T < Tmin or T > Tmax:
            raise Exception('Temperature conversion is outside one or both scales')

    try:
        if current == 'ITS-90':
            pass
        elif current == 'ITS-68':
            range_check(T, 13.999, 4300.0001)
            T = T68_to_T90(T)
        elif current == 'ITS-76':
            range_check(T, 4.9999, 27.0001)
            T = T76_to_T90(T)
        elif current == 'ITS-48':
            range_check(T, 93.149999, 4273.15001)
            T = T48_to_T90(T)
        elif current == 'ITS-27':
            range_check(T, 903.15, 4273.15)
            T = T27_to_T90(T)
        else:
            raise Exception('Current scale not supported')
        # T should be in ITS-90 now

        if desired == 'ITS-90':
            pass
        elif desired == 'ITS-68':
            range_check(T, 13.999, 4300.0001)
            T = T90_to_T68(T)
        elif desired == 'ITS-76':
            range_check(T, 4.9999, 27.0001)
            T = T90_to_T76(T)
        elif desired == 'ITS-48':
            range_check(T, 93.149999, 4273.15001)
            T = T90_to_T48(T)
        elif desired == 'ITS-27':
            range_check(T, 903.15, 4273.15)
            T = T90_to_T27(T)
        else:
            raise Exception('Desired scale not supported')
    except ValueError:
        raise Exception('Temperature could not be converted to desired scale')
    return float(T)

r Converts the a temperature reading made in any of the scales ITS - 90 ITS - 68 ITS - 48 ITS - 76 or ITS - 27 to any of the other scales . Not all temperature ranges can be converted to other ranges ; for instance ITS - 76 is purely for low temperatures and 5 K on it has no conversion to ITS - 90 or any other scale . Both a conversion to ITS - 90 and to the desired scale must be possible for the conversion to occur . The conversion uses cubic spline interpolation .


def GWP(CASRN, AvailableMethods=False, Method=None):
    r'''This function handles the retrieval of a chemical's Global Warming
    Potential, relative to CO2. 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.

    Returns the GWP for the 100yr outlook by default.

    Parameters
    ----------
    CASRN : string
        CASRN [-]

    Returns
    -------
    GWP : float
        Global warming potential, [(impact/mass chemical)/(impact/mass CO2)]
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to obtain GWP with the
        given inputs

    Other Parameters
    ----------------
    Method : string, optional
        The method name to use. Accepted methods are IPCC (2007) 100yr',
        'IPCC (2007) 100yr-SAR', 'IPCC (2007) 20yr', and 'IPCC (2007) 500yr'.
        All valid values are also held in the list GWP_methods.
    AvailableMethods : bool, optional
        If True, function will determine which methods can be used to obtain
        the GWP for the desired chemical, and will return methods
        instead of the GWP

    Notes
    -----
    All data is from [1]_, the official source. Several chemicals are available
    in [1]_ are not included here as they do not have a CAS.
    Methods are 'IPCC (2007) 100yr', 'IPCC (2007) 100yr-SAR',
    'IPCC (2007) 20yr', and 'IPCC (2007) 500yr'.

    Examples
    --------
    Methane, 100-yr outlook

    >>> GWP(CASRN='74-82-8')
    25.0

    References
    ----------
    .. [1] IPCC. "2.10.2 Direct Global Warming Potentials - AR4 WGI Chapter 2:
       Changes in Atmospheric Constituents and in Radiative Forcing." 2007.
       https://www.ipcc.ch/publications_and_data/ar4/wg1/en/ch2s2-10-2.html.
    '''
    def list_methods():
        methods = []
        if CASRN in GWP_data.index:
            methods.append(IPCC100)
            if not pd.isnull(GWP_data.at[CASRN, 'SAR 100yr']):
                methods.append(IPCC100SAR)
            methods.append(IPCC20)
            methods.append(IPCC500)
        methods.append(NONE)
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]

    if Method == IPCC100:
        return float(GWP_data.at[CASRN, '100yr GWP'])
    elif Method == IPCC100SAR:
        return float(GWP_data.at[CASRN, 'SAR 100yr'])
    elif Method == IPCC20:
        return float(GWP_data.at[CASRN, '20yr GWP'])
    elif Method == IPCC500:
        return float(GWP_data.at[CASRN, '500yr GWP'])
    elif Method == NONE:
        return None
    else:
        raise Exception('Failure in in function')

def
GWP
(
CASRN
,
AvailableMethods
=
False
,
Method
=
)
:
r
def
list_methods
(
)
:
methods
=
[
]
if
CASRN
in
GWP_data
.
index
:
methods
.
append
(
IPCC100
)
if
not
pd
.
isnull
(
GWP_data
.
at
[
CASRN
,
'SAR 100yr'
]
)
:
methods
.
append
(
IPCC100SAR
)
methods
.
append
(
IPCC20
)
methods
.
append
(
IPCC500
)
methods
.
append
(
)
return
methods
if
AvailableMethods
:
return
list_methods
(
)
if
not
Method
:
Method
=
list_methods
(
)
[
0
]
if
Method
==
IPCC100
:
return
float
(
GWP_data
.
at
[
CASRN
,
'100yr GWP'
]
)
elif
Method
==
IPCC100SAR
:
return
float
(
GWP_data
.
at
[
CASRN
,
'SAR 100yr'
]
)
elif
Method
==
IPCC20
:
return
float
(
GWP_data
.
at
[
CASRN
,
'20yr GWP'
]
)
elif
Method
==
IPCC500
:
return
float
(
GWP_data
.
at
[
CASRN
,
'500yr GWP'
]
)
elif
Method
==
:
return
else
:
raise
Exception
(
'Failure in in function'
)

r This function handles the retrieval of a chemical s Global Warming Potential relative to CO2 . 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 .