David Saylor commited on
Commit Β·
24fbee3
1
Parent(s): 53aedd4
blueprint for exposure module
Browse files- CHRIS.py +4 -169
- color_module/templates/index.html +2 -2
- exposure_module/__init__.py +5 -0
- exposure_module/exposure.py +98 -0
- {static β exposure_module/static}/exposure_COU.md +0 -0
- exposure_module/static/images/FDAgraphic.png +3 -0
- exposure_module/static/images/FDAlogo.png +3 -0
- {static β exposure_module/static}/md2html.sh +0 -0
- {templates β exposure_module/templates}/exposure_index.html +1 -1
- {templates β exposure_module/templates}/exposure_report.html +0 -0
- functions.py +1 -1
- static/exposure_COU.html +0 -45
CHRIS.py
CHANGED
|
@@ -1,67 +1,4 @@
|
|
| 1 |
-
import
|
| 2 |
-
import numpy as np
|
| 3 |
-
from flask import Flask, render_template, request
|
| 4 |
-
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
|
| 5 |
-
import matplotlib
|
| 6 |
-
matplotlib.use('Agg')
|
| 7 |
-
import matplotlib.pyplot as plt
|
| 8 |
-
import io
|
| 9 |
-
import base64
|
| 10 |
-
|
| 11 |
-
def sigfigs(number, n):
|
| 12 |
-
return round(number, n - int(math.floor(math.log10(math.fabs(number)))) - 1)
|
| 13 |
-
|
| 14 |
-
# Named polymer matrices and category numbers
|
| 15 |
-
nPoly = 20
|
| 16 |
-
PolyData = np.zeros((nPoly,), dtype=[('name', 'a75'), ('Category', 'i')])
|
| 17 |
-
PolyData[0] = ('Silicone', 0)
|
| 18 |
-
PolyData[1] = ('Polyethylene (density <= 0.94 g/cm3)', 1)
|
| 19 |
-
PolyData[2] = ('Polyethylene (density > 0.94 g/cm3)', 2)
|
| 20 |
-
PolyData[3] = ('Polyethylene terephthalate', 3)
|
| 21 |
-
PolyData[4] = ('Polyurethane (polyether)', 1)
|
| 22 |
-
PolyData[5] = ('Polycarbonate', 3)
|
| 23 |
-
PolyData[6] = ('Polyoxymethylene', 2)
|
| 24 |
-
PolyData[7] = ('Poly(methyl methacrylate)', 3)
|
| 25 |
-
PolyData[8] = ('Acrylonitrile butadiene styrene', 2)
|
| 26 |
-
PolyData[9] = ('Polyether block amide', 1)
|
| 27 |
-
PolyData[10] = ('Polyamide', 3)
|
| 28 |
-
PolyData[11] = ('Polystyrene', 3)
|
| 29 |
-
PolyData[12] = ('Polyvinyl chloride (plasticized)', 0)
|
| 30 |
-
PolyData[13] = ('Polytetrafluoroethylene', 2)
|
| 31 |
-
PolyData[14] = ('Polyvinyl acetate', 1)
|
| 32 |
-
PolyData[15] = ('Polypropylene', 2)
|
| 33 |
-
PolyData[16] = ('Polybutylene terephthalate', 3)
|
| 34 |
-
PolyData[17] = ('Polyetheretherketone', 3)
|
| 35 |
-
PolyData[18] = ('Fluorinated ethylene propylene', 2)
|
| 36 |
-
PolyData[19] = ('Other polymer', 4)
|
| 37 |
-
|
| 38 |
-
nCA = 14
|
| 39 |
-
caData = np.zeros((nPoly,), dtype=[('name', 'a75'), ('TI', 'd'), ('MW', 'd')])
|
| 40 |
-
caData[0] = ('Titanium dioxide (CAS#:13463-67-7)', 1.0, 1100.)
|
| 41 |
-
caData[1] = ('Carbon black (CAS#:1333-86-4)', 2.0, 1100.)
|
| 42 |
-
caData[2] = ('Pigment brown 24 (CAS#:68186-90-3)', 0.5, 1100.)
|
| 43 |
-
caData[3] = ('Zinc Oxide (CAS#:1314-13-2)', 0.05, 1100.)
|
| 44 |
-
caData[4] = ('Pigment Red 101 (CAS#: 1309-37-1)', 1.0, 1100.)
|
| 45 |
-
caData[5] = ('Solvent violet 13 (CAS#:81-48-1)', 0.0013, 319.4)
|
| 46 |
-
caData[6] = ('Manganese phthalocyanine (CAS#:14325-24-7)', 0.15, 567.5)
|
| 47 |
-
caData[7] = ('Pigment blue 15 (CAS#:147-14-8)', 0.15, 576.1)
|
| 48 |
-
caData[8] = ('Phthalocyanine green (CAS#:1326-53-6)', 0.15, 1092.8)
|
| 49 |
-
caData[9] = ('Ultramarine blue (CAS#:57445-37-5)', 3.3, 1100.)
|
| 50 |
-
caData[10] = ('Pigment Yellow 138 (CAS#:30125-47-4)', 1.0, 693.96)
|
| 51 |
-
caData[11] = ('Other metal oxide color additive', 1.0, 1100.0)
|
| 52 |
-
caData[12] = ('Other non-metal oxide color additive', 1.0, 1100.0)
|
| 53 |
-
caData[13] = ('Other compound (non-color additive)', 1.0, 1100.0)
|
| 54 |
-
|
| 55 |
-
polymers = np.zeros(nPoly, dtype='object')
|
| 56 |
-
for i in range(nPoly):
|
| 57 |
-
polymers[i] = PolyData[i][0].decode('UTF-8')
|
| 58 |
-
|
| 59 |
-
CAs = np.zeros(nCA, dtype='object')
|
| 60 |
-
caMW = np.zeros(nCA, dtype='object')
|
| 61 |
-
for i in range(nCA):
|
| 62 |
-
CAs[i] = caData[i][0].decode('UTF-8')
|
| 63 |
-
for i in range(nCA):
|
| 64 |
-
caMW[i] = caData[i][2]
|
| 65 |
|
| 66 |
app = Flask(__name__)
|
| 67 |
app.debug = True
|
|
@@ -69,114 +6,12 @@ app.debug = True
|
|
| 69 |
from color_module import blueprint
|
| 70 |
app.register_blueprint(blueprint)
|
| 71 |
|
|
|
|
|
|
|
|
|
|
| 72 |
@app.route('/', methods=['GET'])
|
| 73 |
def app_init():
|
| 74 |
return render_template('main.html')
|
| 75 |
|
| 76 |
-
@app.route('/exposure', methods=['GET'])
|
| 77 |
-
def exposure():
|
| 78 |
-
return render_template('exposure_index.html', polymers=polymers, CAs=CAs, caMW=caMW)
|
| 79 |
-
|
| 80 |
-
@app.route('/exposure', methods=['POST'])
|
| 81 |
-
def exp_post():
|
| 82 |
-
amount = float(request.form["amount"])
|
| 83 |
-
mass = float(request.form["mass"])
|
| 84 |
-
density = float(request.form["density"])
|
| 85 |
-
vol = mass / density
|
| 86 |
-
polymer = request.form["polymer"]
|
| 87 |
-
pIndex = (np.where(polymers == polymer)[0])[0]
|
| 88 |
-
area = float(request.form["area"])
|
| 89 |
-
exposure = request.form["exposure"]
|
| 90 |
-
MW = float(request.form["MW"])
|
| 91 |
-
chemName = '*' + request.form["chemName"] + '*'
|
| 92 |
-
|
| 93 |
-
if exposure != "limited":
|
| 94 |
-
time = 24.
|
| 95 |
-
else:
|
| 96 |
-
time = float(request.form["exptime"])
|
| 97 |
-
if exposure != "long-term":
|
| 98 |
-
TTC = 0.12
|
| 99 |
-
else:
|
| 100 |
-
TTC = 0.0015
|
| 101 |
-
|
| 102 |
-
assume1 = request.form.get("assume1") is not None
|
| 103 |
-
assume2 = request.form.get("assume2") is not None
|
| 104 |
-
assume3 = request.form.get("assume3") is not None
|
| 105 |
-
assume4 = request.form.get("assume4") is not None
|
| 106 |
-
assume5 = request.form.get("assume5") is not None
|
| 107 |
-
|
| 108 |
-
assume = np.array((assume1, assume2, assume3, assume4, assume5))
|
| 109 |
-
|
| 110 |
-
release, diff = calcexposure(MW, amount, vol, area, time, pIndex)
|
| 111 |
-
|
| 112 |
-
MOS = TTC / release
|
| 113 |
-
|
| 114 |
-
release = sigfigs(release, 2)
|
| 115 |
-
MOS = sigfigs(MOS, 2)
|
| 116 |
-
diff = sigfigs(diff, 2)
|
| 117 |
-
|
| 118 |
-
fig, ax = plt.subplots(figsize=(6, 4))
|
| 119 |
-
plt.subplots_adjust(left=0.15, bottom=0.15, right=0.95, top=0.95, wspace=0.0, hspace=0.0)
|
| 120 |
-
tarray = np.arange(1.,31.,1.)
|
| 121 |
-
rates = calcrates(MW, amount, vol, area, tarray, pIndex)
|
| 122 |
-
ax.plot(tarray,rates,'o')
|
| 123 |
-
ax.set(
|
| 124 |
-
xlabel='time (days)',
|
| 125 |
-
ylabel='release rate (mg/day)',
|
| 126 |
-
)
|
| 127 |
-
pngImage = io.BytesIO()
|
| 128 |
-
FigureCanvas(fig).print_png(pngImage)
|
| 129 |
-
pngImageB64String = "data:image/png;base64,"
|
| 130 |
-
pngImageB64String += base64.b64encode(pngImage.getvalue()).decode('utf8')
|
| 131 |
-
|
| 132 |
-
return render_template('exposure_report.html', polymers=polymers, pIndex=pIndex, release=release,
|
| 133 |
-
assume=assume, area=area, vol=vol, amount=amount, diff=diff, time=time, exposure=exposure, TTC=TTC,
|
| 134 |
-
MOS=MOS, chemName=chemName, image=pngImageB64String)
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
def calcexposure(MW, amount, vol, area, time, pIndex):
|
| 138 |
-
Ap = np.array((16.9, 11.7, 8.2, 2.6))
|
| 139 |
-
L = vol / area
|
| 140 |
-
if PolyData[pIndex][1] < 4:
|
| 141 |
-
D = 1e4 * np.exp(Ap[PolyData[pIndex][1]] - 0.1351 * MW ** (2. / 3.) + 0.003 * MW - 10454. / 310.)
|
| 142 |
-
else:
|
| 143 |
-
Va = 4.76 + 1.32 * MW
|
| 144 |
-
D = 7.4e-8 * (18. * 2.6) ** 0.5 * 310. / 0.6913 / Va ** 0.6
|
| 145 |
-
|
| 146 |
-
D = D * 3600.
|
| 147 |
-
tau = D * time / L ** 2.
|
| 148 |
-
if tau <= 0.5:
|
| 149 |
-
release = 2. * amount * np.sqrt(tau / np.pi)
|
| 150 |
-
else:
|
| 151 |
-
release = amount * (1. - (8. / (np.pi ** 2.)) * np.exp(-tau * np.pi ** 2. / 4.))
|
| 152 |
-
|
| 153 |
-
return release, D
|
| 154 |
-
|
| 155 |
-
def calcrates(MW, amount, vol, area, time, pIndex):
|
| 156 |
-
Ap = np.array((16.9, 11.7, 8.2, 2.6))
|
| 157 |
-
L = vol / area
|
| 158 |
-
if PolyData[pIndex][1] < 4:
|
| 159 |
-
D = 1e4 * np.exp(Ap[PolyData[pIndex][1]] - 0.1351 * MW ** (2. / 3.) + 0.003 * MW - 10454. / 310.)
|
| 160 |
-
else:
|
| 161 |
-
Va = 4.76 + 1.32 * MW
|
| 162 |
-
D = 7.4e-8 * (18. * 2.6) ** 0.5 * 310. / 0.6913 / Va ** 0.6
|
| 163 |
-
D = D * 86400.
|
| 164 |
-
|
| 165 |
-
rates = np.zeros(len(time))
|
| 166 |
-
tau = D * time[0] / L ** 2.
|
| 167 |
-
if tau < 0.2:
|
| 168 |
-
rates[0] = 2. * amount * np.sqrt(tau / np.pi)
|
| 169 |
-
else:
|
| 170 |
-
rates[0] = amount * (1. - (8. / (np.pi ** 2.)) * np.exp(-tau * np.pi ** 2. / 4.))
|
| 171 |
-
|
| 172 |
-
for i in range(1, len(time)):
|
| 173 |
-
tau = D * time[i] / L ** 2.
|
| 174 |
-
if tau < 0.2:
|
| 175 |
-
rates[i] = 2. * amount * np.sqrt(tau / np.pi) - np.sum(rates[:i])
|
| 176 |
-
else:
|
| 177 |
-
rates[i] = amount * (1. - (8. / (np.pi ** 2.)) * np.exp(-tau * np.pi ** 2. / 4.)) - np.sum(rates[:i])
|
| 178 |
-
|
| 179 |
-
return rates
|
| 180 |
-
|
| 181 |
if __name__ == '__main__':
|
| 182 |
app.run()
|
|
|
|
| 1 |
+
from flask import Flask, render_template
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
app = Flask(__name__)
|
| 4 |
app.debug = True
|
|
|
|
| 6 |
from color_module import blueprint
|
| 7 |
app.register_blueprint(blueprint)
|
| 8 |
|
| 9 |
+
from exposure_module import blueprint
|
| 10 |
+
app.register_blueprint(blueprint)
|
| 11 |
+
|
| 12 |
@app.route('/', methods=['GET'])
|
| 13 |
def app_init():
|
| 14 |
return render_template('main.html')
|
| 15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
if __name__ == '__main__':
|
| 17 |
app.run()
|
color_module/templates/index.html
CHANGED
|
@@ -28,8 +28,8 @@
|
|
| 28 |
|
| 29 |
|
| 30 |
<p> For details on how to use CHRIS, please read the <a href="{{url_for('.static', filename='README.html')}}"> instructions.</a> and
|
| 31 |
-
<a href="{{url_for('
|
| 32 |
-
found <a href="{{url_for('
|
| 33 |
|
| 34 |
<body>
|
| 35 |
|
|
|
|
| 28 |
|
| 29 |
|
| 30 |
<p> For details on how to use CHRIS, please read the <a href="{{url_for('.static', filename='README.html')}}"> instructions.</a> and
|
| 31 |
+
<a href="{{url_for('.static', filename='COU.html')}}"> context of use (COU)</a>. Answers to frequently asked questions can be
|
| 32 |
+
found <a href="{{url_for('.static', filename='FAQ.html')}}"> here</a>.</p>
|
| 33 |
|
| 34 |
<body>
|
| 35 |
|
exposure_module/__init__.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from flask import Blueprint
|
| 2 |
+
|
| 3 |
+
blueprint = Blueprint('exposure_module', __name__, template_folder='templates', static_folder='static', static_url_path='/exposure_module')
|
| 4 |
+
|
| 5 |
+
from . import exposure
|
exposure_module/exposure.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
from flask import Flask, render_template, request
|
| 3 |
+
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
|
| 4 |
+
import matplotlib
|
| 5 |
+
matplotlib.use('Agg')
|
| 6 |
+
import matplotlib.pyplot as plt
|
| 7 |
+
import io
|
| 8 |
+
import base64
|
| 9 |
+
from functions import *
|
| 10 |
+
from . import blueprint
|
| 11 |
+
|
| 12 |
+
# Named polymer matrices and category numbers
|
| 13 |
+
nPoly = 20
|
| 14 |
+
PolyData = np.zeros((nPoly,), dtype=[('name', 'a75'), ('Category', 'i')])
|
| 15 |
+
PolyData[0] = ('Silicone', 0)
|
| 16 |
+
PolyData[1] = ('Polyethylene (density <= 0.94 g/cm3)', 1)
|
| 17 |
+
PolyData[2] = ('Polyethylene (density > 0.94 g/cm3)', 2)
|
| 18 |
+
PolyData[3] = ('Polyethylene terephthalate', 3)
|
| 19 |
+
PolyData[4] = ('Polyurethane (polyether)', 1)
|
| 20 |
+
PolyData[5] = ('Polycarbonate', 3)
|
| 21 |
+
PolyData[6] = ('Polyoxymethylene', 2)
|
| 22 |
+
PolyData[7] = ('Poly(methyl methacrylate)', 3)
|
| 23 |
+
PolyData[8] = ('Acrylonitrile butadiene styrene', 2)
|
| 24 |
+
PolyData[9] = ('Polyether block amide', 1)
|
| 25 |
+
PolyData[10] = ('Polyamide', 3)
|
| 26 |
+
PolyData[11] = ('Polystyrene', 3)
|
| 27 |
+
PolyData[12] = ('Polyvinyl chloride (plasticized)', 0)
|
| 28 |
+
PolyData[13] = ('Polytetrafluoroethylene', 2)
|
| 29 |
+
PolyData[14] = ('Polyvinyl acetate', 1)
|
| 30 |
+
PolyData[15] = ('Polypropylene', 2)
|
| 31 |
+
PolyData[16] = ('Polybutylene terephthalate', 3)
|
| 32 |
+
PolyData[17] = ('Polyetheretherketone', 3)
|
| 33 |
+
PolyData[18] = ('Fluorinated ethylene propylene', 2)
|
| 34 |
+
PolyData[19] = ('Other polymer', 4)
|
| 35 |
+
|
| 36 |
+
polymers = np.zeros(nPoly, dtype='object')
|
| 37 |
+
for i in range(nPoly):
|
| 38 |
+
polymers[i] = PolyData[i][0].decode('UTF-8')
|
| 39 |
+
|
| 40 |
+
@blueprint.route('/exposure', methods=['GET'])
|
| 41 |
+
def exposure():
|
| 42 |
+
return render_template('exposure_index.html', polymers=polymers)
|
| 43 |
+
|
| 44 |
+
@blueprint.route('/exposure', methods=['POST'])
|
| 45 |
+
def exp_post():
|
| 46 |
+
amount = float(request.form["amount"])
|
| 47 |
+
mass = float(request.form["mass"])
|
| 48 |
+
density = float(request.form["density"])
|
| 49 |
+
vol = mass / density
|
| 50 |
+
polymer = request.form["polymer"]
|
| 51 |
+
pIndex = (np.where(polymers == polymer)[0])[0]
|
| 52 |
+
area = float(request.form["area"])
|
| 53 |
+
exposure = request.form["exposure"]
|
| 54 |
+
MW = float(request.form["MW"])
|
| 55 |
+
chemName = '*' + request.form["chemName"] + '*'
|
| 56 |
+
|
| 57 |
+
if exposure != "limited":
|
| 58 |
+
time = 24.
|
| 59 |
+
else:
|
| 60 |
+
time = float(request.form["exptime"])
|
| 61 |
+
if exposure != "long-term":
|
| 62 |
+
TTC = 0.12
|
| 63 |
+
else:
|
| 64 |
+
TTC = 0.0015
|
| 65 |
+
|
| 66 |
+
assume1 = request.form.get("assume1") is not None
|
| 67 |
+
assume2 = request.form.get("assume2") is not None
|
| 68 |
+
assume3 = request.form.get("assume3") is not None
|
| 69 |
+
assume4 = request.form.get("assume4") is not None
|
| 70 |
+
assume5 = request.form.get("assume5") is not None
|
| 71 |
+
|
| 72 |
+
assume = np.array((assume1, assume2, assume3, assume4, assume5))
|
| 73 |
+
|
| 74 |
+
release, diff = calcexposure(MW, amount, vol, area, time, pIndex, PolyData)
|
| 75 |
+
|
| 76 |
+
MOS = TTC / release
|
| 77 |
+
|
| 78 |
+
release = sigfigs(release, 2)
|
| 79 |
+
MOS = sigfigs(MOS, 2)
|
| 80 |
+
diff = sigfigs(diff, 2)
|
| 81 |
+
|
| 82 |
+
fig, ax = plt.subplots(figsize=(6, 4))
|
| 83 |
+
plt.subplots_adjust(left=0.15, bottom=0.15, right=0.95, top=0.95, wspace=0.0, hspace=0.0)
|
| 84 |
+
tarray = np.arange(1.,31.,1.)
|
| 85 |
+
rates = calcrates(MW, amount, vol, area, tarray, pIndex, PolyData)
|
| 86 |
+
ax.plot(tarray,rates,'o')
|
| 87 |
+
ax.set(
|
| 88 |
+
xlabel='time (days)',
|
| 89 |
+
ylabel='release rate (mg/day)',
|
| 90 |
+
)
|
| 91 |
+
pngImage = io.BytesIO()
|
| 92 |
+
FigureCanvas(fig).print_png(pngImage)
|
| 93 |
+
pngImageB64String = "data:image/png;base64,"
|
| 94 |
+
pngImageB64String += base64.b64encode(pngImage.getvalue()).decode('utf8')
|
| 95 |
+
|
| 96 |
+
return render_template('exposure_report.html', polymers=polymers, pIndex=pIndex, release=release,
|
| 97 |
+
assume=assume, area=area, vol=vol, amount=amount, diff=diff, time=time, exposure=exposure, TTC=TTC,
|
| 98 |
+
MOS=MOS, chemName=chemName, image=pngImageB64String)
|
{static β exposure_module/static}/exposure_COU.md
RENAMED
|
File without changes
|
exposure_module/static/images/FDAgraphic.png
ADDED
|
Git LFS Details
|
exposure_module/static/images/FDAlogo.png
ADDED
|
Git LFS Details
|
{static β exposure_module/static}/md2html.sh
RENAMED
|
File without changes
|
{templates β exposure_module/templates}/exposure_index.html
RENAMED
|
@@ -24,7 +24,7 @@
|
|
| 24 |
may be needed despite a positive outcome. For color additives, please use the <a href="https://chris-osel.pythonanywhere.com">color additive module</a>. </strong></p>
|
| 25 |
|
| 26 |
For details on how to use CHRIS, please click the information icons next to each section header and read the
|
| 27 |
-
<a href="{{url_for('static', filename='exposure_COU.html')}}"> context of use (COU)</a>.
|
| 28 |
|
| 29 |
<body>
|
| 30 |
|
|
|
|
| 24 |
may be needed despite a positive outcome. For color additives, please use the <a href="https://chris-osel.pythonanywhere.com">color additive module</a>. </strong></p>
|
| 25 |
|
| 26 |
For details on how to use CHRIS, please click the information icons next to each section header and read the
|
| 27 |
+
<a href="{{url_for('.static', filename='exposure_COU.html')}}"> context of use (COU)</a>.
|
| 28 |
|
| 29 |
<body>
|
| 30 |
|
{templates β exposure_module/templates}/exposure_report.html
RENAMED
|
File without changes
|
functions.py
CHANGED
|
@@ -22,7 +22,7 @@ def calcexposure(MW, amount, vol, area, time, pIndex, PolyData):
|
|
| 22 |
|
| 23 |
return release, D
|
| 24 |
|
| 25 |
-
def calcrates(MW, amount, vol, area, time, pIndex):
|
| 26 |
Ap = np.array((16.9, 11.7, 8.2, 2.6))
|
| 27 |
L = vol / area
|
| 28 |
if PolyData[pIndex][1] < 4:
|
|
|
|
| 22 |
|
| 23 |
return release, D
|
| 24 |
|
| 25 |
+
def calcrates(MW, amount, vol, area, time, pIndex, PolyData):
|
| 26 |
Ap = np.array((16.9, 11.7, 8.2, 2.6))
|
| 27 |
L = vol / area
|
| 28 |
if PolyData[pIndex][1] < 4:
|
static/exposure_COU.html
DELETED
|
@@ -1,45 +0,0 @@
|
|
| 1 |
-
<!DOCTYPE html>
|
| 2 |
-
<html lang="en">
|
| 3 |
-
<head>
|
| 4 |
-
<meta charset="UTF-8">
|
| 5 |
-
</head>
|
| 6 |
-
|
| 7 |
-
<header>
|
| 8 |
-
<img src="images/FDAlogo.png" style="float: left;" height="100"/>
|
| 9 |
-
<img src="images/FDAgraphic.png" style="float: right;" height="100"/>
|
| 10 |
-
<br clear="all" />
|
| 11 |
-
<h1 style="text-align:center"><font color="#0070C0">C</font>olor <font color="#0070C0">H</font>azard and <font color="#0070C0">RIS</font>k calculator (CHRIS) </h1>
|
| 12 |
-
</header>
|
| 13 |
-
<h2 id="context-of-use-cou">Context of Use (COU)</h2>
|
| 14 |
-
<p>The bulk chemical module of the CHemical RISk calculator (CHRIS) is (proposed to be) qualified to conduct screening level risk assessments to aid in the biocompatibility evaluation of bulk additives and impurities in polymeric medical device components. These assessments can assist device manufacturers by providing instantaneous feedback on whether the presence of the bulk chemical would require additional justification and/or testing to demonstrate acceptable biological risk. The output of CHRIS is a conservative margin of safety (MOS = toxicological safety limit Γ· exposure dose) value for a bulk chemical contained within a polymeric medical device component. Based on the MOS value, the calculator determines if further assessment of one or more biocompatibility endpoints is necessary for the specific chemical.</p>
|
| 15 |
-
<p>Because CHRIS only addresses compounds with a distribution that is macroscopically homogeneous within the matrix, the tool can only be used to assess bulk additives and impurities. Therefore, only compounds that are introduced either intentionally or unintentionally during synthesis (e.g., residual monomers and oligomers, catalysts, initiators) or compounding (e.g., stabilizers, antioxidants, plasticizers) are within scope. Surface residuals from processing, cleaning, and sterilization are excluded. Also, CHRIS requires the total amount of the chemical to be established in advance, e.g., based on a certificate of analysis. Further CHRIS only addresses individual chemicals; therefore, a favorable outcome by CHRIS does not imply acceptable biological risk for the final finished form of a medical device. CHRIS is also not intended to establish device classification or identify biocompatibility requirements.</p>
|
| 16 |
-
<p>CHRIS provides clinically relevant, yet still conservative, exposure dose estimates using a physics-based transport model for polymeric systems where transport data are available to support the use of the model. The model applies worst-case boundary conditions for release of a substance from the polymer matrix and is based on four (4) primary assumptions:</p>
|
| 17 |
-
<ol type="1">
|
| 18 |
-
<li>The clinical use environment does not cause the polymer matrix to swell or degrade.</li>
|
| 19 |
-
<li>The chemical is homogeneously distributed throughout the polymer.</li>
|
| 20 |
-
<li>The total amount of the chemical is present in dilute concentrations (<= 2 m/v %).</li>
|
| 21 |
-
<li>Any particles/aggregates of the chemical present in the polymer are much smaller than the smallest component dimension (<= 50x).</li>
|
| 22 |
-
</ol>
|
| 23 |
-
<p>While these assumptions are typically valid for bulk additives and impurities in biostable polymers, users of CHRIS must confirm conformance to the underlying assumptions or provide supporting justification to ensure compliance for a given system. Further, CHRIS only enables system specific exposure estimates for nineteen (19) polymeric systems that are generally biostable (non-swelling and non-degrading). These polymers are listed below. To estimate chemical release based on the model, the diffusion coefficient of the chemical in the polymer matrix must be specified. For the nineteen (19) listed polymeric systems, a worst-case (upper bound) diffusion coefficient, as a function of molecular weight, has been established based on data from the literature. For polymer matrices that are not included in this list, CHRIS assigns an ultra-conservative diffusion coefficient that assumes the polymer has the properties of water. Note that the worst-case diffusion coefficient is only defined over a molecular weight range of 100 to 1100 g/mol. Therefore, for substances with a molecular weight > 1100 g/mol, the value of the diffusion coefficient assuming a molecular weight of 1100 g/mol can be used as a conservative value; for substances with a molecular weight < 100 g/mol, CHRIS currently cannot be used to estimate exposure.</p>
|
| 24 |
-
<ul>
|
| 25 |
-
<li>Silicone</li>
|
| 26 |
-
<li>Polyethylene (density <= 0.94 g/cm<sup>3</sup>)</li>
|
| 27 |
-
<li>Polyethylene (density > 0.94 g/cm<sup>3</sup>)</li>
|
| 28 |
-
<li>Polyethylene terephthalate</li>
|
| 29 |
-
<li>Polyurethane (polyether)</li>
|
| 30 |
-
<li>Polycarbonate</li>
|
| 31 |
-
<li>Polyoxymethylene</li>
|
| 32 |
-
<li>Poly(methyl methacrylate)</li>
|
| 33 |
-
<li>Acrylonitrile butadiene styrene</li>
|
| 34 |
-
<li>Polyether block amide</li>
|
| 35 |
-
<li>Polyamide</li>
|
| 36 |
-
<li>Polystyrene</li>
|
| 37 |
-
<li>Polyvinyl chloride</li>
|
| 38 |
-
<li>Polytetrafluoroethylene</li>
|
| 39 |
-
<li>Polypropylene</li>
|
| 40 |
-
<li>Polyvinyl acetate</li>
|
| 41 |
-
<li>Polybutylene terephthalate</li>
|
| 42 |
-
<li>Polyetheretherketone</li>
|
| 43 |
-
<li>Fluorinated ethylene propylene</li>
|
| 44 |
-
</ul>
|
| 45 |
-
<p>In the absence of adequate toxicological and exposure data for a chemical in a polymeric matrix, a toxicological risk assessment can be conducted for systemic biocompatibility endpoints by comparing the exposure estimate to an appropriate threshold of toxicological concern (TTC). This is the approach used by CHRIS in this module. The TTC values are based on systemic toxicity, thus CHRIS can address acute systemic toxicity, subacute/subchronic toxicity, genotoxicity, carcinogenicity, and reproductive and developmental toxicity. It does not, however, address cytotoxicity, sensitization, irritation, hemocompatibility, material mediated pyrogenicity, or implantation. Therefore, an MOS >= 1 implies the chemical will not raise a safety concern with respect to only the systemic biocompatibility endpoints, provided the chemical is not within the cohort of concern, which is reflected in the output of CHRIS.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|