Wednesday, July 1, 2009

eVSM to QUEST Interface

eVSM to QUEST Interface

 

Overview

The CCAT eVSM Utilities tool with the DELMIA QUEST (http://3ds.com) option allows you to export Value Stream Map information to the DELMIA QUEST (QUeuing Event Simulation Tool).

 

CCAT has developed a set of Simulation Control Logic (SCL) macros in QUEST for importing plain text files in tab-delimited format, and transforming that data into QUEST modeling constructs.

 

The CCAT eVSM Utilities makes it very easy to generate the plain text files and automates the subsequent import within QUEST.

Terminology

  • QUEST - QUeuing Event Simulation Tool.  This is Discrete Event Simulation Software provided by Dassault Systemes, and is used for the modeling and simulation of stochastic manufacturing systems
  • eVSM - electronic Value Stream Mapping software (http://evsm.com).
  • NVU - Name-Value-Unit.  An NVU is a construct within eVSM for holding process data.  The Name portion describes the name of the data, the Value is simply the data value, and Unit is the name of the unit the Value is measured in

Format Overview

The overall format for importing to QUEST is as such:

  • Two rows of column header information
  • One row delineating units in columns
  • Process information in rows

 

Each row of simulation data represents a process in QUEST.  Each column holds different data about the process.

 

There are three pieces of required data for each process in eVSM:

  • Cycle Time - The processing time of the process
  • Workstation - The name of the machine resource where the process is completed.  This may also be a comma-delimited list of machines, each machine being capable of running the same process
  • Product - The name of the product part class of the process

Configuration Files

The eVSM->QUEST SCL macros were built to be flexible enough to import VSM data from eVSM using whatever standardized NVU names you want.  An eVSM->QUEST configuration file has a .esm file extension, and is simply a list of setting names and values, similar to a QUEST .inc file.

 

The CCAT eVSM Utilities come with a pre-configured configuration file called QUEST_DIRECT.esm, and is stored in the DATA folder of the QUEST library you install the macros to.  This file is used as the default configuration file for exporting directly from eVSM.

 

Aside from mapping NVU names to data fields the SCL builder macros need, there are also several high-level settings that can be used to control how the SCL builder macros run.  The following are descriptions of several of these settings:

  • CELL_DELIM - The delimiting character between columns in the input text file.  By default this is tab, but a comma can be used (and can be generated by MS Excel)
  • COMMENT_LINE - This character tells the SCL builder macros that a line is not to be read as a process.  The default value is the # character
  • Geo - These settings allow you to specify the default geometry for buffers and machines
  • Workcell spacing options - These settings allow you to specify the spacing from a machine where the input and output buffers are to be placed.  You may also offset the location of the machine labor point in the y-axis using the LABOR_Y_SPACING setting
  • Logic - These settings allow you to specify the logics to assign to various elements by default (in-buffer routing logic, process logic, etc...).  The SCL file in which the logics are located must be compiled before the build.  This can be done by listing your logic files in your configuration file with the variable name as SCL_FILE#, where # is a number between 1 and 5, and where no two listed logic files share the same number.  These files will be compiled before the SCL builder macros execute

Data Overview

As previously mentioned, there are three required pieces of information you must provide for a process in eVSM.  In reality, there are six pieces of data the SCL builder macros need in order to build a model; however, the following three pieces of data are automatically populated for you within eVSM :

  • Operation- The name of the process
  • Tag - A unique identifier for the process (no other process can have the same tag, but may have the same name)
  • Next Op - The Tag of the process downstream of the current process.  This is used for identifying process sequences and routings

In addition to this required information, there is a set of optional NVUs you may provide to the SCL builder macros:

  • Changeover Time - The time required to change a machine from one process to another - modeled as a setup process in QUEST, between each process on the machine
  • Load Time - The time required to load a part onto a machine before the cycle process begins.  This is modeled as a setup process and is executed when the same process is performed twice in a row.  This means the load time must be included in changeover time, as the first load time is not run
  • Operator - The name of the laborer class to be required on a process.  If a process has a changeover and/or load time assigned to it, the operator is assigned to the load/changeover process(es).  Otherwise the operator is assigned to the cycle process
  • Operators - Depending on the assign_all_operators_to_process setting in the configuration file used.  If the setting is 0, then the operators value represents the number of laborers in the labor class.  If the setting is 1, then that number of operators is assigned to the process the laborer is assigned to
  • Num Elements - The number of elements in the machine class
  • MTTR/MTBF/Uptime - This is machine reliability data commonly used in simulation. Two of the three listed NVUs must be present to properly assign QUEST failures to the machines.  If Uptime is provided, the NVU not present (MTTR or MTBF) is calculated based on the Uptime value and whatever value is present
  • Scrap - The rejection rate of the process.  The rejection rate tells QUEST what percentage of parts to scrap, which means the parts are destroyed, and not repaired.  The SCL builder macros do not currently support part repair
  • GeometryThe display geometry file name for the listed Workstation.  This will override the configuration file level setting
  • TimeToNext - The time for the part to get to its next operation.  The time delay is executed on the output buffer of the machine which the process is run on, and is not resource-constrained.  The part enters the buffer, and after the TimeToNext is elapsed it moves on to the next process.  This may be used for modeling outside operations which are not being modeled.  This value may be provided as an SCL expression (meaning you may use build-in distribution functions)
  • Shifts - The number of shifts the listed Workstation of the process works.

Units

The builder assumes that the data file coming in was created using eVSM.  As of eVSM version 4, units are placed in the third row, and so the builder assumes row 3 of the data file it reads contains the units for all the NVU's.  The builder will look to these units to determine the units for: cycle time, setup time, load time, IAT, time to next operation, and Mean Time To Repair (MTTR).  If no units are found for a specific variable, default values are assumed (minutes for cycle, setup, and load times; hours for IAT & MTTR)

Location/Layout Information

The SCL builder macros need to know where to put the machines listed in the Workstation NVU of a process.  This can be provided multiple ways:

  • Shape of the Value Stream Map
  • Locations from an eVSM Spaghetti Chart
  • Manual location

When building from eVSM, you only have a choice between laying out machines in the shape of the VSM, or getting locations from an eVSM Spaghetti Chart. 

 

If you choose the shape of the VSM, the SCL builder macros will place a machine in the location of the first process that uses that machine in its Workstation NVU.  To locate based off an eVSM Spaghetti Chart, you must provide the name of the page the Spaghetti Chart is on, and the column from Excel corresponding to the place names set in the eVSM Spaghetti Chart.  For example, if you name all your Spaghetti Places based on the values from your Workstation NVUs, you would tell the builder interface in eVSM to use the Workstation column for locating machines.

CCAT eVSM Utilities interface to SCL Builder Macros

Layout Options

Select a radio button to tell the builder how to locate machines in QUEST.  Using "No layout" or "Layout file" will locate machines in the shape of the VSM.  Using "Layout from page" requires that you specify the name of the eVSM Spaghetti Chart page, and the name of the column in the eVSM Excel Calculator spreadsheet which matches up processes with the location names in your eVSM Spaghetti Chart

 

esm File

You may specify an esm configuration file, if you have a customized file you need to use for the export.  If left blank, the default QUEST_DIRECT.esm is used.

 

Pre- and Post-Build BCL Commands

You may specify a list of BCL commands to be executed before and after the SCL builder macros are executed.  You may wish to compile logic files before the build, or to run different SCL macros after the builder execution.

 

These commands should be stored in the eVSM Excel Calculator spreadsheet.  The worksheet the BCL commands are stored in should be named the same as the page your VSM is in, with "_BCL" appended on the end of the name.  The easiest way to set this up is to click the "Import BCL from Excel" button, and the worksheet will be created, if necessary.

 

You must specify which columns contain which commands, where Pre-build BCL commands must have " *--PRE_BUILD_BCL*" in the first row cell of the pre-build commands column.  " *--POST_BUILD_BCL*" must be in the first row cell of the post-build commands column.

 

Build Process

Once you have your settings complete in the CCAT eVSM Utilities, click the "Build" button.  This will execute the eVSM Calculator, after which the CCAT eVSM Utilities will export the machine locations to Excel, as well as the Next Op data for each process (based on the connections between processes in your VSM).  Finally, the CCAT eVSM Utilities will export your Excel data to a tab-delimited text file, and start QUEST and tell it to execute a BCL script generated with your pre- and post-build BCL commands, as well as commands to run the SCL builder macros.

 

The SCL builder macros begin by reading the spreadsheet data to an internal string array, and identifying all the column names, as well as reading units for different NVUs.  Next, the builder copies data it has mapped to specific fields to a different string array, and begins the build process.

 

The build process begins with building part classes based on the Product column, then it builds a process for each row in the data array.  Next, the process products and requirements are set based on the links between processes and their products.  For instance, if two processes both have a process with tag "B10", the builder will interpret the process as an assembly process, and will require one of each of the Product part classes from the feeding processes.  Then, based on the Product of the process, the process will be set to either pack one of the requirements into the other, or it will create a new part (if the product is not one of the requirements).

 

Next, shifts are added to machines based on the Shift data, if provided.  If a machine is listed as having more than three shifts, then each shift is set as a time of 24 hours divided by the highest shift number found.  If the maximum shift number is 3 or less, then each shift is set as 8 hours.  Later on in the build, these shifts will be assigned to your machines.  If the shift times need to be changed this can easily be done either manually or through BCL.  The hardest part is done for you, which is creating and assigning the shifts to machines.

 

Next, workstations are created.  A workstation is just a machine, an input buffer, and an output buffer.  An input buffer receives and holds work until its machine can take it.  An output buffer holds finished work until it can be moved to the next workstation. 

 

As noted above, if TimeToNext is provided for a process, the workstation's output buffer will hold the part for whatever that TimeToNext value is.

 

Each workstation gets added to its own group so you may easily move a workstation around within a model.

 

Next, the builder will build connections between workstations.  This is done based on the requirements of the processes on different machines.

 

Next, laborers are assigned to processes.  If a process has loading or changeover associated with it then the laborer is assigned only to the loading/changeover process(es).  Otherwise the laborer is assigned to the cycle process.

 

Next, loading and changeover machines are assigned to machines.  After that, the builder assigns a process sequence to each part class, based on the chain of requirements and products of all the processes previously built.  One noted problem with this is that the BCL statement to build a process sequence must contain the names of all the processes in the sequence, rather than simply adding one process to the sequence.  This means that you may run against a string size limit when building a model with many long-named processes.  To fix this, modify the BIG_STRING_SIZE constant in the build_from_vsm_generic.scl file to something larger.

 

The builder then assigns action logics, if applicable, as listed in the configuration file.  Next comes machine failures, which are created and assigned if a process lists a machine's reliability as detailed above.

 

Lastly, the builder goes back to the original input array and finds any data columns that were not mapped to known constructs, and creates user attributes on the processes holding that data.  This means you can very easily pass data between eVSM and QUEST without customizing the build_from_vsm_generic.scl file.

 

The builder then cleans up any build errors and data arrays, and saves the model to QUESTLib\Last_Build_Model.mdl.  Also, the builder creates a BCL script of all BCL commands that get executed throughout the build process, and a log file is kept at QUESTlib\Output\writer_log.txt.


Monday, June 29, 2009

Automating DXF import to QUEST

QUEST doesn't come with a BCL command for easily importing geometry, and although that would be very convenient, it's still possible to convert various CAD geometry to QUEST's PDB format.

QUEST doesn't have CAD converts baked into the QUEST.exe application file, but rather uses standalone executables located in the quest\bin folder in your QUEST installation. QUEST simply calls these executables using command line arguments to pass in information about what the user is trying to do through the QUEST UI. The converter then performs the conversion, and dumps out a temporary pdb file into your temp directory (default is C:\Tmp). QUEST has been waiting for the converter exe file to terminate, after which it just does a "retrieve" of the temp file the converter created.

So, in a nutshell, to automate this ourselves, we simply have to call the appropriate converter with the right command line arguments, and we can go around the relatively clunky QUEST UI for dealing with our CAD importing.

My use case will be generating dxf/dwg layouts from vector drawings in MS Visio, and generating a pdb file for QUEST. This means I'll be using VBA in Visio, but the same thing could easily be done using SCL (although there might be a few snags, such as making your SCL code wait until the conversion is complete)

Before I start into laying out the arguments for converting a dwg to pdb, I should mention that DELMIA/Deneb have made it a little easier on us in running these converters. They have provided some DOS batch files for setting environment variables, which the converters basically need to be sure you are a licensed QUEST user.

So to convert dwg to pdb, we use the dwg2pdb.bat and corresponding dwg2pdb.exe files. If you look at dwg2pdb.bat, you can see there's about 5 lines for telling Windows where dwg2pdb.exe is. You can get away with deleting all that junk, and finding the line that says:

%DENEB_BIN_DIR%\dwg2pdb.exe $1 ...

and replacing the %DENEB_BIN_DIR% with the full path to your QUEST installations bin dir (mine is C:\delmia\quest\bin)

The only environment variable you need to make sure is set is the LM_LICENSE_FILE, which you should have set already in your quest.bat file, and if your installation of QUEST works, you shouldn't even need to change this.

So, on to the command line arguments. To see what the arguments are, I quickly built an exe in VB6 that just echos out the command line arguments in a message box. So I renamed my dwg2pdb.exe to something else, and renamed my command line echo exe to dwg2pdb.exe. Then I went into QUEST and ran an import, at which time I was shown that there are four arguments you need to pass to run a dwg conversion:

  1. The full path to the dwg/dxf input file
  2. The full path to the output pdb file location
  3. The full path to a configuration file called dwg_cmd (more on that later)
  4. The full path to an output text callout file location
The first two arguments are fairly straightforward. You just need to get the full path to the input file, and decide where to send the output file.

The third argument is for the full path to a file called "dwg_cmd", which is automatically generated by the QUEST UI when you tell QUEST some of the parameters of the input geometry, such as the default length units, point tolerance, etc... On my system, at least, this file was stored in the quest directory. So I modified it to a default length unit of Inches, and copied the file to quest\bin. This will serve as my default dwg import profile.

The fourth and final argument was the full path to where you'd like the converter to build a plain text file containing all the text from the dwg/dxf file. You'll notice when imporing a file with text, you get the floating annotations containing your drawing text. I guess this is where that text comes from. The format is somewhat easy to understand. Basically, the first line details the number of text annotations there are. Then the annotations start. The first three lines of an annotation are the x, y, and z locations of the text callout, respectively. I'm not entirely certain what the next four lines are, though they could be rotation angles and font sizes. The next line is the number of characters in the callout, and the final line of a callout is the callout text.

Okay, so now we know all the arguments we'll need to pass to dwg2pdb.exe or .bat, to get things translated. When I tried this though, I got an error saying the executable could not find lmgr8b.dll, which is some runtime that QUEST needs in order to operate (and I'm assuming it's for the FlexLM license manager QUEST uses)

To fix this problem, I simply copied the lmgr8b.dll file from my quest dir into my quest\bin dir, and everything seemed to work. I could pass in my arguments and get a pdb file out.

So now anywhere I can generate command line arguments, I can also convert dwg/dxf files into the QUEST format automatically.

Wednesday, May 20, 2009

Selecting a file from a QUEST library (using SCL)

QUEST SCL provides a means for an SCL programmer to call the standard file selection dialog box, where the user can pick a file from a specific folder from a specific set of libraries. This function is called FILE_POP_UP. You pass in a string or string array containing the directory (or directories) to be shown in the dialog box.

The way I use FILE_POP_UP, I use the inquire_config_path to populate a string array with all the libraries containing a specified folder name, and pass that array to FILE_POP_UP. I've encapsulated this functionality into a single SCL routine you can use:

routine get_filename( folder_name : String ) : String
Var
cpaths : array [50] of String
numpths : Integer
result : String
Begin
inquire_config_path( folder_name + '$LIB',cpaths, numpths)
FILE_POP_UP(cpaths, result)
return result
End

Now rather than havign to remember how to use inquire_config_path along with FILE_POP_UP, I can simply call a routine like so:

sel_file_path = get_filename( 'DATA' )

And of course, when you want the user to be able to select an SCL logic file, you'll want to be able to provide the option of selecting from the LOGICS and SCLMACROS folders from your libraries, so I've created a routine that takes two folder names, and combines their inquire_config_path results into a single array that gets passed to the FILE_POP_UP. Here it is:

routine get_filename_multiple( folder_name1 : String ; folder_name2 : String ) : String
Var
cpaths , cpaths2 : array [50] of String
the_paths : Array[ 100 ] of String
numpths , numpths2 , i , write_idx : Integer
result : String
Begin

inquire_config_path( folder_name1 + '$LIB',cpaths, numpths)
inquire_config_path( folder_name2 + '$LIB',cpaths2, numpths2)
write_idx = 0
for i = 0 to numpths - 1 do
if( cpaths[ i ] <> '' ) then
the_paths[ write_idx ] = cpaths[ write_idx ]
write_idx = write_idx + 1
endif
endfor
for i = 0 to numpths2 - 1 do
if( cpaths2[ i ] <> '' ) then
the_paths[ write_idx ] = cpaths2[ i ]
write_idx = write_idx + 1
endif
endfor
FILE_POP_UP(the_paths, result)
return result

End

You can use it like so:

sel_file_path = get_filename_multiple( 'LOGIC' , 'SCLMACRO' )


Executing shell calls in SCL and BCL

The combination of QUEST BCL and SCL is extremely powerful not only for building and runnign simulation models, but also for providing a better experience for you to use QUEST models. BCL and SCL can allow you to greatly simplify modeling tasks, at the tradeoff of lowering QUEST's flexibility from infinite, to match with some set of assumptions you've come up with.

One powerful tool here, is the ability to generate system shell calls, and here I'll talk about this on Windows machines, only.

QUEST BCL has a call named "SYSTEM" which takes a single string argument, enclosed in single quotes. The QUEST BCL documentation gives an example of copying a file:

SYSTEM 'copy thisfile thatfile'

where thisfile is the path to the file to copy, and thatfile is the path to the file you want to copy to. This is useful enough, and pretty self explanatory, especially if you've used the Windows command line enough.

The example I'd like to provide lays in launching applications, and in this case, Microsoft Excel. To simply launch a file from the command line, all you need to do is feed the command shell the path to the file to open. Windows knows how to handle pretty much any file type you throw at it, and in the traditional GUI use of Windows you're prompted if Windows doesn't know what to do with the file.

This works fine for files where there's only one program for viewing or editing a particular file type. But what happens if you want to chose what program to use? Using the command line shell, we can specify the program file to use to open a file by passing the path of our file as an argument in starting the application. Most major applications support this.

So if you have Open Office set as the default editor of Excel files, passing an Excel file to the command shell will open it in Open Office. But if for some reason you want to open this file in Excel (without changing the default behavior) we just have to start Excel with our file as a command line argument.

So here's an SCL routine you can use to launch an Excel file:

routine launch_excel( file_name : String ) : Integer
Const
EXCEL_LOCATION 'C:/Program Files (x86)/Microsoft Office/Office12/excel.exe'
Var
bclerr : Integer
bclmsg : String
Begin

bclmsg = "SYSTEM '" + EXCEL_LOCATION + " "

bclmsg = bclmsg + file_name

bclmsg = bclmsg + " &'"
if( EXCEL_LOCATION <> '' ) then
bclerr = bcl(bclmsg)
endif
return bclerr
End

All we're doing is using the SYSTEM BCL call with the file_name argument as a commmand line argument. Pretty simple, eh?

Precompiled (always there) SCL routines

Over the course of the last few years, I have developed some SCL utility logics that I use quite often and don't like having to copy over and over again. For example, a routine for replacing strings, or converting text to upper or lower case.

It's nice to have these logics, but normally, if you wanted to use them, you'd have to find a copy of the routines declared somewhere on your computer (possibly using my subroutine indexer). However, QUEST provides a directory within your QUESTlib folder called USERDEF, with a folder for logics that, if present there, will compile every time QUEST starts up.

This means that any procedures and routines within one of those USERDEF files will be available to you without having to copy them to the logic you're working on. They're always there. If you're trying to use a precompiled routine, however, you'll have to remember to declare the routine in the Extern section of your logic file.

What I usually do to cover this is to put in the extern definition for all my routines along with the definition of the routine in the USERDEF library. This way I can just go in and grab the extern def rather than the actual SCL definition.

In fact, to make it even easier to set up the extern definitions for all my routines, I've actually written an SCL macro that will do this, more or less, for me. You can download it at:


Just load this into an SCL macro button, and when executed it will prompt you to select an SCL file. It will then search through the file you selected and export the extern representation for all your routines to a text file. It will then launch notepad and open this file for you.

Then all you have to do is copy the extern definitions. Hopefully that makes life a little easier for you.

Wednesday, May 6, 2009

Excel VBA UDFs for QUEST BCL (wow, enough acronyms?)

If you have any familiarity with Excel VBA, you've probably made at least one User Defined Function (UDF) for use in an Excel spreadsheet. If you're not familiar with it, you basically just create a function within an Excel VBA standard module that may or may not take arguments, and returns something that can be displayed in Excel. For example, here is a simple function that just returns the sum of two arguments.

Function MySum(arg1 As Variant, arg2 As Variant)
MySum = arg1 + arg2
End Function

In this function, arg1 and arg2 are of Variant types, meaning the user is able to pass in a literal number or a selected Excel cell (called a Range). By defining variables as Variants, we can assume that whatever the user passes into the function can be cast into the variable type required by the operators we are using (in this case the addition/concatentation operator +).

What some people don't necessarily think of though, is to use VBA to create string concatenating UDFs. Here's an example that just puts two pieces of text together:

Function MyConcat(arg1 As Variant, arg2 As Variant)
MyConcat = CStr(arg1) & CStr(arg2)
End Function

You can see it's similar to MySum, except that we are using the & operator which is just for string concatenation in this use (where the + operator can be addition or concatenation). Also, we are making use of the built-in VBA function CStr to cast our variant data into strings. This is because the & operator requires strings as operands.

Now to the BCL part. We can use something similar to MyConcat to make it so we can easily create BCL commands by simply passing one or more arguments into specially created UDFs. Here's an example for creating a cycle process:

Public Function create_cycle_process(process_name As Variant) As String
create_cycle_process = "CREATE CYCLE PROCESS '" & process_name & "'"
End Function

So a user only has to pass in the name of the process they want to create, and VBA returns a properly formatted BCL command to execute in QUEST. This can be pretty handy.

Even better though, is that VBA allows optional arguments in UDFs, so we can easily account for the optional arguments in many BCL commands. A good example of this is the CREATE ELEMENT CLASS command, which requires that you provide the element class type and the element class name, but allows you to also specify the number of elements and the geometry file path to use for the class display. Without optional arguments you would have to write four different UDFs to be able to build a CREATE ELEMENT CLASS command with all the possible arguments. But with VBA we can do it one. Here's how:

Public Function create_element_class(class_name, elem_type, Optional num_elem, Optional geo_name)
Dim Result
Result = "CREATE " & elem_type & " CLASS '" & class_name & "'"
If Not IsMissing(num_elem) Then
Result = Result & " NUMBER OF ELEMENTS " & CStr(num_elem)
End If
If Not IsMissing(geo_name) Then
Result = Result & " GEO '" & geo_name & "'"
End If
create_element_class = Result
End Function

This function starts by creating the base BCL command using the required arguments, class_name and elem_type. Then, it uses the VBA function IsMissing to see if our optional arguments were omitted in the function call. If not, they are used to add to the BCL command. Finally, the BCL command is returned to the user. Now the user no longer needs to remember the proper syntax for creating an element class BCL command.

To make it even easier on the user, we can provide higher level functions that provide the proper elem_type for them, so they don't have to remember those either:

Function create_mach_class(class_name , Optional num_elem , Optional geo_name )
create_mach_class = create_element_class(class_name, "MACHINE", num_elem, geo_name)
End Function

Function create_source_class(class_name , Optional num_elem , Optional geo_name )
create_source_class = create_element_class(class_name, "SOURCE", num_elem, geo_name)
End Function

Function create_sink_class(class_name , Optional num_elem , Optional geo_name )
create_sink_class = create_element_class(class_name, "SINK", num_elem, geo_name)
End Function

Function create_buffer_class(class_name , Optional num_elem , Optional geo_name )
create_buffer_class = create_element_class(class_name, "BUFFER", num_elem, geo_name)
End Function

Function create_conveyor_class(class_name , Optional num_elem , Optional geo_name )
create_conveyor_class = create_element_class(class_name, "CONVEYOR", num_elem, geo_name)
End Function

Function create_accessory_class(class_name , Optional num_elem , Optional geo_name )
create_accessory_class = create_element_class(class_name, "ACCESSORY", num_elem, geo_name)
End Function

Function create_agv_controller_class(class_name , Optional num_elem , Optional geo_name )
create_agv_controller_class = create_element_class(class_name, "AGV_CONTROLLER", num_elem, geo_name)
End Function

Function create_labor_controller_class(class_name , Optional num_elem , Optional geo_name )
create_labor_controller_class = create_element_class(class_name, "LABOR_CONTROLLER", num_elem, geo_name)
End Function

Function create_carrier_class(class_name , Optional num_elem , Optional geo_name )
create_carrier_class = create_element_class(class_name, "CARRIER", num_elem, geo_name)
End Function

Function create_agv_class(class_name , Optional num_elem , Optional geo_name )
create_agv_class = create_element_class(class_name, "AGV", num_elem, geo_name)
End Function

Function create_labor_class(class_name , Optional num_elem , Optional geo_name )
create_labor_class = create_element_class(class_name, "LABOR", num_elem, geo_name)
End Function

Function create_path_system_class(class_name , Optional num_elem , Optional geo_name )
create_path_system_class = create_element_class(class_name, "PATH SYSTEM", num_elem, geo_name)
End Function

Hopefully this has given you a good primer on using VBA UDFs to create QUEST BCL commands in Excel, so you can smarter BCL scripts that will be easier to modify and to execute in QUEST.

Friday, March 13, 2009

Wait Until Event

A lot of times in modeling a system in QUEST there comes a need for some synchronization between different elements. For instance, one model I made had a large piece removed from the main assembly part, which was stored until the main assembly part arrived at a specified machine. Once that assembly part leaves for the machine, the large part should start being delivered to the machine (while the machine is running a process to prepare the assembly part for installation of the big part).
When I first started with QUEST, I probably would have written some logic on the storage buffer holding my part to look at the machine at a specified time interval to see if the main assembly part had arrived yet. You can set the time interval to whatever you want, and there are drawbacks no matter what. If you specify a small interval (like 5 seconds), your model will slow down to a crawl because your logic is running more or less constantly. Add multiple elements running this logic and you can kiss model performance goodbye.
So what if you specify a larger interval? Again, you're still going to be running your logic a lot more than you need to, and with the larger interval you run the risk of not noticing the main assembly part arriving until too late.
There are a few ways we can address this problem without using a time interval to constantly keep checking our machine. Some would suggest using signals, where our machine would send a signal to our buffer saying the part is there, and it's time to route the part on to the machine. This will have good performance in the model, as the logic in the buffer just uses a WAIT UNTIL SIGNAL SCL command to wait.
What I don't like about this is the need to write logic for the machine to use to send the signal to the buffer. And what if we can't be sure what buffer is holding our part? Then our logic has to search for the part and alert that buffer using a signal. This is all doable, but I prefer to use (what I think is) a simpler approach: the WAIT UNTIL EVENT SCL command.
The WAIT UNTIL EVENT command would be used similar to how we would use the WAIT UNTIL SIGNAL command, except that QUEST is raising the event for us, so no logic needed anywhere except on the buffer routing the part.
To use the WAIT UNTIL EVENT command, you simply provide an event constant, and optionally a pointer to the element/element class you want to watch, as well as whether you want your logic to run right before the event, or right after. There are some other options (you can look for events on a part/part class, or segment).
So for the example above with the assembly part and the part that needs to move to the machine, our buffer would just have a loop that goes something like this:
while( true ) do
WAIT UNTIL EVENT PART_XFER FOR ELEMENT_CLASS the_elem_handle
-- look at the_elem_handle's inparts to see if our assembly part is there...
endwhile
and then our logic can continue, and route the part out of the buffer to the waiting machine. One thing to note here, too, is that to use the PART_XFER constant you must have #include at the top of your SCL file or your logics won't know what PART_XFER is and it won't compile. You could just look up the numeric codes for the event constants if you'd prefer, but the code is easier to read (especially after a year without looking at or thinking about that particular logic) and more future proof if you use the constant names.
This is just one example where we can use the WAIT UNTIL EVENT SCL command in place of using signals. Your mileage may vary, in that the events we want may not be exposed for use in the WAIT UNTIL EVENT command (for instance, when a part actually arrives at an element). In these cases you may need to use signals, but hopefully you'll be able to use WAIT UNTIL EVENT just as effectively.