Robert Elder commited on
Commit ·
abe0ff4
1
Parent(s): eccd0e1
updates to quantity module
Browse files- functions.py +8 -0
- quantity_functions.py +109 -59
- quantity_module/data/bounds.pkl +0 -3
- quantity_module/data/copy-data.sh +15 -8
- quantity_module/data/db-D-interp-37-clean.xlsx +2 -2
- quantity_module/data/db-D-interp-50-clean.xlsx +2 -2
- quantity_module/data/{bounds-50.pkl → db-D-interp-allT-clean.xlsx} +2 -2
- quantity_module/data/db-D.xlsx +0 -3
- quantity_module/data/db-properties-polymer.xlsx +0 -3
- quantity_module/data/param_distribution_allT.json +0 -0
- quantity_module/quantity.py +21 -32
- quantity_module/templates/quantity_index.html +72 -41
- quantity_module/templates/quantity_report.html +18 -11
functions.py
CHANGED
|
@@ -13,6 +13,12 @@ def SigFigs(number, n):
|
|
| 13 |
if number == 0: return number
|
| 14 |
return round(number, n - int(math.floor(math.log10(math.fabs(number)))) - 1)
|
| 15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
def Piringer(Mw, Ap, T=310.):
|
| 17 |
# Semi-empirical model for D(Mw) given polymer property Ap- Toxicol. Sci. 2019, 172 (1), 201–212.
|
| 18 |
if Mw > 1100.: # if molecule is greater than 1100 g/mol, default to that value as worst case
|
|
@@ -85,6 +91,8 @@ def CdfPlot(vals, units=None):
|
|
| 85 |
xlabel = 'Total quantity' if units is None else f'Total quantity ({units})'
|
| 86 |
fig, ax = plt.subplots(figsize=(6, 4))
|
| 87 |
ax.ecdf(vals, c='b', lw=3)
|
|
|
|
|
|
|
| 88 |
ax.set_xscale('log')
|
| 89 |
ax.set(
|
| 90 |
xlabel=xlabel,
|
|
|
|
| 13 |
if number == 0: return number
|
| 14 |
return round(number, n - int(math.floor(math.log10(math.fabs(number)))) - 1)
|
| 15 |
|
| 16 |
+
def HtmlNumber(number,n):
|
| 17 |
+
number_str = f'{number:.{n}e}'
|
| 18 |
+
base, exponent = number_str.split('e')
|
| 19 |
+
html_output = f'{base} × 10<sup>{exponent[0] if exponent[0]=="-" else ""}{int(exponent[1:]):d}</sup>'
|
| 20 |
+
return html_output
|
| 21 |
+
|
| 22 |
def Piringer(Mw, Ap, T=310.):
|
| 23 |
# Semi-empirical model for D(Mw) given polymer property Ap- Toxicol. Sci. 2019, 172 (1), 201–212.
|
| 24 |
if Mw > 1100.: # if molecule is greater than 1100 g/mol, default to that value as worst case
|
|
|
|
| 91 |
xlabel = 'Total quantity' if units is None else f'Total quantity ({units})'
|
| 92 |
fig, ax = plt.subplots(figsize=(6, 4))
|
| 93 |
ax.ecdf(vals, c='b', lw=3)
|
| 94 |
+
q50 = np.nanquantile(vals,0.5)
|
| 95 |
+
ax.plot([q50,q50],[0,0.5],'k--',[q50],[0.5],'ko',[ax.get_xlim()[0],q50],[0.5,0.5],'k--',lw=2,ms=10)
|
| 96 |
ax.set_xscale('log')
|
| 97 |
ax.set(
|
| 98 |
xlabel=xlabel,
|
quantity_functions.py
CHANGED
|
@@ -18,8 +18,8 @@ from functions import PowerLaw, Piringer
|
|
| 18 |
### TODO arbitrary T
|
| 19 |
|
| 20 |
## sampling parameters
|
| 21 |
-
N_sample = int(
|
| 22 |
-
rng = np.random.Generator(np.random.PCG64(seed=12345))
|
| 23 |
|
| 24 |
## list of solvents to include
|
| 25 |
solvents = sorted(['ethanol', 'isopropanol', 'acetonitrile', 'toluene', 'dichloromethane', 'hexane'])
|
|
@@ -28,6 +28,9 @@ solvents = sorted(['ethanol', 'isopropanol', 'acetonitrile', 'toluene', 'dichlor
|
|
| 28 |
T_cut = 20
|
| 29 |
MW_cut = 20
|
| 30 |
|
|
|
|
|
|
|
|
|
|
| 31 |
#### read data files
|
| 32 |
# CHRIS bounds
|
| 33 |
#with open('quantity_module/data/bounds.pkl', 'rb') as fp:
|
|
@@ -35,11 +38,15 @@ MW_cut = 20
|
|
| 35 |
#with open('quantity_module/data/bounds-50.pkl', 'rb') as fp:
|
| 36 |
# params_dict_ub_50, params_dict_lb_50, params_dict_ub_band_50, params_dict_lb_band_50, params_dict_q95_50, params_dict_q50_50, params_dict_q05_50 = pickle.load(fp)
|
| 37 |
# CHRIS parameter distributions
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
# other stuff
|
| 44 |
df_visc = pd.read_excel('quantity_module/data/solvent-viscosity.xlsx')
|
| 45 |
df_desc = pd.read_excel(f'quantity_module/data/data-descriptors-mordred-numconfs51.xlsx', usecols=['Solute_InChIKey', 'Vabc','VMcGowan'])
|
|
@@ -47,19 +54,29 @@ df_desc = pd.read_excel(f'quantity_module/data/data-descriptors-mordred-numconfs
|
|
| 47 |
#df2 = pd.read_excel('quantity_module/data/db-D.xlsx', sheet_name=1) ## XXX?
|
| 48 |
#df2['CHRIS Class'] = df2['CHRIS Class'].fillna('none')
|
| 49 |
#df2['New Class'] = df2['New Class'].fillna('none')
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
df_final_37['
|
| 56 |
-
df_final_37['
|
| 57 |
-
|
| 58 |
-
df_final_50['
|
| 59 |
-
df_final_50['
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
#### solvent-specific viscosity
|
| 65 |
# add MW
|
|
@@ -100,30 +117,43 @@ def get_WC(T,solv,V):
|
|
| 100 |
return D_WC, eta, params['MW']
|
| 101 |
|
| 102 |
#### add Wilke-Chang
|
| 103 |
-
|
| 104 |
-
#
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
#
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
|
| 128 |
def get_V(mol):
|
| 129 |
calc = mordred.Calculator([mordred.descriptors.VdwVolumeABC, mordred.descriptors.McGowanVolume])
|
|
@@ -170,14 +200,17 @@ def get_c_dist(T,Tg,MW):
|
|
| 170 |
cs = cs[cs>0]
|
| 171 |
return cs
|
| 172 |
|
| 173 |
-
def get_D_dists(w,T,Polymer_Tg,Solvent_Name,Solvent_MW,Solute_MW,CHRIS_category,N=
|
| 174 |
"""
|
| 175 |
D_dist_noswell, D_dist_swell, (c, Ds, DWCs, DCs) = get_D_dists(Swelling_wtfrac,T,Polymer_Tg,Solvent_Name,Solvent_MW,Solute_MW,CHRIS_category,return_DCs=True,N=N)
|
| 176 |
"""
|
| 177 |
-
if
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
|
|
|
|
|
|
|
|
|
| 181 |
#Solvent_MW = solvmws[Solvent_Name]
|
| 182 |
cs = get_c_dist(T,Polymer_Tg,Solvent_MW)
|
| 183 |
if Solute_MW < 50:
|
|
@@ -196,17 +229,34 @@ def get_D_dists(w,T,Polymer_Tg,Solvent_Name,Solvent_MW,Solute_MW,CHRIS_category,
|
|
| 196 |
c = rng.choice(cs, N)
|
| 197 |
lnD_D0 = c*w/(1+(c-1)*w) * np.log(DWCs/Ds)
|
| 198 |
## distribution of D_CHRIS
|
| 199 |
-
if
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
else:
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
D_dist_noswell = rng.choice(D_list, N)
|
| 211 |
D_dist_swell = np.exp(np.log(D_dist_noswell)+lnD_D0)
|
| 212 |
if return_DCs:
|
|
|
|
| 18 |
### TODO arbitrary T
|
| 19 |
|
| 20 |
## sampling parameters
|
| 21 |
+
N_sample = int(1e6)
|
| 22 |
+
#rng = np.random.Generator(np.random.PCG64(seed=12345))
|
| 23 |
|
| 24 |
## list of solvents to include
|
| 25 |
solvents = sorted(['ethanol', 'isopropanol', 'acetonitrile', 'toluene', 'dichloromethane', 'hexane'])
|
|
|
|
| 28 |
T_cut = 20
|
| 29 |
MW_cut = 20
|
| 30 |
|
| 31 |
+
use_new = True
|
| 32 |
+
T_cut_new = 0.5
|
| 33 |
+
|
| 34 |
#### read data files
|
| 35 |
# CHRIS bounds
|
| 36 |
#with open('quantity_module/data/bounds.pkl', 'rb') as fp:
|
|
|
|
| 38 |
#with open('quantity_module/data/bounds-50.pkl', 'rb') as fp:
|
| 39 |
# params_dict_ub_50, params_dict_lb_50, params_dict_ub_band_50, params_dict_lb_band_50, params_dict_q95_50, params_dict_q50_50, params_dict_q05_50 = pickle.load(fp)
|
| 40 |
# CHRIS parameter distributions
|
| 41 |
+
if not use_new:
|
| 42 |
+
param_dists = {}
|
| 43 |
+
with open('quantity_module/data/param_distribution_37.json','r') as fp:
|
| 44 |
+
param_dists[37] = json.load(fp)
|
| 45 |
+
with open('quantity_module/data/param_distribution_50.json','r') as fp:
|
| 46 |
+
param_dists[50] = json.load(fp)
|
| 47 |
+
else:
|
| 48 |
+
with open('quantity_module/data/param_distribution_allT.json','r') as fp:
|
| 49 |
+
param_dists = json.load(fp)
|
| 50 |
# other stuff
|
| 51 |
df_visc = pd.read_excel('quantity_module/data/solvent-viscosity.xlsx')
|
| 52 |
df_desc = pd.read_excel(f'quantity_module/data/data-descriptors-mordred-numconfs51.xlsx', usecols=['Solute_InChIKey', 'Vabc','VMcGowan'])
|
|
|
|
| 54 |
#df2 = pd.read_excel('quantity_module/data/db-D.xlsx', sheet_name=1) ## XXX?
|
| 55 |
#df2['CHRIS Class'] = df2['CHRIS Class'].fillna('none')
|
| 56 |
#df2['New Class'] = df2['New Class'].fillna('none')
|
| 57 |
+
if not use_new:
|
| 58 |
+
## clean data
|
| 59 |
+
df_final_37 = pd.read_excel('quantity_module/data/db-D-interp-37-clean.xlsx')
|
| 60 |
+
df_final_50 = pd.read_excel('quantity_module/data/db-D-interp-50-clean.xlsx')
|
| 61 |
+
# convert all T to K
|
| 62 |
+
df_final_37['T'] = df_final_37['T'] + 273.15
|
| 63 |
+
df_final_37['Polymer_Tg'] = df_final_37['Polymer_Tg'] + 273.15
|
| 64 |
+
df_final_37['Polymer_Tm'] = df_final_37['Polymer_Tm'] + 273.15
|
| 65 |
+
df_final_50['T'] = df_final_50['T'] + 273.15
|
| 66 |
+
df_final_50['Polymer_Tg'] = df_final_50['Polymer_Tg'] + 273.15
|
| 67 |
+
df_final_50['Polymer_Tm'] = df_final_50['Polymer_Tm'] + 273.15
|
| 68 |
+
# add volumes
|
| 69 |
+
df_final_37 = pd.merge(df_final_37, df_desc[['Solute_InChIKey', 'Vabc', 'VMcGowan']], how='left', on='Solute_InChIKey', suffixes=('', '_dupe'))
|
| 70 |
+
df_final_50 = pd.merge(df_final_50, df_desc[['Solute_InChIKey', 'Vabc', 'VMcGowan']], how='left', on='Solute_InChIKey', suffixes=('', '_dupe'))
|
| 71 |
+
else:
|
| 72 |
+
## clean data
|
| 73 |
+
df_final = pd.read_excel('quantity_module/data/db-D-interp-allT-clean.xlsx')
|
| 74 |
+
# convert all T to K
|
| 75 |
+
df_final['T'] = df_final['T'] + 273.15
|
| 76 |
+
df_final['Polymer_Tg'] = df_final['Polymer_Tg'] + 273.15
|
| 77 |
+
df_final['Polymer_Tm'] = df_final['Polymer_Tm'] + 273.15
|
| 78 |
+
# add volumes
|
| 79 |
+
df_final = pd.merge(df_final, df_desc[['Solute_InChIKey', 'Vabc', 'VMcGowan']], how='left', on='Solute_InChIKey', suffixes=('', '_dupe'))
|
| 80 |
|
| 81 |
#### solvent-specific viscosity
|
| 82 |
# add MW
|
|
|
|
| 117 |
return D_WC, eta, params['MW']
|
| 118 |
|
| 119 |
#### add Wilke-Chang
|
| 120 |
+
if not use_new:
|
| 121 |
+
## 50 C
|
| 122 |
+
# estimate Vabc for those with nan values
|
| 123 |
+
m = pd.isna(df_final_50['Vabc'])
|
| 124 |
+
v = np.polyval(popt_V, df_final_50['VMcGowan'][m])
|
| 125 |
+
df_final_50.loc[m, 'Vabc'] = v
|
| 126 |
+
T = df_final_50['T']
|
| 127 |
+
V = df_final_50['Vabc']
|
| 128 |
+
for solv in solvents:
|
| 129 |
+
D_WC, eta, MW_solvent = get_WC(T, solv, V)
|
| 130 |
+
df_final_50[f'eta_{solv}'] = eta
|
| 131 |
+
df_final_50[f'D_WC_{solv}'] = D_WC
|
| 132 |
+
df_final_50[f'MW_solvent_{solv}'] = MW_solvent
|
| 133 |
+
## 37 C
|
| 134 |
+
# estimate Vabc for those with nan values
|
| 135 |
+
m = pd.isna(df_final_37['Vabc'])
|
| 136 |
+
v = np.polyval(popt_V, df_final_37['VMcGowan'][m])
|
| 137 |
+
df_final_37.loc[m, 'Vabc'] = v
|
| 138 |
+
T = df_final_37['T']
|
| 139 |
+
V = df_final_37['Vabc']
|
| 140 |
+
for solv in solvents:
|
| 141 |
+
D_WC, eta, MW_solvent = get_WC(T, solv, V)
|
| 142 |
+
df_final_37[f'eta_{solv}'] = eta
|
| 143 |
+
df_final_37[f'D_WC_{solv}'] = D_WC
|
| 144 |
+
df_final_37[f'MW_solvent_{solv}'] = MW_solvent
|
| 145 |
+
else:
|
| 146 |
+
# estimate Vabc for those with nan values
|
| 147 |
+
m = pd.isna(df_final['Vabc'])
|
| 148 |
+
v = np.polyval(popt_V, df_final['VMcGowan'][m])
|
| 149 |
+
df_final.loc[m, 'Vabc'] = v
|
| 150 |
+
T = df_final['T']
|
| 151 |
+
V = df_final['Vabc']
|
| 152 |
+
for solv in solvents:
|
| 153 |
+
D_WC, eta, MW_solvent = get_WC(T, solv, V)
|
| 154 |
+
df_final[f'eta_{solv}'] = eta
|
| 155 |
+
df_final[f'D_WC_{solv}'] = D_WC
|
| 156 |
+
df_final[f'MW_solvent_{solv}'] = MW_solvent
|
| 157 |
|
| 158 |
def get_V(mol):
|
| 159 |
calc = mordred.Calculator([mordred.descriptors.VdwVolumeABC, mordred.descriptors.McGowanVolume])
|
|
|
|
| 200 |
cs = cs[cs>0]
|
| 201 |
return cs
|
| 202 |
|
| 203 |
+
def get_D_dists(w,T,Polymer_Tg,Solvent_Name,Solvent_MW,Solute_MW,CHRIS_category,rng,N=100000,return_DCs=False):
|
| 204 |
"""
|
| 205 |
D_dist_noswell, D_dist_swell, (c, Ds, DWCs, DCs) = get_D_dists(Swelling_wtfrac,T,Polymer_Tg,Solvent_Name,Solvent_MW,Solute_MW,CHRIS_category,return_DCs=True,N=N)
|
| 206 |
"""
|
| 207 |
+
if not use_new:
|
| 208 |
+
if np.abs(T-310)<2:
|
| 209 |
+
df_final_T = df_final_37
|
| 210 |
+
if np.abs(T-323)<2:
|
| 211 |
+
df_final_T = df_final_50
|
| 212 |
+
else:
|
| 213 |
+
df_final_T = df_final.loc[np.abs(df_final['T']-T)<T_cut_new]
|
| 214 |
#Solvent_MW = solvmws[Solvent_Name]
|
| 215 |
cs = get_c_dist(T,Polymer_Tg,Solvent_MW)
|
| 216 |
if Solute_MW < 50:
|
|
|
|
| 229 |
c = rng.choice(cs, N)
|
| 230 |
lnD_D0 = c*w/(1+(c-1)*w) * np.log(DWCs/Ds)
|
| 231 |
## distribution of D_CHRIS
|
| 232 |
+
if not use_new:
|
| 233 |
+
if Solute_MW > 50:
|
| 234 |
+
params = param_dists[T-273.15][f'{CHRIS_category}_hi']
|
| 235 |
+
else:
|
| 236 |
+
params = param_dists[T-273.15][f'{CHRIS_category}_lo']
|
| 237 |
+
if params[0] == 'pir':
|
| 238 |
+
A_list = params[1:]
|
| 239 |
+
D_list = [Piringer(Solute_MW, Ai, T) for Ai in A_list]
|
| 240 |
+
else:
|
| 241 |
+
Ball = params[1]
|
| 242 |
+
A_list = params[2:]
|
| 243 |
+
D_list = np.exp([PowerLaw(Solute_MW, Ai, Ball) for Ai in A_list])
|
| 244 |
else:
|
| 245 |
+
if Solute_MW > 50:
|
| 246 |
+
subkey = f'{CHRIS_category}_hi'
|
| 247 |
+
else:
|
| 248 |
+
subkey = f'{CHRIS_category}_lo'
|
| 249 |
+
allparams = [param_dists[Ti][subkey] for Ti in param_dists if T+T_cut_new >= int(Ti)+273.15 >= T-T_cut_new]
|
| 250 |
+
#allparams = [param_dists[Ti][subkey] for Ti in param_dists if T+T_cut_new > int(Ti)+273.15 > T-T_cut_new]
|
| 251 |
+
D_list = []
|
| 252 |
+
for params in allparams:
|
| 253 |
+
if params[0] == 'pir':
|
| 254 |
+
A_list = params[1:]
|
| 255 |
+
D_list += [Piringer(Solute_MW, Ai, T) for Ai in A_list]
|
| 256 |
+
else:
|
| 257 |
+
Ball = params[1]
|
| 258 |
+
A_list = params[2:]
|
| 259 |
+
D_list += list(np.exp([PowerLaw(Solute_MW, Ai, Ball) for Ai in A_list]))
|
| 260 |
D_dist_noswell = rng.choice(D_list, N)
|
| 261 |
D_dist_swell = np.exp(np.log(D_dist_noswell)+lnD_D0)
|
| 262 |
if return_DCs:
|
quantity_module/data/bounds.pkl
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:832efc7ec94168572bd7e6c33fddfeb61974ecbb0b9b5cc88165042943fe11c1
|
| 3 |
-
size 4415
|
|
|
|
|
|
|
|
|
|
|
|
quantity_module/data/copy-data.sh
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
|
|
|
|
|
| 1 |
cp /Users/robert.elder/doc/experiments/01-diffusion/data/solvent-viscosity.xlsx .
|
| 2 |
cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/descs/data-descriptors-mordred-numconfs51.xlsx .
|
| 3 |
-
cp /Users/robert.elder/doc/experiments/
|
| 4 |
-
cp /Users/robert.elder/doc/experiments/01-diffusion/data/db-D.xlsx .
|
| 5 |
-
cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/bounds-99/bounds.pkl .
|
| 6 |
-
cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/bounds-99/bounds-50.pkl .
|
| 7 |
-
cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/bounds-99/param_distribution_37.json .
|
| 8 |
-
cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/bounds-99/param_distribution_50.json .
|
| 9 |
-
cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/bounds-99/db-D-interp-37-clean.xlsx .
|
| 10 |
-
cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/bounds-99/db-D-interp-50-clean.xlsx .
|
| 11 |
cp /Users/robert.elder/doc/experiments/01-diffusion/data/vrentas-duda-params.xlsx .
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
|
| 3 |
cp /Users/robert.elder/doc/experiments/01-diffusion/data/solvent-viscosity.xlsx .
|
| 4 |
cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/descs/data-descriptors-mordred-numconfs51.xlsx .
|
| 5 |
+
cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/bounds-99/param_distribution_allT.json .
|
| 6 |
+
cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/bounds-99/db-D-interp-allT-clean.xlsx .
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
cp /Users/robert.elder/doc/experiments/01-diffusion/data/vrentas-duda-params.xlsx .
|
| 8 |
+
|
| 9 |
+
if 0;
|
| 10 |
+
cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/bounds-99/param_distribution_37.json .
|
| 11 |
+
cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/bounds-99/param_distribution_50.json .
|
| 12 |
+
cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/bounds-99/db-D-interp-37-clean.xlsx .
|
| 13 |
+
cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/bounds-99/db-D-interp-50-clean.xlsx .
|
| 14 |
+
#cp /Users/robert.elder/doc/experiments/08-solubility/data/db-properties-polymer.xlsx .
|
| 15 |
+
#cp /Users/robert.elder/doc/experiments/01-diffusion/data/db-D.xlsx .
|
| 16 |
+
#cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/bounds-99/bounds.pkl .
|
| 17 |
+
#cp /Users/robert.elder/doc/experiments/01-diffusion/data/tmp-plots/bounds-99/bounds-50.pkl .
|
| 18 |
+
fi
|
quantity_module/data/db-D-interp-37-clean.xlsx
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5c046f45ede6419629615b2e7397d74dc22c19db8556853638dd0c54ef9fad3f
|
| 3 |
+
size 546002
|
quantity_module/data/db-D-interp-50-clean.xlsx
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2086bf5769a47fb6ff95f4f1dc4368788f03d6365300e5c40f6631798929116d
|
| 3 |
+
size 314780
|
quantity_module/data/{bounds-50.pkl → db-D-interp-allT-clean.xlsx}
RENAMED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b34934f1be324e95766d57b156ee29822b1ed282b3f0b4402e5405a8752c8acd
|
| 3 |
+
size 10436853
|
quantity_module/data/db-D.xlsx
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:713467099d12a6482f175c3c0d402bf84829bec0319c33708fcef257a8ce0aa3
|
| 3 |
-
size 884005
|
|
|
|
|
|
|
|
|
|
|
|
quantity_module/data/db-properties-polymer.xlsx
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:c7a9829f683c9e0de82cc5ec8501afc71e11e0614e42dda7795d03cc70d82b32
|
| 3 |
-
size 37454
|
|
|
|
|
|
|
|
|
|
|
|
quantity_module/data/param_distribution_allT.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
quantity_module/quantity.py
CHANGED
|
@@ -2,7 +2,7 @@ import sys,numbers
|
|
| 2 |
import numpy as np
|
| 3 |
import pandas as pd
|
| 4 |
from flask import render_template, request
|
| 5 |
-
from functions import SigFigs, Piringer, WilkeChang, CdfPlot
|
| 6 |
from functions import Piecewise, PowerLaw
|
| 7 |
from qrf_functions import QRF_Apply, QRF_Ceramic
|
| 8 |
from . import blueprint
|
|
@@ -123,9 +123,10 @@ def exp_post():
|
|
| 123 |
## use categories
|
| 124 |
## TODO what is the correct worst-case for a generic polymer? G2?
|
| 125 |
CHRIS_category = categories[pIndex]
|
| 126 |
-
|
|
|
|
| 127 |
M0_pred = get_M_dist(D_dist_swell, M_expt, PolymerVolume, SurfaceArea, SolventVolume, ExtractionTime*3600, K_expt=K_expt)
|
| 128 |
-
if
|
| 129 |
print('Swelling_wtfrac, T+273.15, Polymer_Tg+273.15, SolventName, SolventMW, SoluteMW, CHRIS_category')
|
| 130 |
print(Swelling_wtfrac, T+273.15, Polymer_Tg+273.15, SolventName, SolventMW, SoluteMW, CHRIS_category)
|
| 131 |
print(np.nanquantile(D_dist_swell, [0.05,0.5,0.95]))
|
|
@@ -138,33 +139,21 @@ def exp_post():
|
|
| 138 |
method = 'wc'
|
| 139 |
|
| 140 |
# Generate the rate plot using matplotlib
|
| 141 |
-
pngImageB64String = CdfPlot(M0_pred[~np.isnan(M0_pred)], units=units)
|
| 142 |
-
|
| 143 |
-
#
|
| 144 |
-
|
| 145 |
-
#
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
# tlist.append(float(request.form['exposureuserbox']))
|
| 157 |
-
# release_list = [SheetRelease(amount, vol, area, t*24, diff) for t in tlist]
|
| 158 |
-
# #print(release_list, file=sys.stderr)
|
| 159 |
-
# frac_list = [str(SigFigs(r/amount*100,2))+'%' for r in release_list]
|
| 160 |
-
# release_list = [SigFigs(r,2) for r in release_list]
|
| 161 |
-
# df_rel = pd.DataFrame(np.transpose([tlist,release_list,frac_list]),columns=['Exposure duration (days)',f'Cumulative exposure ({units})','Cumulative exposure (%)'])
|
| 162 |
-
# df_rel['Exposure duration (days)'] = df_rel['Exposure duration (days)'].astype(float)
|
| 163 |
-
# release_table = df_rel.sort_values(by='Exposure duration (days)').to_html(index=False)
|
| 164 |
-
#
|
| 165 |
-
# release = SigFigs(release, 2)
|
| 166 |
-
# MOS = SigFigs(MOS, 2)
|
| 167 |
-
# diff = SigFigs(diff, 2)
|
| 168 |
|
| 169 |
tau = np.nanquantile(D_dist_swell,0.5) * (ExtractionTime*3600) / (PolymerVolume/SurfaceArea)**2
|
| 170 |
|
|
@@ -172,9 +161,9 @@ def exp_post():
|
|
| 172 |
tau_out = SigFigs(tau,6)
|
| 173 |
|
| 174 |
return render_template('quantity_report.html', show_properties=show_properties, polymers=polymers, pIndex=pIndex,
|
| 175 |
-
area=SurfaceArea, vol=PolymerVolume, units=units, M=M_expt, M0=M0_out, time=ExtractionTime,
|
| 176 |
solventvol=SolventVolume, solventname=SolventName, swelling=Swelling_percent, K=K_expt, T=T, tau=tau_out,
|
| 177 |
-
chemName=chemName, MW=MW, LogP=LogP, rho=rho, mp=mp, iupac=iupac, cas=cas, smiles=smiles, molImage=molImage,
|
| 178 |
LogP_origin=LogP_origin, rho_origin=rho_origin, mp_origin=mp_origin, ceramic=is_ceramic, methods=[method,Polymer_Tg,PolymerDensity],
|
| 179 |
mass=mass, density=PolymerDensity)
|
| 180 |
|
|
|
|
| 2 |
import numpy as np
|
| 3 |
import pandas as pd
|
| 4 |
from flask import render_template, request
|
| 5 |
+
from functions import SigFigs, HtmlNumber, Piringer, WilkeChang, CdfPlot
|
| 6 |
from functions import Piecewise, PowerLaw
|
| 7 |
from qrf_functions import QRF_Apply, QRF_Ceramic
|
| 8 |
from . import blueprint
|
|
|
|
| 123 |
## use categories
|
| 124 |
## TODO what is the correct worst-case for a generic polymer? G2?
|
| 125 |
CHRIS_category = categories[pIndex]
|
| 126 |
+
rng = np.random.Generator(np.random.PCG64(seed=12345))
|
| 127 |
+
D_dist_noswell, D_dist_swell = get_D_dists(Swelling_wtfrac, T+273.15, Polymer_Tg+273.15, SolventName, SolventMW, SoluteMW, CHRIS_category, rng, return_DCs=False, N=N_sample)
|
| 128 |
M0_pred = get_M_dist(D_dist_swell, M_expt, PolymerVolume, SurfaceArea, SolventVolume, ExtractionTime*3600, K_expt=K_expt)
|
| 129 |
+
if 0:
|
| 130 |
print('Swelling_wtfrac, T+273.15, Polymer_Tg+273.15, SolventName, SolventMW, SoluteMW, CHRIS_category')
|
| 131 |
print(Swelling_wtfrac, T+273.15, Polymer_Tg+273.15, SolventName, SolventMW, SoluteMW, CHRIS_category)
|
| 132 |
print(np.nanquantile(D_dist_swell, [0.05,0.5,0.95]))
|
|
|
|
| 139 |
method = 'wc'
|
| 140 |
|
| 141 |
# Generate the rate plot using matplotlib
|
| 142 |
+
#pngImageB64String = CdfPlot(M0_pred[~np.isnan(M0_pred)], units=units)
|
| 143 |
+
|
| 144 |
+
# table of percentiles
|
| 145 |
+
#vals = np.quantile(M0_pred, [0.05,0.25,0.5,0.75,0.95])
|
| 146 |
+
#vals = [SigFigs(v,6) for v in np.quantile(M0_pred, [0.05,0.25,0.5,0.75,0.95])]
|
| 147 |
+
vals = np.quantile(M0_pred, [0.05,0.25,0.5,0.75,0.95])
|
| 148 |
+
pcts = np.round(vals/vals[2]*100,1)
|
| 149 |
+
vals = [HtmlNumber(v,3) for v in vals]
|
| 150 |
+
#df_table = pd.DataFrame(data=np.array([[r'5<sup>th</sup>', r'25<sup>th</sup>', r'50<sup>th</sup> (median)', r'75<sup>th</sup>', r'95<sup>th</sup>'], vals]).T, columns=[r'Percentile', r'\( M_0 \)'])
|
| 151 |
+
df_table = pd.DataFrame(data=np.array([[r'5<sup>th</sup>', r'25<sup>th</sup>', r'50<sup>th</sup> (median)', r'75<sup>th</sup>', r'95<sup>th</sup>'], vals, pcts]).T, columns=[r'Percentile', r'\( M_0 \)'+f' ({units})', r'\( M_0 \) (% median)'])
|
| 152 |
+
#df_table[r'\( M_0 \)'] = df_table[r'\( M_0 \)'].astype(float)
|
| 153 |
+
#table = df_table.to_html(index=False, escape=False, justify='center')
|
| 154 |
+
#table = df_table.style.set_properties(subset=['\( M_0 \)'], **{'text-align': 'right'}).format(lambda x: f"{float(x):.3f}", subset='\( M_0 \)').set_table_attributes('border="1"').hide(axis='index').to_html(index=False, escape=False, justify='center')
|
| 155 |
+
table = df_table.style.set_properties(subset=[f'\( M_0 \) ({units})', r'\( M_0 \) (% median)'], **{'text-align': 'right'}).set_table_attributes('border="1"').hide(axis='index').to_html(index=False, escape=False, justify='center')
|
| 156 |
+
#print(table)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
|
| 158 |
tau = np.nanquantile(D_dist_swell,0.5) * (ExtractionTime*3600) / (PolymerVolume/SurfaceArea)**2
|
| 159 |
|
|
|
|
| 161 |
tau_out = SigFigs(tau,6)
|
| 162 |
|
| 163 |
return render_template('quantity_report.html', show_properties=show_properties, polymers=polymers, pIndex=pIndex,
|
| 164 |
+
area=SurfaceArea, vol=PolymerVolume, units=units, M=M_expt, M0=M0_out, time=ExtractionTime,
|
| 165 |
solventvol=SolventVolume, solventname=SolventName, swelling=Swelling_percent, K=K_expt, T=T, tau=tau_out,
|
| 166 |
+
chemName=chemName, MW=MW, LogP=LogP, rho=rho, mp=mp, iupac=iupac, cas=cas, smiles=smiles, molImage=molImage, table=table,
|
| 167 |
LogP_origin=LogP_origin, rho_origin=rho_origin, mp_origin=mp_origin, ceramic=is_ceramic, methods=[method,Polymer_Tg,PolymerDensity],
|
| 168 |
mass=mass, density=PolymerDensity)
|
| 169 |
|
quantity_module/templates/quantity_index.html
CHANGED
|
@@ -11,6 +11,12 @@
|
|
| 11 |
<script src="{{ url_for('static',filename='bootstrap.min.js') }}" integrity="sha384-VHvPCCyXqtD5DqJeNxl2dtTyhF78xXNXdkwX1CZeRusQfRKp+tA7hAShOK/B/fQ2" crossorigin="anonymous"></script>
|
| 12 |
<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='styles.css') }}">
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
</head>
|
| 15 |
|
| 16 |
<img src="{{ url_for('static',filename='images/FDAlogo.png') }}" style="float: left;" height="100"/>
|
|
@@ -31,22 +37,33 @@ For a history of updates, please see the <a href="{{url_for('.static', filename=
|
|
| 31 |
|
| 32 |
<!-- Chemical input section -->
|
| 33 |
|
| 34 |
-
<
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
<!-- Modal -->
|
| 52 |
<div id="LeachModal" class="modal fade" role="dialog">
|
|
@@ -77,17 +94,29 @@ For a history of updates, please see the <a href="{{url_for('.static', filename=
|
|
| 77 |
|
| 78 |
<!-- Polymer matrix input section -->
|
| 79 |
|
| 80 |
-
<
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
<
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
</
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
<!-- Modal -->
|
| 93 |
<div id="PolymerModal" class="modal fade" role="dialog">
|
|
@@ -115,19 +144,21 @@ Glass transition temperature (°C): <input name="Polymer_Tg" id="Polymer_Tg"
|
|
| 115 |
|
| 116 |
<!-- Extraction parameters input section -->
|
| 117 |
|
| 118 |
-
<
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
|
|
|
|
|
|
| 131 |
|
| 132 |
<!-- Modal -->
|
| 133 |
<div id="ExtractionModal" class="modal fade" role="dialog">
|
|
@@ -160,7 +191,7 @@ Glass transition temperature (°C): <input name="Polymer_Tg" id="Polymer_Tg"
|
|
| 160 |
<p><button type="submit">Estimate total quantity</button></p>
|
| 161 |
|
| 162 |
<!--
|
| 163 |
-
<
|
| 164 |
Cumulative exposure duration(s):
|
| 165 |
<input type="checkbox" id="exposure1d" name="exposure1d" value="exposure1d" checked=True, disabled=True>
|
| 166 |
<label for="exposure1d">1 day</label>
|
|
|
|
| 11 |
<script src="{{ url_for('static',filename='bootstrap.min.js') }}" integrity="sha384-VHvPCCyXqtD5DqJeNxl2dtTyhF78xXNXdkwX1CZeRusQfRKp+tA7hAShOK/B/fQ2" crossorigin="anonymous"></script>
|
| 12 |
<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='styles.css') }}">
|
| 13 |
|
| 14 |
+
<style>
|
| 15 |
+
table, th, td {
|
| 16 |
+
border: 1px solid black;
|
| 17 |
+
text-align: left;
|
| 18 |
+
}
|
| 19 |
+
</style>
|
| 20 |
</head>
|
| 21 |
|
| 22 |
<img src="{{ url_for('static',filename='images/FDAlogo.png') }}" style="float: left;" height="100"/>
|
|
|
|
| 37 |
|
| 38 |
<!-- Chemical input section -->
|
| 39 |
|
| 40 |
+
<table id="table1" align="left" style="float: none;">
|
| 41 |
+
<tr><td colspan="2"><h4> Chemical identity <button type="button" class="Info_btn" data-toggle="modal" data-target="#LeachModal" >ⓘ</button> </h4></td></tr>
|
| 42 |
+
|
| 43 |
+
<tr>
|
| 44 |
+
<th> Identifier type </th>
|
| 45 |
+
<td> <select name="IDtype">
|
| 46 |
+
<option value="CAS" selected>CAS</option>
|
| 47 |
+
<option value="SMILES" >SMILES</option>
|
| 48 |
+
<option value="common" >Common name</option>
|
| 49 |
+
</select>
|
| 50 |
+
</td>
|
| 51 |
+
</tr>
|
| 52 |
+
<tr>
|
| 53 |
+
<th>Identifier</th>
|
| 54 |
+
<td><input name="chemName" id="chemName" type="text" value="" required></td>
|
| 55 |
+
</tr>
|
| 56 |
+
</tr>
|
| 57 |
+
<th>Extracted amount</th>
|
| 58 |
+
<td><input name="amount" id="amount" value="1.0" step="any" min="0.000001" type="number" required></td>
|
| 59 |
+
</tr>
|
| 60 |
+
</tr>
|
| 61 |
+
<th> Amount units</th>
|
| 62 |
+
<td><select name="units">
|
| 63 |
+
<option value="mg" selected>mg</option>
|
| 64 |
+
<option value="µg">µg</option>
|
| 65 |
+
</select>
|
| 66 |
+
</td>
|
| 67 |
|
| 68 |
<!-- Modal -->
|
| 69 |
<div id="LeachModal" class="modal fade" role="dialog">
|
|
|
|
| 94 |
|
| 95 |
<!-- Polymer matrix input section -->
|
| 96 |
|
| 97 |
+
<tr><td colspan="2"><h4> Polymer matrix <button type="button" class="Info_btn" data-toggle="modal" data-target="#PolymerModal">ⓘ</button> </td></tr></h4>
|
| 98 |
+
<tr>
|
| 99 |
+
<th>Matrix</th>
|
| 100 |
+
<td><select name="polymer" id="polymer" style="max-width:20em;">
|
| 101 |
+
<option value="{{polymers[0]}}" selected>{{polymers[0]}}</option>
|
| 102 |
+
{% for polymer in polymers[1:] %}
|
| 103 |
+
<option value="{{polymer}}">{{polymer}}</option>
|
| 104 |
+
{% endfor %}
|
| 105 |
+
</select>
|
| 106 |
+
</td>
|
| 107 |
+
</tr>
|
| 108 |
+
<tr>
|
| 109 |
+
<th>Mass (g)</th>
|
| 110 |
+
<td><input name="mass" id="mass" step="any" value="1.0" min="0.000001" type="number" required> </td>
|
| 111 |
+
</tr>
|
| 112 |
+
<tr>
|
| 113 |
+
<th>Density (g/cm<sup>3</sup>)</th>
|
| 114 |
+
<td><input name="density" id="density" step="any" value="1.0" min="0.01" type="number" required></td>
|
| 115 |
+
</tr>
|
| 116 |
+
<tr>
|
| 117 |
+
<th>Glass transition temperature (°C)</th>
|
| 118 |
+
<td><input name="Polymer_Tg" id="Polymer_Tg" step="any" min="-273.15" max="500" value="0" type="number" required></td>
|
| 119 |
+
</tr>
|
| 120 |
|
| 121 |
<!-- Modal -->
|
| 122 |
<div id="PolymerModal" class="modal fade" role="dialog">
|
|
|
|
| 144 |
|
| 145 |
<!-- Extraction parameters input section -->
|
| 146 |
|
| 147 |
+
<tr><td colspan="2"><h4> Extraction parameters <button type=button class="Info_btn" data-toggle="modal" data-target="#ExtractionModal">ⓘ</button></td></tr> </h4>
|
| 148 |
+
<tr><th>Device surface area (cm<sup>2</sup>)</th><td> <input name="area" id="area" step="any" value="5.0" min="0.001" type="number" required></td></tr>
|
| 149 |
+
<tr><th>Duration (hours)</th><td> <input name="time" id="time" step="any" value="24.0" min="0.001" type="number" required></td></tr>
|
| 150 |
+
<tr><th>Temperature (°C)</th><td> <input name="T" id="T" step="any" value="50.0" min="20" max="75" type="number" required></td></tr>
|
| 151 |
+
<tr><th>Solvent</th>
|
| 152 |
+
<td> <select name="solventname" id="solventname">
|
| 153 |
+
<option value="{{solvents[0]}}" selected>{{solvents[0]}}</option>
|
| 154 |
+
{% for solvent in solvents[1:] %}
|
| 155 |
+
<option value="{{solvent}}">{{solvent}}</option>
|
| 156 |
+
{% endfor %}
|
| 157 |
+
</select> </td></tr>
|
| 158 |
+
<tr><th>Solvent volume (mL)</th><td> <input name="solventvol" id="solventvol" step="any" value="10.0" min="0.001" type="number" required></td></tr>
|
| 159 |
+
<tr><th>Swelling amount (wt%)</th><td> <input name="swelling" id="swelling" step="any" value="10.0" max="100.0" min="0.0" type="number" required></td></tr>
|
| 160 |
+
<tr><th>Partition coefficient</th><td> <input name="K" id="K" step="any" value="10.0" min="0.00001" type="number" required></td></tr>
|
| 161 |
+
</table>
|
| 162 |
|
| 163 |
<!-- Modal -->
|
| 164 |
<div id="ExtractionModal" class="modal fade" role="dialog">
|
|
|
|
| 191 |
<p><button type="submit">Estimate total quantity</button></p>
|
| 192 |
|
| 193 |
<!--
|
| 194 |
+
<h4> Exposure assessment <button type=button class="Info_btn" data-toggle="modal" data-target="#ExposureModal">ⓘ</button> </h4>
|
| 195 |
Cumulative exposure duration(s):
|
| 196 |
<input type="checkbox" id="exposure1d" name="exposure1d" value="exposure1d" checked=True, disabled=True>
|
| 197 |
<label for="exposure1d">1 day</label>
|
quantity_module/templates/quantity_report.html
CHANGED
|
@@ -75,13 +75,13 @@
|
|
| 75 |
|
| 76 |
<p>
|
| 77 |
{% if methods[0]=="category" %}
|
| 78 |
-
<u> Modeling extraction from {{polymers[pIndex]}} estimates the total quantity
|
| 79 |
{% elif methods[0]=="wc" %}
|
| 80 |
-
<u> Modeling extraction from the polymer (with worst-case diffusion in water assumed because no T<sub>g</sub> was specified) estimates the total quantity
|
| 81 |
{% elif methods[0]=="qrf" %}
|
| 82 |
-
<u> Modeling extraction from the polymer (with density = {{methods[2]}} g/cm<sup>3</sup> and T<sub>g</sub> = {{methods[1]}} °C) estimates the total quantity
|
| 83 |
{% elif methods[0]=="qrf/wc" %}
|
| 84 |
-
<u> Modeling extraction from the polymer (with worst-case diffusion in water assumed because this system is outside the model training domain) estimates the total quantity
|
| 85 |
{% endif %}
|
| 86 |
<p>
|
| 87 |
|
|
@@ -111,18 +111,23 @@ where \( \tau= D t A^2 / V^2 \) and \( A \) and \( V \) are the surface area and
|
|
| 111 |
It can be helpful to examine the cumulative amount released over various exposure durations. For example, the 30-day cumulative exposure may be compared to the TSL<sub>≤30 d</sub> as recommended in ISO 10993-17:2023. Note that this calculation assumes a single device is used for the entire duration. If multiple devices are used concurrently or sequentially (e.g., daily replacement), this should be accounted for during toxicological risk assessment.
|
| 112 |
</p>
|
| 113 |
|
|
|
|
| 114 |
<div>
|
| 115 |
{{ release_table | safe }}
|
| 116 |
</div> -->
|
| 117 |
|
| 118 |
<p>
|
| 119 |
-
This estimate was derived using the
|
| 120 |
|
| 121 |
\[
|
| 122 |
-
\frac{M}{M_0} = \
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
\]
|
| 124 |
|
| 125 |
-
where \( \tau= D t A^2 / V_p^2 \), \( A \) and \( V_p \) are the surface area and volume of the polymer matrix, respectively, \( D \) is a conservative estimate of the diffusion coefficient of the extractable within the polymer matrix, and \( t \) is time. The quantity \( \Psi = V_s/V_p K \), where \( V_s \) is the solvent volume and \( K \) is the polymer-solvent partition coefficient for the extractable. \( M_0 \) is total quantity initially contained in the polymer. Based on the input provided, the calculation used the following values:
|
| 126 |
</p>
|
| 127 |
|
| 128 |
<p>
|
|
@@ -132,14 +137,16 @@ Duration \( t \) = {{time}} h <br>
|
|
| 132 |
Temperature = {{T}} °C <br>
|
| 133 |
Solvent = {{solventname}} <br>
|
| 134 |
Solvent volume \( V_s \) = {{solventvol}} cm<sup>3</sup> <br>
|
| 135 |
-
Polymer volume \( V_p \) = {{vol}} cm<sup>3</sup> (based on polymer mass = {{mass}} g and density = {{density}} g/cm<sup>3</sup> <br>
|
| 136 |
-
Partition coefficient = {{K}} <br>
|
| 137 |
Swelling = {{swelling}} wt% (used to estimate \( D \))<br>
|
| 138 |
</p>
|
| 139 |
|
| 140 |
-
<p>The total quantity reported above is the median of
|
| 141 |
|
| 142 |
-
<
|
|
|
|
|
|
|
| 143 |
|
| 144 |
<p>The progress of the extraction can be expressed through the dimensionless time \( \tau = Dt/L^2 \), where \( D \) is the solute diffusivity in the polymer, \( t \) is the extraction duration, and \( L = V_p/A \) is the characteristic length scale. For your extraction, \( \tau \) = {{tau}}. Extractions with \( \tau \) ≥ 0.1 result in more accurate estimates of the total quantity, and when \( \tau \) ≥ 1.0 the extracted amount may be used directly as the total quantity.</p>
|
| 145 |
|
|
|
|
| 75 |
|
| 76 |
<p>
|
| 77 |
{% if methods[0]=="category" %}
|
| 78 |
+
<u> Modeling extraction from {{polymers[pIndex]}} estimates the total quantity = {{M0}} {{units}}. </u>
|
| 79 |
{% elif methods[0]=="wc" %}
|
| 80 |
+
<u> Modeling extraction from the polymer (with worst-case diffusion in water assumed because no T<sub>g</sub> was specified) estimates the total quantity = {{M0}} {{units}}. </u>
|
| 81 |
{% elif methods[0]=="qrf" %}
|
| 82 |
+
<u> Modeling extraction from the polymer (with density = {{methods[2]}} g/cm<sup>3</sup> and T<sub>g</sub> = {{methods[1]}} °C) estimates the total quantity = {{M0}} {{units}}. </u>
|
| 83 |
{% elif methods[0]=="qrf/wc" %}
|
| 84 |
+
<u> Modeling extraction from the polymer (with worst-case diffusion in water assumed because this system is outside the model training domain) estimates the total quantity = {{M0}} {{units}}. </u>
|
| 85 |
{% endif %}
|
| 86 |
<p>
|
| 87 |
|
|
|
|
| 111 |
It can be helpful to examine the cumulative amount released over various exposure durations. For example, the 30-day cumulative exposure may be compared to the TSL<sub>≤30 d</sub> as recommended in ISO 10993-17:2023. Note that this calculation assumes a single device is used for the entire duration. If multiple devices are used concurrently or sequentially (e.g., daily replacement), this should be accounted for during toxicological risk assessment.
|
| 112 |
</p>
|
| 113 |
|
| 114 |
+
(1.+alpha)*(1.-np.exp(T/alpha**2.)*sp.special.erfc(np.sqrt(T)/alpha))
|
| 115 |
<div>
|
| 116 |
{{ release_table | safe }}
|
| 117 |
</div> -->
|
| 118 |
|
| 119 |
<p>
|
| 120 |
+
This estimate was derived using the solutions to the conservative plane sheet model for mass release, \( M \):
|
| 121 |
|
| 122 |
\[
|
| 123 |
+
\frac{M(\tau)}{M_0} = \left\{
|
| 124 |
+
\begin{array}{cr}
|
| 125 |
+
(1+\Psi) \left[1-\exp\left( \frac{\tau}{\alpha^2} \right) \mathop{\rm erfc} \left( \frac{\tau^{0.5}}{\Psi} \right) \right] & \tau \leq 0.05 \\
|
| 126 |
+
\frac{1}{1+1/\Psi}\left[1-\sum^\infty_{n=1} \frac{2\Psi(1+\Psi)}{1+\Psi+\Psi^2q_n^2}\exp\left(-\tau q_n^2\right)\right] & \tau > 0.05
|
| 127 |
+
\end{array} \right.
|
| 128 |
\]
|
| 129 |
|
| 130 |
+
where \( \tau= D t A^2 / V_p^2 \), \( A \) and \( V_p \) are the surface area and volume of the polymer matrix, respectively, \( D \) is a conservative estimate of the diffusion coefficient of the extractable within the polymer matrix, and \( t \) is time. The quantity \( \Psi = V_s/V_p K \), where \( V_s \) is the solvent volume and \( K \) is the polymer-solvent partition coefficient for the extractable. \( q_n \) are the roots of \( \tan x + \Psi x \). \( M_0 \) is total quantity initially contained in the polymer. Based on the input provided, the calculation used the following values:
|
| 131 |
</p>
|
| 132 |
|
| 133 |
<p>
|
|
|
|
| 137 |
Temperature = {{T}} °C <br>
|
| 138 |
Solvent = {{solventname}} <br>
|
| 139 |
Solvent volume \( V_s \) = {{solventvol}} cm<sup>3</sup> <br>
|
| 140 |
+
Polymer volume \( V_p \) = {{vol}} cm<sup>3</sup> (based on polymer mass = {{mass}} g and density = {{density}} g/cm<sup>3</sup>) <br>
|
| 141 |
+
Partition coefficient \( K \)= {{K}} <br>
|
| 142 |
Swelling = {{swelling}} wt% (used to estimate \( D \))<br>
|
| 143 |
</p>
|
| 144 |
|
| 145 |
+
<p>The total quantity reported above is the median of the distribution of predicted amounts. Additional percentiles are provided here for informational purposes:</p>
|
| 146 |
|
| 147 |
+
<div>
|
| 148 |
+
{{ table | safe }}
|
| 149 |
+
</div>
|
| 150 |
|
| 151 |
<p>The progress of the extraction can be expressed through the dimensionless time \( \tau = Dt/L^2 \), where \( D \) is the solute diffusivity in the polymer, \( t \) is the extraction duration, and \( L = V_p/A \) is the characteristic length scale. For your extraction, \( \tau \) = {{tau}}. Extractions with \( \tau \) ≥ 0.1 result in more accurate estimates of the total quantity, and when \( \tau \) ≥ 1.0 the extracted amount may be used directly as the total quantity.</p>
|
| 152 |
|