SFPPy is a Python-based framework for compliance testing of food contact materials and recycled plastic safety assessment under:
- πΊπΈ US FDA regulations
- πͺπΊ European Union regulations (EFSA, EU 10/2011, etc.)
- π¨π³ Chinese GB standards
- π Other international guidelines
This project translates well-established chemical migration models from MATLAB and other languages to pure Python, ensuring minimal dependencies.
migration.py
ποΈ - Core solver using a Patankar finite-volume method for mass transfer modeling.geometry.py
π - Defines 3D packaging geometries and calculates volume/surface area.food.py
π - Models food layers and their interactions with packaging.layer.py
π - Defines materials and layers for multilayer packaging.property.py
π - Computes physical and chemical properties (e.g., diffusion, partitioning).loadpubchem.py
π¬ - Retrieves molecular properties from PubChem (cached locally).
π Click to expand
π‘ The
patankar
folder is named in honor of Suhas V. Patankar, who developed and popularized the finite volume method, which this project adapts for mass transfer problems with an arbitrary number of Rankine discontinuities.π§ The modules include a knowledge management system via extensible classes, allowing easy expansion to cover additional cases and implement new prediction methods.
# Clone the repository
git clone https://github.com/ovitrac/SFPPy.git
cd SFPPy
# Install dependencies
pip install -r requirements.txt
π§ Learn how to use
SFPPy
from Wiki Pages.
SFPPy is fully object-oriented and supports multiple syntax styles, ranging from a functional approach to a more abstract, operator-driven paradigmβall in a Pythonic manner. The snippets below demonstrate both approaches.
π Click to expand
from patankar.food import ethanol # food database
from patankar.layer import layer # material database
# Define the food contact medium and layers
simulant = ethanol() # here a food simulant
A = layer(layername="layer 1 (contact)", D=1e-15, l=50e-6, C0=0, k=1) # SI units
B = layer(layername="layer 2", D=(1e-9, "cm**2/s"), l=(100, "um"),k=2)
multilayer = A + B # layer A is contact (food is on the left)
# Run solver, plot the migration kinetics CF(t) and concentration profiles in P Cx(x,t)
solution = simulant.migration(multilayer)
hCF = solution.plotCF() # concentration kinetic in the simulant (F) for default times
hCx = solution.plotCx() # concentration profile in the multilayer packaging
# Print in PDF and PNG, export to Excel
hCF.print("myresult")
solution.comparison.save_as_csv("myresult.csv") # CSV format
solution.comparison.save_as_excel("myresult.xlsx") # Excel format
π Notations:
π Click to expand
from patankar.loadpubchem import migrant # connect to pubchem for missing substances
from patankar.food import oliveoil,water # food simulants
from patankar.layer import gPET # "glassy" PET (i.e., T<Tg)
m = migrant("bisphenol A") # bisphenol A = BPA
# Print basic properties
print(m.M, m.logP, m.polarityindex) # Molecular weight, logP value, polarity Index P'
print(m.smiles) # CC(C)(C1=CC=C(C=C1)O)C2=CC=C(C=C2)O
# Add BPA to material (P) and food simulants (F1,F2) to calculate binary properties
F1 = oliveoil(migrant=m) # F1 = food simulant oliver oil with BPA
F2 = water(migrant=m) # F2 = water with BPA
P = gPET(migrant=m) # P = PET with BPA
KFP1 = P.k / F1.k # F-to-P1 partition coefficient, k= Henry-like coefficients
KFP2 = P.k / F2.k # F-to-P2 partition coefficient, k= Henry-like coefficients
# Print partition coefficients, with k values calculated from Flory-Huggins theory
print(KFP1,KFP2) # [0.93498524] [0.00093499]
π‘ The examples show how to inject m
intoΒ food
(various classes )Β and layer
(various classes) to get customized and conservative simulations for specific substances and polymers. All properties, diffusivities
Add toxicological data from Toxtree
from patankar.loadpubchem import migrantToxtree # combine PubChem and ToxTree
substance = migrantToxtree("formaldehyde")
output
<migrantToxtree object>
Compound: formaldehyde
Name: formaldehyde
cid: 712
CAS: ['50-00-0', '8013-13 [...] 80-5', '30525-89-4']
M (min): 30.026
M_array: [30.026]
formula: CH2O
smiles: C=O
logP: [1.2]
P' (calc): [3.91591487]
Toxicology: Low (Class I)
TTC: 1.5 [Β΅g/kg bw/day]
CF TTC: 0.09 [mg/kg food intake]
alert 1: Alert For Schiff Bas [...] Formation Identified
Out: <migrantToxtree: Oplossin [...] [Dutch] - M=30.026 g/mol>
π‘ A local installation of Toxtree (java) is included with SFPPy
For the European FCM and Articles Regulation, Annex I - Authorised Substances, use the ECHA webpage
π¦ Click to expand
from patankar.geometry import Packaging3D # import basic shapes
pkg = Packaging3D('bottle', # bottle is a composite shape
body_radius=(5, 'cm'), body_height=(0.2, 'm'),
neck_radius=(19, "mm"), neck_height=(40, "mm"))
vol, area = pkg.get_volume_and_area() # extract volume and surface area
print("Volume (mΒ³):", vol)
print("Surface Area (mΒ²):", area)
π‘ The examples show how to use either pkg
or its properties to achieve mass transfer simulation for a specific geometry.
π The geometry.py
module provides tools to compute surface-area-to-volume ratios, extract wall thicknesses, and generate equivalent 1D models for mass transfer simulations.
π¦ Click to expand
π SFPPy leverages multiple inheritance to define food contact conditions by combining storage conditions, food types, and physical properties.
π Additionally, two operators play a key role in SFPPyβs intuitive syntax:
- β for combining layers and merging results
- β© for naturally representing mass transfer
With these operators, mass transfer can be abstracted into a simple, visual representation:
-
πβ©π
(Direct transfer from green to red, symbolizing migration.) -
πβ©π β©π
(Includes an intermediate step, depicting progressive migration.) -
πβ©π‘β©π β©π
(More detailed, illustrating multiple contamination stages over time.) -
πβ‘β©π
(Emphasizes active food transformation, with accelerated mass transfer.)
π SFPPy makes this abstraction possible with simple, expressive code.
from patankar.layer import gPET, PP
from patankar.food import ambient, hotfilled, realfood, fat, liquid, stacked
from patankar.loadpubchem import migrant
# Define migrant and packaging layers (ABA: PET-PP-PET)
m = migrant("limonene")
A = gPET(l=(20, "um"), migrant=m, C0=0)
B = PP(l=(500, "um"), migrant=m, C0=200)
ABA = A + B + A # the most left layer is contact (food on the left)
# Define storage and processing conditions:
# 1:storage in stacks >> 2:hot-filled container >> 3:long-term storage of packaged food
class contact1(stacked, ambient): name = "1:setoff"; contacttime = (4, "months")
class contact2(hotfilled, realfood, liquid, fat): name = "2:hotfilling"
class contact3(ambient, realfood, liquid, fat): name = "3:storage"; contacttime = (6, "months")
# Instantiate and simulate with β©
medium1, medium2, medium3 = contact1(), contact2(), contact3()
medium1 >> ABA >> medium1 >> medium2 >> medium3 # Automatic chaining
# Merge all kinetics into a single one and plot the migration kinetics
sol123 = medium1.lastsimulation + medium2.lastsimulation + medium3.lastsimulation
sol123.plotCF()
Each contact class inherits attributes from multiple base classes, allowing flexible combinations of:
-
π Storage Conditions:
ambient
: Defines standard storage at room temperaturehotfilled
: Represents high-temperature filling processesstacked
: Models setoff migration when packaging layers are stacked
-
π₯ Food Types & Interactions:
realfood
: Represents actual food matricesliquid
: Specifies that the food is a liquidfat
: Indicates a fatty food, influencing partitioning behavior
π¬ By combining these components, SFPPy allows streamlined, physics-based simulations with minimal code. π
π¦ Click to expand
# Any numeric property can be attached to a simulation with layerLink
from patankar.layer import layerLink
# Attach a variable function barrier thickness to ABA
fb_thickness = layerLink("l",indices=0) # index 0 = layer 1 (A) in contact with F
# Reuse ABA from Snippet 3 [...]
ABA.llink = fb_thicknesses
# Change dynamically the simulation by changing fb_thicknesses[0]
fb_thicknesses[0] = 12e-6 # 12 Β΅m
medium1.lastsimulation.rerun()
# [...]
π‘ Dynamic parameter binding using layerLink
connections allows:
β
Dynamic updates of [i]
refers to the layer i+1
).
β
Seamless integration of simulation and optimization tasks.
β
Robust handling of parameter uncertainties in complex simulation scenarios.
The project includes four detailed examples (example1.py
, example2.py
, example3.py
, and **example4.py**
), showcasing real-world scenarios with various materials, substances, food types, geometries, and usage conditions.
Example 1: | Mass Transfer from βΆ Monolayer Materials
- π₯ͺ Simulates the migration of Irganox 1076 and Irgafos 168 from a 100 Β΅m LDPEfilm into a fatty sandwich π₯over 10 days at 7Β°C.
- π Evaluates migration kinetics and their implications for food safety.
Example 2| Mass Transfer in β»οΈ Recycled PP Bottles
- πΌ Investigates toluenekbd< migration from a 300 Β΅m thick recycled PP bottle into a fatty liquid food.
- π‘οΈ Assesses the effect of a PET functional barrier (FB) of varying thickness on reducing migration.
Example 3 | Advanced Migration Simulation βοΈ with Variants
- π¦ Simulates migration in a trilayer (ABA) multilayer system, with PET (A) and recycled PP (B).
- π₯ Evaluates migration behavior across storage with set-off, hot-filling, and long-term storage conditions.
- βοΈ Explores variants where the migrant and layer thickness are modified to assess performance.
- πβ©π Example 3 showcases the mass transfer operator β©.
Example 4 | Parameter Fitting and Optimization βοΈ
- β
Fit diffusivities (
$D$ ) and partitioning coefficients ($\frac{k}{k_0}$ ) from migration kinetic data π. - β
Utilize dynamic parameter linking π𧲠with
layerLink
. - β Integrate simulation results directly with experiments for sensitivity analysis and optimization
β οΈ Disclaimer: These examples do not discuss sources of uncertainty. Please refer to our publications for details on the limitations of the presented approaches and assumptions.
β SFPPy
: is free and opensource.
β SFPPy
: accepts any unit as (value,"unit")
or ([value1,value2...],"unit")
.
β Operator-based chaining: >>
handles automatic mass transfer and property propagation
β Minimal code for complex simulations: +
joins layers and merges results across storage conditions
β Pythonic abstraction: Works with PubChem, ToxTree, predefined polymer materials, and 3D packaging geometries
β Built-in visualization & export: Supports Excel (.xlsx
), CSV, PDF, PNG and Matlab (if its really needed)
π¬ SFPPy
powers scalable, real-world safe food packaging simulations.
MIT License
INRAE - Olivier Vitrac
This project is part of the SFPPy initiative, aiming to bring the SafeFoodPackaging Portal version 3 (SFPP3) to the general public.
For further details, consult the online documentation and the release page for new capabilities.
π½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈ
π½οΈπ½οΈπππππ½οΈπ½οΈππππππ½οΈπ½οΈπππππ½οΈπ½οΈπ½οΈπππππ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈ
π½οΈππ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈππ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈππ½οΈπ½οΈπ½οΈππ½οΈπ½οΈππ½οΈπ½οΈπ½οΈππ½οΈπ½οΈππ½οΈπ½οΈπ½οΈππ½οΈ
π½οΈπ½οΈππππ½οΈπ½οΈπ½οΈπππππ½οΈπ½οΈπ½οΈπππππ½οΈπ½οΈπ½οΈπππππ½οΈπ½οΈπ½οΈπ½οΈππ½οΈππ½οΈπ½οΈ
π½οΈπ½οΈπ½οΈπ½οΈπ½οΈππ½οΈπ½οΈππ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈππ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈππ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈππ½οΈπ½οΈπ½οΈ
π½οΈπππππ½οΈπ½οΈπ½οΈππ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈππ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈππ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈππ½οΈπ½οΈπ½οΈ
π½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈπ½οΈ
Enlarge your window if you cannot read the logo. The snake is the totem for Python