Top Banner
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
44
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: OmniTRANSProjects

Minnerva

T14 Projects

Using OmniTRANS on Projects

Intercollegiate MSc in Transport

Prepared for:

Centre for Transport Studies

Imperial College London & University College London

Page 2: OmniTRANSProjects

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

Page 3: OmniTRANSProjects

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

Page 4: OmniTRANSProjects

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

Page 5: OmniTRANSProjects

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.

Page 6: OmniTRANSProjects

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.

Page 7: OmniTRANSProjects

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.

Page 8: OmniTRANSProjects

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 .

Page 9: OmniTRANSProjects

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

Page 10: OmniTRANSProjects

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:

Page 11: OmniTRANSProjects

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.

Page 12: OmniTRANSProjects

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

Page 13: OmniTRANSProjects

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.

Page 14: OmniTRANSProjects

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.

Page 15: OmniTRANSProjects

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

Page 16: OmniTRANSProjects

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.

Page 17: OmniTRANSProjects

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.

Page 18: OmniTRANSProjects

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

Page 19: OmniTRANSProjects

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.

Page 20: OmniTRANSProjects

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

Page 21: OmniTRANSProjects

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

Page 22: OmniTRANSProjects

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.

Page 23: OmniTRANSProjects

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]

Page 24: OmniTRANSProjects

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.”

Page 25: OmniTRANSProjects

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-

Page 26: OmniTRANSProjects

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]

Page 27: OmniTRANSProjects

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

Page 28: OmniTRANSProjects

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

Page 29: OmniTRANSProjects

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

Page 30: OmniTRANSProjects
Page 31: OmniTRANSProjects

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.

Page 32: OmniTRANSProjects

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)

Page 33: OmniTRANSProjects

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

Page 34: OmniTRANSProjects

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.

Page 35: OmniTRANSProjects

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.

Page 36: OmniTRANSProjects

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.

Page 37: OmniTRANSProjects

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.)

Page 38: OmniTRANSProjects

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

Page 39: OmniTRANSProjects

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.

Page 40: OmniTRANSProjects

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

Page 41: OmniTRANSProjects

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.

Page 42: OmniTRANSProjects

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

Page 43: OmniTRANSProjects

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"}

Page 44: OmniTRANSProjects

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.