27. October 2021

Using the new controls for Unit Pools in INOSIM 13

The control frameworks for the Unit Pool Allocation control and the Transfer to/from Unit Pool control in the new INOSIM version 13 have changed. The changes offer some new possibilities to use the controls. Even though they offer new features, you do not have to change the way to write these controls. Here we want to show what has changed and what the benefits of the new behavior of the controls are.

Unit Pool Allocation control

In INOSIM, Unit Pool Allocation controls are used to decide which unit out of a pool should be allocated by a UnitProcedure. With the new INOSIM version, the functionality of this control is improved. In version 12, the framework for the Unit Pool Allocation control looked like this:

Function Sample_UnitPoolAllocation(proc As ProcedureInstance, u As Unit) As Boolean

    ' Always allocate the requested unit
    Sample_UnitPoolAllocation = True

End Function

The control has two input arguments: the ProcedureInstance calling the control and the unit it tries to allocate. The return value of the new control is a Boolean that allows the proposed unit to be allocated. When the control is called, it proposes the first available unit (u) in the pool. Within your control, you can decide if a unit is accepted or not. If you decline a unit, the control is called again for the next available unit in the pool. This behavior can result in many calls of the control, even though you know right away which unit must be allocated.

In Version 13, this behavior has been improved. The new framework looks like the following:

Sub Sample_UnitPoolAllocation(proc As ProcedureInstance, p As UnitPool, _
        u As Unit, ByRef allocate As Boolean)

End Sub

First thing you notice is that the new control is, like other controls in INOSIM, a sub instead of a function. Instead of setting the return value of the control to true or false to accept or decline a unit, the variable allocate is used. The main improvement is that in the first call of the control it is possible to decide whether a unit can be allocated for the procedure by setting the PendingUnitsMode of the procedure for the members of the unit pool. The PendingUnitsMode can be set to puAllocate, puIgnore and puDefault. For puAllocate, the unit is used for the Procedure Instance, with puIgnore it is not used. Units with the PendingUnitsMode puDefault are treated like in Version 12, the control is called for all units with this PendingUnitsMode until a unit is accepted for the procedure. Differently than in Version 12, where u is the first proposed unit in the first call, the first call of the control in Version 13 can be identified when the argument u is nothing. Additionally, the unit pool for which the control is called has been introduced as a new argument of the control. This makes it easier to access the members of the unit pool.

Example: Multi-Product Plant

We will have a look at a multi-product plant as an example for the benefits of the new control. In our example, we have a plant which produces 20 different products and for these products has 20 different product tanks. In the model, the production of each product takes one day. After the production, the product is filled into trucks. The same Allocation Control is used for choosing the tank within the production and for choosing the tank that is emptied by a truck.

Layout for the example. There is one production line which produces 20 different products. The products are stored in 20 different tanks.

Both, the production orders and the filling orders, do have the material which they are currently producing as a property. In this example, the products and tanks are numbered by 1 to 20. So, the tank can be chosen according to the product’s name. The behavior of the control is like in Version 12. For every order, the control is called for the members of the tank pool until the fitting unit is found:

Sub Product_Tank_V12(proc As ProcedureInstance, p As UnitPool, _
        u As Unit, ByRef allocate As Boolean)
    
    If u Is Nothing Then
        Exit Sub
    End If 
    'skipping the first call of the control to have the same behavior as in Version 12

    If u.Name="Tank " & Right(proc.Order.Material.Name,Len(proc.Order.Material.Name)-Len("Produkt ")) Then
        allocate=True 
        'If the number of the product name is the same as the number of the tank
    Else
        allocate=False '
    End If

End Sub

To find the right tank, the control tests every member of the unit pool that is currently available. If the control does not find the right unit, e.g., because it is allocated by another order, the control must be called again if any of the members of the pool is becoming available again. This can lead to a lot of calls of the control to find the correct unit.

The benefit of the behavior in Version 13 is now that in the first call of the control you can decide which unit is allowed for the allocation of the procedure. As the call is only called once, this saves a lot of simulation time.

Dim pm As Unit
    If u Is Nothing Then 'identifies the first call of the control 
        For Each pm In p.Members
            If pm.Name="Tank " & Right(proc.Order.Material.Name,Len(proc.Order.Material.Name)-Len("Produkt ")) Then
                proc.PendingUnitsMode(pm.Name)=PendingUnitMode.puAllocate 
                'the tank which has the same number as the product is allowed to be allocated
            Else
                proc.PendingUnitsMode(pm.Name)=PendingUnitMode.puIgnore 
                'all other tanks are ignored
            End If
        Next
    End If

Within the same model, the use of the control that exploits the new behavior of the Version 13 control saves 36% of simulation time in this simple model, when simulating one year of production. In more complex models, this could be even more advantageous. Furthermore, it is possible to assign a procedure to a unit that is not ready for allocation at the moment, e.g., because it is still allocated. In Version 12, the control would have been called for this procedure every time a unit from the pool becomes available and all units would have been tested. What you might have accomplished with custom code, INOSIM 13 is now supporting natively by assigning a fixed unit from a pool to a procedure.

Workaround / Compatibility with V12 controls

If you wish to use a Version 12 model with Version 13 or want to have the behavior of the control like it was in Version 12, you can just skip the first call of the control by inserting the following code at the very top of your control:

If u Is Nothing Then
    Exit Function 'in the first call the control is skipped
End If

Transfer from/to Unit Pool Control

The behavior of the Transfer from/to Unit Pool Control changed as well. In a transfer control, you can select the sink or source for the transfer operations SimpleInflux, SimpleOutflux or SimpleTransfer. In Version 12, the framework for the Transfer from/to Unit Pool Control looks like this:

Function Sample_Transfer(cop As OrderOperation, u As Unit, _
        amount As Double, ByRef retry As Boolean) As Unit
    ' take the first suitable unit

    Set Sample_Transfer = cop.SourceSinkUnits(1)

End Function

The inputs of the control are the current OrderOperation that is calling the control, the remaining amount of the transfer, and the Boolean retry. If retry is set to true, the control is called again to select another suitable unit in case the transfer is stopped due to full or empty units. The parameter u is nothing in the first call of the control. In later calls, it is the currently used unit for the transfer. The return value of the function is the unit that should be used for the transfer.

In the new version, the framework has slightly changed:

Sub Sample_Transfer(p As UnitPool, cop As OrderOperation, amount As Double, _
        ByRef u As Unit, ByRef retry As Boolean)

End Sub

First of all, the control is no longer a function with a return value but a procedure. The parameter u is the unit that is used for the transfer. In the first call, the proposed unit for the transfer is stored in the parameter u. To identify the first call of the control in Version 13, you would use:

If cop.Transfer Is Nothing Then
      'first call
Else
      'later call 
End If

In case the transfer property is nothing, you can change the parameter u to the unit that should be used for the transfer. As an additional parameter, you have the unit pool for which the control is called.

Example: Educt Transfer

In the following example, Educt A for a reaction should be taken from a tank pool. In the first call of the control, a tank is set for the transfer. When this tank runs empty the control is called again and the fullest tank from the pool is selected to continue the transfer. For the next transfer, the same tank is used until it is empty. Then again, the now fullest tank should be selected. In Version 12, the control could look like this:

Public LastEductTank As Unit 'Global Variable

Function Educt_Transfer(cop As OrderOperation, u As Unit, amount As Double, _
        ByRef retry As Boolean) As Unit

    Dim pm As Unit
    Dim EductTank As Unit
    Dim i As Integer

    retry=True
    
    If LastEductTank Is Nothing Then
        'in the beginning the last tank has to be set to the first member of 
        'the SourceSinkUnits collection, the pool cannot directly be accessed

        Set LastEductTank=cop.SourceSinkUnits(1)

    End If
    
    If u Is Nothing Then
        'for the first call of the control the tank from the last 
        'transfer	should be used until it is empty

        Set EductTank=LastEductTank

    Else
        'if one tank runs empty, the control is called again and 
        'the tank	with the highest content should be used

        Set EductTank=u
    
        For i=1 To cop.SourceSinkUnits.Count

            If cop.SourceSinkUnits.Item(i).Contents > EductTank.Contents Then
                Set EductTank=cop.SourceSinkUnits.Item(i)

            End If

        Next

    End If

    Set Educt_Transfer=EductTank	'set the chosen unit

    Set LastEductTank=EductTank	'update the last educt tank used

End Function

In Version 12, the unit pool for which the control is called cannot be addressed directly. Instead, you could access the SourceSinkUnits collection of the operation. In Version 13, it is possible to directly access the unit pool that calls the control.

Public LastEductTank As Unit 'Global Variable

Sub Educt_Transfer(p As UnitPool, cop As OrderOperation, amount As Double, _
        ByRef u As Unit, ByRef retry As Boolean)

      Dim pm As Unit
      Dim EductTank As Unit

      retry=True

      If LastEductTank Is Nothing Then
        'in the beginning the Last Tank has to be set to 
        'the first member of the unit pool

            lastEductTank=p.Members.Item(1)

      End If

      If cop.Transfer Is Nothing Then 
        'identifies the first call of the	control for this transfer

        'for the first call of the control the tank from the 
        'last transfer should be first used until it is empty

            EductTank=LastEductTank
      Else
        'if one tank runs empty, the control is called again 
        'and the tank 	with the highest content should be used

            EductTank=u

            For Each pm In p.Members
                  If pm.Contents > EductTank.Contents Then
                        EductTank=pm
                  End If
            Next

      End If

      u=EductTank 'set the chosen unit

      LastEductTank=u 'update the last Educt tank used

End Sub

With the control in Version 12, it was not possible to access information about the Unit Pool for which the control is called. Now it is not only possible to access the members of this pool, but also other properties, like its name.

Workaround / Compatibility with V12 Controls

If you want to use an existing model from Version 12 in Version 13, you can keep the old controls. One thing that needs to be changed is the way to check if it is the first call of the control. In Version 12, u is nothing, but in Version 13 in the first call u is the first proposed unit. Here, to identify the first call you can use:

If cop.Transfer Is Nothing Then
      'first call
Else
      'later call 
End If

More Questions?

Want to know more about this topic or have another question? Please contact us!

More Tips & Tricks

Did you know INOSIM can be remote-controlled by any program that can send signals via the COM-Interface? Let us sketch a scenario of how this…

10. May 2021

The Reporting Object

The Reporting Object With INOSIM 12, the Reporting object was added to the INOSIM object library. The Reporting object provides extensive options to create and…

Custom Curves and Properties Of Curves in INOSIM Gantt In your model, the same raw material is stored in several tanks, and you wish to…

more

INOSIM Support

During usual business hours

Germany +49 231 97 00 250

USA +1 214 663 3101

support@inosim.com