Table of Contents
SFPPy - Python Framework for Food Contact Compliance and Risk Assessment ๐โฉ๐๐ ๏ธ Overview๐ Main Modules (Located in patankar/
)Why Patankar?๐ | 1 | QUICK START๐ก | 2 | USAGE SNIPPETS| 2.1 | Snippet 1๏ธโฃ | Simple Migration Simulation| 2.2 | Snippet 2๏ธโฃ | Retrieving Molecular Properties and Toxicological Data| 2.3 | Snippet 3๏ธโฃ | Defining a Custom Packaging Shape| 2.4 | Snippet 4๏ธโฃ | Using โฉ as Mass Transfer Operator in Chained Simulations๐งฉ How It Works| 2.5 | Snippet 5๏ธโฃ | Parameter linking ๐ via layerLink
๐ | 3 | CASE STUDIES| 3.1 | Example 1: | Mass Transfer from โถ Monolayer Materials| 3.2 | Example 2 | Mass Transfer in โป๏ธ Recycled PP Bottles| 3.3 | Example 3 | Advanced Migration Simulation โ๏ธ with Variants| 3.4 | Example 4 | Parameter Fitting and Optimization โ๏ธ๐ | 3 | Why SFPPy?
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. For example, for materials in contact with ๐๐ cosmetics and ๐งด home care products read CosPaTox guidelines.
This project translates well-established chemical migration models from MATLAB/Octave and other languages to pure Python๐, ensuring minimal dependencies.
๐ก If you need background or training, please refer to ๐ this book on
migration modeling
or the European training platform ๐จ๐ผโ๐ป FitNESS.โจNote that can also fit your own experimental ๐งซโฒ๐ก
migration kinetics
with SFPPy (seeexample 4
) and explore new strategies to identify โ๏ธ partition coefficients and ๐ฒ diffusivities from โmolecular structures.
patankar/
)module | description |
---|---|
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 and ToxTree (cached locally). |
โ 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 ๐Python classes, allowing easy expansion to cover additional cases and implement new ๐ฎprediction methods and models
. I recommend this reading if you plan to โจ modifySFFPy
for your own needs.
xxxxxxxxxx
# Clone the repository
git clone https://github.com/ovitrac/SFPPy.git
cd SFPPy
# Install dependencies
pip install -r requirements.txt
๐ง SFPPy
ย is built on a minimum number of packages ๐ฆ๐ฆ, which are all standard. Customized libraries are included in ๐patankar/private/
ย and do not require specific installation.ย
โ
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.
xxxxxxxxxx
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:
xxxxxxxxxx
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
xxxxxxxxxx
from patankar.loadpubchem import migrantToxtree # combine PubChem and ToxTree
substance = migrantToxtree("formaldehyde")
output
xxxxxxxxxx
<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
xxxxxxxxxx
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.
โ ๏ธ Note: To efficiently simulate the migration of substances from packaging materials, SFPPy unfolds complex 3D packaging geometries into an equivalent 1D representation. This transformation assumes that substance desorption is predominantly governed by diffusion within the walls of the packaging.
๐ 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.
๐ 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.
xxxxxxxxxx
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 temperature
hotfilled
: Represents high-temperature filling processes
stacked
: Models setoff migration when packaging layers are stacked
๐ฅ Food Types & Interactions:
realfood
: Represents actual food matrices
liquid
: Specifies that the food is a liquid
fat
: Indicates a fatty food, influencing partitioning behavior
๐ฌ By combining these components, SFPPy allows streamlined, physics-based simulations with minimal code. ๐
layerLink
xxxxxxxxxx
# 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.
๐ฅช 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.
๐ผ 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.
๐ฆ 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 โฉ.
โ
Fit diffusivities (
โ
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.
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