Function Editor

All topics specific to modeling questions in Enterprise Dynamics
Post Reply
Katinka
Posts: 23
Joined: Thursday 14 June, 2012 - 08:42

Function Editor

Post by Katinka »

Hi Marlies,

As you suggested before, I'm trying to use the Function Editor for pieces of code that need to be executed in multiple triggers. However, I don't know exactly how to transform the codes into a function. I've checked the example model, and I fully understand it, but that's really straightforward (with just one numerical value). I also tried to search for other topics about the Function Editor on this forum, but those words are too common.

For example this piece of code on the Entry Trigger of a Warehouse Atom:

Code: Select all

If(
 Label([Direction], i) = 2,
 DestroyAtom(i),
 
do( 
  Var([valRow], vbValue),
  valRow := Label([CurRow], refWaitingOrders),
  
  Cell( valRow, 1, refWaitingOrders) := label([aisle], i),
  Cell( valRow, 2, refWaitingOrders) := label([rack], i),
  Cell( valRow, 3, refWaitingOrders) := ptv(i),
  Cell( valRow, 4, refWaitingOrders) := ptv(c),
  Cell( valRow, 5, refWaitingOrders) := round(time),  
   
  Label([CurRow], refWaitingOrders) := Label([CurRow], refWaitingOrders) + 1,
  If(
   Label([CurRow], refWaitingOrders) > nRows( Label([CurRow], refWaitingOrders)),
   nRows( refWaitingOrders) := nRows( refWaitingOrders) + 1000
  )
 )
)
May I take (for example)
p(1) = label([aisle], i) or p(1)=i and subsequently use label([aisle], p(1))
or should I take p(1) = ptv(i) and subsequently label([aisle], vtp(p(1))) ?
Furthermore, may I e.g. use Label([CurRow], refWaitingOrders) in the function (like a global variable) or should it be defined as an input parameter as well?

Katinka
marlies
Posts: 301
Joined: Monday 17 January, 2011 - 09:28

Re: Function Editor

Post by marlies »

Hi Katinka,

To answer your question I'll need to explain three things:
1. The use of parameters in a function.
2. The use of Local variables in a function or any other piece of code.
3. The use of Global variables.

1. The use of parameters in a function.
When you define a function using the Function Editor you also define the number of parameters for that function. Parameters can be different things: it can be values, strings, atom references etc. A function could be for example:

Code: Select all

Atom_ChangeName( i, [ProductA])
In this example the first parameter is an atom reference "i" and the second parameter is a string "[ProductA]"

Another example:

Code: Select all

MultiServer_ChangeCapacity( c, 5)
The first parameter is again an atom reference, now "c" and the second parameter is a value "5".

In the function editor you can refer to the paramters using p(1), p(2) etc. This means for the first example:
Every time you use p(1) in the function code, the atom reference to "i" will be known. Using p(2) in the function code will be the same as the string [ProductA] as this was given as additional information in the 2nd parameter. So, in the function itself you only need to use p(1) and p(2) to get the information used between the brackets in the function call.

In this way we can also use the same function in another way:

Code: Select all

Atom_ChangeName( c, [MachineA])
In this example the atom reference for the function is "c" and the text in p(2) will return the string [MachineA]. In the function code we would still use p(1) and p(2)!

The function code could be for example:

Code: Select all

Do(
  Name(p(1)) := p(2)
)
2. The use of Local variables in function code.
To make your function code readable and understandable it is good to make use of LOCAL variables. Local means that the variable is known only within the function/piece of code itself and not outside in other places of the model. Local variables have to be defined using the word VAR. Local variables always have a variabletype which can be vbString, vbValue, vbAtom etc. Once you have defined a Local variable, you can store the parameter information in it. In the example below I store the atom reference from p(1) into a local variable with the name atmToChange and type vbAtom. I store the new name in a local variable with the name strNewName and type vbString.
In the example above we would get:

Code: Select all

Do(
{ declare vbAtom variable }
Var([atmToChange], vbAtom),
{ and store information from p(1), from now on atmToChange is the same as p(1) which is the same as "i". }
atmToChange := p(1),
{ declare vbString variable }
Var([strNewName], vbString),
{ and store information from p(2), from now on strNewName is the same as p(2) which is the same as [ProductA] }
strNewName := p(2),

{ Execute the code using the new variables }
Name(atmToChange) := strNewName
)
In the example it doesn't really make sense, but when you need to refer to a parameter more than 1 time it is better to use a variable instead of using p(1) all the time.

3. The use of Global variables.
In your post you also asked how to use the refWaitingOrders. The refWaitingOrders is a Global variable, created by the table atom itself (the word to declare a global variable is Dim, types can be vbAtom, vbString, vbValue again). A global variable is known anywhere in your model, so you may use that one within the function code itself. As long as the label to be used in the function is Label([CurRow], refWaitingOrders) every time you call the function, you can just leave that. There is no need to create a parameter for it.

The function for the entry trigger could be a function with 2 parameters: a reference to the warehouse c and a reference to the product i:

Code: Select all

Warehouse_EntryTrigger( c, i)
Without using local variables the code in the function editor would be (note that I use p(2) and p(1) multiple times):

Code: Select all

Do(
 If(
  Label([Direction], p(2)) = 2,
  DestroyAtom( p(2)),
  
  do( 
   Var([valRow], vbValue),
   valRow := Label([CurRow], refWaitingOrders),
   
   Cell( valRow, 1, refWaitingOrders) := label([aisle], p(2)),
   Cell( valRow, 2, refWaitingOrders) := label([rack], p(2)),
   Cell( valRow, 3, refWaitingOrders) := ptv( p(2)),
   Cell( valRow, 4, refWaitingOrders) := ptv( p(1)),
   Cell( valRow, 5, refWaitingOrders) := round(time),  
    
   Label([CurRow], refWaitingOrders) := Label([CurRow], refWaitingOrders) + 1,
   If(
    Label([CurRow], refWaitingOrders) > nRows( Label([CurRow], refWaitingOrders)),
    nRows( refWaitingOrders) := nRows( refWaitingOrders) + 1000
   )
  )
 )
)
With the use of local variables the code could be (now I use p(1) and p(2) only once:

Code: Select all

Do(
 Var([atmRack], vbAtom),
 atmRack := p(1),
 Var([atmProduct], vbAtom),
 atmProduct := p(2),
 
 If(
  Label([Direction], atmProduct) = 2,
  DestroyAtom(atmProduct),
  
  do( 
   Var([valRow], vbValue),
   valRow := Label([CurRow], refWaitingOrders),
   
   Cell( valRow, 1, refWaitingOrders) := label([aisle], atmProduct),
   Cell( valRow, 2, refWaitingOrders) := label([rack], atmProduct),
   Cell( valRow, 3, refWaitingOrders) := ptv(atmProduct),
   Cell( valRow, 4, refWaitingOrders) := ptv(atmRack),
   Cell( valRow, 5, refWaitingOrders) := round(time),  
    
   Label([CurRow], refWaitingOrders) := Label([CurRow], refWaitingOrders) + 1,
   If(
    Label([CurRow], refWaitingOrders) > nRows( Label([CurRow], refWaitingOrders)),
    nRows( refWaitingOrders) := nRows( refWaitingOrders) + 1000
   )
  )
 )
)
Good luck!

Regards, Marlies
Katinka
Posts: 23
Joined: Thursday 14 June, 2012 - 08:42

Re: Function Editor

Post by Katinka »

Hi Marlies,

Thanks for your answer. I've made a really easy model to check if I understand it, but so far it doesn't work.
I added the model to this message, and the goal of the function 'Test' is to close the input channel of the Queue Atom as soon as there are >= 3 products in the queue. However, the channel doesn't close at all.
What did I do wrong?

Katinka
Attachments
Test.mod
(11.6 KiB) Downloaded 335 times
marlies
Posts: 301
Joined: Monday 17 January, 2011 - 09:28

Re: Function Editor

Post by marlies »

Hi Katinka,

The way you use the function and references is ok. The problem is in the code of the function itself. Just replace:

Code: Select all

CloseIC(1,atmQueue)
By:

Code: Select all

CloseInput(atmQueue)
The problem is that closeic/closeoc/openic/openoc/openallic/openalloc etc. are commands that are typically used internally in the standard atom functionality. When you use them in a trigger or function, it can/will be overruled by the atom itself.

To control input and output in triggers it is better to use:
CloseInput/CloseOutput/OpenInput/OpenOutput which cannot be overruled by the atom functionality.

Regards, Marlies
Katinka
Posts: 23
Joined: Thursday 14 June, 2012 - 08:42

Re: Function Editor

Post by Katinka »

Hi Marlies,

After adjusting the code, everything worked well in my sample model :)
I also used the Function Editor in my 'real' model and everything seemed to go well, until now..
After opening my model, I received errors about references in the Function Editor being invalid. These references were pointing to Table atoms.

In the Model Tree I saw that the Function Editor is placed below the Tables; whereas in the helpfunction I read that the Function Editor atom will automatically rank itself higher in the model than the Table Atoms.
Maybe this is the reason for the errors? How can I adjust the position of the Function Editor Atom in the Model Tree?

Katinka
Katinka
Posts: 23
Joined: Thursday 14 June, 2012 - 08:42

Re: Function Editor

Post by Katinka »

The weirdest (or annoying) thing is that these errors only occur after closing and restarting ED and not while working in the current file. If I open a file of yesterday morning, the errors are already there, but yesterday I could still perfectly work with it.
marlies
Posts: 301
Joined: Monday 17 January, 2011 - 09:28

Re: Function Editor

Post by marlies »

Hi Katinka,

When you drag a table into your model the references will be created. They will be available for any other atom, even if it's in a higher rank. But, when your reload the model the references will be created at the moment the referenced atom will be loaded. So, when you use a reference in an atom that has a higher rank, it will not exist yet. That's why you get these errors only when you reopen a model. We will check the funcitionality of the function editor on this part and see if we can make it better.

For now, you could just influence the rank of the function editor using the interact window (shift+F6). Select the Function Editor in the Model Tree and execute the following code: SetRank( e1, TreeAtom). Where e1 should be the required rank number: highest possible rank, but below all the table atoms in your model.

Regards, Marlies
User avatar
MatthijsJongboer
Posts: 200
Joined: Thursday 11 November, 2010 - 14:12

Re: Function Editor

Post by MatthijsJongboer »

The attachments will solve the register function errors.
Attachments
FunctionEditorAdd.gui
New GUI for Function Editor Add function
(9.7 KiB) Downloaded 338 times
Function Editor.atm
New Function Editor atom
(2.87 KiB) Downloaded 354 times
Katinka
Posts: 23
Joined: Thursday 14 June, 2012 - 08:42

Re: Function Editor

Post by Katinka »

Thank you both for your help!
Post Reply