Thursday, December 18, 2008

Compiling SCL from SCL (ish)

I don't know about you, but in the past I've developed QUEST solutions where it would have been nice to be able to use SCL code to identify a set of other SCL files to compile.  However, there is no straightforward way to do this as using the SCL_COMPILE BCL command from an SCL script will generate an error and not compile the SCL file.

There is a workaround, however, and that is to use BCL to execute an SCL subroutine which returns the path of an SCL file to the bcl_msg BCL variable.  You can then use the SCL_COMPILE command passing bcl_msg as an argument to compile an SCL file selected using SCL code.

The downside is that if the routine doesn't return a file path the BCL code still tries to compile the blank string file path, and shows an error in the message window.  Unfortunately (as far as I can tell) you can't use conditional statements in a BCL script, so there's not much we can do about this.  I'd say if you need to be able to compile SCL from SCL, it's worth the small inconvenience of seeing the error message when you don't specify a file.

I've used this technique to compile SCL files listed in a configuration file (not the QUEST kind) that could only be parsed using SCL (rather than straight BCL), so that users can specify different SCL logics in building a QUEST model from an eVSM file.

This may not be of any use to anyone reading this, so I've provided an example which hopefully will make using QUEST just a little bit easier to use.  I don't know about you, but I often debug my SCL code by writing a little, then compiling it in QUEST, until it's all done and working.  However, if you're working on multiple SCL files it can be a pain to go to the Run->Simulate->Compile button and pick files in various folders.

So what I've done is created a BCL macro that calls an SCL routine that keeps track of (up to) the last 49 or so SCL files that I've compiled (in the current session) and gives me the option of selecting another file to compile.  So I've basically duplicated the Run->Simulate->Compile functionality, and added a list of the most recently compiled files for you to chose from.

You can get the BCL script here and the corresponding SCL file here.  Keep in mind that you need to modify the BCL script to compile the SCL file wherever it is saved on your computer.

Tuesday, November 11, 2008

Select an Element

QUEST SCL provides a function for selecting items (including elements) from the QUEST world, aptly named Select.   Basically, you tell the function what you want to pick (elements, cad_parts, etc...), the selection mode (mouse pick, pick from a list, or key in the name), and you pass in a string variable that will be set by the routine to the selected item's name (You also have to specify a text prompt, and whether or not you want the selected item to be highlighted).

I usually don't need to use all the available options in the Select function, so I've put together a routine I use often that I can drop into an SCL macro or call with an Extern reference, so here it is:

   routine select_an_element( prompt : String ) : Element
   Var
   elem_name : String
   picked_elem : Element
   Begin
      while( select( prompt , ELEMENT , PICK_MODE , TRUE , elem_name ) ) do
         picked_elem = get_element( elem_name )
      endwhile
      return picked_elem
   End

Like I said, this is just an easy to implement routine you can drop into your code without worrying too much about it, which is how I like to program...

Tuesday, October 21, 2008

Set part class dimensions

As far as the QUEST online documentation shows, there is no BCL command for setting a part class' dimensions.

I thought it would be possible to do this by exporting a part class to a text file, modifying the text file with the new dimensions, and then re-importing the text file to overwrite our part class with the new dimensions.

Here is the resulting SCL macro.

You can use it from within SCL by calling set_pclass_dimensions with a handle to the part class, then the 3 arguments to set the part class dimensions to.

You can call it from a BCL script using the following commands, setting the full path to the set_pclass_dimensions.scl file, substituting Part1 with the name of the part class you want, and setting the dimensions to the sizes you want:

SCL_COMPILE 'set_pclass_dimensions.scl' 0
SCL_EXEC set_pclass_dimensions_by_name WITH ARGUMENTS 'Part1' , 100 , 200 , 300

SCL Subroutine Indexer

If you're anything like me, you've written a large variety of SCL logics and have tons of procedures and routines buried in files which are in turn buried in different QUEST LOGICS and SCLMACROS libraries.  Sometimes I need a logic that I know I've already written, but can't remember where it is.  I use Google Desktop to find files, but it is unable to search within the text of a plain text file unless it has an extension it recognizes (i.e. not .scl).

Rather than write a plugin for Google Desktop to enable SCL search, I went the quicker, dirtier, and easier path (for me, anyway) and wrote a couple macros in Excel to index a set of SCL files (extracting all procedure and routine declarations) into an Excel worksheet.  A while back I wrote an interface for Excel's AutoFilter that makes setting filters on large datasets a little easier than without.

One thing to note is I haven't set it up to read any subroutine declarations that span multiple lines (using the line continuation character "\") so at the moment it won't pick up the full declaration.

Updated:  10/21/08 - Modified the auto-filter helper to run faster in populating the result list box for large data sets

To use this indexer, simply copy the SCL_Indexer.xls file to your computer, and open it in Excel.  I signed the VBA project with a digital certificate created on my own computer, so you should be able to import the certificate, but to be honest I'm not sure how that will work, and you may be stuck hitting "enable macros" every time you open the file.  If nothing else, you can try saving the file to a trusted location.

When you open the file (with macros enabled) the indexer will create a toolbar called "AutoFilterHelper".  This toolbar contains the buttons for running the indexer and searching the index (In Excel 2007 a section will be added to the Addins ribbon with the buttons).

To use the indexer just click on the binocular button.  This will open a form that allows you to select a directory or file, and to index it.  You may select to index any subdirectories from a directory.  Hit cancel while it's indexing if you want it to stop.

Once the index is built you will see that the worksheet is populated with all procedure and routines indexed, with the return type (Null means it's a procedure) and arguments listed.  The file name for each subroutine is listed as well.

To use the auto filter helper, click on the magnifying glass, and select the column header you want to search.  It may take some time to populate the result box, but you will see a list of all subroutine names in the bottom right box.  To search the list, start typing in the text box and the results in the result box will reflect what you've typed in the search box.

Select an item in the result box and click "Apply Filter" and that filter will be applied in the index worksheet.  For more information on auto filter: http://www.contextures.com/xlautofilter01.html

Monday, October 6, 2008

SCL Code "Profiler"

I've written a fairly large SCL macro, which you'll be able to get soon here.

In order to keep tabs on how much of this 8000+ line macro is real code, I decided to write an SCL logic "profiler", which really just goes through and counts the number of comment lines, blank lines, and everything else, and reports it out for you.  So really in my (currently) 8195 lines of code there's really 5978 lines of code, 1061 blank lines, and 1156 lines commented out.

The line counter code can be downloaded here.

Wednesday, October 1, 2008

String Replace

This routine gives you similar functionality to the replace function in VBA. Basically, the routine just reads through a string argument and replaces any instance of to_replace with replace_with.
As far as I can tell there is no built-in function in SCL for doing this...

routine replace_string( full_string : String ; to_replace : String ; replace_with : String ) : String
Var
   result : String
   start_idx : Integer
   rep_idx : Integer
Begin
   start_idx = 11
   result = full_string
   while( index( result , to_replace , start_idx ) > 0 ) do
      rep_idx = index( result , to_replace , start_idx )
      result = leftstr( result , index( result , to_replace , start_idx ) - 1 ) + replace_with + rightstr( result , len( result ) - index( result , to_replace , start_idx ) - len( to_replace ) + 1 )
      start_idx = rep_idx + len( replace_with )
   endwhile
   return result
End

Friday, September 19, 2008

Batch Control Language (BCL)

QUST has two macro/scripting languages, SCL and BCL. BCL is short for Batch Control Language, and it is basically there to let you automate almost everything you can do through the QUEST User Interface. This automation can be done through straight-up BCL scripts, which are plain-text files containing a series of BCL formatted commands. An example of such a command is:

CREATE SOURCE CLASS 'Source1'

which will create a new source class named Source1. This will also create one element in the Source1 class. You can locate this element using the follwing command:

LOCATE ELEMENT 'Source1_1' AT 100 , 100 , 0

This kind of scripting can be tedious and error-prone. The good thing is, almost all BCL commands are supported for use through SCL programming. This means you can write an SCL script to read a list of element names and locations, and execute BCL calls to create and locate those elements.

To use BCL within an SCL script, you use the BCL( command_text : String ) : Integer function. All you do is provide a string argument that contains your BCL command, and SCL will have QUEST execute it. The BCL function returns an integer containing the error code, so you can know whether or not the command executed properly. A list of error code numbers and their corresponding descriptions can be found in the bclerr.inc file in your QUESTlib\Include folder.

It's also possible to have QUEST execute a BCL script as soon as the QUEST.exe program starts. Details for setting up QUEST to run this way from Excel can be found here.

So, assuming you've set up QUEST to run a BCL script generated in Excel, you may now be wondering how to generate BCL scripts in Excel. I have set up a number of Excel VBA User Defined Functions (UDFs) that can be used to generate a subset of all the BCL commands. I'm currently working on building a version of this that I can release for everyone to use, but until then why not start building your own BCL UDFs?

upper & lower case

Sometimes in writing QUEST logics, especially those that deal with user input or reading from text files, I've had to compare two pieces of text for equality where the case of the text wasn't an issue.  The thing with SCL is that text comparisons are case sensitive, which meant I needed a way to convert a text string to either all caps or all lower case characters.  I never found anything for this in QUEST's SCL docs, so I made my own, and here they are.  The routines work by reading each character in a string individually, and seeing if it's already in the desired case.  If not, we just add or subtract 32 to/from its ASCII value to convert between upper and lower case characters in ASCII text.


routine is_lower( the_string : String ) : Integer
Const
   first_lower 97
   last_lower 122
   upper_to_lower 32
Var
   the_char : String  
   result : Integer
Begin
   the_char = leftstr( the_string , 1 )
   if( asc( the_char ) <= last_lower AND asc( the_char ) >= first_lower ) then
      result = true
   else
      result = false
   endif
   return result
End

routine is_upper( the_string : String ) : Integer
Const
   first_upper 65
   last_upper 90
   upper_to_lower 32
Var
   the_char : String  
   result : Integer
Begin
   the_char = leftstr( the_string , 1 )
   if( asc( the_char ) <= last_upper AND asc( the_char ) >= first_upper ) then
      result = true
   else
      result = false
   endif
   return result
End          

routine upper( the_string : String ) : String  
--Return upper case version of the_string
Const
   first_lower 97
   last_lower 122
   upper_to_lower 32
Var
   i : Integer
   result , check_char : String  
Begin
result = ''
for i = 1 to len( the_string ) do
   check_char = substr( the_string , i , 1 )
   if( is_lower( check_char ) ) then
      check_char = chr( asc( check_char ) - 32 )
   endif
   result = result + check_char
endfor
return result
End

routine lower( the_string : String ) : String  
--Return upper case version of the_string
Const
   first_lower 97
   last_lower 122
   upper_to_lower 32
Var
   i : Integer
   result , check_char : String  
Begin
result = ''
for i = 1 to len( the_string ) do
   check_char = substr( the_string , i , 1 )
   if( is_upper( check_char ) ) then
      check_char = chr( asc( check_char ) + 32 )
   endif
   result = result + check_char
endfor
return result
End

Inquire Element Location

The QUEST BCL Language has a command called "Inquire Element Location", which just takes the specified element's location and prints it to the BCL output window.  It may not seem at first to be of much use there, but we can make use of a special variable declaration in SCL to access this output text.

To illustrate using the BCL output from SCL here's an example SCL macro which will print the location of every element in the current model to a tab-delimited text file, and launch that file for viewing in Excel.  I have another macro which I may share that will let you read this format back into QUEST, modifying element locations as read from the text file.

Handling 6 Degree of Freedom data in SCL

QUEST elements are located in 3D space in the QUEST world, and can be rotated about 3 axes, giving a total of six pieces of information required to completely locate some element in 3D space in QUEST.  In order to give our SCL code some degree of modularity and elegance, we need an easy way of passing all the location information.

We can settle for just passing all six parameters around every time we want to work with QUEST locations.  Over time this can get old, especially if you work a lot with locating elements in QUEST.  Also it helps to have a good methodology in place for dealing with locations, like having a routine for pulling the location of an element, or a procedure for locating an element with little hassle.

The solution I use is to have an SCL Structure for a 3D location.  From the QUEST SCL docs:

A structure is a group of variables which can be manipulated collectively or individually. A structure is analogous to a record which consists of many fields. 

What this means to me is that I can have as much information stored in a structure as I need, and move that information around by passing just a single variable.

The name I chose for my 3D location structure was "spot", and here's how I've defined a spot in SCL:

structure spot
x : Real
y : Real 
z : Real
yaw : Real
pitch : Real
roll : Real
elem_there : Element
endstructure

Basically the spot is just keeping track of 3D location and orientation, storing these values as type real.  I also have a handle to an element, which you would set when inquiring about en element's location.  My thinking there was that some day I might need a way to populate locations in a QUEST model without overlapping items, so I added the elem_there field.

One thing to note about using structures, is that you can work with a structure variable, or a pointer to a structure variable.  Those of you with experience in C probably know the distinctions and caveats to each technique, but I usually use a pointer to a structure, just because it's a little less confusing thinking about whether or not the structure I'm using is what I think it is.

Moving forward, we now need a way to inquire the location of an element in QUEST and return a pointer to a spot structure, after populating a spot.  The routine itself makes use of a bcl command called "INQUIRE ELEMENT LOCATION", which simply places the location of the element in a comma-delimited text string on the BCL command output window.

Accessing the text in the BCL command output window is pretty simple, just declare a variable at the top of your scl file in a declaration section called "BCL_VAR".  The string to declare for the BCL command output window is "bcl_msg : String".  The only other BCL_VAR is "bcl_status : Real" which will tell you the result of a BCL command.  More on that another time.

So your BCL_VAR declaration should look like this:

BCL_VAR
   bcl_msg : String

Now for the inquire_loaction routine:
routine inquire_location( the_element : Element ) : @spot
Const
   the_delim ','
Var
   bcl_err : Integer
   the_loc : String
   result : @spot
Begin
   result = new()
   if( the_element <> NULL ) then
      bcl_err = BCL( "INQUIRE ELEMENT '" + the_element->name + "' LOCATION" )
      the_loc = bcl_msg
      parse_str( the_loc , the_delim , result->x , result->y , result->z , result->yaw , result->pitch , result->roll )
   endif
   return result
End

A few things to note:
  • result is declared as being of type @spot, which is a pointer to a spot structure
  • We make use of the new() routine to allocate memory for a spot structure.  We have to remember to free this portion of memory later using the free() procedure.
  • We make use of the parse_str routine for parsing the string into chunks for us.  This is a built in routine in SCL.
  • We use the -> symbol as a member pointer rather than a dot because we're working with a pointer to a structure.  If we were using a straight structure, we'd us a dot.
The routine basically just executes the "INQUIRE ELEMENT LOCATION" BCL command, extracts the output text from the BCL output window, and parses it to a new pointer to a spot structure, and returns the pointer to the calling function.

To tie it all together, see the write_elem_locs.scl file to see how we can build a tab-delimited text file of all our element names and locations, and launch the file in Excel.

You can execute the macro by saving it to an SCLMACROS folder in a QUEST library, or you can compile the file and execute the write_all_locations function through BCL.

Thursday, June 5, 2008

Select A Process

QUEST has a pretty powerful construct that I haven't really seen in any other simulation packages: processes. A process is a data structure in QUEST that holds pretty much all the information you need to run a process in a simulation.

SCL exposes a lot of the information in a process, which you can see in the SCL documentation. However, selecting a process interactively in SCL is not built in (as far as I can tell). So here's a routine for selecting a process in a QUEST model.

routine select_a_process() : Process
Const
max_process 200
Var
result , the_process : Process
num_processes_found , pick_process , list_picked : Integer
the_processes : Array[ max_process ] of String
Begin

num_processes_found = 0
the_process = first_process
while( the_process <> NULL and num_processes_found < max_process ) do
the_processes[ num_processes_found ] = the_process->name
num_processes_found = num_processes_found + 1
the_process = the_process->next
endwhile
list_picked = item_pop_up( 'Select a process' , the_processes , pick_process )
return get_process( the_processes[ pick_process ] )
End


Basically the macro traverses the QUEST model's linked list of processes and adds them to an array. Then we use the item_pop_up routine to select a process from a list generated by our array. The item_pop_up returns the index of the selected process in the array, and we return that process pointer. You can use this routine to select a process that you want to act on in a SCL macro.

Wednesday, June 4, 2008

File I/O

QUEST SCL has a set of easy to use subroutines for dealing with file input and output. If you've done file I/O in VB or VBA you'll see the syntax is very similar.

File I/O is performed in SCL using file streams. This basically means that you use SCL to open a file and either read it or write to it. To open a file you first need to determine the file stream you want to use. This is just an integer value unique to the file you want to access. If you're planning to open a file stream and close it within a single subroutine the file stream should be an integer between 1 and 15. Anything above that is a global stream, which can be manipulated from any subroutine you're running. This complicates things a bit, and I personally don't use global streams very often. This is because you can pretty easily just append data to a file if you prefer.

There are two ways to pick a stream. You can use a literal integer value and just keep an eye on which you use (in case you decide to manipulate several files at once). Or you can do what I do and use an integer variable so it's easy to change things around, and it makes the code easier to read.

There is a way to ensure you always have a good file stream to use, which is to check file streams starting with one until you find one that's not opened yet. This is facilitated with a while loop and the QUEST built in function is_open.

The is_open function just takes in an integer value and returns true if it's in use as a file stream and false if it's not. Here's the start of a procedure for writing data to a file:

procedure print_data_to_file()
Var
out_stream : Integer
Begin
out_stream = 1
while( is_open( out_stream ) ) do
out_stream = out_stream + 1
endwhile
End


When this procedure gets to the end, out_stream will have a value that is acceptable for use in manipulating file operations. But how do we start file manipulation? With the "open" procedure. This procedure is a little different in that arguments are not passed in parenthesis, but instead the command is built like a sentence. The syntax is:

OPEN FILE name FOR [ BINARY | TEXT ] { OUTPUT | APPEND | INPUT } AS unit_no

In this procedure we can leave out the binary/text declaration, as SCL will default to text. We need to declare how we're opening the file, though. We have the option of: output, append, or input. If we output, then if the file exists it will be wiped clean and started new. If we choose append we have to make sure the file exists to begin with or we'll get an error. If we do append, then any data we write to the file just gets appended to the end of the file. Lastly, if we open for input then we can't make any changes to the file; we're just reading its contents.

From this point on things are pretty straightforward if you're writing out to the file. You simply use the "write" procedure and specify the output stream in order to output to that stream. Here's an example procedure:

procedure print_machine_class_names()
Var
   out_stream : Integer
   check_class : Element_Class
Begin
   out_stream = 1
   while( is_open( out_stream ) ) do
      out_stream = out_stream + 1
   endwhile
   OPEN FILE 'C:/Tmp/machine_names.txt' FOR OUTPUT AS out_stream
   check_eclass = first_element_class
   while( check_eclass <> NULL ) do
      if( check_eclass->type == MACHINE ) then
         write( #out_stream , check_eclass->name , cr )
      endif
      check_eclass = check_eclass->next_eclass
   endwhile
   close #out_stream
End

This is a very straightforward example that first creates/resets the machine_names.txt file, and then proceeds to print out the name of every machine encountered in the model. The last thing it does is close the file stream using the close procedure.

Reading data from a text file is a little less straightforward but not much harder to do. We need to start the same way as writing: find a valid file stream and open the file. Here's the base code:

procedure read_data_from_file()
Var
   in_stream : Integer
Begin
   in_stream = 1
   while( is_open( in_stream ) ) do
      in_stream = in_stream + 1
   endwhile
   OPEN FILE 'C:\Tmp\file_read_example.txt' FOR INPUT AS in_stream
End

Once the file is open, we need to start reading the file. We can do this using the read_line procedure. The syntax is as follows:

READ_LINE ( [ #unit_no,] lvalue )

where lvalue is a string variable we pass in whose value gets assigned as the next line read from the specified file stream. One thing to note here, is that when SCL gets to the end of the file, read_line will return a special predefined string called $EOF. We just keep reading until read_line gives us the $EOF string.

Here is some sample code for reading lines from a file and writing them to the screen.

procedure read_data_from_file()
Var
   in_stream : Integer
   curr_line : String
Begin
   in_stream = 1
   while( is_open( in_stream ) ) do
      in_stream = in_stream + 1
   endwhile
   OPEN FILE 'C:\Tmp\file_read_example.txt' FOR INPUT AS in_stream
   read_line( #in_stream , curr_line )
   while( not curr_line == $EOF ) do
      write( curr_line , cr )
      read_line( #in_stream , curr_line )
   endwhile
   close #in_stream
End

File I/O is a powerful tool for use in QUEST. You can use this to read in a tab-delimited data file with any number of possible uses. For example you can read in process cycle times and assign those times to the specified processes. The possibilities here are really endless, and hopefully this will give you a good idea of how to get started.

Tuesday, June 3, 2008

Simulation Control Language (SCL)

Simulation Control Lanugage (SCL) is the runtime language used in QUEST for defining logics. It's pretty similar to Visual Basic and Pascal as far as I can tell, in terms of syntax. It's a fairly high level language allowing easy manipulation of files, and even execution of Windows API functions.

SCL is not only used for defining logics in a model (init, process, route, etc), but can also be used to build QUEST macros that you run using custom buttons or even remote execution through QUEST's Batch Control Lanugage (BCL). The possibilities with SCL aren't necessarily limitless, but it's a very robust language and it takes a lot of effort to run into its limitations.

SCL files are stored in text files and are not embedded within a simulation model like some other simulation packages do. This makes it easy to apply SCL code to different models, but it also means you can destroy the functionality of any number of models just by modifying a single logic file to fit a single case.

To get you started with SCL, I'll go with the old standby and just create a simple "Hello World" program to illustrate some basic SCL concepts.

To start, you first need to open a text editor and start your scl file. You can use notepad or any text editor. I prefer to use RJ-TextEd (See here) because it allows code folding and syntax highlighting; so if you have a large number of subroutines in a file you can more easily navigate the file than using notepad.

With your text editor of choice open, first create a new subroutine by defining it:

procedure hello_world()

The word "procedure" tells the scl compiler that this is a subroutine that does not return anything. If you want to return a value you replace the word "procedure" with "routine". I'll cover routines in more detail at a later time. You're also able to pass in different arguments to subroutines, but we don't need to worry about that just yet. We just want to display "hello world" in QUEST.

With your procedure name defined, we can finish defining the procedure by defining the start and end of the program:

procedure hello_world()
Begin

End

All code that you execute must fall between the Begin and End lines of the subroutine you're using. Each line of code represents one command (unless you use the line continuation character, "\").

QUEST has some decent documentation on SCL built in subroutines. From this documentation under the I/O Routines section we can find a procedure called "write" that will let us print a message to the QUEST user screen. The syntax is:

WRITE ( #unit_no, pr_expr [ , pr_expr,... ] )

where "#unit_no" is an optional argument which can specify a file or window or tcp/ip stream to write to. Disregard this for now. "pr_expr" is the message we want to write, which can be a variable of just about any type (although some types just print their memory address), though we should stick to printing simple data types( String , Real , Integer ). So the "[ , pr_expr ]" means we can specify any number of variables we want.

We don't need to pass a variable to the "write" procedure; we can pass literal strings or integer/double values as well. To write "hello world" in QUEST, we'd simply call:

write( 'hello world' , cr )

where cr is a built in QUEST variable that is basically a carriage return and line feed.

You can see I used a single quote to define a literal string, "hello world". This is the SCL compiler's preferred way of defining a literal string, but you can use double quotes if you want, as long as you are consistent in a single string definition (you can't say "hello world').

The finished procedure reads as follows:

procedure hello_world()
Begin
write( 'hello world' , cr )
End

Save your scl file into the "SCLMACROS" folder of any QUEST library you have appended. You can save with a txt or scl extension, it really doesn't matter. As long as the information is present in ASCII text the SCL compiler won't care.

We don't need to create a user button to run this macro, and so it'll probably be easier for now to just compile and run the file using BCL. To execute BCL go to File->BCL. You will be given a BCL prompt where you can type or paste a command to execute. The first line of BCL to execute is:

SCL_COMPILE 'hello_world.scl' 0

Replace 'hello_world.scl' with whatever you named your file. Don't worry about the full file path; as long as it's in an "SCLMACROS" folder QUEST should be able to find it. If the file is not found, make sure the library it's in is appended.

The next line of BCL will read:

SCL_EXEC hello_world

This line will execute the hello_world procedure stored in memory after compiling your logic file. When you run this a window should pop up in QUEST that says "hello world".

That was a bit long winded for a hello world type subroutine, but hopefully it explains how you need to define subroutines for QUEST SCL files.

Introduction Post

The purpose of this blog will primarily be somewhere for me to put some of my knowledge of DELMIA QUEST (QUeueing Event Simulation Tool) out on the Internet. This is for two main reasons: one, I'd like to have somewhere to keep some of the tools I've written for QUEST, and two, maybe someone somewhere will get some value out of what I leave here.

I spend a lot of my time these days working on ways to automate the use of QUEST through QUEST's Batch Control Language (BCL) and Simulation Control Language (SCL), so that's probably what most posts will focus on for now.

I'm always looking to learn more about QUEST and simulation packages in general, so leave a comment or send an email (if that's available).

I run a Google Group on DELMIA QUEST, which at the moment doesn't have a lot of activity. If you're interested in joining go to http://groups.google.com/group/delmia_quest and join, and I'll more than likely approve you.

Happy simulating.