Incorporating a Module into the FRAMEwork System (FRAMES)


Title Page
Legal Notice
Table of Contents
Introduction
Example
STEP 1
STEP 2
STEP 3
STEP 4
STEP 5
APPENDIX A
APPENDIX B
APPENDIX C
APPENDIX D

Although it is by far easier to incorporate a model using the Application Programming Interface and editors provided with FRAMES, in some cases modelers will want to incorporate their models using pre- and post-processors. One such case is when it is vital that the testing and use of the legacy model be left undisturbed.

If a pre- and post-processor must be developed to wrap the model, modelers still need to start with Step 1, Add Units and Measures, and Step 2, Define Model Inputs and Boundary Conditions. Instead of continuing to Step 3 (Develop an Invocation of the Model), modelers would follow the instructions outlined below.

A model needs the API to interface with FRAMES. The standard way to access these functions is the "Use" statement. The FRAMES API is divided into System Developer (SystemDev), DataSet, Error, and Conversion subcomponents. So to make use of the DataSet API, a model's coding would include "use DataSet" within the function call. Pre-processor code, then, would include coding to access the SystemDev and DataSet functions. Documentation for these functions is also provided in the FRAMES 2.0 software. The files can be access by double-clicking "index.html" in the developer sub-directory of "c:\program files\framesv2\" (assuming FRAMES is installed in the standard location).

All FRAMES 2.0 modules are passed three arguments on the command-line. These arguments tell the module the invocation (because there could be many) it should process and the names and locations of the associated simulation files. The processor passes this information into the OpenIO function, which connects the model to FRAMES. Another way to think of this connection is a processor registering itself with the IO system as a consumer/producer of information.

Unfortunately, the method for getting the command-line arguments is not standardized. The following example shows how to get the command-line arguments using a Lahey F95 compiler and the final call to OpenIO:

     call getCL(commandline)   ! get the commandline handed the program
     READ(commandline,*) path,simulation,moduleId
     WRITE(*,*)TRIM(Path)," ",TRIM(Simulation)," ",TRIM(moduleid)
     READ(*,*)ierr
     pid=OpenIO(path,simulation,moduleId)

The program id (pid) returned from the OpenIO function should be positive. A negative pid indicates the FRAMES 2.0 system could not register the pre-processor as a consumer/producer. The pid is used in all subsequent calls to the API and can be thought of as a way to state who is making changes or reading datasets.

The GetIconUISet is a convienient function for getting the name of the input dataset the model is supposed to read. Remember the module does not know how many times it is going to be invoked, so it needs to read and write the datasets requested by the FRAMES 2.0 system. Otherwise, the system will not recognize or allow the changes.

Once the input dataset is known, the model can start to read values from it. All the read function calls are similar. Modelers who developed for 3MRA will find these function calls identical to the ones used in that effort, with the addition of the pid. For example, "readReal" takes the pid, input dataset name, variable name, and units. Note that the measure is not required in the call because the measure is bound to the variable name in the dictionary. In a sense, the dictionary has determined acceptable units for a variable, and the readReal function is simply getting the specifics.

After reading all the values from the input dataset and writing them to the native file format, the model signals to the FRAMES API that the process is complete by calling CloseIO. Once this function is called, all other API functions that need the pid will fail unless the model calls OpenIO again and re-registers with the API. The flag that is given along with the pid tells the sytem whether to retain changes. For example, in the pre-processor a value of 1 in the DataSet tells the API to cancel any changes. The flag value is 0 t ocall the CloseIO function in the post-processor, because the post-processor does modify datasets.

One unique aspect of the post-processor is that a module can produce a dataset for more than one consumer. To ensure that all consumers of a dataset are satisfied, the post-processor needs to find the names of the datasets needed for each consumer. A series of loops and conditionals are used to find those dataset names. The code below is required:

if (NumOMod(pid,moduleId,NOMod).ge.0) then     ! Read the number of outputs
      do i=1,NOMod
        IF (getOModId(pid,moduleId,i,OModId).ge.0) then
          if (NumOModSet(pid,moduleId,OModId,NOSet).ge.0) then
            do j=1,NoSet
              if (getODictionary(pid,moduleId,oModId,j,OutputDictionary).ge.0) then ! Get the dictionary
                if (OutputDictionary.eq."CSTROutput") then                      ! Is it the UI dictionary we expect
                  if (getODataSet(pid,moduleId,oModId,j,OutputDataSet).ge.0) then ! Get the dataset name
                    OutputSetFound=.TRUE.                                    ! Set the flag that says it is OK
                  end if
                &end if
              END if
            END do
          END if
        END if
      end do
end if

This code structurally loops across all output modules (consumers) and for each consumer finds what the expected datasets. If a dataset dictionary matches the one the module produces, that module stores the name in OutputDataSet. The remainder of the post-processor code is very similar to the pre-processor other, except that values are read from the native format and written to the API dataset.

After the pre- and post-processors are written and compiled, the modeler constructs a batch file to execute them in the appropriate sequence. In MS-DOS, arguments can be passed to a program called within the batch file by using %#. So a simple batch file needed to wrap an existing model called CSTR would be as follows:

CSTRPre.exe %1 %2 %3
CSTR.exe
CSTRPost.exe %1 %2 %3

The %1 %2 %3 will be replaced by the path, simulation and module name that all FRAMES 2.0 modules are given when they are invoked.

Note that one of the more powerful features in FRAMES is that a modeler is no longer required to provide a user interface. In FRAMES 1.x, a modeler not only had to deliver a wrapped module that matched the specifications of the system, but that modeler also had to provide an executable that would get all input from the user and store it in the module input dataset. FRAMES 2.0 eliminates this additional effort by providing a General Module User Interface (GMUI) through the Data Client Editor (DCE). The DCE is also used to retrieve data from disparate databases. In both roles it serves the purpose of allowing the user to view and edit datasets. Chossing the DCE as the user interface allows the modeler to populate input and run the model.

Note also that the rules for completeness in the DCE are very general. Currently the DCE enforces that scalar values must be populated, vectors can empty, and arrays with indices must have the same number of elements as the indices. In general the DCE checks that all the values are populated in accordance with their indices. However, if a model includes interesting interdependencies between parameters, a custom user interface is in order.

FRAMES also allows additional arguments to be passed to a model if needed. The additional arguments are passed before the path, simulation, and module name. So if an additional argument of "/fast" was needed, the argument would look something like the following:

yourModule.exe /fast "c:\program files\framesv2" mytestsim.sim mymod

The quotes around the path are necessary because "program files" has a space in it. This space sometimes causes problems between different versions of MS-Windows. The number of additional arguments passed to modules is unlimited (other than an MS-Windows limit), but each module needs to find the path, simulation, and module name correctly.

The model also needs to be described in FRAMES and categorized. Return to Step 4, Provide a Description of the Model and follow it and Step 5, Categorize a Model, to complete incorporating a model into FRAMES. Modelers can also refer to an example for specific coding information.


Battelle Logo
Home | Security and Privacy | Contact Us