Module DFVtol
Expand source code
import numpy as np
import matplotlib.pyplot as plt
# This script shows the prediction of diffusivities of toluene using hole Free-Volume theory
# at different temperatures in different polymers (LDPE, PMMA, PS, PVAc, PET).
# gPET corresponds to dry PET (unplasticized) and wPET corresponds to plasticized PET.
#
# Data have been extracted from the script figure8_revSep2019_2025.m used to generate
# Figure 9 for the reference mentioned below.
#
# REFERENCE
# Zhu Y., Welle, F. and Vitrac O. A blob model to parameterize polymer hole free volumes and solute diffusion",
# *Soft Matter* **2019**, 15(42), 8912-8932. DOI: https://doi.org/10.1039/C9SM01556F
#
# ABSTRACT
# Solute diffusion in solid polymers has tremendous applications in packaging,
# reservoir, and biomedical technologies but remains poorly understood. Diffusion
# of non-entangled linear solutes with chemically identical patterns (blobs) deviates
# dramatically in polymers in the solid-state (αlin > 1, Macromolecules 2013, 46, 874)
# from their behaviors in the molten state (αlin = 1, Macromolecules, 2007, 40, 3970).
# This work uses the scale invariance of the diffusivities, D, of linear probes
# D(N·M_blob + M_anchor,T,Tg) = N^(-αlin(T,Tg)) * D(M_blob + M_anchor,T,Tg) comprising
# N identical blobs of mass M_blob and possibly one different terminal pattern (anchor of
# mass M_anchor) to evaluate the amounts of hole-free volume in seven polymers (aliphatic,
# semi-aromatic and aromatic) over a broad range of temperatures (−70 K ≤ T − Tg ≤ 160 K).
# The new parameterization of the concept of hole-free volumes opens the application of
# the free-volume theory (FVT) developed by Vrentas and Duda to practically any polymer,
# regardless of the availability of free-volume parameters. The quality of the estimations
# was tested with various probes including n-alkanes, 1-alcohols, n-alkyl acetates, and
# n-alkylbenzene. The effects of enthalpic and entropic effects of the blobs and the anchor
# were analyzed and quantified. Blind validation of the reformulated FVT was tested
# successfully by predicting from first principles the diffusivities of water and toluene
# in amorphous polyethylene terephthalate from 4 °C to 180 °C and in various other polymers.
# The new blob model would open the rational design of additives with controlled diffusivities
# in thermoplastics.
# Constants
R = 8.31
T0K = 273.15 # K
# Polymer data (Tg in K) stored in a dictionary.
data = {
'LDPE': {'Tg': 148.15, 'D0': 1.87e-08, 'xi': 0.615, 'ref': 3, 'Ka': 144, 'Kb': 40, 'E': 0, 'r': 0.5},
'PMMA': {'Tg': 381.15, 'D0': 1.87e-08, 'xi': 0.56, 'ref': 2, 'Ka': 252, 'Kb': 65, 'E': 0, 'r': 0.5},
'PS': {'Tg': 373.15, 'D0': 4.8e-08, 'xi': 0.584, 'ref': 2, 'Ka': 144, 'Kb': 40, 'E': 0, 'r': 0.5},
'PVAc': {'Tg': 305.15, 'D0': 1.87e-08, 'xi': 0.86, 'ref': 4, 'Ka': 142, 'Kb': 40, 'E': 0, 'r': 0.5},
'gPET': {'Tg': 349.15, 'D0': 1.0205e-08, 'xi': 0.6761, 'ref': 5, 'Ka': 252, 'Kb': 65, 'E': 0, 'r': 0.6153},
'wPET': {'Tg': 316.15, 'D0': 1.02046e-08, 'xi': 0.6761, 'ref': 5, 'Ka': 252, 'Kb': 65, 'E': 0, 'r': 0.277734},
}
# References list (for documentation)
references = [
'Vrentas and Vrentas, 1994',
'Zielinski and Duda, 1992',
'Lutzow et al., 1999',
'Hong, 1995',
# toluene in PET
'Welle,2008',
'Pennarun et al., 2004',
'Welle,2013',
'our work (permeation)',
'our work (sorption)',
]
# Main function that computes the predicted diffusivity DscalingPlike
def DscalingPlike(T, polymer):
"""
Compute the predicted diffusivity using the scaling law.
Parameters:
T : float
Temperature in Kelvin.
polymer : str
Polymer name (must be one of the keys in the data dictionary).
Returns:
float: Predicted diffusivity.
"""
# Helper function to lookup a property value from the data dictionary.
def lookup(P, prop):
return data[P][prop]
# Define alpha for T >= Tg.
def alpha(T, Tg, Ka, Kb):
return 1 + Ka / (T - Tg + Kb)
# Define alphag for T < Tg.
def alphag(T, Tg, Ka, Kb, r):
return 1 + Ka / (r * (T - Tg) + Kb)
deltaT = 2 # (K) sharpness of the transition at Tg
# Heaviside-like function using tanh.
def H(T_val, Tg_val):
return 0.5 * (1 + np.tanh(4 / deltaT * (T_val - Tg_val)))
# Composite alpha function that smoothly transitions between alpha and alphag.
def alphaT(T, Tg, Ka, Kb, r):
# Note: H(lookup(polymer, 'Tg'), T) computes H(Tg,T) and H(T, lookup(polymer, 'Tg')) computes H(T,Tg)
return H(lookup(polymer, 'Tg'), T) * alphag(T, Tg, Ka, Kb, r) + H(T, lookup(polymer, 'Tg')) * alpha(T, Tg, Ka, Kb)
betalin = 1
# Function to compute Plike (see publication, Plike holds polymer effects)
def Plike(T, polymer):
Tg = lookup(polymer, 'Tg')
Ka = lookup(polymer, 'Ka')
Kb = lookup(polymer, 'Kb')
r = lookup(polymer, 'r')
return (alphaT(T, Tg, Ka, Kb, r) + betalin) / 0.24
# Compute the predicted diffusivity.
D0 = lookup(polymer, 'D0')
E = lookup(polymer, 'E')
xi = lookup(polymer, 'xi')
return D0 * np.exp(-E / (R * T)) * np.exp(-xi * Plike(T, polymer))
# Test data (similar to a DataFrame) stored as a list of dictionaries.
test_data = [
{'polymer': 'PS', 'T': 451.15, 'Dexp': 4e-11},
{'polymer': 'PS', 'T': 433.15, 'Dexp': 1.5e-11},
{'polymer': 'PS', 'T': 413.15, 'Dexp': 2e-12},
{'polymer': 'PS', 'T': 383.15, 'Dexp': 1.5e-13},
{'polymer': 'PMMA', 'T': 433.15, 'Dexp': 9e-13},
{'polymer': 'PMMA', 'T': 413.15, 'Dexp': 2e-13},
{'polymer': 'PMMA', 'T': 403.15, 'Dexp': 8e-14},
{'polymer': 'LDPE', 'T': 343.15, 'Dexp': 7e-11},
{'polymer': 'PVAc', 'T': 383.15, 'Dexp': 2e-12},
{'polymer': 'PVAc', 'T': 353.15, 'Dexp': 1e-13},
{'polymer': 'PVAc', 'T': 313.15, 'Dexp': 8e-16},
{'polymer': 'PS', 'T': 388.15, 'Dexp': 7.2e-13},
{'polymer': 'PS', 'T': 451.15, 'Dexp': 4e-11},
{'polymer': 'PS', 'T': 433.15, 'Dexp': 1.5e-11},
{'polymer': 'PS', 'T': 413.15, 'Dexp': 2e-12},
{'polymer': 'PS', 'T': 383.15, 'Dexp': 1.5e-13},
{'polymer': 'PS', 'T': 388.15, 'Dexp': 7.2e-13},
{'polymer': 'PMMA', 'T': 433.15, 'Dexp': 9e-13},
{'polymer': 'PMMA', 'T': 413.15, 'Dexp': 2e-13},
{'polymer': 'PMMA', 'T': 403.15, 'Dexp': 8e-14},
{'polymer': 'wPET', 'T': 313.15, 'Dexp': 4.1e-16},
{'polymer': 'gPET', 'T': 313.15, 'Dexp': 2e-18},
{'polymer': 'gPET', 'T': 313.15, 'Dexp': 3.8e-18},
{'polymer': 'gPET', 'T': 333.15, 'Dexp': 2.6e-17},
{'polymer': 'wPET', 'T': 313.15, 'Dexp': 6.3e-17},
{'polymer': 'wPET', 'T': 313.15, 'Dexp': 2.1e-16},
{'polymer': 'wPET', 'T': 313.15, 'Dexp': 4.8e-16},
{'polymer': 'wPET', 'T': 323.15, 'Dexp': 4.1e-16},
{'polymer': 'wPET', 'T': 323.15, 'Dexp': 6.1e-16},
{'polymer': 'gPET', 'T': 373.15, 'Dexp': 3.26e-15},
{'polymer': 'gPET', 'T': 453.15, 'Dexp': 2.78e-12},
{'polymer': 'gPET', 'T': 434.15, 'Dexp': 1.17e-12},
{'polymer': 'gPET', 'T': 414.15, 'Dexp': 1.9e-13},
{'polymer': 'gPET', 'T': 394.15, 'Dexp': 2.47e-14},
]
# Compute predicted diffusivity for each test data point.
for entry in test_data:
entry['Dpred'] = DscalingPlike(entry['T'], entry['polymer'])
# Plot experimental vs predicted D values.
plt.figure(figsize=(8, 6))
# Define a color map for polymers.
colors = {
'LDPE': 'blue',
'PMMA': 'green',
'PS': 'red',
'PVAc': 'orange',
'gPET': 'purple',
'wPET': 'brown'
}
# Plot points for each polymer with its own color.
for polymer in colors.keys():
x = [entry['Dexp'] for entry in test_data if entry['polymer'] == polymer]
y = [entry['Dpred'] for entry in test_data if entry['polymer'] == polymer]
if x: # Only plot if there are data points.
plt.scatter(x, y, label=polymer, color=colors[polymer], edgecolors='k')
# Plot the reference line y = x.
x_vals = np.logspace(-20, -10, 100)
plt.plot(x_vals, x_vals, 'k-', label='y = x')
plt.xscale('log')
plt.yscale('log')
plt.xlabel('experimental D values (m$^2$/s)')
plt.ylabel('predicted D values (m$^2$/s)')
plt.title('DFV vs. experimental D values')
plt.legend()
plt.show()
Functions
def DscalingPlike(T, polymer)
-
Compute the predicted diffusivity using the scaling law.
Parameters
T : float Temperature in Kelvin. polymer : str Polymer name (must be one of the keys in the data dictionary).
Returns
float
- Predicted diffusivity.
Expand source code
def DscalingPlike(T, polymer): """ Compute the predicted diffusivity using the scaling law. Parameters: T : float Temperature in Kelvin. polymer : str Polymer name (must be one of the keys in the data dictionary). Returns: float: Predicted diffusivity. """ # Helper function to lookup a property value from the data dictionary. def lookup(P, prop): return data[P][prop] # Define alpha for T >= Tg. def alpha(T, Tg, Ka, Kb): return 1 + Ka / (T - Tg + Kb) # Define alphag for T < Tg. def alphag(T, Tg, Ka, Kb, r): return 1 + Ka / (r * (T - Tg) + Kb) deltaT = 2 # (K) sharpness of the transition at Tg # Heaviside-like function using tanh. def H(T_val, Tg_val): return 0.5 * (1 + np.tanh(4 / deltaT * (T_val - Tg_val))) # Composite alpha function that smoothly transitions between alpha and alphag. def alphaT(T, Tg, Ka, Kb, r): # Note: H(lookup(polymer, 'Tg'), T) computes H(Tg,T) and H(T, lookup(polymer, 'Tg')) computes H(T,Tg) return H(lookup(polymer, 'Tg'), T) * alphag(T, Tg, Ka, Kb, r) + H(T, lookup(polymer, 'Tg')) * alpha(T, Tg, Ka, Kb) betalin = 1 # Function to compute Plike (see publication, Plike holds polymer effects) def Plike(T, polymer): Tg = lookup(polymer, 'Tg') Ka = lookup(polymer, 'Ka') Kb = lookup(polymer, 'Kb') r = lookup(polymer, 'r') return (alphaT(T, Tg, Ka, Kb, r) + betalin) / 0.24 # Compute the predicted diffusivity. D0 = lookup(polymer, 'D0') E = lookup(polymer, 'E') xi = lookup(polymer, 'xi') return D0 * np.exp(-E / (R * T)) * np.exp(-xi * Plike(T, polymer))