Send to script

All topics on coding 4Dscript in Enterprise Dynamics.
Smiliej
Posts: 13
Joined: Wednesday 22 April, 2015 - 12:18

Send to script

Post by Smiliej »

Can someone helpo me with the following problem:
I have 28 product and I have given them the label ProductID and a number from 1 till 28 so I could give cycletimes per server. Now my problem is that I need to send the product to a specific server. From 1 Que to 6 different servers. I have tried the following code:

if(Label([ProductID], first(c)) =1,2,if(Label([ProductID], first(c)) =2,2 and 4,if(Label([ProductID], first(c)) =3,2 and 4,if(Label([ProductID], first(c)) =4,2 and 4,if(Label([ProductID], first(c)) =5,2 and 4,if(Label([ProductID], first(c)) =6,2 and 4,if(Label([ProductID], first(c)) =7,2,if(Label([ProductID], first(c)) =8, 4,if(Label([ProductID], first(c)) =9, 1-6,if(Label([ProductID], first(c)) =10,4,if(Label([ProductID], first(c)) =11,2,if(Label([ProductID], first(c)) =12,5,if(Label([ProductID], first(c)) =13,1,if(Label([ProductID], first(c)) =14,1,if(Label([ProductID], first(c)) =15,1,if(Label([ProductID], first(c)) =16,1,if(Label([ProductID], first(c)) =17,1 and 3,if(Label([ProductID], first(c)) =18,1-6,if(Label([ProductID], first(c)) =19,1,if(Label([ProductID], first(c)) =20,1,if(Label([ProductID], first(c)) =21,1,if(Label([ProductID], first(c)) =22,6,if(Label([ProductID], first(c)) =23,6,if(Label([ProductID], first(c)) =24,3,if(Label([ProductID], first(c)) =25,3,if(Label([ProductID], first(c)) =26,3,if(Label([ProductID], first(c)) =27,3,if(Label([ProductID], first(c)) =28,1)))))))))))))))))))))))))))

This does not work. The que does not send the product away and holds them.
User avatar
HarryBunnik
Posts: 362
Joined: Monday 07 February, 2011 - 11:22

Re: Send to script

Post by HarryBunnik »

Ha,

I can try to help you, but I think we first have to get clear what it is exactly that you want to achieve. How do you want to distribute the products from the queue?

But first of all, I would like to try to reduce the number of IF's, by using a case statement. Secondly you can use a combination with a WhichIsTrue and an InList function to check if the product has a label with a certain value. So that would give something like:

Code: Select all

Case(
  WhichIsTrue(
    InList(Label([ProductID], first(c)), 1, 3 , 5, 6, 8) > 0, 
    InList(Label([ProductID], first(c)), 3, 7 , 12, 13, 16) > 0,
    ....
  ), 
  1,
  2, 
  ...
)
Here all products with a label ([ProductID], first(c)) that is either 1, 3, 5, 6 or 8 will be found in the first InLIst. So the first statement of the WhichIsTrue gives a true as answer, which will result in a exit to channel 1. All products with a label 3,7,12,13,or 16 are send to 2 etc. etc.
You can use the interact (Shift + F6) to play around with pieces of the code a bit to see how they react.

Then I see in you code that you use the AND statement in a way that is not allowed in 4Dscript. An AND can be used in for instance an If statement to check if a set of statements are all true:

Code: Select all

If(
  And(
    1 = 1, 
    2 = 2
  ), 
  {Then}
  Do(
    ... 
  ),
  {Else}
  Do(
    ...
  )
)


It can't be used to say that when a label([ProductID], first(c)) = 2, the product can use server 2 and 4. Then you should combine all those labels with the same set of possible exits in a InList as described above and then in the outcome of the case statement make a decision between the 2 possible channels or even all 6 channels, so something like:

Code: Select all

Case(
  WhichIsTrue(
    InList(Label([ProductID], first(c)), 1) > 0, 
    InList(Label([ProductID], first(c)), 2, 3 , 4, 5, 6) > 0, 
    InList(Label([ProductID], first(c)), 7) > 0,     
    InList(Label([ProductID], first(c)), 8) > 0,        
    InList(Label([ProductID], first(c)), 9) > 0,        
    ....
  ), 
  1,
  Do(
    {Both channel 2 and 4 are allowed}
    Bernoulli(50, 1, 2)
  )
  2, 
  4, 
  Do(
    {Randomly choose between the available exit channels}
    dUniform(1, 6)
  ),
  ...
)
I hope this gives you some ideas on how to tackle your problem :-)

Cheers,

Harry
Smiliej
Posts: 13
Joined: Wednesday 22 April, 2015 - 12:18

Re: Send to script

Post by Smiliej »

To answer your first question:
I want certain products only to be sent to certain servers.
For example:
Product labeled "ProductID" with value 1 goes to channel 2
Product labeled "ProductID"with value 2 goes to channel 2 and 4, depending on which one is empty.
Product labeled "ProductID"with value 9 goes to any open channel, depending which one is empty.
etc.

I hope this clarifies my situation.

I tried your suggestion but get the following notifications:

Code: Select all

96 Compile error: "Do(Bernoulli(50,1,2))2" is not a valid expression. Reference: Case(WhichIsTrue(InList(Label([ProductID],first(c)),1)>0,InList(Label([ProductID],first(c)),2,3,4,5,6)>0,InList(Label([ProductID],first(c)),7)>0,InList(Label([ProductID],first(c)),8)>0,InList(Label([ProductID],first(c)),9)>0,),1,Do(Bernoulli(50,1,2))2,4,Do(dUniform(1,6)))

Code: Select all

95 Compile error: "," is not a valid expression. Reference: Case(WhichIsTrue(InList(Label([ProductID],first(c)),1)>0,InList(Label([ProductID],first(c)),2,3,4,5,6)>0,InList(Label([ProductID],first(c)),7)>0,InList(Label([ProductID],first(c)),8)>0,InList(Label([ProductID],first(c)),9)>0,),1,Do(Bernoulli(50,1,2))2,4,Do(dUniform(1,6)))
I also tried the script just to see what happens and if it worked I could expand it, but also the compile error occurs:

Code: Select all

case(
 WhichIsTrue(
  InList(Label([ProductID],first(c),13,14,15,16,17,19,20,21,28) > 0,
  Inlist(Label([ProductID],first(c),1,2,3,4,5,6,7,11) > 0,
  Inlist(Label([ProductID],first(c),17,24,25,26,27)> 0,
  Inlist(Label([ProductID],first(c),2,3,4,5,6,8,10)> 0,
  Inlist(Label([ProductID],first(c),12) > 0,
  Inlist(Label([ProductID],first(c),22,23) > 0
 ),
 1,
 2,
 3,
 4,
 5,
 6)
 )))))))))))
I think I do not understand the 4dscript for the full potential. Correct me if I'm wrong but the first row of the inlist means that the labels with that number will be send to channel 1, the next row of the inlist means that the labels with that number will be send to channel 2 etc. Which will mean I get 6 rows, 1 for each channel?
User avatar
HarryBunnik
Posts: 362
Joined: Monday 07 February, 2011 - 11:22

Re: Send to script

Post by HarryBunnik »

That makes it more clear.

I see the error, I forgot the comma behind the Do(Bernoulli()).

And behind the last line in a statement, you're not allowed to use a comma, so that you also have to remove :

Code: Select all

Case(
  WhichIsTrue(
    InList(Label([ProductID],first(c)),1)>0,
    InList(Label([ProductID],first(c)),2,3,4,5,6)>0,
    InList(Label([ProductID],first(c)),7)>0,
    InList(Label([ProductID],first(c)),8)>0,
    InList(Label([ProductID],first(c)),9)>0
  ),
  1,
  Do(
    Bernoulli(50,1,2)
  ), 
  2,
  4,
  Do(
    dUniform(1,6)
  )
)
In your piece of code there are some brackets placed at the wrong place. Instead all at the end, you need them in your InList statement where in your code the bold, italic one is missing: InList(Label([ProductID],first(c) ) ,1)
If you press F11 when you're typing code, you can see the color coding of the brackets, which may help you. :-)

If you add them to your code, it should be working fine.

Yes, that is correct. InList simply checks if the first entry (your label) is in the list (all other parameters). If so, it returns the list number where it was found. So if it is found in the list (return value of the Inlist is bigger then 0), you know it is in the list and you can send it to that particular exit channel.

What will be more difficult it divide it over 2 channels, where one is free. A Bernoulli doesn't take that in account. It only returns a decision based on chance to which channels it will be send, regardless if it is ready or not. In the code below I've added a code that loops over the connected atoms (channel 2 and 4) and returns that channel when the server is ready. If both servers are unavailable, it returns a 50% chance and has to wait until that server is ready.

Code: Select all

Do(
  var([valChannel], vbValue),
  var([valCount], vbValue),  
  
  Case(
    WhichIsTrue(
      InList(Label([ProductID],first(c)),1)>0,
      InList(Label([ProductID],first(c)),2,3,4,5,6)>0
    ), 
    1, 
    Do(
      LoopUntil(
        Do(
          case(
            Count, 
            valChannel := 2,
            valChannel := 4 
          ),      
          ICready(1,out(valChannel, c))
        ), 
        Inc(valCount),
        2
      ), 
      valChannel
    )
  )
)
You'll see that when both servers are closed, it will still give an exit channel of 4. However when the other server might become available again, the whole situation is re-evaluated, so it should go well (I hope ;-) )

I had no time to test the code, but I think it will give you some more ideas :-)

Regards,

Harry
Smiliej
Posts: 13
Joined: Wednesday 22 April, 2015 - 12:18

Re: Send to script

Post by Smiliej »

That worked!
First I tried the brackets, that fixed the error and now it sends the products to the right channel.
Then I saw at some point it stopped working because it waited for the first product to be sent to a specific server that was still busy, I had the queue on FIFO. After I changed it to random it stopped waiting for the first product, but then eventually it stopped sending products all together and the queue kept growing and the servers emptying.
My simulation goes for 1 years and some products take 10 days to finish, which was no problem when I had it set to "send to random open channel".
User avatar
HarryBunnik
Posts: 362
Joined: Monday 07 February, 2011 - 11:22

Re: Send to script

Post by HarryBunnik »

That sounds as if a product has an invalid exit channel assigned and no longer can get out... Can you add your model, so I can have a look at it?

As far as the ordering of the products in the queue, I think that you'll have to write some code to place an applicable product in front of the queue, when a finished product leaves a server. Otherwise you'll have quite a big chance that you'll have products in front that are waiting for their turn at a machine that is at that moment not available.

Regards,

Harry
Smiliej
Posts: 13
Joined: Wednesday 22 April, 2015 - 12:18

Re: Send to script

Post by Smiliej »

Sadly enough I can not save my model since I can not save more than 30 atoms. I've added some screenshots to elaborate.

I'm thinking about adding more queues to make it work, but that means when I make the model bigger I will need a lot of extra atoms. Trying to get the base right so adaptions won't take a lot of time.
Attachments
3.png
3.png (124.17 KiB) Viewed 17393 times
2.png
2.png (117.37 KiB) Viewed 17393 times
1.png
1.png (114.39 KiB) Viewed 17393 times
User avatar
HarryBunnik
Posts: 362
Joined: Monday 07 February, 2011 - 11:22

Re: Send to script

Post by HarryBunnik »

You can try to use an arrival list, instead of all the different sources to create the different products. That way the number of atoms can be strongly reduced (hopefully under 30), because based on the screen shots I can't see anything.

Regards,

Harry
Smiliej
Posts: 13
Joined: Wednesday 22 April, 2015 - 12:18

Re: Send to script

Post by Smiliej »

hah I didn't even know that was possible! Can I however give the products different colors still, like in my case "Kiremko" is blue and "Perfecta" is red?
User avatar
HarryBunnik
Posts: 362
Joined: Monday 07 February, 2011 - 11:22

Re: Send to script

Post by HarryBunnik »

Yes, you can change the Icon of the product on the OnExit trigger, based on it's label.

Code: Select all

Case(
  Label([ProductID], i), 
  {ProductID = 1}
  Icon(i) := IconByName([CircleBlue]), 
  {ProductID = 2}
  Icon(i) := IconByName([CircleRed])   
)
And to see what Icons are available, you can use the Resource Manager (this also would allow you to upload your own icons if you want).

Regards,

Harry
Post Reply