Minner v a T14 Projects Using OmniTRANS on Projects Intercollegiate MSc in Transport Prepared for: Centre for Transport Studies Imperial College London & University College London
Minnerva
T14 Projects
Using OmniTRANS on Projects
Intercollegiate MSc in Transport
Prepared for:
Centre for Transport Studies
Imperial College London & University College London
File Name: OmniTRANSProjects.doc
Document Control
Project Title: T14 Projects
Document Title: Using OmniTRANS on Projects
File Reference: ML0112/2
Author: Miles Logie
Other Authors:
Reviewers:
Issue History
Version Number Date Comment Distribution
1.0 10.1.05 J Polak, R Mackett, T14
1.1 17.1.06Revised for networkmodelling andStudytown_T14 project
J Polak, B Heydecker,T14
CONTENTS PAGE I
I
Contents
Introduction 1Aims of the Information 1
Setting Objectives 1
Structure of the Document 1
Associated Resources 1
Studytown Project 1
OmniTRANS Documentation 2
Bookson Ruby 3
About Scripts 5Ruby in the Context of OmniTRANS 5
Structure of OmniTRANS 5
Thinking OmniTRANS 5
Projects and Variants 6
Dimensions 6
Matrices and Hypercubes 9
Getting Started with the OmniTRANS Job Language 10
What is a Job? 11
Write your First Job 11
The OmniTRANS Job Language (OJL) - Ruby 14
Jobs and PMTURI 21
Working with Matrices 22
Working with Skim Matrices 24
Job Library 24
Anatomy of OmniTRANS Scripts 27Key Studytown Jobs 27
CONTENTS
USING OMNITRANS ON PROJECTS PAGE II
Trip Distribution Modelling 27
ScriptT14_JobDistribution.rb 27
Mode Choice and Public TransportAssignment Modelling 36
ScriptT14_PTAssignModeChoice.rb 36
Highway Equilibrium Assignment 40
ScriptT14_EquilibriumAssignment.rb 40
List of FiguresFigure 1.1 OmniTRANS Online Help 2
Figure 1.2 Ruby Reference 3
Figure 1.3 Some Books on Ruby 4
Figure 2.1 Structure of OmniTRANS 5
Figure 2.2 Example Project Setup for Studytown 8
Figure 2.4 Example Studytown Jobs 25
Figure 3.1 Plot of Flow-Delay Curves 40
USING OMNITRANS ON PROJECTS PAGE 1
1Chapter
1
IntroductionAims of the Information
This document is designed to provide the key information required to make use of theOmniTRANS software for transport modelling projects undertaken as part of the T14course.
For projects involving model development, rather than merely use of establishedmodels, it is necessary to be acquainted with the creation of OmniTRANS jobs scriptedin the Ruby computer language. The full mastering of Ruby and the specialisedOmniTRANS classes that are used with it requires more time than is reasonablyavailable in the T14 course. The approach used in this document is therefore to build onthe examples already available as part of the OmniTRANS Studytown project that wasintroduced 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, itwill be a good starting point to determine how the OmniTRANS jobs from the Studytownproject may best be exploited. This will provide an introduction, but one from which youmay choose to deviate to a greater or less extent. The combination of Ruby and theOmniTRANS classes is powerful enough that you can contemplate implementing veryvaried forms of modelling.
It is best, if possible, to modify existing operational scripts, so one objective in planningthe project is to define an incremental development path that leads away from theexisting Studytown scripts. The most important scripts are discussed further in Chapter3 of this document.
Structure of the Document
The following chapter provides an introduction to Ruby and the third chapter describesthe OmniTRANS jobs that are provided as part of the Studytown project. The scripts inseveral of these jobs are presented in further detail.
Associated Resources
Thefollowing resources provide additional information that given in this document.
StudytownProject
This project has been encountered in the earlier T5 workshop. A variation of thisOmniTRANS project, Studytown_T14, has been provided to assist with the work of theT14 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.
CONTENTS
USING OMNITRANS ON PROJECTS PAGE 2
The OmniTRANS software is accessed from the OmniTRANS item in the ‘Transport’ setof programs available from the standard Start menu and may be used to open theStudytown_T14 project.
The Studytown project is limited to 25 zones and so may be operated using unlicensedversions of OmniTRANS. It has a detailed multi-modal network and various sets ofdemand data.
Not all the data was used in the T5 Exercises, but they enable the project to be exploitedmore widely, such as for project and research work. The provided data has beenderived 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 interfacerelating to the exercises in the Workbook. This interface may be removed by deletingthe files CTSSettings.ini and CTS.ini from the top level of the new OmniTRANS projectthat is created from the Studytown template (or the interface can simply be minimisedand 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 Classesand OmniTRANS Classes indicated as well.
Figure 1.1 OmniTRANS Online Help
The Ruby Reference describes the Ruby language in a standalone form, that is, withoutreference to OmniTRANS. Its contents are indicated in Figure 1.2.
CONTENTS
USING OMNITRANS ON PROJECTS PAGE 3
The Getting Started document describes using OmniTRANS through the use of theother project template provided within the ‘Tutorials’ section, namely ‘Delft’.
This 25-zone project also provides a valid starting point for project work alongsideStudytown. (As OmniTRANS is already installed, the most relevant information starts inChapter 3 of the Getting Started document.)
Figure 1.2 Ruby Reference
Books onRuby
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 thesebooks are illustrated in Figure 1.3. It may be noted that ‘The Pragmatic Programmer’sGuide’ provides the basis for the on-line ruby reference.
For those who are not familiar with programming, these books may appear ratherforbidding, but they are much easier to follow once you have appreciated the basics ofRuby, as introduced in Chapter 2 of this document.
Although the on-line documentation is comprehensive, it will generally be advantageousto have access to a book on Ruby.
CONTENTS
USING OMNITRANS ON PROJECTS PAGE 4
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 5
5Chapter
2About ScriptsRuby in the Context of OmniTRANS
Although the focus of this chapter is on using Ruby, we start with introducing a numberof key concepts used by OmniTRANS.
Structure ofOmniTRANS
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 withthe modelling project and contains the tools required to work with data and toachieve the desired modelling objectives.
The Job Engine is where the calculations and the model processing areundertaken. Interaction with the Job Engine is via 'Job Scripts' that specify theprocessing to take place.
The Database is where all data associated with a Project is stored. In thenormal course of events you have no direct interaction with the database; it ismanaged and controlled transparently by OmniTRANS.
Thinking OmniTRANS
This section introduces some typical OmniTRANS concepts, such as projects andvariants, dimensions and so-called matrix hypercubes, all related to how things areorganised within OmniTRANS. Although these concepts are different from other
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 6
packages, you will experience that they make life a lot easier once they have beenunderstood.
Projects andVariants
As demonstrated in the T5 Workshop, OmniTRANS works with projects and variants.
ProjectsUsually, an OmniTRANS project is the coherent collection of input data, processingjobs, output data and presentational settings used for a specific study. However, morestudies can be combined in one OmniTRANS project or more OmniTRANS projects canbe made for one study.
Technically, an OmniTRANS project is stored in a series of database tables, whichtogether form a relational database system that is situated in one common directory onthe hard disk or a network drive. OmniTRANS takes care that all data is saved at theproper position and that it is stored in a structured manner.
VariantsAn OmniTRANS project comprises one or more variants, and the variants in turn canhave one or more sub-variants. Schematically, a project will typically look something likethe 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 thenumber of project variants being studied expands. Data proliferates and it is easy forerror to creep into analyses.
OmniTRANS deals in an elegant manner by generating 'dimensions' that are associatedwith the primary data objects in the transport model and letting the user define thecontents of these dimensions. Consequently, the way in which the data is stored andmanaged within the database becomes of no direct interest to the user.
More specifically, the key dimensions that are supported are:
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 7
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 foroutputs, 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 andUser. 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 datastorage is: Matrix Cube Matrix (P,M,T,U). Where P,M,T and U are used as indices toidentify the appropriate dimension, e.g. matrix (home to work, car, am peak, non-carowners) 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 theNetwork and the Matrix.
The structure of the Dimensions is user defined and established at the Project Setupstage of building a project (although can be amended at any time). A typical example ofa dimension setup for a multi-modal project is shown below, where it can be seen thatthe dimensions can be arranged hierarchically.
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 8
Figure 2.2 Example Project Setup for Studytown
To Explore the Dimensions Settings of a Project...
Step Action Comment1. Click in the project toolbar. Alternatively, choose Project |
Project Setup in the main menu.2. Double-click on the title bar of the
window.The Project Setup window nowappears in its maximum state.
3. Click on the Dimensions tab.4. Right-click in the centre of the
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 9
To Explore the Dimensions Settings of a Project...Step Action Comment
window and choose Expand Allfrom the local menu.
Matrices and Hypercubes
Conventionally, matrices are two-dimensional expressing the notion of from- and to-zones 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 tostore 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 bethought of as being input matrices which can be variant independent, and those that areoutput and are variant dependent.
As indicated previously on the discussion about Dimensions, OmniTRANS uses theconcept of a Matrix Hypercube to store this multi-dimensional data in a more convenientnotational form. The Purpose, Mode, Time and, if necessary, User-dimensions are usedto reference matrices which are stored conceptually within this framework. So, a tripbased (origin-destination) matrix is always referenced by means of a PMTU-combination.
These should be thought of a being input (trip) matrices, which, depending on how youchoose 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 thegreater flexibility.
Similarly output matrices, which contain skims, select link matrices etc, are arranged intohypercubes. For these, two more dimensions are required, Result and Iteration. So, animpedance matrix is addressed by means of its pmturi-combination. Given that thesematrices are generated using a combination of input networks and input matrixhypercubes they are variant dependent.
It is up to you how you organise your matrix hypercubes and how many you have in aproject.
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 10
Having defined your PMTU framework in the Project Setup window you might build, forexample, 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 andthe estimated trip ends (productions and attractions), so you can keep all data that youused to create a series of matrices together.
You could express this differently by storing everything within one large hypercube andlabelling 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 yourmatrix 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 thatyou label each cube as required, whereas the PMTURI matrices are shown in theProject Manager Data tab and are variant (network/matrix) specific.
To Explore the PMTU Hypercubes in a Project...Step Action Comment1. Click in the Project toolbar. Alternatively, choose Tools | Matrix
Cubes from the main menu.2. Click on the Matrix Cube drop
down list at the top of the window.A list of all defined matrix cubes inthe project appears.
3. Choose a matrix cube from the list. A list of all matrices in the matrixcube appears at the lower part ofthe window.
To Explore the PMTURI Hypercubes in a Project...Step Action Comment1. Click on the Data tab in the Project
Manager window.2. Double-click on one of the
matrices items.A list of all matrices in theregarding hypercube appears.
Getting Started with the OmniTRANS Job Language
OmniTRANS provides a variety of functionalities to assist you in defining a modellingtask. These are expressed as a user-defined job and the syntax is called theOmniTRANS 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 withoutchanging them, it will prove to be very helpful if you have some basic knowledge aboutthe OmniTRANS Job Language. Therefore, in this section you will learn to write, editand run some basic OmniTRANS jobs, chiefly to let you practice with the OJL.
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 11
What is a Job?
A job is a collection of processing commands which perform a specific task. A rathersimple job contents could look like:
# Example of a jobwriteln "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 willimmediately become available; precisely witch will depend on the template chosen foryour project.
Job ManagementAll jobs for the current project are shown under the Jobs tab in the Project ManagerWindow. The Jobs tab is the central place from where to create and run jobs. At the topof the tab sheet is a set of buttons, below which a list has been included of all jobsavailable to the project (in alphabetic order).
Figure 2.3 Sample List of Jobs
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 12
To Access the Job Management...
Step Action Comment1. Click on the Jobs tab in the Project
Manager window.
Create a New JobCreating a new (empty) job is very easy.
To Create a New Job...
Step Action Comment1. Click on the button on top of
the Jobs tab in the ProjectManager window.
A new job will be created with thetemporarily name "New" (possiblyfollowed by a number). The newjob appears at the end of the jobslist and is selected automatically.
Edit a JobOnce you have created a new job, you can edit the job and change its contents to yourwishes.
To Edit a Job...
Step Action Comment1. Click on the button on top of
the Jobs tab in the ProjectManager window.
Alternatively, press F4.A text editor window with the jobcontents 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 canhowever use any other text editor; some editors (e.g. UltraEdit, have establishedconfiguration files used to highlight the syntax of Ruby in different colours). To explorethis 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 (followedby 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.
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 13
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 Comment1. Choose File | Exit from the main
menu of the Editor.If you changed the contents of thejob, a window appears with aquestion if you want to save yourchanges.
2. Click Yes. The Editor window is closed. Youare back in OmniTRANS.
The Job Engine Output ScreenIn the Job Engine Output Screen (at the lower side of the Jobs tab) information relatingto the progress of a job is presented.
The Output section shows the progress of current jobs as well as information abouterrors 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 jobYou can run a job from the Jobs tab in the Project Manager window.
To Run a Job...
Step Action Comment1. Click on the job you want to run in
the jobs list on the Jobs tab in theProject Manager window.
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 14
2. Click on the button on top ofthe Jobs tab.
Alternatively, press the F9-key.The status of the job in the jobs listwill change from "Idle" to"Running".If it is not already visible, the JobEngine window will appear, andyou can follow the progress of thejob.
Jobs can be executed on different variants. However, the jobs we are creating at themoment do not use any variant information, so it does not matter on which variant theyare executed.
Explore job resultsAt 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 thejob). The last line will be similar to the first line, with the name of the job and now the endtime.
If you start the job again, the new output will be printed below the output of the last ranjob.
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 inhuge 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 modellingproblem. The OJL is based on, and provides an extension to, the Ruby object orientedprogramming language. Thus the OJL has combined the characteristics of aprogramming 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 canbe used with the basic language structure to provide a programming language that candeal specifically with the 'transport modelling problem'.
These classes cover algorithmic processes (e.g. traffic assignment) as well as providingaccess to the OmniTRANS data structures (e.g. networks and matrices). This is apowerful model as it opens up the possibilities for users to develop potentially complexand innovative 'modelling scripts' using the combination of the specialist OmniTRANSclasses 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 askingis 'Have I got to be a programmer to run OmniTRANS?' As might be expected, the
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 15
answer is going to be a mixture of 'Yes' and 'No'. At a minimum it will be necessary tounderstand the basics of the OJL syntax and how it is applied. After that it will dependon your skills and requirements as to how much of the (Ruby) syntax you choose tolearn and apply.
The fact that the OJL uses Ruby is entirely transparent to you. The Ruby programmingenvironment is automatically installed on your computer when you install OmniTRANSand you need do nothing special to 'invoke' it. In normal usage you simply express yourmodelling requirements by writing a 'script' using the OJL and submitting it as a job tothe Job Engine; this in turn will interface with Ruby. Only advanced users need to knowmore about interacting with Ruby more directly.
The remainder of this section provides you with some basic knowledge about Ruby andthe OJL, though this is by no way a full description of the possibilities of the OJL andRuby.
Ruby Is an Object-Oriented LanguageLet’s say it again. Ruby is a genuine object-oriented language. Everything youmanipulate is an object, and the results of those manipulations are themselves objects.
When you write object-oriented code, you’re normally looking to model concepts fromthe real world into your code. Typically during this modelling process you’ll discovercategories of things that need to represent a code. In a jukebox, the concept of a ‘song’might be such a category. In Ruby, you’d define a class to represent each of theseentities. A class is a combination of state (for example, the name of the song) andmethods that use that state (perhaps a method to play the song).
Once you have these classes, you’ll typically want to create a number of instances ofeach. For a jukebox system containing a class called Song, you could have separateinstances for popular hits such as ‘Ruby Tuesday’, ‘Enveloped in Phython’, ‘String of thePearls’ 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 associatedwith 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 uniquecharacteristics. First, every object has a unique object identifier. Second, you can defineinstance variables, variables with values that are unique to each instance. Theseinstance variables hold an object’s state. Each of the songs, for example, will probablyhave an instance variable that holds the song title.
Within each class, you can define instance methods. Each method is a chunk offunctionality which may be called from within the class and (depending on accessibilityconstraints) from outside. These instance methods in turn have access to the object’sinstance variables, and hence to the object’s state.
Methods are invoked by sending a message to an object. The message contains themethod’s name, along with any parameters the method may need. When an objectreceives a message, it looks into its own class for a corresponding method. If found, themethod is executed. If the method isn’t found,… well, we’ll get to that later.
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 16
This business of methods by sending a message may sound complicated, but inpractice it is very natural. Let’s look at some method calls (remember that the arrows inthe code examples show the values returned by the corresponding expressions).
“gin joint”.length 9“Rick”.index(“c”) 2-1942.abs 1942sam.play(aSong) “duh dum, da dum de dum..”
Here, the thing before the period is called the receiver, and the name after the period isthe method to be invoked. The first example asks a string for its length, and the secondasks a different string to find the index of the letter ‘c’. The third line has a numbercalculate its absolute value. Finally, we ask Sam to play us a song.
It’s worth noting here a major difference between Ruby and most other languages. Inmost other languages you’d find the absolute value of some number by calling aseparate 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 takecare of the details internally. You simple send the message abs to a number object andlet 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 thatRuby is a genuine OO language.
Source LayoutRuby is a line-oriented language. Ruby expressions and statements are terminated atthe end of a line unless the statement is obviously incomplete – for example if the lasttoken on a line is an operator or comma. A semicolon can be used to separate multipleexpressions on a line. You can also put a backslash at the end of a line to continue ontothe next. Comments start with ‘#’ and run to the end of the physical line. Comments areignored during compilation.
Some examples:
a = 1b = 2; c = 3d = 4 + 5 + # no ‘\’ needed
6 + 7e = 8 + 9 \ # ‘\’ needed
+ 10
Physical lines between a line starting with ‘=begin’ and a line starting with ‘=end’ areignored by the compiler and may be used for embedded documentation.
a = 1=begin
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 17
This line is ignored!Note that the # sign is not needed
=endb = 2
The Basic Ruby TypesThe basic types in Ruby are numbers, strings, arrays, hashes, ranges, symbols andregular expressions. The most important ones will be discussed below shortly.
Ruby integers are objects of the class Fixnum or Bignum. Fixnum objects hold integersthat 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 onlyby available memory. Some examples:
123456 # Fixnum123_456 # Fixnum (underscore ignored)-543 # Negative Fixnum123_456_789_123_345_789 # Bignum
A numerical literal with a decimal point and/or an exponent is turned into a Float object,corresponding to the native architecture’s double data type.
12.34 12.34-.1234e2 -12.341234e-2 12.34
Ruby provides a number of mechanisms for creating literal strings. Each generatesobjects of type String.
‘hello’ hello‘a backslash \’\\\’’ a backslash ‘\’“\123Smile” Smile“Say \”Hello\”” Say “Hello”‘Con’ “cat” ‘enate’ Concatenate
As you can see, the single-quoted string literals allow less substitutions then theirdouble-quoted counterpart.
Outside the context of a conditional expression, expr..expr and expr…expr constructRange objects. The two-dot form creates a inclusive range, while the three-dot formcreates a range that excludes the specified high value.
1..10‘a’..’z’1...11
Ruby’s 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 anyobject as a key. Some examples:
[ 1, 2, 5, 6] # array with four elements
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 18
[ 1, ‘cat’, 3.14] # array with three elements# hash with three elements:{“red” => 0xf00, “green => 0x0f0, “blue” => 0x00f}
Names, Variables and ConstantsRuby 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 consistsof a lowercase letter followed by name characters:
fredanObject_xthree_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 namecharacters:
@@name@@_@@Size
A constant (the scope is global or confined to a class or module) name starts with anuppercase letter followed by name characters. Class names and module names areconstants, and follow the constant naming conventions. By convention, constantvariables are normally spelled using uppercase letters and underscores throughout.
MyClassPIMY_CONST
Global variables (apply across the entire scope of a program), and some special systemvariables, start with a dollar sign (‘$’) followed by name characters.
$params$Ot$PROGRAM
For the time being, you will mostly use local variables and constants.
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 19
Operator ExpressionsExpressions may be combined using operators. A view of examples of some basicoperator expressions:
v1 = 2 + 2 # v1 = 4v2 = v1 - 1 # v2 = 3s1 = "Hello "s2 = "world!"s3 = s1 + s2 # s3 = "Hello world!"a1 = [1,2,3]a2 = [4,5,6]a3 = a1 + a2 # a3 = [1,2,3,4,5,6]a4 = [5]a5 = a2 – a3 # a5 = [4,6]v3 = 3 * 8 # v3 = 24v4 = v3 / 4 # v4 = 6
OmniTRANS ClassesThe Ruby language has been extended with a whole bunch of classes which are usefulfor performing traffic and transport modelling tasks. These classes are calledOmniTRANS 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 OmniTRANSproject, such as matrices, networks and database tables. Some examples:
# generating a 25*25 matrixmat = OtMatrix.new(25)
# getting the selection from the active networknetwork = OtNetwerk.newselection = network.selection
# performing a sql-query on the databasequery = OtQuery.newquery.sql = ‘Select * from link where linknr < 7000’query.open
Data import/export classes are used to import and/or export network data from and tovarious external formats, such as ASCII, Trips, Tranplan and GIS. Some examples:
require ‘OtConversion’
# perform TRIPS importimport = OtTripsImport.new
import.network = [1,1]
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 20
import.nodeFile = “c:\\data\nodes.dat”import.linkFile = “c:\\data\\links.dat”import.linkType = 3
import.execute
# perform generic ASCII exportexport = 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 samestructure. You create an object (with new), set a series of properties and then trigger theactual 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 assignmentassign = 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 jobdirectory 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 directorywriteln $Ot.rubyDirectory
More information about the OmniTRANS classes will be provided in later lessons.
Handle Error MessagesWhen you run a job, the Job Engine first checks whether it understands the contents ofyour job prior to the actual run. If it finds things that it does not understand, it willgenerate an error and the run will be cancelled.
The Job Engine puts a red round icon in the job engine output screen followed by anerror message. The error message is followed by some additional Ruby informationabout the location of the error in the job.
Alternatively, the job start to run but an error is encounter during the run. Again, the JobEngine puts a red round icon in the job engine followed by additional information and thejob will be aborted.
If you produce the following job:
qriteln “This is a test.”
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 21
It will generate the error message: “undefined method ‘qriteln’ for main:Object” followedby an indication that the run stopped at line 1. On the basis of the error message youknow that you made a mistake in line 1 of the job and that the Job Engine does notrecognises 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 errora = 1b = 2c = a + bwriteln d
It will generate the error message: “undefined local variable or method ‘d’ formain: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 Enginewill not know the type and the contents of the variable (they are undefined) and thus itcan not write a value to the screen. What you originally intended was of course:
# Another job with errora = 1b = 2c = a + bwriteln c
Learning to understand the meaning of the error messages and find the solutions forsolving the errors is a matter of a lot of practice. Although a lot of effort has been put inthe error handling of the OmniTRANS Job Engine, you will not be the first person thatdoes not understand what he or she did wrong until you hit yourself for not seeing theproblem and its solution much earlier.
Jobs and PMTURI
Jobs also use the OmniTRANS PMTURI dimensions concept, which makes the jobsindependent upon path- and filenames and thus easily transferable between variantsand projects (through templates).
Most OmniTRANS import/export and modelling classes use the PMTURI concept toidentify input and output data. An example:
assign = OtTraffic.newassign.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 PMTURIdimensions on location [1,1,1,1,1,1]. The second property indicates the origin-
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 22
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 thenetwork using mode and time period [2,2].
Not only OmniTRANS import/export and modelling classes use the PMTURIdimensions concept. They are also used in various data access classes. Someexamples:
cube = OtMatrixCube.newmat = cube[1,1,1,1]cube.delete([1,2,1,1])network = OtNetwork.newnetwork.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 thatcube. In the third line a specific matrix is deleted from the matrix cube. The fourth lineaccesses 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.
WorkingwithMatrices
The three things you use most while working with jobs are writing information to thescreen, running the OmniTRANS modelling classes and working with matrices. The firstis very easy and you have seen some examples by now. The second will become clearwhen you are going to trip distributions and assignments. The third however needssome immediate attention.
Access a Matrix from a HyperCube in a JobGiven the fact that you have an OD-matrix stored in a matrix hypercube, you can accessthe 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 hypercubenamed “TestCube”. You can leave the name of the cube away if you want to access theactive matrix cube. The second line makes a copy of the OD-matrix that is stored onposition [1,1,1,1] and stores it in the temporary memory of the Job Engine under thevariable name “mat”. You can now do with “mat” whatever you want, but the actual OD-matrix stored in your project is not changed.
Write the Contents of a Matrix to the ScreenTo 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 byaccessing particular cells of the matrix. For example:
writeln mat[12,20]
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 23
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 thescreen.
Change the Contents of a MatrixThere are various ways to change the contents of a matrix variable within a job. You canuse the [ ] brackets to access and change certain parts of the matrix or you can usespecific matrix functions.
Some examples with [ ]:
mat[2,6] = 100mat[1..10,3] += 50mat[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 lineadds up a value of 50 to the cells in the rows 1 to 10 in column 3. The third line copiesthe contents of a block of 5 by 5 cells from one location to another. The last line fills thewhole matrix with a value of 20.
Various methods are available to manipulate the matrix contents. Some examples:
mat = mat.transpose # or mat.transpose!mat.fillIntra(5)mat = mat.replaceEq(0,99999)
The first line transposes the matrix on its diagonal. The second line fills the intrazonalcells in the matrix (the diagonal) according to the values of the 5 nearest cells in eachrow. The third line replaces the values in all cells where the value equals 0 by 99999.
Work with Multiple MatricesIn 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 multipleinteger values. For example:
mat3 = mat1 + mat2mat4 = mat3 * growthmatmat5 = (mat3 + mat4) / 2
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 24
The first line adds up to matrices and puts the result in a third. The second line multipliesa matrix with another (growth) matrix. A matrix multiplication takes place on cell-by-celllevel. The third line adds up to matrix, divides the result by two and puts the result in athird matrix.
Put a Matrix (back) in a HyperCubeIf you do not specifically tell the Job Engine that you want to store a matrix variable inyour project, the variable will be lost after the job run ends. In order to put a matrixvariable (back) in a HyperCube you can do:
mc[1,1,1,1] = mat
SummarySummarising, in most of the cases you will create a copy of the matrix in the memory ofthe Job Engine, you will change the contents of the matrix and finally overwrite theoriginal 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.newmat = mc[1,1,1,1]mat = mat * 1.12mc[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.newmc[1,1,1,1] = mc[1,1,1,1] * 1.12
Workingwith SkimMatrices
Skim or impedance matrices are stored in a different type of matrix hypercube, withPMTURI dimensions instead of PMTU. To access a skim matrix:
sc = OtSkimCube.newskm = sc[1,1,1,1,1,]
Once you have the matrix as a variable, you can do the same things with skim matricesas normal OD-matrices.
In order to put the skim matrix variable (back) into the skim matrix hypercube you cando:
sc[1,1,1,1,1] = skm
JobLibrary
Omnitrans International and their customers have produced a large library with jobs fora variety of tasks, based on 5 years of experiences. An important part of these jobs are
ABOUT SCRIPTS
USING OMNITRANS ON PROJECTS PAGE 25
provided by way of the OmniTRANS templates. Another source for jobs is the website ofOmniTRANS.
You can easily add existing jobs to your project by simply copying them into the Jobsfolder of your OmniTRANS project (outside OmniTRANS). As long as your files havethe extension .job, OmniTRANS will recognise them and show them on the Jobs tab ofthe Project Manager window.
Figure 2.4 Example Studytown Jobs
USING OMNITRANS ON PROJECTS PAGE 27
27Chapter
3Anatomy of OmniTRANS ScriptsKey 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 customisedinterface. These mainly are displayed using the ‘gear cog’ icon. This section thereforeconcentrates on the scripts that are most likely to be of interest for use on T14 projectsand which are given the prefix ‘T14_’.
This section considers three scripts. It dissects two scripts T14_JobDistribution.rb andT14_PTAssignModeChoice.rb to present a number of fragments of scripts that are usedfor a variety of purposes. Collectively, the fragments cover a wide range of functions thatare 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 necessarilythe same as the order in which they arise in the original scripts. However, you shouldinspect the original scripts to gain a fuller appreciation of the context in which thefragments are used. Also, refer back to the exercises in the T5 Workbook for additionalinformation. For clarity, some elements of the scripts are adapted from the originals forpresentation here.
Trip Distribution Modelling
Script T14_JobDistribution.rb
This script uses Gravity modelling for trip distribution (T5 Workbook Exercise LU2).
Purpose Getting Started
Script Fragment Comments
# job to Calculate Distribution ofTrip to Work
require $Ot.dirJob()+"startOK"
title="JobDistribution"
StartOK.run(title) # Check usermeans to run this job
A ‘#’ means a comment
‘$Ot’ signifies a standard OmniTRANSclass
StartOK is a user-defined class. It is notessential to use it, but the ‘require‘statement is needed at the top of the scriptif it used.
MODE CHOICE STUDY TOPICS
USING OMNITRANS ON PROJECTS PAGE 28
Purpose Establish PMTURI and Other BasicSettings
Script Fragment Comments
# ensure we have the correct variant
$Ot.currentVariant = 'BaseYear'
# define purpose list. include all
purp_list = [1,10,20,30,40,50]
# define time periods
time_list = [2,3,4] # 24hr, am peak,interpeak, pm 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] # car,lgv/mgv, hgv
hmode = Hash.new
hmode = { 'Car' => 11,
'LGV/MGV' => 14,
'HGV' => 15}
beta = Array.new(3,-4.9)
gamma = Array.new(3,24.0)
testname = Array.new(3)
Current (highlighted) variant is the default
These examples use lists
Note comments following at end of the line
The Hash class is useful here for givingnames to dimensions for use in printing,etc.
These arrays are used to store informationfor convenience, in this case three sets ofcoefficients (beta and gamma) and namesof the test runs.
Note here the coefficients are given defaultvalues (-4.9 and 24.0)
MODE CHOICE STUDY TOPICS
USING OMNITRANS ON PROJECTS PAGE 29
Purpose Accessing Matrices
Script Fragment Comments
# Establish matrices for base(current) year
mcBYear = OtMatrixCube.open
bYmat = mcBYear[purpose,11,2,6]
Open a Matrix Cube and give it a localname
Extract a matrix from the Matrix Cube usingthe PMTU dimensions, and give it a name
Purpose Looping or Repetition
Script Fragment Comments
# Obtain the coefficients from file
Coeffs(beta,gamma,testname,unitLog,unitDistrib)
testname = ["Base","Case1","Case2"]
for i in 0..2 # for each test
b = beta[i]
g = gamma[i]
beta_gamma1 = [1.0,b,g]
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
# choose the pmtu combinations for theoutput matrices to be calculatedif i == 0 then
u = 1else
u = 6 + iend
distrib.odMatrix=[purpose,11,2,u]
# ... lines removed
end
We are dealing here with three sets ofcoefficients respectively for a Base situationand two test cases.
This is indicated by the three names thatare entered in the list here.
This is a ‘for’ loop that gives the variableithe values of 0, 1, and 2, respectively.
Now b and g, and hence beta_gamma1,take different values for each pass of theloop.
[Notes: the for loop is just one way oflooping within Ruby. Array indexes start atzero, not one, in Ruby.]
We create a new instance of a Gravitymodel class each time around the loop.
We store information in different places oneach loop.
end signifies the end of the loop
MODE CHOICE STUDY TOPICS
USING OMNITRANS ON PROJECTS PAGE 30
Purpose Run a Distribution (Gravity) Model
Script Fragment Comments
# create an instance of the class;call it 'distrib'
distrib = OtGravityModel.new
opCube = 'Future_Year_Matrices'
writeln "Output matrix is stored inMatrix Cube #{opCube}"
unitLog.puts "Output matrix isstored in Matrix Cube #{opCube}"
distrib.matrixCube = opCube
# choose the pmtu combinations for theoutput matrices to be calculatedif i == 0 then
u = 1else
u = 6 + iend
distrib.odMatrix=[purpose,11,2,u]
# specify the skim matrices to be used
distrib.skimMatrix =[10,11,2,6,21,1] # HBW time skim forcars in AM peak
# set function type to be used
distrib.functionType = TOPLOGNORMAL
# define function
distrib.functionSpec=beta_gamma1
# constrain balancing to theproductions
distrib.balance= PRODUCTIONS
# constrain the group to productions
distrib.groups= PRODUCTIONS
# set the number of iterations
(This script fragment gives more details ofthe contents of the for loop describedabove.)
We are choosing to store the results of thedistribution in a new Matrix Cube that wealso name.
We write information to the screen(‘writeln’) and to a log file(‘unitLog.puts’)
‘#{some_variable}’ means output thevalue of ‘some_variable’ not the text itself
These lines are to adjust where informationis stored, depending on which test iscurrently running.
See the OtGravityModeldocumentation for more details on theproperties and methods of this class.
MODE CHOICE STUDY TOPICS
USING OMNITRANS ON PROJECTS PAGE 31
Purpose Run a Distribution (Gravity) Model
Script Fragment Comments
distrib.iterations=10
# start the run
distrib.execute
Purpose Using Text Files
Script Fragment Comments
# ===Directory and File Information ==
outputs = "Outputs" # name ofoutput sub-directory
# Outputs/Log directory(Jobs\Outputs directory in project forin-/output files)
outputdir =$Ot.jobDirectory()+outputs
writeln("Output directory is",outputdir)
outputdir += "\\"
# Variant directoryvardir = $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"
“Outputs” is a user-defined sub-directoryname
This defines that “Outputs” is to be a sub-directory of the standard Jobs directory inthe OmniTRANS project.
Confirm where output is to be located
This appends a single back-slash (\) to thepath name defined by outputdir; this is sothat a file name can be added to it. (Twoback-slashes are used because ‘\’ is aspecial character – see the Rubydocumentation.)
‘unitLog’ is an instance of the File classthat is used to read and write informationthat the user has given the name‘Log_title.txt’, where ‘title’ has been definedearlier.
MODE CHOICE STUDY TOPICS
USING OMNITRANS ON PROJECTS PAGE 32
Purpose Using Text Files
Script Fragment Comments
unitLog.puts "Log of "+title+"Processing\n"
unitLog.puts "Trip Distributioninformation output to file:#{outputdir+title+".txt"}\n"
writeln "Summary of TripDistribution information (also writtento log file)"
writelnunitLog.puts "Summary of Trip
Distribution information\n\n"
filePath =$Ot.dirPrj()+"User_External_Data"+"\\DistributionCoeffs.txt"
unitDistrib =File.new(filePath,File::CREAT |File::RDONLY)# ==========================
‘unitLog.puts’ provides a means ofwriting a line to the file. (The “\n” elementoutputs a new line.)
Here we define another instance of the Fileclass to read information from a file calledDistributionCoeffs.txt in thestandard User_External_Datadirectory
Purpose Processing a CSV type file
Script Fragment Comments
def Coeffs(beta,gamma,testname,unitLog, unitDistrib)# =========# Obtain Top Log Normal coefficients
information from file
allspaceRE = /^\s*\n/commentRE = /^\s*#/dataLine = false
cols = ["Name","Beta","Gamma"]
nrow = 0i = 0
This fragment of script defines (def) afunction, Coeffs, to read data from a CSVtype file.
If information is input to a file in a strict waythen the script for reading data can bemuch simpler than shown here, but thisillustrates a number of ways of working withRuby and it allows more flexibility in thecontents of the file.
The two variablesallspaceRE andcommentRE are ‘Regular Expressions’ thatprovide powerful ways of working with textand alphameric data. See the Rubydocumentation for more details.
cols provides a list of column names forthe expected contents of the file.
MODE CHOICE STUDY TOPICS
USING OMNITRANS ON PROJECTS PAGE 33
Purpose Processing a CSV type file
Script Fragment Comments
unitDistrib.each { |line|
unitLog.puts line
next if line =~ commentRE #skip comments
next if line =~ allspaceRE #skip blank lines
line =~ /(\w)(\W)/ # separatoris first non-word characterencountered
# sep = $2sep = "\t" # separator is a tab
pieces = line.split(sep)
if dataLine thenrowname = pieces[0]testname[i] = rownamebeta[i] = pieces[1].to_fgamma[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 += 1end
nrow += 1if !dataLine
dataLine = trueend
rowdata = ""} # unitDistrib
puts "End of Distribution
nrow counts the number of rows and iidentifies which column is being processed.
The eachmethod provides a way ofobtaining each line of the file referenced byunitDistrib in turn. The line variableholds the contents of the current line.
Each line of the file is output to the log file.
This commented-out line provides a way ofautomatically finding out what separatorhas been used, but it is safer to assume atab character as a separator character.
The splitmethod splits the line intopieces according to the occurrence ofseparator characters in the line.
Provided that the current line holds data,rather than header information, we assignthe different pieces of the line to variables inthe script. As all the data is read as text(‘string’ format), we need to convert someof it to decimal (‘float’) form using the to_fmethod. (to_i may be used to convertdata to integer form.)
MODE CHOICE STUDY TOPICS
USING OMNITRANS ON PROJECTS PAGE 34
Purpose Processing a CSV type file
Script Fragment Comments
Coefficient data; #{nrow} linesprocessed"
unitLog.puts "End of DistributionCoefficient data"
end # Coeffs
Purpose Generating Reports – Using Selections
Script Fragment Comments
network = OtNetwork.newexternal =
network.selection('ExternalCentroids')
external.each{|ex|puts "External zone -> #{ex}"
}
internal =network.inversion('ExternalCentroids')
# set the purposepurpose = purp_list[1] # HBW
# Establish matrices for base(current) year
mcBYear = OtMatrixCube.openbYmat = mcBYear[purpose,11,2,6]
biimx = bYmat[internal,internal]biemx = bYmat[internal,external]beimx = bYmat[external,internal]beemx = bYmat[external,external]
This part of the code identifies zones in thenetwork that the user has previouslydefined in OmniTRANS to be ‘ExternalCentroids’ (by using a selection tool andsaving the selection with this name).
The external zones are listed on the screento confirm that the selection is beingapplied.
Here, all zones that are not ‘External’ areconsidered as ‘Internal’.
Reporting here is to be for just one purpose(home-based work trips)
Obtain the required matrix from the relevantMatrix Cube
Define four sub-sets of the matrix accordingto whether trips are internal to internal,internal to external, external to internal, orexternal to external
MODE CHOICE STUDY TOPICS
USING OMNITRANS ON PROJECTS PAGE 35
Purpose Generating Customised Reports
Script Fragment Comments
# Access new (future year) matricesmcFYear = 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] # timeskim for cars in AM peak (minutes)
ftottime = fiimx * skmfsumvhrs = ftottime.sum / 60.0btottime = biimx * skmbsumvhrs = btottime.sum / 60.0pcdiff = ((fsumvhrs - bsumvhrs) *
100.0) / fsumvhrswriteln " 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)"
This is similar to the selection processdescribed above
The lines in bold type are a single line towrite out to the screen information on thenumber of internal to internal trips. Thesprintf function is used to control theformatting, see the Ruby documentation.
Here we calculate some statistics, makinguse of the contents of a skim matrix
Information is output to the log file as wellas the screen.
MODE CHOICE STUDY TOPICS
USING OMNITRANS ON PROJECTS PAGE 36
Mode Choice and Public Transport Assignment Modelling
Script T14_PTAssignModeChoice.rb
This script uses logit modelling for mode choice and assignment modelling (T5Workbook Exercise TIS2).
Purpose Cost Skims
Script Fragment Comments
# define purpose list, include allpurp_list = [1,10,20,30,40,50]purp = 10
# define time periodstime_list = [2,3,4] # 24hr, am peak,interpeak, pm peaktime = 2htime = Hash.newhtime = { 2 => 'AM peak',
3 => 'Off peak',4 => 'PM peak'}
# define user dimensionsuser_list = [1,2,3,4,5]
mode_list = [40,41,42] # All_PT, Bus,Trainhmode = Hash.newhmode = { 11 => 'Car',
40 => 'All PT',41 => 'Bus',42 => 'Train'}
mode = 11
writeln "Doing Car cost skims fortime 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]
The PMTU dimensions are specified aslists as this makes it easier to docalculations for sets of dimensions but, forsimplicity, the code here just selects one setof PMTU dimensions.
traffic is an instance of the standardOtTraffic traffic assignment class. Seethe documentation on this class for moredetails on the properties and methods
Removing the comment would causing theclass to load (assign) traffic to the highway
MODE CHOICE STUDY TOPICS
USING OMNITRANS ON PROJECTS PAGE 37
Purpose Cost Skims
Script Fragment Comments
traffic.routeFactors = [0,1] #time-based paths
traffic.skimMatrix =[1,11,2,1,[20,21,22],1]traffic.execute
mode = 41writeln "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
network as well as calculate cost skims.
This defines where skims are stored in theskim matrix cube.
Similar calculation of public transport skimsusing the standard OtTransit class. Seethe documentation on this class for moredetails on the properties and methods.
Purpose Logit Choice
Script Fragment Comments
require $Ot.dirJob()+"Choice" #Use Choice class
# ___PMTURI Dimensions________p, m, t, u = 1, 1, 2, 1
This script uses a user-specified class, Choice,for undertaking logit choice modelling1.
1 Standardised OmniTRANS logit choice modelling classes are currently in preparation.
MODE CHOICE STUDY TOPICS
USING OMNITRANS ON PROJECTS PAGE 38
Purpose Logit Choice
Script Fragment Comments
# Because the choice is acrossmodes, 'm' is set here arbitrarilyto 1# r and i locate generalised
cost datar, i, = 22, 1
rcc = 30 # r dimension forstoring composite costs
pmtu = [p, m, t, u, r, i,rcc] # forecast/current yearbasepmtu = [p, m, t, u, r, i]
# pmturi values can differ betweenbase and forecast yearbasepmtu = nil.to_a # an
empty array as not incremental
# ___Mode and DimensionValues_________modes = Hash.new# Set mode names and dimensions;
must match project datamodes = { 'All_Modes' => 1,
'Car' => 11,'All_Transit' => 40,'Train' => 42,'Bus' => 41}
# ___GeneralData______________________runparams = Hash.new# Set general information for
runrunparams = { 'zones' => 25,
# number of zones'basecube' => nil,
# 'basecube' => "Base_Year",matrix cube for base year(incremental modelling)
'logit' =>"ChoiceDataTIS2.txt", # name ofchoice structure specification
Composite cost matrices are an output of theChoice class.
This example is for absolute logit choicemodelling, but the Choice class also supportsincremental logit choice modelling. In this lattercase, more information must be provided todefine the base and forecast year data.
The Choice class assumes the hierarchic choicemodel has been defined in a file (here calledChoiceDataTIS2.txt) that defines the modesand the scaling factors (lamda) for the choices.The form of the file is shown below for a hierarchythat splits total travel demand (‘All_Modes’) in to‘Car’ and ‘All_Transit’; All_Transit is split into Busand Train modes.
The format of the file is flexible with regard tospacing. The Level values serve merely asannotation.
The specification of the general information forthe choice model run is entered in the form ofelements of a Hash array called runparams.This part of the script is replicated below (with thecomments removed) to emphasise the form ofthe data input.
# Logit Choice Model Data# =======================
# User data on choices
# Level Demand Lamda Choices0 All_Modes 0.02 Car All_Transit1 All_Transit 0.045 Bus Train
MODE CHOICE STUDY TOPICS
USING OMNITRANS ON PROJECTS PAGE 39
Purpose Logit Choice
Script Fragment Comments
file'inputs' =>
"user_External_Data", # sub-pathlocation of ASCII inputs
'outputs' =>"Outputs", # sub-pathlocation of ASCII outputs
'logfile' =>"Log_ModeChoice.txt"} # name ofrun log file
# Settings if incremental logitis not to be used:# basepmtu = nil.to_a # an
empty array# 'basecube' => nil # set to
nothing# ===End of User SuppliedInformation=================
# ____Choice modelling____________
writeln "Calculating modechoice"
mnl = Choice.new(modes, pmtu,basepmtu, runparams) #initialisationmnl.msplit # run choice model
# mnl.report('full') # reporton resultsmnl.report('short') # report on
results
Once the input data has been specified, a newinstance of the multinomial logit choice modelclass is created and supplied with the dataspecification as arguments (the list of items inbrackets)
Execution of the choice model is invoked usingthe msplit method (note, execute would bemore standard).
Two forms of reporting are supported; the shortform is used in this case.
runparams = { 'zones' => 25,'basecube' => nil,'logit' => "ChoiceDataTIS2.txt",'inputs' => "user_External_Data",'outputs' => "Outputs",'logfile' => "Log_ModeChoice.txt"}
MODE CHOICE STUDY TOPICS
USING OMNITRANS ON PROJECTS PAGE 40
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 moresophisticated approach.
It uses capacity restrained network equilibrium modelling for loading demand matrices oftwo classes of vehicles, heavy goods vehicles (HGVs) and cars, onto the highwaynetwork. HGV vehicles are converted into passenger car units (pcu). The WardropEquilibrium 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 alterlink speeds according to network loadings. The flow-delay relationships are held in thefile …\Jobs\pointsPerType.rb. A script, Plot Speed Flow Curves, is provided that may berun 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 OmniTRANSOtAssign class. The first assignment loads a trip matrix of heavy goods vehicles usingAll-or-Nothing assigment. The results of this assignment provide a ‘pre-load’, whichaffects the network capacity available for the following Equilibrium assignment used toload a car trip matrix.
The final part of the script adds the results of the HGV and car assignments togetherand presents the results as a bandwidth diagram. This may be viewed by switching fromthe Jobs tab to the network tab.
The script runs using the currently active network variant and matrix cube, so it includesa check for the user to confirm that these are the intended values.