Model Developer step-by-step tutorial for the creation of the Pasteurization example

Introduction

Intended audience

Model developers who want to develop process models with the LIBPF® process modeling technology.

Scope

Give a step-by-step tutorial and a reference for the steps required to re-create from scratch the Pasteurization example.

Directory structure

Each kernel / service is typically arranged in a subdirectory of the LIBPF® SDK.

For this example we assume there is a pasteur directory for the kernel / service. Inside the kernel / service subdirectory, create two directories include and src.

The resulting directory structure is then:

LIBPF --- include
       |
       L- src
       |
       L- scripts
       |
       L- pasteur --- include
       |          |
       |          L--- src
       |          |
       |          L--- ...
       |
       L- ...

Declare the classes

Multiple models can be provided by one kernel.

The best practice is to declare each class in a separate file, with the same name as the class.

In this example there is only one, the Pasteur class so create a header file in the pasteur/include directory and name it “Pasteur.h”

Type (or copy-paste) the flowsheet model declaration:


We strongly suggest to start here the code documentation in a doxygen-fashion.

Take care of “CUSTOM variables”, “MANDATORY” methods and “NON-MANDATORY” methods.

The “CUSTOM variables” are input/output parameters, that the model will show in the foreground. Some of them are simply pulled-up internal variable (see FlowSheet::pre and FlowSheet::post).Other can be involved in complex calculation (see Makeuserequation).

Driver

Create a model driver file in the pasteur/src directory and name it “PasteurDriver.cc”

Include all model headers

If your models’ declarations are scattered in several header files, include them all.

In this example there is only one:


Register the kernel / service

A kernel / service must be registered with:

For the pasteur example:


Register the provided types

Here the types are registered, along with a description and a list of options that will be used by the various interfaces to present these information to the user.

Type aliases can be defined, where a base type is pre-configured with certain default values for some options.

String options are defined using enumerators (see below).


We suggest to keep eventual tentative models, components, and model registrations. When you do not need them anymore just comment “//” them.

Populate the list of components

These components will be available for all the models using this driver.

In this case we will use four components already available in LIBPF®:


Populate the enumerators

These enumerators can be used to supply the string options during type construction


Define the classes

Now it is possible to start to write the actual model.

Multiple models can be provided by one kernel.

As for the class declaration in separate headers, the best practice is to define each class in a separate file, with the same name as the class.

In this example there is only one, the Pasteur class so create the model source file in the pasteur/src directory and name it “Pasteur.cc”

The usual workflow is an iterative improvement of the model through the following steps:

Implement the constructor

The class constructor must contain:

Register variables

The “CUSTOM variables” declared in the Pasteur.h file must be “registered” as part of the model.

There are two required steps:




Process options

If the model supports any string or integer option, specify in this section their default value; for each string option also specify the associated enumerator.


Define the units

We suggest to start always with the simplest model possible (i.e. none or one unit operation) and try to connect this with source and sink vertexes.

Units are vertexes defined using strings which specify: the type of the unit, a custom name and a description.

It is also possible to specify some options. These options are useful to pass the number of stages or the number of splits or the reaction list or any other unit-specific-supported option.

          

Define the streams and the flowsheet connections

Streams are edges which connect vertexes. The streams are defined using strings which specify: the type of the stream, a custom name and a description.

In addition to the user-defined units, all flowsheets come with the predefined “source” and “sink” vertexes, that represent the battery limits.

The inlet streams to the flowsheet come from the “source” vertex “out” port. The outlet streams from the flowsheet go to the “sink” vertex “in” port.


The registration of vertex and edge is sequential, so before the “addStream” of a certain stream, the “addUnit” connected by that stream must be known.

Fine-tune the graphical appearance

It is also possible to customize here the icons and icon sized of the units that will be used in the process flow diagram


Implement the setup

This method initializes the model by setting up input variables at their default value and by providing estimates to some results to help convergence.

Process options

The options supplied to the constructor can be used to customize the model here:


Specify inlet streams

Provide default values for the inlet streams to the flowsheet:


Specify unit operations

Provide default values for the operating conditions of the units:


Cut streams:

When a flowsheet has a recycle, this must be temporary cut and initialized for the correct system calculation.

In the present example, the “recycle” is represented by the stream around the recuperation. We choose to cut and initialize the hot inlet stream (S05) of the exchanger.


Input/Output interfacing

Set/modify the Input/Output behavior of the model variable in order to show or hide them in the graphic interface as input or output parameters.

This operation is strongly suggested for the “CUSTOM variable” since their default behavior is to hide them all.

Sometime it could be useful to modify the default behavior of internal parameter such as the volumetric flow of the stream.


Implement the pre-calculations

You can optionally run some pre-calculate operations; the most frequent use is to compute the model inputs based on some custom variable.

Only put here explicit equations, which do not need a “simultaneous” resolution. If you have calculations that have to be solved iteratively, insert them in the makeUserEquation method below.

In this example model we do not have pre-calculate operations.

Implement the post-calculations

You can optionally run some post-calculate operations after the flowsheet has been solved.

You can have two type of post-calculation instructions:

Custom warning / error messages

Some checks on the results are possible as “warnings” or as “errors”.

This will alert in case of possible wrong behavior of the model

In this example model we do not have custom messages.

Assignment of the output “CUSTOM variables”

This is the right place to compute custom results.

Only put here explicit equations. If you have implicit calculations that have to be solved iteratively, insert them in the makeUserEquation method below.


Implement the makeUserEquation method

This method is used to implement custom implicit user equation that have to be solved iteratively.

In this example we have just bound some internal parameter to some “CUSTOM variables”:


Control flowsheet resolution

Finally there are some method useful to control the flowsheet calculation: iteration, simultaneous support and pre-sequential computation:


Pasteurization Model references

LIBPF® references