-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathbase.py
126 lines (101 loc) · 3.85 KB
/
base.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# -*- coding: utf-8 -*-
from decimal import *
class BaseAQI(object):
"""A generic AQI class"""
def iaqi(self, elem, cc):
"""Calculate an intermediate AQI for a given pollutant. This is
the heart of the algo. Return the IAQI for the given pollutant.
.. warning:: the concentration is passed as a string so
:class:`decimal.Decimal` doesn't act up with binary floats.
:param elem: pollutant constant
:type elem: int
:param cc: pollutant contentration (µg/m³ or ppm)
:type cc: str
"""
raise NotImplementedError
def aqi(self, ccs, iaqis=False):
"""Calculate the AQI based on a list of pollutants. Return an
AQI value, if `iaqis` is set to True, send back a tuple
containing the AQI and a dict of IAQIs.
:param ccs: a list of tuples of pollutants concentrations with
pollutant constant and concentration as values
:type ccs: list
:param iaqis: return IAQIs with result
:type iaqis: bool
"""
_iaqis = {}
for (elem, cc) in ccs:
_iaqi = self.iaqi(elem, cc)
if _iaqi is not None:
_iaqis[elem] = _iaqi
_aqi = max(_iaqis.values())
if iaqis:
return (_aqi, _iaqis)
else:
return _aqi
def cc(self, elem, iaqi):
"""Calculate a concentration for a given pollutant. Return the
concentration for the given pollutant based on the intermediate AQI.
.. warning:: the intermediate AQI is passed as a string
:param elem: pollutant constant
:type elem: int
:param cc: intermediate AQI
:type cc: str
"""
raise NotImplementedError
def list_pollutants(self):
"""List pollutants covered by an algorithm, return a list of
pollutant names.
"""
raise NotImplementedError
class PiecewiseAQI(BaseAQI):
"""A piecewise function AQI class (like EPA or MEP)"""
piecewise = None
def iaqi(self, elem, cc):
if self.piecewise is None:
raise NameError("piecewise struct is not defined")
if elem not in self.piecewise['bp'].keys():
return None
_cc = Decimal(cc).quantize(self.piecewise['prec'][elem],
rounding=ROUND_DOWN)
# define breakpoints for this pollutant at this contentration
bps = self.piecewise['bp'][elem]
bplo = None
bphi = None
idx = 0
for bp in bps:
if _cc >= bp[0] and _cc <= bp[1]:
bplo = bp[0]
bphi = bp[1]
break
idx += 1
# get corresponding AQI boundaries
(aqilo, aqihi) = self.piecewise['aqi'][idx]
# equation
value = (aqihi - aqilo) / (bphi - bplo) * (_cc - bplo) + aqilo
return value.quantize(Decimal('1.'), rounding=ROUND_HALF_EVEN)
def cc(self, elem, iaqi):
if self.piecewise is None:
raise NameError("piecewise struct is not defined")
if elem not in self.piecewise['bp'].keys():
return None
_iaqi = int(iaqi)
# define aqi breakpoints for this pollutant at this IAQI
bps = self.piecewise['aqi']
bplo = None
bphi = None
idx = 0
for bp in bps:
if _iaqi >= bp[0] and _iaqi <= bp[1]:
bplo = bp[0]
bphi = bp[1]
break
idx += 1
# get corresponding concentration boundaries
(cclo, cchi) = self.piecewise['bp'][elem][idx]
# equation
value = (cchi - cclo) / (bphi - bplo) * (_iaqi - bplo) + cclo
return Decimal(value).quantize(self.piecewise['prec'][elem],
rounding=ROUND_DOWN)
def list_pollutants(self):
return self.piecewise['units'].items()