question

chao.g avatar image
1 Like"
chao.g asked michael.smith commented

Data Import into simulation

If I have 100 processors in a model, I need to setup process time information, I can certainly read those from excel into a global table, but still I have to go into each individual processor to setup link to right location of table, that's really time consuming, can I do this in a central location, say on model reset trigger, where I finish all the data read process, that way, I can update them in just one location instead of 100 locations, same question applies for MTTR/MTBF for these 100 stations, I don't want to define them individually and then assign value and logic to them. Can someone provide a sample model, maybe with 3 or 5 processors of how this can be done?

FlexSim 16.1.0
global tableexcel importprocess timeuser commandreset trigger
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Brandon Peterson avatar image
3 Likes"
Brandon Peterson answered Brandon Peterson edited

Chao,

Here is a sample model that uses a global table to supply processors with their names and process times. The model demonstrates four methods for automatically updating the row value for each processor. In all cases the names of the processors are updated on reset and a label called "PRow" is set on the processor with the global table row it needs to use for processing. The process time data in the global table is stored as a string that is executed by the process trigger.

The first two methods (Top two model flows) use center port connections to define the processor's row in the global table. In the flow on the left side the reset trigger of each processor is responsible for obtaining the center port connection rank and updating the name and PRow label on the processor. In the flow on the right side the reset trigger of object "ProcessorCPConnection2" updates the names and sets the PRow label for all of the processors connected to it.

The last two methods (Bottom two model flows) use a container rank to define the processor's row in the global table. In both flows the processors are contained in the 2x2 green visual plane object at the top left of the flow. In the flow on the left side the reset trigger of each processor is responsible for obtaining the processor's rank in the visual plane and updating the name and PRow label accordingly. In the flow on the right side the reset trigger of the visual plane updates the names and sets the PRow label for all of the processors contained inside of it.

In all four methods:

  • You can very easily update the processor names and process times by changing the values in the global table.
  • You can easily remove processors from the model by:
    • deleting the processor and updating the global table accordingly (deleting the corresponding row)
  • You can easily add processors to the model by:
    • Top Models (center port connection)
      • Create a copy of an existing processor
      • Create the center port connection
      • Add a row to the global table and fill in the appropriate data
  • Bottom Models (Container)
    • Create a copy of an existing processor (make sure it is placed in the visual plane with the other processors)
    • Add a row to the global table and fill in the appropriate data

I hope this gives a good starting point,

Brandon


· 2
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

chao.g avatar image chao.g commented ·

Hi Brandon,

Really appreciate the detail response, maybe I am not describing clearly, what I am looking for is to write a bunch of code on the under Model Trigger - On Reset in the toolbox under modeling logic.

I am trying to find way to put all logic in the same place, rather than spread them & duplicate them in different objects.

Like for buffer capacity setting,

under Model Trigger - On Reset:

setvarnum(buffer1,"maxcontent",excel value),

I can use a for loop to set as many buffer as I need in one time.

Similarly, I want to be able to access the Process Time field and define value for that in the same location(Model Trigger - On Reset) for all the processors, rather than going to each individual processor and say Use Global table.

So, basically I am looking for a bunch of code only under Model Trigger - On Reset: that will setup the processor time, downtime for each processor. That way, in the future, when I am updating the modeling, I just look at this location with all the code, it's way easier for me to update.

Hope this makes my problem clear.

Thanks,

Chao

0 Likes 0 ·
Brandon Peterson avatar image Brandon Peterson ♦ chao.g commented ·

Chao,

Here is an updated version of the model. I reduced the number of model flows to 2 (the two right models from the previous version), the top one uses the center port connection approach and the bottom uses the container approach. I added a text label called "ProcessTime" that contains the process time trigger code for the processors on the "ProcessorCPConnection" and "ProcessorContainer" objects. The text from that label is copied into the process time trigger of the processors by the respective objects during reset. After the text is copied into the trigger the trigger node is rebuilt.

I also added some code to check and make sure that the number of rows in the table was the same as the number of connections or contained objects. I intentionally added another row to the table so that these checks would produce the error messages for you. To fix the model you can either remove the extra row from the table or you can add the processors to the model. Here is how to add the processors:

  • Top model flow:
    • Disconnect the last processor and sink of the top model flow.
    • Place a processor from the library into the model inbetween the last processor and sink of the top model flow.
    • Connect the last processor to the new processor and the new processor to the sink ("A" Input/Output connections).
    • Connect the new processor to the "ProcessorCPConnection" object ("S" center port connection).
  • Bottom model flow:
    • Disconnect the last processor and sink of the bottom model flow.
    • Place a processor from the library into the model on top of the "ProcessorContainer" object (2x2 green square above the first queue in the bottom flow).
    • Move the new processor to a location between the last processor and sink of the bottom model flow.
    • Connect the last processor to the new processor and the new processor to the sink ("A" Input/Output connections).

When you reset the model the new processors will have the "PRow" label added and set, their names updated, and their process time triggers updated.

While this model does not use the Model Reset Trigger you can duplicate either of these approaches very easily. Simply copy the reset code from one of the objects in to the Model Reset Trigger and then adjust the current treenode to correctly point back to the object you copied the code from.

I understand that you may want to take this further than the sample I have provided. Therefore, let me give you some key points to consider when making things more complex.

  • Object referencing - You will always need a way to reference/find the objects that you want to adjust. If you want to increase the complexity to the point where you are creating and/or destroying them (auto building) then you will want to make sure that your method is robust enough to handle some damage caused by users. I would recommend the container method over the connections method. In my opinion it is harder to accidentally damage.
  • Trigger Manipulation - At some point you will need to adjust the code in the object's triggers. This will require you to either build the text with code (I don't recommend) or store the text in another location and copy it into the objects. Where I am using a label in this example you could easily change to a method that uses imported table data or nodes stored in a location you create in the "Tools" node in the model. If you are auto building the model then I like to create a customized object (processor in your case) and store it in a node in the "Tools" node in the model. This way I can just copy it and place it where I want without having to worry about copying all of the different triggers, labels, size, etc. that I want adjusted. I usually put up a message that asks the user if they want to totally rebuild the model or just adjust it.
  • Auto Building - Fun in a type II way (Type II fun is defined as "fun only in retrospect"). This greatly increases the complexity of what we are doing here. You will need to expand the amount of data you bring to the table and code that gets executed to include one or more of the following topics:
    • Object position, size, color, etc.
    • Labels
    • Connections
      • Input / Output
      • Center
  • Flow Logic
  • Other objects like:
    • Network Nodes
    • Task Executers

I hope this information is helpful to you,

Brandon

2 Likes 2 ·
Steven Hamoen avatar image
3 Likes"
Steven Hamoen answered michael.smith commented

Hi Chao,

What if you would make a usercommand (for instance for the reset trigger), write the call to this user command on the resettrigger of 1 of your processors. Then select all other processors and copy the onreset trigger from this 1 processor to all other processors by using the "edit selected objects".

That way there is only 1 place where there is code that you have to change and that is your usercommand. The copying has to be done only once and is very easy. You could also put all processors in a group so you can easily select them again later on if you need to copy another piece of code on all processors.

Steven

· 1
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

michael.smith avatar image michael.smith commented ·

Too add I have several models like this, each processor has a label which references it's row in the data table and is read by the User Command, so on Reset you could pass the DoStuffCommand(getlabel(current,"ID_Num"); Also if all your objects are connected to one object (you could do a mass connect to a dummy object) you can send code from that as a for loop to write an increment label value to the object on the out port for example. (nrop(current) will return the number of outputs)

0 Likes 0 ·
Will Bishop avatar image
0 Likes"
Will Bishop answered

@chao.gao,

I think I understand what you are going for. I want the same thing -- centrally managing model inputs (like processor cycle times and MTBF/MTTR downtime) and deploying updates quickly and programmatically. I followed your suggestion to use custom flexscript code in a Model Trigger "OnModelReset" to update Processor cycle times.

The code below (run on model reset) programmatically updates Process cycle times for Processors listed in a pair of Global Tables (imported from an Excel file "data/inputs.xlsx"). I broke the input data into two tables: a "cycle_time" table that gives cycle time expressions for each manufacturing "Step", and an "equipment" table that maps individual equipment (i.e. Processors) to the appropriate manufacturing "Step". The code does the following:

  1. Query cycle time expressions (defined by Step) for each equipment Processor.
  2. Loop through each query record to [A] load the matching named Processor node (if it exists), and [B] updated the "cycletime" variable node.
/**Custom Code*/
treenode processor;	// processor node
treenode ct; 		// processor cycletime node

// query equipment cycle times
query("SELECT s.STEP AS STEP, \
		e.EQUIPMENT AS EQUIPMENT, \
		s.CT_DIST AS CT_DIST \
	FROM gt_equipment e, gt_cycle_time s \
	WHERE e.STEP = s.STEP");
// loop through each equipment record and update cycletime
int n_rows = getquerymatchcount();
for (int i = 1; i <= n_rows; i++) {
	// get the processor node that matches the current equipment record
	processor = node(getqueryvalue(i, "EQUIPMENT"), model());
	// load and update the 'cycletime' variable for the current processor
	ct = getvarnode(processor, "cycletime");
	setnodestr(ct, concat("treenode current = ownerobject(c); \n",
			"treenode item = param(1); \n",
			"return /**/", getqueryvalue(i, "CT_DIST"), "/**direct*/;"));
}

This seems to work with one big caveat. When you make an update to the Excel file, you need to click "Reset" twice -- the first time imports the excel changes (after enabling the "Import table on Model Reset" feature), and the second time runs the script above with the new Global Table data. It seems like the Excel import happens after the "OnModelReset" script is run. Maybe this can be changed, or maybe the Excel import can be triggered from within the flexscript code to avoid this.

It seems like this method can hopefully be used to update any variable in a Processor node (or any node)model-inputs.zip.

See the attached .zip file for the example model and Excel data file.


model-inputs.zip (33.7 KiB)
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.