You are on page 1of 44

Minnerva

T14 Projects
Using OmniTRANS on Projects
Intercollegiate MSc in Transport

Prepared for: Centre for Transport Studies Imperial College London & University College London

Document Control
Project Title: T14 Projects

Document Title: Using OmniTRANS on Projects File Reference: ML0112/2 Author: Other Authors: Reviewers: Miles Logie

Issue History Version Number 1.0 1.1 Date 10.1.05 17.1.06 Revised for network modelling and Studytown_T14 project Comment Distribution J Polak, R Mackett, T14 J Polak, B Heydecker, T14

File Name:

OmniTRANSProjects.doc

Contents
Introduction
Aims of the Information Setting Objectives Structure of the Document Associated Resources Studytown Project OmniTRANS Documentation Books on Ruby

1
1 1 1 1 1 2 3

About Scripts
Ruby in the Context of OmniTRANS Structure of OmniTRANS Thinking OmniTRANS Projects and Variants Dimensions Matrices and Hypercubes Getting Started with the OmniTRANS Job Language What is a Job? Write your First Job The OmniTRANS Job Language (OJL) - Ruby Jobs and PMTURI Working with Matrices Working with Skim Matrices Job Library

5
5 5 5 6 6 9 10 11 11 14 21 22 24 24

Anatomy of OmniTRANS Scripts


Key Studytown Jobs

27
27

CONTENTS

PAGE I

CONTENTS

Trip Distribution Modelling Script T14_JobDistribution.rb Mode Choice and Public Transport Assignment Modelling Script T14_PTAssignModeChoice.rb Highway Equilibrium Assignment Script T14_EquilibriumAssignment.rb

27 27 36 36 40 40

List of Figures
Figure 1.1 OmniTRANS Online Help Figure 1.2 Ruby Reference Figure 1.3 Some Books on Ruby Figure 2.1 Structure of OmniTRANS Figure 2.2 Example Project Setup for Studytown Figure 2.4 Example Studytown Jobs Figure 3.1 Plot of Flow-Delay Curves 2 3 4 5 8 25 40

USING OMNITRANS ON PROJECTS

PAGE II

Chapter

Introduction
Aims of the Information
This document is designed to provide the key information required to make use of the OmniTRANS software for transport modelling projects undertaken as part of the T14 course. For projects involving model development, rather than merely use of established models, it is necessary to be acquainted with the creation of OmniTRANS jobs scripted in the Ruby computer language. The full mastering of Ruby and the specialised OmniTRANS classes that are used with it requires more time than is reasonably available in the T14 course. The approach used in this document is therefore to build on the examples already available as part of the OmniTRANS Studytown project that was introduced in the T5 course and documented in the corresponding Workbook.

Setting Objectives
In deciding how to address the requirements that have been set for the T14 project, it will be a good starting point to determine how the OmniTRANS jobs from the Studytown project may best be exploited. This will provide an introduction, but one from which you may choose to deviate to a greater or less extent. The combination of Ruby and the OmniTRANS classes is powerful enough that you can contemplate implementing very varied forms of modelling. It is best, if possible, to modify existing operational scripts, so one objective in planning the project is to define an incremental development path that leads away from the existing Studytown scripts. The most important scripts are discussed further in Chapter 3 of this document.

Structure of the Document


The following chapter provides an introduction to Ruby and the third chapter describes the OmniTRANS jobs that are provided as part of the Studytown project. The scripts in several of these jobs are presented in further detail.

Associated Resources
The following resources provide additional information that given in this document.

Studytown Project
This project has been encountered in the earlier T5 workshop. A variation of this OmniTRANS project, Studytown_T14, has been provided to assist with the work of the T14 project. Studytown_T14 is available in the T14 area of the Acer server (\\acer\Public\POLAK\MSc\T14) as a zip file and may be copied to a convenient area (typically on the H: drive) and given a name of your choice.

USING OMNITRANS ON PROJECTS

PAGE 1

CONTENTS

The OmniTRANS software is accessed from the OmniTRANS item in the Transport set of programs available from the standard Start menu and may be used to open the Studytown_T14 project. The Studytown project is limited to 25 zones and so may be operated using unlicensed versions of OmniTRANS. It has a detailed multi-modal network and various sets of demand data. Not all the data was used in the T5 Exercises, but they enable the project to be exploited more widely, such as for project and research work. The provided data has been derived from varied sources and in varied ways; it does not represent any real location. As noted in the T5 Workshop, the Studytown project has a customised user interface relating to the exercises in the Workbook. This interface may be removed by deleting the files CTSSettings.ini and CTS.ini from the top level of the new OmniTRANS project that is created from the Studytown template (or the interface can simply be minimised and ignored.

OmniTRANS Documentation
The on-line Help for OmniTRANS provides three sources of information:

OmniTRANS Manual Ruby Reference Getting Started

The section in OmniTRANS Manual on The Job Engine should be particularly noted. This is shown in Figure 1.1, with some of the contents for the Ruby Standard Classes and OmniTRANS Classes indicated as well.

Figure 1.1 OmniTRANS Online Help The Ruby Reference describes the Ruby language in a standalone form, that is, without reference to OmniTRANS. Its contents are indicated in Figure 1.2.

USING OMNITRANS ON PROJECTS

PAGE 2

CONTENTS

The Getting Started document describes using OmniTRANS through the use of the other project template provided within the Tutorials section, namely Delft. This 25-zone project also provides a valid starting point for project work alongside Studytown. (As OmniTRANS is already installed, the most relevant information starts in Chapter 3 of the Getting Started document.)

Figure 1.2 Ruby Reference

Books on Ruby
The Ruby language is used in a wide range of applications, not just transport modelling, and a number of books are available that assist with learning about it. Four of these books are illustrated in Figure 1.3. It may be noted that The Pragmatic Programmers Guide provides the basis for the on-line ruby reference. For those who are not familiar with programming, these books may appear rather forbidding, but they are much easier to follow once you have appreciated the basics of Ruby, as introduced in Chapter 2 of this document. Although the on-line documentation is comprehensive, it will generally be advantageous to have access to a book on Ruby.

USING OMNITRANS ON PROJECTS

PAGE 3

CONTENTS

Figure 1.3 Some Books on Ruby The URL for the Ruby web site is http://www.ruby-lang.org .

USING OMNITRANS ON PROJECTS

PAGE 4

Chapter

About Scripts
Ruby in the Context of OmniTRANS
Although the focus of this chapter is on using Ruby, we start with introducing a number of key concepts used by OmniTRANS.

Structure of OmniTRANS
OmniTRANS has the following schematic structure:

Figure 2.1 Structure of OmniTRANS The User Interface provides the major point of contact that the user has with the modelling project and contains the tools required to work with data and to achieve the desired modelling objectives. The Job Engine is where the calculations and the model processing are undertaken. Interaction with the Job Engine is via 'Job Scripts' that specify the processing to take place. The Database is where all data associated with a Project is stored. In the normal course of events you have no direct interaction with the database; it is managed and controlled transparently by OmniTRANS.

Thinking OmniTRANS
This section introduces some typical OmniTRANS concepts, such as projects and variants, dimensions and so-called matrix hypercubes, all related to how things are organised within OmniTRANS. Although these concepts are different from other

USING OMNITRANS ON PROJECTS

PAGE 5

ABOUT SCRIPTS

packages, you will experience that they make life a lot easier once they have been understood.

Projects and Variants


As demonstrated in the T5 Workshop, OmniTRANS works with projects and variants. Projects Usually, an OmniTRANS project is the coherent collection of input data, processing jobs, output data and presentational settings used for a specific study. However, more studies can be combined in one OmniTRANS project or more OmniTRANS projects can be made for one study. Technically, an OmniTRANS project is stored in a series of database tables, which together form a relational database system that is situated in one common directory on the hard disk or a network drive. OmniTRANS takes care that all data is saved at the proper position and that it is stored in a structured manner. Variants An OmniTRANS project comprises one or more variants, and the variants in turn can have one or more sub-variants. Schematically, a project will typically look something like the following:

A variant comprises network data, and matrix and zone based data (demand data), although all of these data items are optional. Variants are managed in the Project Manager window.

Dimensions
Transport modelling data naturally expands into multiple dimensions (purpose, mode, time etc) and can become very complex and difficult to manage as these and the number of project variants being studied expands. Data proliferates and it is easy for error to creep into analyses. OmniTRANS deals in an elegant manner by generating 'dimensions' that are associated with the primary data objects in the transport model and letting the user define the contents of these dimensions. Consequently, the way in which the data is stored and managed within the database becomes of no direct interest to the user. More specifically, the key dimensions that are supported are:

USING OMNITRANS ON PROJECTS

PAGE 6

ABOUT SCRIPTS

Purpose; Mode; Time; U ser defined (e.g. car ownership group; ticket type, etc); And for generated data two extra dimensions are available: Result; I teration.
The first four dimensions can be thought of as being used for inputs and the last two for outputs, although in practice all six can be used for storing model outputs. Networks can have two dimensions associated with them, namely Mode and Time, whereas Matrices can be defined by four dimensions, namely Purpose, Mode, Time and User. This means that when managing network data the hierarchy of data storage is: Project Variant Network (M,T). And when managing matrices the hierarchy of data storage is: Matrix Cube Matrix (P,M,T,U). Where P,M,T and U are used as indices to identify the appropriate dimension, e.g. matrix (home to work, car, am peak, non-car owners) and network variant x (transit, pm peak). Therefore, when doing an assignment, it would be natural to reference the same Mode and Time dimensions in both the Network and the Matrix. The structure of the Dimensions is user defined and established at the Project Setup stage of building a project (although can be amended at any time). A typical example of a dimension setup for a multi-modal project is shown below, where it can be seen that the dimensions can be arranged hierarchically.

USING OMNITRANS ON PROJECTS

PAGE 7

ABOUT SCRIPTS

Figure 2.2 Example Project Setup for Studytown To Explore the Dimensions Settings of a Project... Step Action Comment

1. 2. 3. 4.

Click

Alternatively, choose Project | Project Setup in the main menu. Double-click on the title bar of the The Project Setup window now window. appears in its maximum state. Click on the Dimensions tab. Right-click in the centre of the

in the project toolbar.

USING OMNITRANS ON PROJECTS

PAGE 8

ABOUT SCRIPTS

To Explore the Dimensions Settings of a Project... Step Action Comment

window and choose Expand All from the local menu.

Matrices and Hypercubes


Conventionally, matrices are two-dimensional expressing the notion of from- and tozones along each axis. The contents of the matrix relates to a specific set of data, such as observed, am, journey-to-work car based trips, and consequently a series of matrices are required to store data that exist in the 'other dimensions' (other time-periods, modes, purposes etc). There are two types of matrix hypercube used in OmniTRANS; those which can be thought of as being input matrices which can be variant independent, and those that are output and are variant dependent. As indicated previously on the discussion about Dimensions, OmniTRANS uses the concept of a Matrix Hypercube to store this multi-dimensional data in a more convenient notational form. The Purpose, Mode, Time and, if necessary, User-dimensions are used to reference matrices which are stored conceptually within this framework. So, a trip based (origin-destination) matrix is always referenced by means of a PMTUcombination. These should be thought of a being input (trip) matrices, which, depending on how you choose to organise your data, can be either variant dependent or variant independent. OmniTRANS works on the assumption that they are variant independent to give you the greater flexibility. Similarly output matrices, which contain skims, select link matrices etc, are arranged into hypercubes. For these, two more dimensions are required, Result and Iteration. So, an impedance matrix is addressed by means of its pmturi-combination. Given that these matrices are generated using a combination of input networks and input matrix hypercubes they are variant dependent.

It is up to you how you organise your matrix hypercubes and how many you have in a project.

USING OMNITRANS ON PROJECTS

PAGE 9

ABOUT SCRIPTS

Having defined your PMTU framework in the Project Setup window you might build, for example, the following set of hypercubes:

Observed data; Synthesised base year data; Forecast year 1 data - scenario a; Forecast year 1 data - scenario b; Forecast year 2 data - scenario a; Forecast year 2 data - scenario b.
And so on. Within the PMTU Matrix Hypercubes you can also store your socio-economic data and the estimated trip ends (productions and attractions), so you can keep all data that you used to create a series of matrices together. You could express this differently by storing everything within one large hypercube and labelling the dimensions accordingly, but this might not be the best way of operating. However, the point is that you are not constrained in how you choose to organise your matrix base data; you choose the way that best suits your style of modelling and needs. The PMTU Matrix Hypercubes are managed using the Matrix Cube window, noting that you label each cube as required, whereas the PMTURI matrices are shown in the Project Manager Data tab and are variant (network/matrix) specific. To Explore the PMTU Hypercubes in a Project... Step Action Comment

1. 2. 3.

Click

Alternatively, choose Tools | Matrix Cubes from the main menu. Click on the Matrix Cube drop A list of all defined matrix cubes in down list at the top of the window. the project appears. Choose a matrix cube from the list. A list of all matrices in the matrix cube appears at the lower part of the window.

in the Project toolbar.

To Explore the PMTURI Hypercubes in a Project... Step Action Comment

1. 2.

Click on the Data tab in the Project Manager window. Double-click on one of the A list of all matrices in the matrices items. regarding hypercube appears.

Getting Started with the OmniTRANS Job Language


OmniTRANS provides a variety of functionalities to assist you in defining a modelling task. These are expressed as a user-defined job and the syntax is called the OmniTRANS Job Language (OJL). The OJL is based on, and provides an extension to, the Ruby object orientated programming language. Although there is a large library of jobs for specific tasks, which you can use without changing them, it will prove to be very helpful if you have some basic knowledge about the OmniTRANS Job Language. Therefore, in this section you will learn to write, edit and run some basic OmniTRANS jobs, chiefly to let you practice with the OJL.

USING OMNITRANS ON PROJECTS

PAGE 10

ABOUT SCRIPTS

What is a Job?
A job is a collection of processing commands which perform a specific task. A rather simple job contents could look like: # Example of a job writeln "This is a test!"

Jobs can be used to perform a variety of tasks, such as:

Generate impedance matrices; Import an external network and/or matrix; Perform a trip assignment; Model trip distribution and modal split; Perform matrix estimation; Manipulate matrices; Generate reports; Perform complex analyses; Manipulate database tables.

Write your First Job


Jobs are associated with a project. When you create a new project a number of jobs will immediately become available; precisely witch will depend on the template chosen for your project. Job Management All jobs for the current project are shown under the Jobs tab in the Project Manager Window. The Jobs tab is the central place from where to create and run jobs. At the top of the tab sheet is a set of buttons, below which a list has been included of all jobs available to the project (in alphabetic order).

Figure 2.3 Sample List of Jobs

USING OMNITRANS ON PROJECTS

PAGE 11

ABOUT SCRIPTS

To Access the Job Management... Step Action Comment

1.

Click on the Jobs tab in the Project Manager window.

Create a New Job Creating a new (empty) job is very easy. To Create a New Job... Step Action Comment

1.

Click on the button on top of the Jobs tab in the Project Manager window.

A new job will be created with the temporarily name "New" (possibly followed by a number). The new job appears at the end of the jobs list and is selected automatically.

Edit a Job Once you have created a new job, you can edit the job and change its contents to your wishes.

To Edit a Job... Step Action Comment

1.

Click on the button on top of the Jobs tab in the Project Manager window.

Alternatively, press F4. A text editor window with the job contents appears.

Which editor appears is dependent upon your OmniTRANS settings. By default, OmniTRANS uses the standard MS Windows Notepad as the editor for jobs. You can however use any other text editor; some editors (e.g. UltraEdit, have established configuration files used to highlight the syntax of Ruby in different colours). To explore this further, refer to the reference to the on-line help system mentioned below. The contents of a newly created job will look like: print Hello\n The job represents a special statement (print) that writes a text to the screen (followed by a carriage return). You can change the job as you will. A possible result could be:

# This job is created by John. # The job writes the text "Hello world!" on the screen. print "Hello world!\n"

You can also use writeln instead of print.

USING OMNITRANS ON PROJECTS

PAGE 12

ABOUT SCRIPTS

When you are finished editing the job, you can save the file and exit the editor. Assuming that you are using the English version of MicroSoft Notepad:

To Save and Exit the Job Editor... Step Action Comment

1.

Choose File | Exit from the main menu of the Editor.

2.

Click Yes.

If you changed the contents of the job, a window appears with a question if you want to save your changes. The Editor window is closed. You are back in OmniTRANS.

The Job Engine Output Screen In the Job Engine Output Screen (at the lower side of the Jobs tab) information relating to the progress of a job is presented.

The Output section shows the progress of current jobs as well as information about errors and warnings. Error and warning messages indicated with special (red coloured) icons. Progress is tracked by the progress bars that appear in the window. At the top of the window sits a series of buttons which provide options to save, print, clear and copy the output and error messages. Run a job You can run a job from the Jobs tab in the Project Manager window.

To Run a Job... Step Action Comment

1.

Click on the job you want to run in the jobs list on the Jobs tab in the Project Manager window.

USING OMNITRANS ON PROJECTS

PAGE 13

ABOUT SCRIPTS

2.

Click on the the Jobs tab.

button on top of

Alternatively, press the F9-key. The status of the job in the jobs list will change from "Idle" to "Running". If it is not already visible, the Job Engine window will appear, and you can follow the progress of the job.

Jobs can be executed on different variants. However, the jobs we are creating at the moment do not use any variant information, so it does not matter on which variant they are executed. Explore job results At the output screen you will see a line with the title of the job and the time it started. Subsequently, you will see the output that is processed by the job (or by routines in the job). The last line will be similar to the first line, with the name of the job and now the end time. If you start the job again, the new output will be printed below the output of the last ran job. If your job contains an error, you will receive a message. You can also abort a job, which might become useful when you accidentally start jobs in huge projects that are planned to run for a day.

The OmniTRANS Job Language (OJL) - Ruby


The OmniTRANS Job Language allows you to specify a task for virtually any modelling problem. The OJL is based on, and provides an extension to, the Ruby object oriented programming language. Thus the OJL has combined the characteristics of a programming language with the special tasks that are required for transport modelling. It does this by providing a set of specialist 'transport modelling centric' classes that can be used with the basic language structure to provide a programming language that can deal specifically with the 'transport modelling problem'. These classes cover algorithmic processes (e.g. traffic assignment) as well as providing access to the OmniTRANS data structures (e.g. networks and matrices). This is a powerful model as it opens up the possibilities for users to develop potentially complex and innovative 'modelling scripts' using the combination of the specialist OmniTRANS classes and the native Ruby programming language. The OJL therefore comprises:

The entire Ruby language; The specialist OmniTRANS classes; Any classes that may be added in the future, either by Omnitrans International or the user community; Any language extensions provided by third party users; for example, statistical analyses, XML interpreters, etc.
Potentially this is an awesome combination, and the initial question users will be asking is 'Have I got to be a programmer to run OmniTRANS?' As might be expected, the

USING OMNITRANS ON PROJECTS

PAGE 14

ABOUT SCRIPTS

answer is going to be a mixture of 'Yes' and 'No'. At a minimum it will be necessary to understand the basics of the OJL syntax and how it is applied. After that it will depend on your skills and requirements as to how much of the (Ruby) syntax you choose to learn and apply. The fact that the OJL uses Ruby is entirely transparent to you. The Ruby programming environment is automatically installed on your computer when you install OmniTRANS and you need do nothing special to 'invoke' it. In normal usage you simply express your modelling requirements by writing a 'script' using the OJL and submitting it as a job to the Job Engine; this in turn will interface with Ruby. Only advanced users need to know more about interacting with Ruby more directly. The remainder of this section provides you with some basic knowledge about Ruby and the OJL, though this is by no way a full description of the possibilities of the OJL and Ruby. Ruby Is an Object-Oriented Language Lets say it again. Ruby is a genuine object-oriented language. Everything you manipulate is an object, and the results of those manipulations are themselves objects. When you write object-oriented code, youre normally looking to model concepts from the real world into your code. Typically during this modelling process youll discover categories of things that need to represent a code. In a jukebox, the concept of a song might be such a category. In Ruby, youd define a class to represent each of these entities. A class is a combination of state (for example, the name of the song) and methods that use that state (perhaps a method to play the song). Once you have these classes, youll typically want to create a number of instances of each. For a jukebox system containing a class called Song, you could have separate instances for popular hits such as Ruby Tuesday, Enveloped in Phython, String of the Pearls and so on. The word object is used interchangeably with class instance. In Ruby, these object are created by calling a constructor, a special method associated with each class. The standard constructor is called new.

song1 = Song.new(Ruby Tuesday) song2 = Song.new(Enveloped in Phyton) # and so on These instances are both derived from the same class, but they have unique characteristics. First, every object has a unique object identifier. Second, you can define instance variables, variables with values that are unique to each instance. These instance variables hold an objects state. Each of the songs, for example, will probably have an instance variable that holds the song title. Within each class, you can define instance methods. Each method is a chunk of functionality which may be called from within the class and (depending on accessibility constraints) from outside. These instance methods in turn have access to the objects instance variables, and hence to the objects state. Methods are invoked by sending a message to an object. The message contains the methods name, along with any parameters the method may need. When an object receives a message, it looks into its own class for a corresponding method. If found, the method is executed. If the method isnt found, well, well get to that later.

USING OMNITRANS ON PROJECTS

PAGE 15

ABOUT SCRIPTS

This business of methods by sending a message may sound complicated, but in practice it is very natural. Lets look at some method calls (remember that the arrows in the code examples show the values returned by the corresponding expressions).

gin joint.length Rick.index(c) -1942.abs sam.play(aSong)

9 2 1942 duh dum, da dum de dum..

Here, the thing before the period is called the receiver, and the name after the period is the method to be invoked. The first example asks a string for its length, and the second asks a different string to find the index of the letter c. The third line has a number calculate its absolute value. Finally, we ask Sam to play us a song. Its worth noting here a major difference between Ruby and most other languages. In most other languages youd find the absolute value of some number by calling a separate function and passing in that number. For example:

number = Math.abs(number)

//Java

In Ruby, the ability to determine an absolute value is built into the numbers they take care of the details internally. You simple send the message abs to a number object and let it do the work.

number = number.abs

# Ruby

The same applies to all Ruby objects. This is part of what we mean when we say that Ruby is a genuine OO language. Source Layout Ruby is a line-oriented language. Ruby expressions and statements are terminated at the end of a line unless the statement is obviously incomplete for example if the last token on a line is an operator or comma. A semicolon can be used to separate multiple expressions on a line. You can also put a backslash at the end of a line to continue onto the next. Comments start with # and run to the end of the physical line. Comments are ignored during compilation. Some examples:

a = 1 b = 2; c = 3 d = 4 + 5 + 6 + 7 e = 8 + 9 \ + 10

# no \ needed # \ needed

Physical lines between a line starting with =begin and a line starting with =end are ignored by the compiler and may be used for embedded documentation. a = 1 =begin

USING OMNITRANS ON PROJECTS

PAGE 16

ABOUT SCRIPTS

This line is ignored! Note that the # sign is not needed =end b = 2 The Basic Ruby Types The basic types in Ruby are numbers, strings, arrays, hashes, ranges, symbols and regular expressions. The most important ones will be discussed below shortly. Ruby integers are objects of the class Fixnum or Bignum. Fixnum objects hold integers that fit into the native machine word minus 1 bit. Whenever a Fixnum exceeds its range, it is automatically converted to a Bignum object, whose range is effectively limited only by available memory. Some examples:

123456 123_456 -543 123_456_789_123_345_789

# # # #

Fixnum Fixnum (underscore ignored) Negative Fixnum Bignum

A numerical literal with a decimal point and/or an exponent is turned into a Float object, corresponding to the native architectures double data type. 12.34 -.1234e2 1234e-2 12.34 -12.34 12.34

Ruby provides a number of mechanisms for creating literal strings. Each generates objects of type String. hello a backslash \\\\ \123Smile Say \Hello\ Con cat enate hello a backslash \ Smile Say Hello Concatenate

As you can see, the single-quoted string literals allow less substitutions then their double-quoted counterpart. Outside the context of a conditional expression, expr..expr and exprexpr construct Range objects. The two-dot form creates a inclusive range, while the three-dot form creates a range that excludes the specified high value.

1..10 a..z 1...11 Rubys arrays and hashes are indexed collections. Both store collection of objects, accessible using a key. With arrays, the key is an integer, whereas hashes support any object as a key. Some examples:

[ 1, 2, 5, 6]

# array with four elements

USING OMNITRANS ON PROJECTS

PAGE 17

ABOUT SCRIPTS

[ 1, cat, 3.14] # array with three elements # hash with three elements: {red => 0xf00, green => 0x0f0, blue => 0x00f} Names, Variables and Constants Ruby names are used to refer to constants, variables, methods, classes, and modules. The first character of a name helps Ruby to distinguish its intended use. A local variable (its scope is dependent on the context in which it is used) name consists of a lowercase letter followed by name characters:

fred anObject _x three_two_one An instance variable (apply within the scope of an object) name starts with an at sign (@) followed by an upper- or lowercase letter, optionally followed by name characters: @name @_ @Size A class variable (shared amongst descendents of the class) name starts with two at signs (@@) followed by an upper- or lowercase letter, optionally followed by name characters: @@name @@_ @@Size A constant (the scope is global or confined to a class or module) name starts with an uppercase letter followed by name characters. Class names and module names are constants, and follow the constant naming conventions. By convention, constant variables are normally spelled using uppercase letters and underscores throughout.

MyClass PI MY_CONST Global variables (apply across the entire scope of a program), and some special system variables, start with a dollar sign ($) followed by name characters.

$params $Ot $PROGRAM For the time being, you will mostly use local variables and constants.

USING OMNITRANS ON PROJECTS

PAGE 18

ABOUT SCRIPTS

Operator Expressions Expressions may be combined using operators. A view of examples of some basic operator expressions: v1 v2 s1 s2 s3 a1 a2 a3 a4 a5 v3 v4 = = = = = = = = = = = = 2 + 2 v1 - 1 "Hello " "world!" s1 + s2 [1,2,3] [4,5,6] a1 + a2 [5] a2 a3 3 * 8 v3 / 4 # v1 = 4 # v2 = 3

# s3 = "Hello world!"

# a3 = [1,2,3,4,5,6] # a5 = [4,6] # v3 = 24 # v4 = 6

OmniTRANS Classes The Ruby language has been extended with a whole bunch of classes which are useful for performing traffic and transport modelling tasks. These classes are called OmniTRANS classes and all start with the characters Ot. There are four main categories of OmniTRANS classes:

Data access classes; Data import/export classes; Modelling classes; Utility classes.
Data access classes arrange the access to various forms of data in an OmniTRANS project, such as matrices, networks and database tables. Some examples:

# generating a 25*25 matrix mat = OtMatrix.new(25) # getting the selection from the active network network = OtNetwerk.new selection = network.selection # performing a sql-query on the database query = OtQuery.new query.sql = Select * from link where linknr < 7000 query.open Data import/export classes are used to import and/or export network data from and to various external formats, such as ASCII, Trips, Tranplan and GIS. Some examples:

require OtConversion # perform TRIPS import import = OtTripsImport.new import.network = [1,1]

USING OMNITRANS ON PROJECTS

PAGE 19

ABOUT SCRIPTS

import.nodeFile = c:\\data\nodes.dat import.linkFile = c:\\data\\links.dat import.linkType = 3 import.execute # perform generic ASCII export export = OtAsciiExport.new export.network = [[1,1]] export.fileName = c:\\data\\network.txt export.supportTransitLines = false export.execute The data import/export classes as well as the modelling classes all have the same structure. You create an object (with new), set a series of properties and then trigger the actual import/export/model by using the execute method. Modelling classes are used for serious transport modelling task such as trip distribution, modal split, matrix estimation and trip assignment. An examples:

# Traffic assignment assign = OtTraffic.new assign.load = [1,1,1,1,1,1] assign.assignMethod = AON assign.execute Utility classes provide technical utilities concerning OmniTRANS, such as giving the job directory or read and/or write settings of an ini-file. Examples:

# Display a message box $Ot.Messagebox(Message from Ruby,Message,MB_OKCANCEL) # Return the Ruby directory writeln $Ot.rubyDirectory More information about the OmniTRANS classes will be provided in later lessons. Handle Error Messages When you run a job, the Job Engine first checks whether it understands the contents of your job prior to the actual run. If it finds things that it does not understand, it will generate an error and the run will be cancelled. The Job Engine puts a red round icon in the job engine output screen followed by an error message. The error message is followed by some additional Ruby information about the location of the error in the job. Alternatively, the job start to run but an error is encounter during the run. Again, the Job Engine puts a red round icon in the job engine followed by additional information and the job will be aborted. If you produce the following job:

qriteln This is a test.

USING OMNITRANS ON PROJECTS

PAGE 20

ABOUT SCRIPTS

It will generate the error message: undefined method qriteln for main:Object followed by an indication that the run stopped at line 1. On the basis of the error message you know that you made a mistake in line 1 of the job and that the Job Engine does not recognises the statement you are using. Naturally, the solution for this problem is:

writeln This is a test. If you run the following job:

# Another job with error a = 1 b = 2 c = a + b writeln d It will generate the error message: undefined local variable or method d for main:Object. The Job Engine tells you that it does not know the variable named d, which is rather logical, since you did not give it any value. In that case the Job Engine will not know the type and the contents of the variable (they are undefined) and thus it can not write a value to the screen. What you originally intended was of course:

# Another job with error a = 1 b = 2 c = a + b writeln c Learning to understand the meaning of the error messages and find the solutions for solving the errors is a matter of a lot of practice. Although a lot of effort has been put in the error handling of the OmniTRANS Job Engine, you will not be the first person that does not understand what he or she did wrong until you hit yourself for not seeing the problem and its solution much earlier.

Jobs and PMTURI


Jobs also use the OmniTRANS PMTURI dimensions concept, which makes the jobs independent upon path- and filenames and thus easily transferable between variants and projects (through templates). Most OmniTRANS import/export and modelling classes use the PMTURI concept to identify input and output data. An example:

assign = OtTraffic.new assign.load = [1,1,1,1,1,1] assign.odMatrix = [1,2,1,1] assign.network = [2,2] assign.execute The first property indicates that the assignment results will be stored in the PMTURI dimensions on location [1,1,1,1,1,1]. The second property indicates the origin-

USING OMNITRANS ON PROJECTS

PAGE 21

ABOUT SCRIPTS

destination matrix is taken out of the current matrix hypercube from the PMTU location [1,2,1,1]. And the third property indicates that the shortest-paths will be searched in the network using mode and time period [2,2]. Not only OmniTRANS import/export and modelling classes use the PMTURI dimensions concept. They are also used in various data access classes. Some examples: cube = OtMatrixCube.new mat = cube[1,1,1,1] cube.delete([1,2,1,1]) network = OtNetwork.new network.addLoad([1,1,1,1,1,1],[1,2,1,1,1,1]) The first line accesses a matrix cube, where the second line gets a matrix from that cube. In the third line a specific matrix is deleted from the matrix cube. The fourth line accesses a network, where the fifth line adds two loads in this network. Things will become clearer when you take a closer look at working with matrices.

Working with Matrices


The three things you use most while working with jobs are writing information to the screen, running the OmniTRANS modelling classes and working with matrices. The first is very easy and you have seen some examples by now. The second will become clear when you are going to trip distributions and assignments. The third however needs some immediate attention. Access a Matrix from a HyperCube in a Job Given the fact that you have an OD-matrix stored in a matrix hypercube, you can access the matrix in your job by using the following code:

mc = OtMatrixCube.new(TestCube) mat = mc[1,1,1,1] The first line defines the variable mc which holds the address of the matrix hypercube named TestCube. You can leave the name of the cube away if you want to access the active matrix cube. The second line makes a copy of the OD-matrix that is stored on position [1,1,1,1] and stores it in the temporary memory of the Job Engine under the variable name mat. You can now do with mat whatever you want, but the actual ODmatrix stored in your project is not changed. Write the Contents of a Matrix to the Screen To get an idea of the contents of a matrix you can do:

writeln mat If you want to see the contents of a specific part of the matrix this is possible by accessing particular cells of the matrix. For example: writeln mat[12,20]

USING OMNITRANS ON PROJECTS

PAGE 22

ABOUT SCRIPTS

This will write the number of trips from zone 12 to zone 20 to the screen. If you want to write a larger part of the matrix to the screen you can use ranges:

writeln mat[1..3,10..14] This will write contents of the rows 1,2 and 3 and the columns 10,11,12,13 and 14 to the screen. Change the Contents of a Matrix There are various ways to change the contents of a matrix variable within a job. You can use the [ ] brackets to access and change certain parts of the matrix or you can use specific matrix functions.

Some examples with [ ]: mat[2,6] = 100 mat[1..10,3] += 50 mat[1..5,1..5] = mat[6..10,6..10] mat[] = 20 The first line puts the value of 100 in the cell on row 2 and column 6. The second line adds up a value of 50 to the cells in the rows 1 to 10 in column 3. The third line copies the contents of a block of 5 by 5 cells from one location to another. The last line fills the whole matrix with a value of 20. Various methods are available to manipulate the matrix contents. Some examples:

mat = mat.transpose mat.fillIntra(5) mat = mat.replaceEq(0,99999)

# or mat.transpose!

The first line transposes the matrix on its diagonal. The second line fills the intrazonal cells in the matrix (the diagonal) according to the values of the 5 nearest cells in each row. The third line replaces the values in all cells where the value equals 0 by 99999. Work with Multiple Matrices In many cases you work with more than one matrix at a time. This can be done by:

mc = OtMatrixCube.new(TestCube) mat1 = mc[1,1,1,1] mat2 = mc[1,2,1,1] You can use expressions to work with multiple matrices, just as you work with multiple integer values. For example: mat3 = mat1 + mat2 mat4 = mat3 * growthmat mat5 = (mat3 + mat4) / 2

USING OMNITRANS ON PROJECTS

PAGE 23

ABOUT SCRIPTS

The first line adds up to matrices and puts the result in a third. The second line multiplies a matrix with another (growth) matrix. A matrix multiplication takes place on cell-by-cell level. The third line adds up to matrix, divides the result by two and puts the result in a third matrix. Put a Matrix (back) in a HyperCube If you do not specifically tell the Job Engine that you want to store a matrix variable in your project, the variable will be lost after the job run ends. In order to put a matrix variable (back) in a HyperCube you can do:

mc[1,1,1,1] = mat Summary Summarising, in most of the cases you will create a copy of the matrix in the memory of the Job Engine, you will change the contents of the matrix and finally overwrite the original matrix with the contents of the copy. An example showing a complete job:

# This job increases the contents of the matrix by 12%. mc = OtMatrixCube.new mat = mc[1,1,1,1] mat = mat * 1.12 mc[1,1,1,1] = mat If you like short definitions, the following job does the same as the previous one:

# This job increases the contents of the matrix with 12%. mc = OtMatrixCube.new mc[1,1,1,1] = mc[1,1,1,1] * 1.12

Working with Skim Matrices


Skim or impedance matrices are stored in a different type of matrix hypercube, with PMTURI dimensions instead of PMTU. To access a skim matrix:

sc = OtSkimCube.new skm = sc[1,1,1,1,1,] Once you have the matrix as a variable, you can do the same things with skim matrices as normal OD-matrices. In order to put the skim matrix variable (back) into the skim matrix hypercube you can do:

sc[1,1,1,1,1] = skm

Job Library
Omnitrans International and their customers have produced a large library with jobs for a variety of tasks, based on 5 years of experiences. An important part of these jobs are

USING OMNITRANS ON PROJECTS

PAGE 24

ABOUT SCRIPTS

provided by way of the OmniTRANS templates. Another source for jobs is the website of OmniTRANS. You can easily add existing jobs to your project by simply copying them into the Jobs folder of your OmniTRANS project (outside OmniTRANS). As long as your files have the extension .job, OmniTRANS will recognise them and show them on the Jobs tab of the Project Manager window.

Figure 2.4 Example Studytown Jobs

USING OMNITRANS ON PROJECTS

PAGE 25

27

Chapter

Anatomy of OmniTRANS Scripts


Key Studytown Jobs
A view of the jobs available in the Studytown project has been provided in Figure 2.7. Some of the jobs are only relevant to operation of the project via the customised interface. These mainly are displayed using the gear cog icon. This section therefore concentrates on the scripts that are most likely to be of interest for use on T14 projects and which are given the prefix T14_. This section considers three scripts. It dissects two scripts T14_JobDistribution.rb and T14_PTAssignModeChoice.rb to present a number of fragments of scripts that are used for a variety of purposes. Collectively, the fragments cover a wide range of functions that are encountered in typical applications of OmniTRANS. The script T14_EquilibriumAssignment is also introduced. The fragments are presented in an order that aids explanation, which is not necessarily the same as the order in which they arise in the original scripts. However, you should inspect the original scripts to gain a fuller appreciation of the context in which the fragments are used. Also, refer back to the exercises in the T5 Workbook for additional information. For clarity, some elements of the scripts are adapted from the originals for presentation here.

Trip Distribution Modelling


Script T14_JobDistribution.rb
This script uses Gravity modelling for trip distribution (T5 Workbook Exercise LU2). Purpose Script Fragment # job to Calculate Distribution of Trip to Work require $Ot.dirJob()+"startOK" title="JobDistribution" StartOK.run(title) means to run this job # Check user $Ot signifies a standard OmniTRANS class StartOK is a user-defined class. It is not essential to use it, but the require statement is needed at the top of the script if it used. Getting Started Comments A # means a comment

USING OMNITRANS ON PROJECTS

PAGE 27

MODE CHOICE STUDY TOPICS

Purpose

Establish PMTURI and Other Basic Settings Comments Current (highlighted) variant is the default

Script Fragment # ensure we have the correct variant $Ot.currentVariant = 'BaseYear'

# define purpose list. include all purp_list = [1,10,20,30,40,50]

These examples use lists

Note comments following at end of the line # define time periods time_list = [2,3,4] interpeak, pm peak # 24hr, am peak,

htime = Hash.new htime = { 'AM peak' => 2, 'Off peak' => 3, 'PM peak' => 4} # define user dimensions user_list = [1,2,3,4,5] # all, CA, NCA, STA, NSTA mode_list = [11,14,15] lgv/mgv, hgv hmode = Hash.new hmode = { 'Car' => 11, 'LGV/MGV' => 14, 'HGV' => 15} # car,

The Hash class is useful here for giving names to dimensions for use in printing, etc.

These arrays are used to store information for convenience, in this case three sets of coefficients (beta and gamma) and names of the test runs. Note here the coefficients are given default values (-4.9 and 24.0)

beta = Array.new(3,-4.9) gamma = Array.new(3,24.0) testname = Array.new(3)

USING OMNITRANS ON PROJECTS

PAGE 28

MODE CHOICE STUDY TOPICS

Purpose Script Fragment # Establish matrices for base (current) year mcBYear = OtMatrixCube.open bYmat = mcBYear[purpose,11,2,6]

Accessing Matrices Comments

Open a Matrix Cube and give it a local name Extract a matrix from the Matrix Cube using the PMTU dimensions, and give it a name

Purpose Script Fragment # Obtain the coefficients from file Coeffs(beta,gamma,testname,unitLog, unitDistrib)

Looping or Repetition Comments We are dealing here with three sets of coefficients respectively for a Base situation and two test cases. This is indicated by the three names that are entered in the list here. This is a for loop that gives the variable i the values of 0, 1, and 2, respectively. Now b and g, and hence beta_gamma1, take different values for each pass of the loop. [Notes: the for loop is just one way of looping within Ruby. Array indexes start at zero, not one, in Ruby.]

testname = ["Base","Case1","Case2"] for i in 0..2 b = beta[i] g = gamma[i] beta_gamma1 = [1.0,b,g] # for each test

unitLog.puts "Gravity Model #{testname[i]} run with beta = #{b} and gamma = #{g}"

# create an instance of the class; call it 'distrib' distrib = OtGravityModel.new

We create a new instance of a Gravity model class each time around the loop.

# choose the pmtu combinations for the output matrices to be calculated if i == 0 then u = 1 else u = 6 + i end distrib.odMatrix=[purpose,11,2,u]

We store information in different places on each loop.

# ... lines removed end signifies the end of the loop end

USING OMNITRANS ON PROJECTS

PAGE 29

MODE CHOICE STUDY TOPICS

Purpose Script Fragment # create an instance of the class; call it 'distrib' distrib = OtGravityModel.new

Run a Distribution (Gravity) Model Comments (This script fragment gives more details of the contents of the for loop described above.) We are choosing to store the results of the distribution in a new Matrix Cube that we also name. We write information to the screen (writeln) and to a log file (unitLog.puts) #{some_variable} means output the value of some_variable not the text itself These lines are to adjust where information is stored, depending on which test is currently running.

opCube = 'Future_Year_Matrices' writeln "Output matrix is stored in Matrix Cube #{opCube}" unitLog.puts "Output matrix is stored in Matrix Cube #{opCube}" distrib.matrixCube = opCube

# choose the pmtu combinations for the output matrices to be calculated if i == 0 then u = 1 else u = 6 + i end distrib.odMatrix=[purpose,11,2,u] # specify the skim matrices to be used distrib.skimMatrix = [10,11,2,6,21,1] cars in AM peak # HBW time skim for See the OtGravityModel documentation for more details on the properties and methods of this class.

# set function type to be used distrib.functionType = TOPLOGNORMAL # define function distrib.functionSpec=beta_gamma1 # constrain balancing to the productions distrib.balance= PRODUCTIONS

# constrain the group to productions distrib.groups= PRODUCTIONS

# set the number of iterations

USING OMNITRANS ON PROJECTS

PAGE 30

MODE CHOICE STUDY TOPICS

Purpose Script Fragment distrib.iterations=10 # start the run distrib.execute

Run a Distribution (Gravity) Model Comments

Purpose Script Fragment # ===Directory and File Information == outputs = "Outputs" output sub-directory # Outputs/Log directory (Jobs\Outputs directory in project for in-/output files) outputdir = $Ot.jobDirectory()+outputs writeln("Output directory is ",outputdir) outputdir += "\\" # name of

Using Text Files Comments

Outputs is a user-defined sub-directory name

This defines that Outputs is to be a subdirectory of the standard Jobs directory in the OmniTRANS project.

Confirm where output is to be located This appends a single back-slash (\) to the path name defined by outputdir; this is so that a file name can be added to it. (Two back-slashes are used because \ is a special character see the Ruby documentation.)

# Variant directory vardir = $Ot.dirPrj()+"BaseYear" writeln("Log directory is: ", outputdir+"Log_"+title+".txt") unitLog = File.new(outputdir+"Log_"+title+".txt" ,File::TRUNC | File::CREAT | File::RDWR) unitLog.puts "Job: ",__FILE__,"\n" unitLog.puts "Date: ",Time.now,"\n"

unitLog is an instance of the File class that is used to read and write information that the user has given the name Log_title.txt, where title has been defined earlier.

USING OMNITRANS ON PROJECTS

PAGE 31

MODE CHOICE STUDY TOPICS

Purpose Script Fragment unitLog.puts "Log of "+title+" Processing\n" unitLog.puts "Trip Distribution information output to file: #{outputdir+title+".txt"}\n" writeln "Summary of Trip Distribution information (also written to log file)" writeln unitLog.puts "Summary of Trip Distribution information\n\n" filePath = $Ot.dirPrj()+"User_External_Data"+"\\D istributionCoeffs.txt" unitDistrib = File.new(filePath,File::CREAT | File::RDONLY) # ==========================

Using Text Files Comments unitLog.puts provides a means of writing a line to the file. (The \n element outputs a new line.)

Here we define another instance of the File class to read information from a file called DistributionCoeffs.txt in the standard User_External_Data directory

Purpose Script Fragment def Coeffs(beta,gamma,testname, unitLog, unitDistrib) # ========= # Obtain Top Log Normal coefficients information from file

Processing a CSV type file Comments This fragment of script defines (def) a function, Coeffs, to read data from a CSV type file. If information is input to a file in a strict way then the script for reading data can be much simpler than shown here, but this illustrates a number of ways of working with Ruby and it allows more flexibility in the contents of the file. The two variables allspaceRE and commentRE are Regular Expressions that provide powerful ways of working with text and alphameric data. See the Ruby documentation for more details. cols provides a list of column names for the expected contents of the file.

allspaceRE = /^\s*\n/ commentRE = /^\s*#/ dataLine = false cols = ["Name","Beta","Gamma"] nrow = 0 i = 0

USING OMNITRANS ON PROJECTS

PAGE 32

MODE CHOICE STUDY TOPICS

Purpose Script Fragment unitDistrib.each { |line| unitLog.puts line next if line =~ commentRE skip comments next if line =~ allspaceRE skip blank lines # #

Processing a CSV type file Comments nrow counts the number of rows and i identifies which column is being processed. The each method provides a way of obtaining each line of the file referenced by unitDistrib in turn. The line variable holds the contents of the current line. Each line of the file is output to the log file.

line =~ /(\w)(\W)/ # separator is first non-word character encountered # sep = $2 sep = "\t" # separator is a tab This commented-out line provides a way of automatically finding out what separator has been used, but it is safer to assume a tab character as a separator character. The split method splits the line into pieces according to the occurrence of separator characters in the line. Provided that the current line holds data, rather than header information, we assign the different pieces of the line to variables in the script. As all the data is read as text (string format), we need to convert some of it to decimal (float) form using the to_f method. (to_i may be used to convert data to integer form.)

pieces = line.split(sep) if dataLine then rowname = pieces[0] testname[i] = rowname beta[i] = pieces[1].to_f gamma[i] = pieces[2].to_f puts "Coeffients for #{rowname}: are #{beta[i]}, #{gamma[i]}" unitLog.puts "Coeffients for #{rowname}: are #{beta[i]}, #{gamma[i]}" i += 1 end nrow += 1 if !dataLine dataLine = true end rowdata = "" } # unitDistrib

puts "End of Distribution

USING OMNITRANS ON PROJECTS

PAGE 33

MODE CHOICE STUDY TOPICS

Purpose Script Fragment Coefficient data; #{nrow} lines processed" unitLog.puts "End of Distribution Coefficient data" end # Coeffs

Processing a CSV type file Comments

Purpose Script Fragment network = OtNetwork.new external = network.selection('External Centroids') external.each{|ex| puts "External zone -> #{ex}" } internal = network.inversion('External Centroids')

Generating Reports Using Selections Comments This part of the code identifies zones in the network that the user has previously defined in OmniTRANS to be External Centroids (by using a selection tool and saving the selection with this name). The external zones are listed on the screen to confirm that the selection is being applied.

Here, all zones that are not External are considered as Internal.

# set the purpose purpose = purp_list[1]

# HBW

Reporting here is to be for just one purpose (home-based work trips)

# Establish matrices for base (current) year mcBYear = OtMatrixCube.open bYmat = mcBYear[purpose,11,2,6] biimx = bYmat[internal,internal] biemx = bYmat[internal,external] beimx = bYmat[external,internal] beemx = bYmat[external,external] Define four sub-sets of the matrix according to whether trips are internal to internal, internal to external, external to internal, or external to external Obtain the required matrix from the relevant Matrix Cube

USING OMNITRANS ON PROJECTS

PAGE 34

MODE CHOICE STUDY TOPICS

Purpose Script Fragment # Access new (future year) matrices mcFYear = OtMatrixCube.open(opCube) fYmat = mcFYear[purpose,11,2,u] fiimx = fYmat[internal,internal] writeln "#{testname[i]} Internal Internal trips are #{sprintf("%10.2f",fiimx.sum)}" sc=OtSkimCube.open skm = sc[10,11,2,6,21,1] # time

Generating Customised Reports Comments This is similar to the selection process described above

The lines in bold type are a single line to write out to the screen information on the number of internal to internal trips. The sprintf function is used to control the formatting, see the Ruby documentation.

skim for cars in AM peak (minutes) ftottime = fiimx * skm fsumvhrs = ftottime.sum / 60.0 btottime = biimx * skm bsumvhrs = btottime.sum / 60.0 pcdiff = ((fsumvhrs - bsumvhrs) * 100.0) / fsumvhrs writeln " Internal - Internal Total Future travel time is #{sprintf("%10.2f",fsumvhrs)}; was #{sprintf("%10.2f",bsumvhrs)}" print " (#{sprintf("%10.2f",pcdiff)}% difference)\n" unitLog.print " Internal - Internal Total Future travel time is #{sprintf("%10.2f",fsumvhrs)}; was #{sprintf("%10.2f",bsumvhrs)}" unitLog.puts " (#{sprintf("%4.2f",pcdiff)}% difference)" Information is output to the log file as well as the screen. Here we calculate some statistics, making use of the contents of a skim matrix

USING OMNITRANS ON PROJECTS

PAGE 35

MODE CHOICE STUDY TOPICS

Mode Choice and Public Transport Assignment Modelling


Script T14_PTAssignModeChoice.rb
This script uses logit modelling for mode choice and assignment modelling (T5 Workbook Exercise TIS2).

Purpose Script Fragment # define purpose list, include all purp_list = [1,10,20,30,40,50] purp = 10 # define time periods time_list = [2,3,4] interpeak, pm peak time = 2 htime = Hash.new htime = { 2 => 'AM peak', 3 => 'Off peak', 4 => 'PM peak'} # define user dimensions user_list = [1,2,3,4,5] mode_list = [40,41,42] Train hmode = Hash.new hmode = { 11 => 'Car', 40 => 'All PT', 41 => 'Bus', 42 => 'Train'} mode = 11 writeln "Doing Car cost skims for time period time period #{htime[time]} for mode #{hmode[mode]}" traffic = OtTraffic.new traffic.matrixCube="Base_Year_Matrices " traffic.network = [10,2] # traffic.load = [10,11,2,1,2,1] # All_PT, Bus, # 24hr, am peak,

Cost Skims Comments The PMTU dimensions are specified as lists as this makes it easier to do calculations for sets of dimensions but, for simplicity, the code here just selects one set of PMTU dimensions.

traffic is an instance of the standard OtTraffic traffic assignment class. See the documentation on this class for more details on the properties and methods Removing the comment would causing the class to load (assign) traffic to the highway

USING OMNITRANS ON PROJECTS

PAGE 36

MODE CHOICE STUDY TOPICS

Purpose Script Fragment traffic.routeFactors = [0,1] time-based paths traffic.skimMatrix = [1,11,2,1,[20,21,22],1] traffic.execute #

Cost Skims Comments network as well as calculate cost skims. This defines where skims are stored in the skim matrix cube.

mode = 41 writeln "Doing PT cost skims for time period time period #{htime[time]} for mode #{hmode[mode]}" transit=OtTransit.new transit.matrixCube="Base_Year_Matrices " transit.network=[40,2] transit.routeFactors = [[41,1,0,1,1,1],[42,1,0,0.5,2,2]] transit.skimsPerMode = true # The list contains six elements in the order # [distance, travel time, gen cost, waiting time, number of transfers, penalty] transit.skimMatrix=[1,40,2,1,[20,21,22 ,23,24,25],1] transit.skimText = "Skim matrix from TIS2" transit.execute Similar calculation of public transport skims using the standard OtTransit class. See the documentation on this class for more details on the properties and methods.

Purpose Script Fragment require $Ot.dirJob()+"Choice" Use Choice class # ___PMTURI Dimensions________ p, m, t, u = 1, 1, 2, 1 #

Logit Choice Comments This script uses a user-specified class, Choice, 1 for undertaking logit choice modelling .

Standardised OmniTRANS logit choice modelling classes are currently in preparation.

USING OMNITRANS ON PROJECTS

PAGE 37

MODE CHOICE STUDY TOPICS

Purpose Script Fragment # Because the choice is across modes, 'm' is set here arbitrarily to 1 # r and i locate generalised cost data r, i, = 22, 1 rcc = 30 # r dimension for storing composite costs pmtu rcc] = [p, m, t, u, r, i, # forecast/current year

Logit Choice Comments

Composite cost matrices are an output of the Choice class.

This example is for absolute logit choice modelling, but the Choice class also supports incremental logit choice modelling. In this latter case, more information must be provided to define the base and forecast year data.

basepmtu = [p, m, t, u, r, i] # pmturi values can differ between base and forecast year basepmtu = nil.to_a # an

empty array as not incremental # ___Mode and Dimension Values_________ modes = Hash.new # Set mode names and dimensions; must match project data modes = { 'All_Modes' 'Car' => 1, => 11, The Choice class assumes the hierarchic choice model has been defined in a file (here called ChoiceDataTIS2.txt) that defines the modes and the scaling factors (lamda) for the choices. The form of the file is shown below for a hierarchy that splits total travel demand (All_Modes) in to Car and All_Transit; All_Transit is split into Bus and Train modes.
# Logit Choice Model Data # =======================

'All_Transit' => 40, 'Train' => 42, 'Bus' # ___General Data______________________ runparams = Hash.new # Set general information for run runparams = { 'zones' # number of zones # 'basecube' 'basecube' => nil, => "Base_Year", => 25, => 41}

# User data on choices # Level Demand Lamda Choices 0 All_Modes 0.02 Car All_Transit 1 All_Transit 0.045 Bus Train

The format of the file is flexible with regard to spacing. The Level values serve merely as annotation. The specification of the general information for the choice model run is entered in the form of elements of a Hash array called runparams. This part of the script is replicated below (with the comments removed) to emphasise the form of the data input.

matrix cube for base year (incremental modelling) 'logit' => "ChoiceDataTIS2.txt", # name of choice structure specification

USING OMNITRANS ON PROJECTS

PAGE 38

MODE CHOICE STUDY TOPICS

Purpose Script Fragment file 'inputs' "user_External_Data", location of ASCII inputs 'outputs' "Outputs", location of ASCII outputs 'logfile' => "Log_ModeChoice.txt"} # name of run log file => # sub-path =>

Logit Choice Comments


runparams = { 'zones' 'basecube' => 'logit' => 'inputs' => 'outputs' => 'logfile' => => 25, nil, "ChoiceDataTIS2.txt", "user_External_Data", "Outputs", "Log_ModeChoice.txt"}

# sub-path

# Settings if incremental logit is not to be used: # basepmtu = nil.to_a empty array # 'basecube' => nil nothing # ===End of User Supplied Information================= # ____Choice modelling____________ writeln "Calculating mode choice" mnl = Choice.new(modes, pmtu, basepmtu, runparams) initialisation mnl.msplit # run choice model # report # report on # Once the input data has been specified, a new instance of the multinomial logit choice model class is created and supplied with the data specification as arguments (the list of items in brackets) Execution of the choice model is invoked using the msplit method (note, execute would be more standard). Two forms of reporting are supported; the short form is used in this case. # an

# set to

# mnl.report('full') on results mnl.report('short') results

USING OMNITRANS ON PROJECTS

PAGE 39

MODE CHOICE STUDY TOPICS

Highway Equilibrium Assignment


The highway network modelling encountered in T5 only involved simple All-or-Nothing assignment methods. The script T14_Equilibrium Assignment.rb illustrates a more sophisticated approach. It uses capacity restrained network equilibrium modelling for loading demand matrices of two classes of vehicles, heavy goods vehicles (HGVs) and cars, onto the highway network. HGV vehicles are converted into passenger car units (pcu). The Wardrop Equilibrium assignment method is specified for achieving a convergent result. A set of flow-delay relationships are defined via a set of user-defined curves that alter link speeds according to network loadings. The flow-delay relationships are held in the file \Jobs\pointsPerType.rb. A script, Plot Speed Flow Curves, is provided that may be run to show the contents of the file graphically as curves, as shown in Figure 3.1.

Figure 3.1 Plot of Flow-Delay Curves

Script T14_EquilibriumAssignment.rb
The T14_Equilibrium script provides two assignment runs using the OmniTRANS OtAssign class. The first assignment loads a trip matrix of heavy goods vehicles using All-or-Nothing assigment. The results of this assignment provide a pre-load, which affects the network capacity available for the following Equilibrium assignment used to load a car trip matrix. The final part of the script adds the results of the HGV and car assignments together and presents the results as a bandwidth diagram. This may be viewed by switching from the Jobs tab to the network tab. The script runs using the currently active network variant and matrix cube, so it includes a check for the user to confirm that these are the intended values.

USING OMNITRANS ON PROJECTS

PAGE 40

You might also like