System Integrator tutorial for access to the Pasteurization models via the LIBPF® Python Model User API
Introduction
Intended audience
System integrators who want to develop solutions based on the modeling of industrial continuous processes with the LIBPF® enabling technology.
Scope
This is a simple tutorial for the usage of the Pasteurization models through the Python Model User API.
We will list the available model types, instantiate one model case, manipulate it, calculate it and get some results.
Prerequisites
-
Basic knowledge of Python 2.7.
-
You should have received from a Model Developer a process model in the form of a kernel, prepared for interfacing with Python. This comes as two files you should put in your current directory:
-
LibpfUserPython.py: the module definition
-
_LibpfUserPython.so: the shared library that contains the actual implementation.
in this example is it assumed that you are working with the Pasteurization model and process (see references below).
-
Step-by-step
Enter the following Python code in a test.py file.
Set-up
Python scripts start with the shebang to indicate that the Python interpreter should be used for execution.
Next we need to load the LibpfUserPython module and the json built-in Python module for JSON encoding /decoding.
Finally we initialize the LibpfUserPython module with initializeKernel.
#!/usr/bin/env python import LibpfUserPython import json LibpfUserPython.initializeKernel()
See what model types are supported
Before we create a case (an instance of a model type) we might want to ask the LibpfUserPython module for the supported model types.
This is easy to do using the Kernel jsonListTypes API.
This method returns a complex JSON object, but in this example we just list the names of the types that can actually be instantiated (many types can only occur as sub-objects and can not be directly instantiated).
Note that the functions in the LibpfUserPython module return error codes that you should better check !
error = LibpfUserPython.intPointer() error.assign(1) print '== Now listing the types that can be instantiatied' jlt = LibpfUserPython.jsonListTypes(error) print '== jsonListTypes error code = %d '% error.value() lt = json.loads(jlt) print '== List of types that can be instantiatied:' for t in lt['types']: if t['instantiable']: print t['name']
Create a case instance
Let us proceed to create a case instance of type Pasteur with some string options set.
For that, we need first to setup a JSON object with the required information. The easy way to do so in Python is to populate a dictionary and then encode it in JSON.
The createCase method can be called with the JSON object as argument, and it will return a handle which can be used to access the new case.
cd = {u'type': u'Pasteur', u'tag': u'test', u'description': u'my first test', u'stringOptions': {u'processType': u'HTST25', u'feedType': u'chocolateIceCream'}, u'integerOptions': {}} cdj = json.dumps(cd) print '== Now instantiating type Pasteur:' ch = LibpfUserPython.createCase(cdj, error) print '== createCase error code = %d' % error.value() myCase = LibpfUserPython.Case(ch) print '== Directory of case object:' dir(myCase)
Calculate the case
A case right after instantiation has all variables at their default value. For the variable values to be meaningful, it must be explicitely calculated with a call to the calculateSync Case API endpoint.
print '== Now calculating instance' ret = myCase.calculateSync() print '== calculateSync error code = %d' % ret
Make changes and recalculate
The main use of the LIBPF® Python Model User API is to change the values of inputs and request additional calculations.
The value changes must be submitted to the set Case API endpoint as a JSON object, and the calculation must be explicitely requested with a call to the calculateSync endpoint:
hi = {u'controlled': [{u'variable': u'coolT', u'end': 283.15}, {u'variable': u'HEATER.deltaP', u'end': 12000.0}]} jhi = json.dumps(hi) print '== Now setting variables' ret = myCase.set(jhi) print '== set error code = %d '% ret ret = myCase.calculateSync() print '== calculateSync error code = %d' % ret
Read results
The results can be accessed via the get Case API endpoint.
mdot = myCase.get("S01:Tphase.mdot", error) print '== get error code = %d' % error.value() print '== S01:Tphase.mdot = %g' % mdot
Clean-up
For clean-up, de-initialize the LibpfUserPython module with uninitializeKernel.
LibpfUserPython.uninitializeKernel()
Execution
Make the test.py file executable then launch it:
chmod u+x test.py ./test.py
Expected output
LIBPF is correctly activated for site com.example_1.0 on this computer. * ****************** LIBPF 01.00.2193 [2015/06/07 15:28:37] ****************** * (C) Copyright 2004-2015 Paolo Greppi simevo s.r.l. * ******************************** Pasteurize ******************************** * (C) Copyright 2014-2015 Paolo Greppi simevo s.r.l. * **************************************************************************** * All rights reserved; do not distribute without permission. * **************************************************************************** == Now listing the types that can be instantiatied == jsonListTypes error code = 0 == List of types that can be instantiatied: Pasteur PasteurHTST15_milkWhole == Now instantiating type Pasteur: Libpf::User::createCase * Creating a new model [ si [] ss [[ feedType, chocolateIceCream] [ processType, HTST25] ]] createCase_ * Instantiate flowsheet ... createCase_ * Creation complete createCase_ * Saving to persistent storage createCase_ * Saved to persistent storage == createCase error code = 0 Libpf::User::Case::Case *** Retrieving dd504852-5eea-4d8c-bb9f-1f8f3cf2ab86 of type Pasteur from persistent storage database Pipe::Pipe *** Entered with 964 Pasteur::Pasteur *** Entered == Directory of case object: == Now calculating instance FlowSheet::calculate * Starting sequential pre-computation ... FlowSheet::calculate * Switch to simultaneous computation ... Model::reportWarning ** ===== Logging warning convergence on deltax; dubious convergence in test Libpf::User::Case::calculateSync * Computation complete with 0 errors and 1 warnings Libpf::User::Case::calculateSync * Updating results to persistent storage Libpf::User::Case::calculateSync * Updated results to persistent storage == calculateSync error code = 0 == Now setting variables Trying to set coolT Trying to set HEATER.deltaP == set error code = 0 ... Model::reportWarning ** ===== Logging warning convergence on deltax; dubious convergence in test Libpf::User::Case::calculateSync * Computation complete with 0 errors and 1 warnings Libpf::User::Case::calculateSync * Updating results to persistent storage Libpf::User::Case::calculateSync * Updated results to persistent storage == calculateSync error code = 0 == get error code = 0 == S01:Tphase.mdot = 1
Pasteurization Model references
-
Detailed process model description for the Pasteurization demo
-
Model Developer step-by-step tutorial for the creation of the Pasteurization example