Developer's Guide

The developer guide

  • provides specification of key-aspects of MATSim (e.g. file formats, simulation events, ...)
  • lists some guidelines for developers (e.g. coding conventions) to keep MATSim maintainable.
  • gives information about certain packages, how to (programmatically) use them and what features they offer.
  • offers additional pieces of information that may/should be of interest to developers (e.g. how to use Eclipse for development, or some Java-tips)

Choose a topic of interest to read more:

Getting and Building the Code

In addition to the resources listed below, the Downloads page also includes important information about getting the source code of MATSim.

Most people will only need the information in "Using Eclipse".

Using Eclipse (3.6, Helios)

Prerequisites

You must have the following software installed and ready to use:

  • Java SDK 1.6 or newer
    To use Maven, you need to have a Java SDK (JDK) installed and not only a Java Runtime Environment (JRE). Best is to download and install the newest version of the "Java SE Development Kit" from java.sun.com.
  • Eclipse
    Download Eclipse from eclipse.org, the package "Eclipse IDE for Java Developers" is enough for MATSim.
    We strongly advise you to use Eclipse Galileo (= Eclipse 3.5) or newer. On older versions, problems with the installation of plugins can happen.
  • Configure Eclipse
    Use UTF8 as File-Encoding.
  • Subversion-Support for Eclipse
    Install the Subclipse Plugin. Subversive is another Plugin for Eclipse that provides SVN functionality, but it does (currently) not work well together with the Maven Plugin. Thus we advise people to use the Subclipse Plugin.
  • Maven-Support for Eclipse
    Install the M2Eclipse Plugin.
  • Make sure Eclipse is running from a JDK
    Configure Eclipse to use a JDK

The following steps were tested with the following combination of tools: Java 1.6 Update 15, Eclipse 3.6 SR 1, Subclipse 1.6.2, M2Eclipse 0.12.0.

Adding the main MATSim project to Eclipse

The main MATSim project includes the API and core implementation of MATSim. It includes everything to start with the basic functionality offered by MATSim and is required in any case.

  • Create a new project in Eclipse (menu File > New > Project...).
  • Choose "SVN > Checkout Projects from SVN" and click "Next".
  • Select the repository location "https://matsim.svn.sourceforge.net/svnroot/matsim". If it does not yet exist, create it.
  • Select the folder "matsim/trunk" and click "next".
  • Select "Check out as a project in the workspace" and give it the name "matsim"
  • Click "Finish".

The project will be checked out, which may take some minutes. The status of the checkout can be observed in the Progress-View of Eclipse.

After the project appears in Eclipse:

  • right-click on the project in the Package Explorer
  • choose "Maven > Enable Dependency Management"

This will convert your project into a Maven/Java project. The first time, Maven may download some required dependencies which can take some minutes. Progress can be observed in the Maven Console View. After that, the project is ready to use.

Adding the MATSim Contributions to Eclipse

The "Contributions" provide stable extensions provided by different developers. Some specialized features are not available in the main MATSim project, but must be loaded separately from the contributions.

To check out the contributions, proceed as for the main MATSim project, but this time select the folder "contrib/trunk".

Choose again "Check out as a project in the workspace" and name it "contrib".

After the checkout has finished, right-click on the project and choose "Maven > Enable Dependency Management". After this, materialize the contributions into own projects, i.e. each contribution should become a separate project in Eclipse (at the time of this writing, there is only one contribution named "sna"). To do this, follow these hints.

Adding the MATSim Playgrounds to Eclipse

The "Playgrounds" provide a place for experimental, often unstable code, for each developer. You should only add the Playgrounds to Eclipse if you plan to develop code for MATSim yourself.

Proceed as for the main MATSim project (or for the contributions), but this time select the folder "playgrounds/trunk" to check out and name the project "playgrounds". After the checkout, enable the Maven Dependency Management and materialize the different playgrounds into separate projects. At the time of this writing, there are about 40 playgrounds, so you should see like 40 additional projects in eclipse.

Using Working Sets in Eclipse 

As each contribution and each playground is a separate project in Eclipse, you may end up with quite a large number of projects in Eclipse you likely will not use much (e.g. the playgrounds of other people). While you could remove those projects, it may be better to just close them if you do not need them. Also, to gain some better overview, you can e.g. create a Working set that contains all the playgrounds.

To do this, select menu "File > New > Other ... > Java > Java Working Set".

Name it "matsim-playgrounds", and all the playground projects to it.

After that, in the Package Explorer, click the little triangle in the upper right and select "Top Level Elements > Working Sets".

Now you can easily hide all the many projects so they do not clutter your view.

Verification

In the end, you should have the following projects in Eclipse:

  • matsim
  • contrib (only if you checked out the contributions)
  • playgrounds (only if you checked out the playgrounds)
  • additional contrib- or playground-projects you are working on, or which you depend on

Configuration

To use the OTFVis visualizer, one has to configure the path to the native libraries. To do so, go the the Java Build Path settings of the main MATSim project and set the "Native library location" within the Maven Dependencies to the correct directory according to your operating systems. The native libraries are located in libs/jogl-1.1.1/<system-dependent>/lib.

Troubleshooting

If you get a warning about Eclipse and JDK, you need to configure Eclipse to use a JDK.

 

Since Eclipse 3.5 it may happen that the code does not compile, even if everything is correctly set up, with the following error message:

Access restriction: The type <<some class name>> is not accessible due to restriction
on required library <<some jar file on your system>>

In that case, go to Project Properties, Java Build Path, Libraries. Make sure that the Java version you use is not set to an "Execution environment", but to an "Alternate JRE". After that, the project should compile. It looks like the Eclipse compiler is overly strict when set to an execution environment, forbidding the access to classes that may not be available on all Java installations, but actually are on all major distributions. [Source]

 

Installing the M2Eclipse Plugin

Installation

Please note that the way how to install plugins differs from each version of Eclipse to the next one. The following description is for Eclipse 3.5.

  • In Eclipse, select the menu "Help > Install New Software".
  • Enter the following Update Site: http://m2eclipse.sonatype.org/sites/m2e
  • Select the following item to be installed, then do the installation:
    • Maven Integration for Eclipse
  • After the installation, restart Eclipse.

Verification

To make sure the plugin was correctly installed, create a new project using menu "File > New > Project...". There should be a new section "Maven" with several options in it to create Projects based on Maven. Select the option "New Maven Project" and click "Next".

If a warning appears "Maven Integration for Eclipse JDK Warning", you have to configure Eclipse to run on a JDK.

If no warning appears, you're installation/configuration should be complete.

Click "Cancel" to leave the "New Maven Project" dialog.

Discussion

  • m2Eclipse 0.10.0 and earlier had a nice integration with SVN/Subclipse. In 0.12.0, this is no longer supported and "Checkout Maven Projects from SCM" no longer works.
  • Problems with resource loading (reported by Konrad Meister)
    I had problems running my playground tests on my desktop with the following setup:
    - Ubuntu 10.04
    - Eclipse 3.5.2 Build-Id: M20100211-1343
    - m2Eclipse 0.10.0-20100209-0800
    Some tests crashed with the error that a resource file from the matsim project could not be found. There are several bug-reports for m2eclipse concerned with resource loading, including correct builder settings (Maven Builder instead of Java Builder) and "**"-excludes for resource directories. I was not able to recover the problem. The tests run successfully on setups with an older version of m2eclipse (0.9.8). I decided to use this version. It can be installed in Eclipse using a different update site URL than indicated above:
    http://m2eclipse.sonatype.org/sites/archives/0.9.8.200905041413/
    which downloads the latest release of m2eclipse 0.9.8. As for the other desktops I tested, my playground runs work again.

 

Installing the Subclipse Plugin

Installation

Please note that the way how to install plugins differs from each version of Eclipse to the next one. The following description is for Eclipse 3.5 - 4.2. See http://subclipse.tigris.org/servlets/ProjectProcess?pageID=p4wYuA for more detailed information by the plugin provider.

  • If not installing on Windows (32-bit), i.e. on Linux, Mac OS X, or Windows 64-bit, first have a look at the notes below, as you first need to install Subversion for your operating system.
  • In Eclipse, select the menu "Help > Install New Software".
  • Enter the Update Site, depending on your version of subversion you installed:
    • If you installed Subversion 1.6: http://subclipse.tigris.org/update_1.6.x
    • If you installed Subversion 1.7: http://subclipse.tigris.org/update_1.8.x
  • Select the following items to be installed:
    • Subclipse
    • Subversion Client Adapter
    • Subversion JavaHL Native Library Adapter
    • SVNKit  Client Adapter
  • After the installation, restart Eclipse.

 

Verification

To verify that the integration works, try the following steps:

  • Open the "SVN Repository Exploring" perspective (menu Window > Open Perspective > Other)
  • Add the following SVN Repository Location: https://matsim.svn.sourceforge.net/svnroot/matsim
    To add it, click on the yellowish icon with "svn" and the plus sign.
  • Test if you can browse to the sub-directories, e.g. matsim/trunk.

 

Installation on Linux, Mac OS X, or Windows 64-bit

While Subclipse includes everything it needs to run on Windows 32-bit, it has some additional dependencies on Linux and Mac OS X. Especially, Subclipse requires that you have the correct version of Subversion installed on your machine along some libraries to make Subversion usable by Subclipse. Please have a look at the detailed information provided directly by the Subclipse team. For Windows 7 64-bit, see these informations.

 

Maven Modules and Eclipse Projects

Introduction

Maven allows hierarchical project structures, where one projects can contain one or more modules – which are essentially independent projects. MATSim uses such so-called "multi-module projects" for the Contributions and Playgrounds. Eclipse can generate for each module a project, so you can specify which modules (e.g. contributions, playgrounds) you really need and you will not have to care about the other projects.

Creating Eclipse Projects from Maven Modules (Eclipse 3.7, Eclipse 4.2)

To create an Eclipse project for a Maven module (e.g. a specific Contribution or specific Playground), follow these steps:

  • Select the "contrib" or "playground" project in the Package Explorer
  • Choose "File > Import" and there "Maven > Existing Maven Projects". Click on "Next".
  • In the following dialog, the list of available contributions/playgrounds will be listed.
  • Select the contributions/playgrounds that you want to have as projects in Eclipse. 
  • If you are using working sets, you can add the to-be-created projects to a working set. If not, it doesn't matter.
  • Click on "Finish" to generate Eclipse Projects for all the selected modules.

Creating Eclipse Projects from Maven Modules (Eclipse 3.6)

To create an Eclipse project for a Maven module (e.g. a specific Contribution or specific Playground), follow these steps:

  • Choose "File > Import" and there "Maven > Materialize Maven Projects".
  • Click twice on "Next", then on "Finish".
  • In the next dialog, select the Playgrounds (or Contributions) location as the Root Directory (this is the actual directory on your file system). You should then see a list of all available modules in the project.
     
  • Select the modules you want to use.
  • If you are using working sets, you can add the to-be-created projects to a working set. If not, it doesn't matter.
  • Click on "Finish" to generate Eclipse Projects for all the selected modules.

Getting rid of unused Eclipse Projects representing Maven Modules

If you have Eclipse Projects representing Maven Modules you no longer need, you can simply delete the Projects in Eclipse's Project Explorer like you delete any other project. Just make sure the option "Delete project contents on disk" is not activated.

Run Eclipse with a JDK

Maven requires Eclipse using a JDK, i.e. Java Development Kit, instead of a Java Runtime Environment (JRE). The main difference is that a JDK also contains a Java Compiler and other tools to develop Java Code, while the JRE is only able to run compiled Java applications.

To check with what Java version (JRE or JDK) Eclipse is running, do the following:

  • Open the menu item "Help > About Eclipse". (On the Mac, it's in the Eclipse-menu, not the Help-menu)
  • Click on "Installation Details".
  • Switch to the tab "Configuration"
  • Search for a line that starts with "-vm". The line following it shows which Java binary is used.

Depending on the name and location of the used Java binary one can figure out if a JRE or a JDK is used:

  • If the path contains "jre" (e.g. as in C:\Program Files\Java\jre6\bin\client\jvm.dll) it is a JRE
  • If the path contains "jdk" (e.g. as in C:\Program Files\Java\jdk1.6.0_31\bin\javaw.exe) it is a JDK.

If no JDK is used for eclipse, change it:

  • Quit Eclipse if it is running
  • Go to the eclipse installation directory and open the file eclipse.ini in a text editor.
  • Search for the line "-vmargs"
  • Before the line "-vmargs", add two lines:
    On the first line, write "-vm".
    On the second line, write the path to your JDK installation (usually something like: "C:\Program Files\Java\jdk1.6.0_31\bin\javaw.exe" on Windows)

Using Eclipse (3.7, Indigo)

With the release of the newest version of Eclipse (Version 3.7, Release "Indigo", released June 22, 2011), a few things have changed. This documentation will be updated soon with more details on how to install MATSim using Eclipse 3.7 / Indigo. The instructions for Eclipse 3.6 / Helios are still available.

Prerequisites

You must have the following software installed and ready to use:

  • Java SDK 1.6 or newer
    To use MATSim, you need to have a Java SDK (JDK) installed and not only a Java Runtime Environment (JRE). Best is to download and install the newest version of the "Java SE Development Kit" from oracle.com.
  • Eclipse
    Download Eclipse 3.7 from eclipse.org, the package "Eclipse IDE for Java Developers" is enough for MATSim. Unzip the downloaded file and place it on some suitable location on your harddisk. Eclipse does not require any special installation. Experience shows that on Windows it's best to install Eclipse at a location that does not require administrative rights.
  • Configure Eclipse
    Use UTF8 as File-Encoding.
  • Subversion-Support for Eclipse
    Install the Subclipse Plugin. Subversive is another Plugin for Eclipse that provides SVN functionality, but it does (currently) not work well together with the Maven Plugin. Thus we advise people to use the Subclipse Plugin. Needs to be revised for Eclipse Indigo. Subversion seems to be better integrated now, but Subclipse works also. One of them needs to be installed!
  • Make sure Eclipse is running from a JDK
    Configure Eclipse to use a JDK

The following steps were tested with the following combination of tools: Java 1.6 Update 24, Eclipse 3.7, Subclipse 1.6.18.

Adding the main MATSim project to Eclipse

The main MATSim project includes the API and core implementation of MATSim. It includes everything to start with the basic functionality offered by MATSim and is required in any case.

  • Create a new project in Eclipse (menu File > New > Project...).
  • Choose "SVN > Checkout Projects from SVN" and click "Next".
  • Select the repository location "https://matsim.svn.sourceforge.net/svnroot/matsim". If it does not yet exist, create it.
  • Select the folder "matsim/trunk" and click "next".
  • Select "Check out as a project in the workspace" and give it the name "matsim"
  • Click "Finish".

The project will be checked out, which may take some minutes. The status of the checkout can be observed in the Progress-View of Eclipse.

After the project appears in Eclipse:

  • right-click on the project in the Package Explorer
  • choose "Configure > Convert to Maven Project"
  • wait a few moments for Eclipse to perform the change
  • right-click again on the project and choose "Maven > Update Project Configuration…", click "OK" in the shown dialog.

This will convert your project into a Maven/Java project. The first time, Maven may download some required dependencies which can take some minutes. Progress can be observed in the Maven Console View. After that, the project is ready to use.

Adding the MATSim Contributions to Eclipse

The "Contributions" provide stable extensions provided by different developers. Some specialized features are not available in the main MATSim project, but must be loaded separately from the contributions.

To check out the contributions, proceed as for the main MATSim project, but this time select the folder "contrib/trunk".

Choose again "Check out as a project in the workspace" and name it "contrib".

After the checkout has finished, right-click on the project and choose "Configure > Convert to Maven Project". After this, materialize the contributions into own projects, i.e. each contribution should become a separate project in Eclipse (at the time of this writing, there is only one contribution named "sna"). To do this, follow these hints.

Please note that the contribs project itself is not a Java project, but just a generic Eclipse project that holds a bunch of files. After materializing the projects you need, you could actually close the contribs project in Eclipse (right-click on project > Close Project). But do not delete it!

Adding the MATSim Playgrounds to Eclipse

The "Playgrounds" provide a place for experimental, often unstable code, for each developer. You should only add the Playgrounds to Eclipse if you plan to develop code for MATSim yourself.

Proceed as for the main MATSim project (or for the contributions), but this time select the folder "playgrounds/trunk" to check out and name the project "playgrounds". After the checkout, convert it to a Maven Project and materialize the different playgrounds into separate projects. At the time of this writing, there are about 40 playgrounds, so you should see like 40 additional projects in Eclipse. As there are so many playgrounds, for most people it is advised to only materialize those projects that they really need. Otherwise, your computer will have to compile many many playgrounds that you don't need at all, which might take quite some time.

As with the contribs project, note that the playground project itself is not a Java project, but just a generic Eclipse project that holds a bunch of files. After materializing the playgrounds you need, you could actually close the playground project in Eclipse (right-click on project > Close Project). But do not delete it!

Using Working Sets in Eclipse 

As each contribution and each playground is a separate project in Eclipse, you may end up with quite a large number of projects in Eclipse you likely will not use much (e.g. the playgrounds of other people). While you could remove those projects, it may be better to just close them if you do not need them. Also, to gain some better overview, you can e.g. create a Working set that contains all the playgrounds.

To do this, select menu "File > New > Other ... > Java > Java Working Set".

Name it "matsim-playgrounds", and all the playground projects to it.

After that, in the Package Explorer, click the little triangle in the upper right and select "Top Level Elements > Working Sets".

Now you can easily hide all the many projects so they do not clutter your view.

Verification

In the end, you should have the following projects in Eclipse:

  • matsim
  • contrib (only if you checked out the contributions)
  • playgrounds (only if you checked out the playgrounds)
  • additional contrib- or playground-projects you are working on, or which you depend on

Configuration

To use the OTFVis visualizer, one has to configure the path to the native libraries. To do so, go the the Java Build Path settings of the main MATSim project and set the "Native library location" within the Maven Dependencies to the correct directory according to your operating systems. The native libraries are located in libs/jogl-1.1.1/<system-dependent>/lib.

Troubleshooting

If you get a warning about Eclipse and JDK, you need to configure Eclipse to use a JDK.

 

Since Eclipse 3.5 it may happen that the code does not compile, even if everything is correctly set up, with the following error message:

Access restriction: The type <<some class name>> is not accessible due to restriction
on required library <<some jar file on your system>>

In that case, go to Project Properties, Java Build Path, Libraries. Make sure that the Java version you use is not set to an "Execution environment", but to an "Alternate JRE". After that, the project should compile. It looks like the Eclipse compiler is overly strict when set to an execution environment, forbidding the access to classes that may not be available on all Java installations, but actually are on all major distributions. [Source]

Using Eclipse (4.2, Juno)

The following sections explain how to install and setup Eclipse Juno (4.2), released in Juni 2012, to work with MATSim. If you have an older version of MATSim, please check the matching documentation: Eclipse 3.6 / Helios, Eclipse 3.7 / Indigo.

Prerequisites

You must have the following software installed and ready to use:

  • Java SDK 1.6 or newer
    To use MATSim, you need to have a Java SDK (JDK) installed and not only a Java Runtime Environment (JRE). Best is to download and install the newest version of the "Java SE Development Kit" from oracle.com.
  • Eclipse
    Download Eclipse 4.2 from eclipse.org, the package "Eclipse IDE for Java Developers" is enough for MATSim. Unzip the downloaded file and place it on some suitable location on your harddisk. Eclipse does not require any special installation. Experience shows that on Windows it's best to install Eclipse at a location that does not require administrative rights.
  • Configure Eclipse
    Use UTF8 as File-Encoding.
  • Subversion-Support for Eclipse
    Install the Subclipse Plugin. There exists an alternative Plugin, Subversive, which provides similar functionality. In our testing, we found Subclipse easier to use. The documentation and screenshots below assume you're using Subclipse.
  • Make sure Eclipse is running from a JDK
    Configure Eclipse to use a JDK

The following steps were tested with the following combination of tools: Java 1.6 Update 31, Eclipse 4.2, Subversive 1.0.0.

Adding the main MATSim project to Eclipse

The main MATSim project includes the API and core implementation of MATSim. It includes everything to start with the basic functionality offered by MATSim and is required in any case.

  • Create a new project in Eclipse (menu File > New > Project...).
  • Choose "SVN > Checkout Projects from SVN" and click "Next".
  • Select the repository location "https://svn.code.sf.net/p/matsim/code/". If it does not yet exist, create it.
  • Select the folder "matsim/trunk" and click "next".
  • Select "Check out as a project in the workspace" and give it the name "matsim"
  • Click "Finish".

The project will be checked out, which may take some minutes. The status of the checkout can be observed in the Progress-View of Eclipse.

After the project appears in Eclipse:

  • right-click on the project in the Package Explorer
  • choose "Configure > Convert to Maven Project"
  • wait a few moments for Eclipse to perform the change
  • right-click again on the project and choose "Maven > Update Project Configuration…", click "OK" in the shown dialog.

This will convert your project into a Maven/Java project. The first time, Maven may download some required dependencies which can take some minutes. Progress can be observed in the Maven Console View. After that, the project is ready to use.

Adding the MATSim Contributions to Eclipse

The "Contributions" provide stable extensions provided by different developers. Some specialized features are not available in the main MATSim project, but must be loaded separately from the contributions.

To check out the contributions, proceed as for the main MATSim project, but this time select the folder "contrib/trunk".

Choose again "Check out as a project in the workspace" and name it "contrib".

After the checkout has finished, right-click on the project and choose "Configure > Convert to Maven Project". After this, materialize the contributions into own projects, i.e. each contribution should become a separate project in Eclipse (at the time of this writing, there is only one contribution named "sna"). To do this, follow these hints.

Please note that the contribs project itself is not a Java project, but just a generic Eclipse project that holds a bunch of files. After materializing the projects you need, you could actually close the contribs project in Eclipse (right-click on project > Close Project). But do not delete it!

Adding the MATSim Playgrounds to Eclipse

The "Playgrounds" provide a place for experimental, often unstable code, for each developer. You should only add the Playgrounds to Eclipse if you plan to develop code for MATSim yourself.

Proceed as for the main MATSim project (or for the contributions), but this time select the folder "playgrounds/trunk" to check out and name the project "playgrounds". After the checkout, convert it to a Maven Project and materialize the different playgrounds into separate projects. At the time of this writing, there are about 40 playgrounds, so you should see like 40 additional projects in Eclipse. As there are so many playgrounds, for most people it is advised to only materialize those projects that they really need. Otherwise, your computer will have to compile many many playgrounds that you don't need at all, which might take quite some time.

As with the contribs project, note that the playground project itself is not a Java project, but just a generic Eclipse project that holds a bunch of files. After materializing the playgrounds you need, you could actually close the playground project in Eclipse (right-click on project > Close Project). But do not delete it!

Using Working Sets in Eclipse 

As each contribution and each playground is a separate project in Eclipse, you may end up with quite a large number of projects in Eclipse you likely will not use much (e.g. the playgrounds of other people). While you could remove those projects, it may be better to just close them if you do not need them. Also, to gain some better overview, you can e.g. create a Working set that contains all the playgrounds.

To do this, select menu "File > New > Other ... > Java > Java Working Set".

Name it "matsim-playgrounds", and all the playground projects to it.

After that, in the Package Explorer, click the little triangle in the upper right and select "Top Level Elements > Working Sets".

Now you can easily hide all the many projects so they do not clutter your view.

Verification

In the end, you should have the following projects in Eclipse:

  • matsim
  • contrib (only if you checked out the contributions)
  • playgrounds (only if you checked out the playgrounds)
  • additional contrib- or playground-projects you are working on, or which you depend on

Configuration

To use the OTFVis visualizer, one has to configure the path to the native libraries. To do so, go the the Java Build Path settings of the main MATSim project and set the "Native library location" within the Maven Dependencies to the correct directory according to your operating systems. The native libraries are located in libs/jogl-1.1.1/<system-dependent>/lib.

Troubleshooting

If you get a warning about Eclipse and JDK, you need to configure Eclipse to use a JDK.

 

Since Eclipse 3.5 it may happen that the code does not compile, even if everything is correctly set up, with the following error message:

Access restriction: The type <<some class name>> is not accessible due to restriction
on required library <<some jar file on your system>>

In that case, go to Project Properties, Java Build Path, Libraries. Make sure that the Java version you use is not set to an "Execution environment", but to an "Alternate JRE". After that, the project should compile. It looks like the Eclipse compiler is overly strict when set to an execution environment, forbidding the access to classes that may not be available on all Java installations, but actually are on all major distributions. [Source]

With Maven on the Command Line

We strongly advise developers to use Maven in combination with an IDE, e.g. Eclipse, to develop for MATSim. But there are still situations when Eclipse is not available, for example if you need to run MATSim remotely on a server. These guidelines merely give some hints, how MATSim can be checked out and compiled on the command line, without giving too much information, assuming the reader already has experience and feels safe on the command line.

# Checking out the Code

mkdir sandbox
cd sandbox
svn co https://svn.code.sf.net/p/matsim/code/matsim/trunk matsim
svn co https://svn.code.sf.net/p/matsim/code/contrib/trunk contrib
svn co https://svn.code.sf.net/p/matsim/code/playgrounds/trunk playgrounds

# compile, test and install main MATSim project
# installation in the local Maven repository is required for Contributions and Playgrounds to compile.

cd matsim
mvn install -DskipTests=true
cd ..

# compile, test, install the Contributions.
# installation in the local Maven repository is required because of dependencies from Playgrounds.

cd contrib
mvn install -DskipTests=true
cd ..

# compile the playgrounds

cd playgrounds
mvn compile
cd ..

# if your playground depends on other playgrounds, those playgrounds must be installed as well:
cd playgrounds
mvn -fae install -DskipTests=true
cd ..

# run the Controler with some config-file, and give it 200MB of RAM
# mvn exec:java automatically sets the classpath to include all dependencies

cd matsim
export MAVEN_OPTS=-Xmx200m
mvn exec:java -Dexec.mainClass="org.matsim.run.Controler" -Dexec.args="/path/to/config.xml"

# alternative call to start the Controler:
# mvn exec:exec substitutes the argument "%classpath" with the actual classpath that includes all dependencies

mvn exec:exec -Dexec.executable="java" -Dexec.outputFile=/path/to/logfile.log -Dexec.args="-Xmx200m -cp %classpath org.matsim.run.Controler /path/to/config.xml"

If Maven is not installed on the machine, download maven and unzip it in a local directory. After that, instead of the simple mvn-command you can use /path/to/your/apache-maven/bin/mvn to run the above commands.

Building a (personal / nightly) release

The following are some notes for proficient Maven users for creating a release-like package of MATSim with Maven.

Create a release for MATSim 

mvn clean
mvn source:jar
mvn -Prelease -DskipTests=true

The above commands create a variety of artifacts in ./target/ that could be used in a release. Most importantly, it creates a matsim-*-release.zip with can easily be used to distribute MATSim.

I advise against using "jar-with-dependencies" as releases, as the meta-information (most importantly license-information form third-parties) is destroyed with that mechanism. 

Creating a release of contribs

# create *and install* the matsim release
cd matsim
mvn clean
mvn source:jar
mvn install -DskipTests=true
mvn -Prelease -DskipTests=true

# install all contribs, they could be required as a dependency
cd ../contribs
mvn clean
mvn install -DskipTests=true

# clean again, so the following jars will be created with the release profile
mvn clean
mvn source:jar
cd myContrib
mvn -Prelease -DskipTests=true
cd ../anotherContrib
mvn -Prelease -DskipTests=true

Notes

The Manifest for the release-jars may be special and must be configured in the plugin-configuration in the pom, thus the release profile ("-Prelease") is used for the generation of the final zip. This is also the reason why it is important to clean before building the release, as Maven might not recompile the jar when just the profile changes, leading to missing entries in the Manifest of the packaged jar-file.

To see the content of the generated zip file, use the following command to unzip it:

unzip target/matsim-0.1.0-SNAPSHOT-release.zip -d target/release

Adding revision information and timestamp is possible with the buildnumber-plugin, but it needs quite some customization. Using the buildnumber-properties in filtered files seems only to work if the buildnumber-plugin is NOT configured in a profile, but in the main part of the pom.

Verification

calling "java -jar target/matsim-x.y.z-release.jar" should show useful build information (revision number and timestamp)

 

Generate your own matsim.jar

We highly recommend the two versions above (see Using Eclipse and With Maven on the Command Line). Nevertheless, sometimes one has to pack his own development as a self-executable file that can be started on the command line, since some machines do neither have Maven nor it is allowed to compile/build code there. In such a case it is useful to assemble your playground (or contribution) to a single jar file.

Prerequisites

In Eclipse Galileo, the MATSim project and your playground (or contribution) is set up as explained in here.

"Install" MATSim with Maven

First, MATSim needs to be packaged as a library in your local Maven repository. For this, create a new Run Configuration: Select Menu Run > Run Configurations..., click on "Maven Build", and press the "New" Button. Configure the build as in the screenshot shown below: Choose the MATSim-project as the base directory, use "install" as the only goal, and add the parameter "skipTests" with the value "true" (Note: The checkbox "Skip Tests" has not the same effect as this parameter, so do not use it!).

After you run that configuration (the first time, Maven might download some additional plugins first), you should see the following final log messages in the "Console" View of Eclipse:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 31 seconds
[INFO] Finished at: Fri Jan 08 13:00:14 CET 2010
[INFO] Final Memory: 4M/14M
[INFO] ------------------------------------------------------------------------

MATSim is now placed in your local Maven repository at "[path/to/your/home/dir]/.m2/repository/org/matsim/matsim/0.2.0-SNAPSHOT/". There, you should find the following files:

matsim-0.2.0-SNAPSHOT-tests.jar
matsim-0.2.0-SNAPSHOT.jar
matsim-0.2.0-SNAPSHOT.pom
maven-metadata-local.xml

Install Contributions and Playgrounds

repeat the above steps for installing MATSim, but this time run the install first on the contrib project, then on the playground project. For this, change the Base directory to the corresponding projects.

Assembly your playground (or contribution) with Maven

If the above is done, you now are able to package your playground (or contribution) with all dependent libraries (including MATSim) into one Jar file. This can then be copied and used on any machine that has only JVM installed.

Right-click on your playground (or your contrib) project and choose "Run As > Run Configurations...".

Define a new Configuration by right-click on "Maven Build", select "New" and set up the new configuration as shown in the Figure above (instead of "balmermi", use the name of your playground in the base directory). Run that Configuration whenever you want to create the Jar.

[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 18.523s
[INFO] Finished at: Mon Jun 28 09:41:47 CEST 2010
[INFO] Final Memory: 10M/81M
[INFO] ------------------------------------------------------------------------

If the final log messages in the "Console" View of Eclipse looks like the above the Jar is created and can be found at "[path/to/your/workspace]/playgrounds/[yourPlayground]/target/[yourPlayground]-0.2.0-SNAPSHOT-jar-with-dependencies.jar".

Starting your Process via the Jar file on the command line

Finally, copy the final Jar file to the machine where you want to run your process and start it via:

java -Xms123m -Xmx456m -cp [yourPlayground]-0.2.0-SNAPSHOT-jar-with-dependencies.jar playground.[yourPlayground].[xyz].[yourMainClass] [arguments]

 

Hints for Using Maven

Checking the Java Runtime of Eclipse

[[might be easier to just ignore this section until the problem acutally happens]]

moved, see here.

Eclipse freezes the first time when enabling dependency management 

We observed several times that Eclipse freezes when enabling the maven dependency manager for the first time. If this happens, we suggest the following: (i) kill Eclipse (ii) start Eclipse again (iii) disable maven dependency management (right click on project, Maven > Disable Dependency Management) (iv) enable maven dependency management again. In the second try, things usually work.

Useful commands, hints

  • You can find the  the Project Object Model description (the pom.xml) in the main folder of the matsim project.
  • You can find a bunch of Maven documentation at http://books.sonatype.com/maven-book/index.html
  • Run maven with one of the default maven phases which are documented at maven.apache.org/guides/getting-started/maven-in-five-minutes.html with the following command: mvn phasename
  • To skip the tests use the -DskipTests option (former: -Dmaven.test.skip=true option)
  • To create a jar containing all library classes execute mvn assembly:assembly
  • There is an issue with the jogl library unter maven.  There is, however, a maven path for native library.  Setting this path to the jogl library path fixes the problem for the time being.  (This will work as long as we have at most one native library.)

Using git locally (essentially, as an SVN client)

I am still learning git myself. There are many aspects to it I have absolutely no clue about. This is the workflow I am trying and researching. I limit myself to things related to our use case, i.e. using git locally while tracking the SVN repository. This seems to be a good general git text.

 
Check out MATSim (not playgrounds etc.) from SVN into a new local git repository (and directory) called matsim. This takes a very long time because it downloads the entire SVN history of the entire MATSim development ever. I suggest you let it run overnight.
 
git svn clone -s https://svn.code.sf.net/p/matsim/code/matsim matsim
 
In git, "clone" means roughly what SVN calls "checkout", and "checkout" means something different. See below.
 
If you want to update your local repository to changes made in the SVN (roughly equivalent to svn update), type
 
git svn rebase
 
It is called "rebase" because of what happens behind the scenes. Any local changes you may have made are removed into a stack, any remote changes from the SVN are applied, and then your local changes are put back on again, so that they are based not on the old state of the trunk, but on the new one. They are rebased.
 
Now, list your local branches.
 
git branch
* master

I recommend you do not develop on master at all, but use it only to track the state of the SVN repository. So let's create a branch to develop a hot new feature.
 
git branch my-feature
git branch
* master
my-feature
 
Remember that in git, everybody has their own repository. Branching, merging, committing are all actions done locally, and are only eventually pushed to a remote server.
 
Now switch to the newly created branch. Yes, switching to a specific branch is called checkout in git.
 
git checkout my-feature
git branch
master
* my-feature
 
Now hack something. Committing is a two-step process in git, and if you are used to commit meaning committing to a remote repository, it is a three-step process. I just changed two files.
 
git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified:   examples/tutorial/config/example1-config.xml
# modified:   src/main/java/org/matsim/ptproject/qsim/QSim.java
# modified:   src/main/java/org/matsim/ptproject/qsim/qnetsimengine/QLinkImpl.java
#
no changes added to commit (use "git add" and/or "git commit -a")
 
There is a part of your working copy called the staging area. It contains everything which will be committed on the next call to git commit. To add changes to the staging area, git add is used.  This is a bit different from SVN, where you only need to add new files. In git, every changed file must be added if you want to commit it. I always add everything (from the root of the repository) like this.
 
git add .
git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
# modified:   examples/tutorial/config/example1-config.xml
# modified:   src/main/java/org/matsim/ptproject/qsim/QSim.java
# modified:   src/main/java/org/matsim/ptproject/qsim/qnetsimengine/QLinkImpl.java
#
 
And then I say:
 
git commit
 
This works just as in SVN, but locally. It will ask for a commit message.
 
Now I have committed to my private, local feature branch. I can switch back and forth between local branches as much as I want. Now I want to commit all the changes made in a branch (which may consist of several commits) to the SVN trunk. I think it is called dcommit because it is a commit in SVN terminology, not in git terminology.
 
git svn dcommit
 
This will most likely fail because the SVN will have changed since my last rebase (see above). So rebase and try again. Resolving rebase conflicts is beyond the scope of this text, but it should work like "regular" rebasing with git, so you only have to look for git documentation on the web, not necessarily for git-with-svn documentation.
 
At the moment, the correct workflow seems to me to git svn dcommit directly from the feature branch, and not to previously merge it into master and git svn dcommit it from there. I can afterwards git checkout master again and call git svn rebase there to update the master (or any other local branch). It will even "recognize" my commits when they come back down from the SVN as the "same" commits I did locally. Some documentation even explicitly advises against committing something to the SVN which is the product of a local merge, as git and SVN are not similar enough for that to make sense in some circumstances. If we start working with a remote git repository, it'll be a whole different story (and a normal case).
 
If you are in the mood to appreciate having a complete history availably locally, and have a bug to fix, try git bisect, which is an incredibly cool feature.
 
For this to be really useful, we probably need to be able to check out matsim and playgrounds into one git repository. It needs to be one because otherwise things like git bisect will not work, obviously. But for that, we need to tell git svn clone about the layout of our SVN repository, which seems to be non-standard (with the subdirectories matsim, playgrounds ...).

Kirill Müller provided the following solution:

# initialize repository
git svn init https://svn.code.sf.net/p/matsim/code matsim-full
cd matsim-full

# activate sparse checkout
git config core.sparsecheckout true

# select directories for checkout
echo matsim/trunk/ >> .git/info/sparse-checkout
echo playgrounds/trunk/ >> .git/info/sparse-checkout
echo contrib/trunk/ >> .git/info/sparse-checkout

# do the actual checkout
git svn fetch

# have some coffee, finish a paper, go home, ...

# loading checkout into work directory
git svn rebase -l

# check the size, this may increase over time
du -hs .
# 1.3G    .

 

To use a checked out repository (either way) in Eclipse:

From an empty workspace, say: Import -> Maven -> Existing Maven Projects. Select the local git repository as the directory. Select all projects. Press OK. You now have matsim an possibly all the contrib and playground projects in your workspace.

Now, make them known to the EGit plugin for Eclipse. Select all projects (at once), say: Team->Share Project. Select git. Leave everything selected, including the checkbox all the way up ("Look for git repository in parent directories."). Hit finish. That's it.

 

Concepts

What are the concepts MATSim is built upon?

MATSim-T Overview

MATSim-T overview (click to enlarge)MATSIM-T consists of several (logically seperated parts). All modules are based on MATSIM-DB which contains all available data points needed for modeling agents and their demand.
World-DB, Network-DB, Facilities-DB, etc... describes the scenario and aggregated information like OD-matrices and so on. MATSIM-FUSION fuse those diverse data into a well deformed data sturture stored into memory.
Based on the scenario information MATSIM-INI them models each individual in the scenario including individual initial demand, called plans (i.e. for a day). The Agents are stored into Agent-DB which refers to the given scenario information of the other databases of MATSIM-DB.
In MATSIM-EA the individual demand of each agent will be optimized using an iterative process. The process steps consists of:

  • MATSIM-EXEC: It is the physical agent-based mobility-simulation in which the agents actually interacts with others
  • MATSIM-SCORES: These modules measure the performance of an executed demand of each agent
  • MATSIM-STRATEGY: Strategy modules changes/mutates/generates executed demand of agents according to the information of the last execution of the demand.

By iterating these steps the overall performance of the system (sum of scores of each plan of each agent) increase until a stable state is reached.
The result are optimized demand of each agent and - as a side effect - the exact description of the last execution of this individual demand. Therefore, at every point in time, we know where and agent is and what it is doing at that time.
These very precice information can then be aggregated via MATSIM-ANALYSIS to extract desired information like traffic volumes, departure histograms, system relaxations, location occupation, and so on.

MATSim-T Process Steps

In fact the process steps are (typically) split up into two to three main parts:

  • Agent modeling and initial individual demand modeling
  • Demand optimization process
  • Analysis

The reason lies into the fact that some parts of MATSim are implemented in C++ while other parts are written in JAVA.  The MATSim core has been fully ported to JAVA; in consequence, C++ modules are optional.
  Because of the flexible data parsing and data writing functionality of MATSim-T, also external modeling application and modules can be used for MATSim-T.
MATSim-T process steps The Figure shows a typical MATSim-T process. An external synthetic population generation program by Martin Frick was used to create the individuals of the scenario. With other base information about the scenario all those data a filled into MATSim-DB. With MATSim-FUSION modules these data points are connected in an appropriate way such they can now be used to add initial demand for each person of the given population. The resulting Agent-DB (and also the Network-DB) are exported into well defined XML data files. To optimize the demand, these data are then read into another Agent-DB written in C++. After the optimization process of MATSim-EA the resulting demand and the resulting MATSim-EXEC description are written into files again which can be used for analysis.

Contributing / Writing Code

The most important rules:

  • Committed Code must compile with Java 6 (current system requirements by MATSim)
  • Only commit to your personal playground, unless you are a package maintainer or you have been given the rights to commit in other locations.

 

The following chapters contain more information for writing code for MATSim.

Coding Conventions

As the project is growing, we need a minimal set of guidelines to insure the stability of the MATSim project and its further development. I try to keep this list as short as possible.

We try to follow the Java Code Conventions
This includes the Naming Conventions (Classes start with capital letters, variables with lowercase letters, ...), the usage of braces in if statements and other stuff. A notable exception are line lengths (we have no problem with lines up to 132 characters).
Indentation
MATSim Source code is indented with tabs, not spaces.
Code is consistent and compiles!
Code committed to the repository has to compile - always. If you want to try out some stuff, do it somewhere else or do not commit it. Classes in org.matsim.* do not reference other classes outside of the org.matsim.*-package except for classes provided by libraries in the libs directory. Especially, org.matsim.*-classes must not reference playground-classes. Also playground classes must not depend on code within src/test/java.
Compilation and the compile order is very important for nightly builds, nightly tests and code analysis. Please make sure your code compiles. Also note that Eclipse's compiler settings may be different from the nightly settings. If you are not sure if your code is compiling due to special settings or dependency issues you can check it by calling mvn compile test-compile from the command line within the project top-level directory.
 
All our code files have the MATSim-specific GPL-Header
In Eclipse, you could add the header to the code template, so every new Java file has this header set by default. To do this, go to the global Preferences in Eclipse (Menu: Window > Preferences), navigate to Java > Code Style > Code Templates. Choose "Code > New Java files" and click on "Edit...". Paste there the following text:
/* *********************************************************************** *
 * project: org.matsim.*
 *                                                                         *
 * *********************************************************************** *
 *                                                                         *
 * copyright       : (C) ${year} by the members listed in the COPYING,        *
 *                   LICENSE and WARRANTY file.                            *
 * email           : info at matsim dot org                                *
 *                                                                         *
 * *********************************************************************** *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *   See also COPYING, LICENSE and WARRANTY file                           *
 *                                                                         *
 * *********************************************************************** */

${filecomment}
${package_declaration}

${typecomment}
${type_declaration}
We use meaningful commit-messages
Commit messages help to rule out quickly some revision of a file when looking for specific changes that, for example, may have introduced a bug in the code. Useless or empty commit messages make it more cumbersome, as the file itself must be looked at in each revision. Additionally, we write commit-messages (as well as comments in the code) in English, as development takes place in many different areas, and not only in german-speaking Countries. KDE has a nice list of SVN Commit Policies, most of them are general enough to also be useful to org.matsim.* ("Never commit code that doesn't compile", "Test your changes before committing", ...)
Do not commit personal test-data
Use another repository if you want to version your personal test-data. We often work with data we are not allowed to give away, as our repository on Sourceforge.net is open for reading to anyone, it is a bad idea to store test-data in this repository, because sooner or later somebody will commit confidental data to the repository which could not be removed! Some simple test-data is available in the directory examples, which is maintained by Michael Balmer and Marcel Rieser – please contact them if you want to add your own examples to this directory.

Naming Conventions

  • We follow the Naming Conventions from Sun's Java Code Conventions.
    Short version: Use CamelCase in general, with:
    • Classes and Interfaces starting with uppercase letters
    • Methods, packages and variables/members starting with lowercase letters
    • Constants use all-uppercase letters together with underscores ("_").
  • Abbrevations should be avoided:
    • getTravTime()  >>  getTravelTime()
    • getDist()  >>  getDistance()
  • Id is an abbreviation for Identifier, the 'd' is thus usually a lowercase letter.
  • Factory methods are named create*(), e.g. createLink(). newLink() or other names should be avoided.
  • Abstract classes should start with Abstract, e.g. AbstractPersonAlgorithm.
  • Interfaces are not specially marked in their name, e.g. there is no pre- or suffix I like SomeInterfaceI.
  • Default Implementations of interfaces end on Impl, if no more specific class-name is suitable, e.g. PlanImpl implements Plan.

 

Becoming a Contributor

You have some cool features or ideas you want to implement and provide to the MATSim community? Then become a contributor! We grant commit rights to people we know personally (e.g. students from affiliated universities) or to people that can convince us that they are doing (or planning to do) nice things with MATSim. As MATSim is a fairly large project with an extensive API where coding mistakes can affect quite a lot of users, we try to guide new contributors closely to help them feel comfortable with their commits quickly. By default, people with commit rights get their own playground where they are allowed to commit their code. Commit rights for other playgrounds, contributions or even the core are given by the respective maintainers of the packages.

To become a contributor, follow those steps:

  1. Register on SourceForge
  2. Write an email that states your SourceForge username and request your account being added to the MATSim project.
  3. In the same email, state your preferred name for your playground. If you work together within someone elses playground, state this persons playground name.
  4. State in the email who is your "guide" in MATSim (see description above)
  5. Send the email to rieser (at) senozon.com

If will then add your account to the MATSim project and create a playground.

 

Committing to the Repository

  • Code to be committed must compile.
    Please make a SVN-Update of complete MATSim before committing your own code to make sure your code compiles together with the code currently in the repository. It is important that your code is written in UTF8, otherwise it may not compile on all machines.
  • By default, only commit to your personal playground. Do not commit to org.matsim.* unless you are the maintainer of a package/module in org.matsim.*, then you can also commit to this package. Only a small group of persons has the right to commit code to org.matsim.core.*, if you're not one of them, do not commit code in there. Talk to one of the core committers if you need changes or want to contribute code into the core.
  • If you commit code to org.matsim.*, run first the test cases before committing and make sure there are no test failures.
  • Write useful commit messages.
    If you only commit to your personal playground, a commit message is optional. In all other cases, a commit message is required.
  • Write your commit messages in English.
  • Do not commit personal data (=non-code) files to the repository.
    Exception is data for test cases, which must be committed to test/input/*. See the detailed discussion of this topic.

KDE has a nice list of additional recommendations for committing code to a repository. The list seems mostly reasonable also for our project, but we don't want to regulate too much, but hope for people's sanity when committing code.

File Formats

MATSim generally uses XML files to store data and configuration. There are separate files for configuration, network, demand, and other data. All the different file formats are based on either DTDs (Document Type Descriptions) or XML Schemas, which can be used to validate the XML-files against. The DTD-files and XML schemas are available at http://matsim.org/files/dtd/ and usually contain some documentation about the meaning of the XML-tags in comments.

Data on SourceForge-repository

Some questions occurred about committing data to the MATSim project on SourceForge. To clarify, what kind of data is allowed to commit and where to put it, here a short guideline:

  1. Only commit source files in "src" and its subdirectories. Do not commit any data files under "src"!
    Exception:
    • MATSim "config.xml" files are allowed under "src/playground/<username>".
  2. If you need to use data during the development and you want to keep that data on a save place, please use internal storages of you institution (e.g. internal CVS repositories, internal shared folders, etc.)
  3. When you write JUnit test cases under "test/src", you are allowed to add required data to "test/input" or "test/scenario". Then please follow the following constraints:
    • Use—if possible—already existing scenario data sets given in "test/scenario".
    • Add only small data sets (some Kbytes to max. 2 Mbytes) to "test/input" or "test/scenario". Note that bigger files may be compressed with gzip since MATSim supports reading and writing gzipped files with org.matsim.utils.io.IOUtils.getBufferedReader() and IOUtils.getBufferedWriter() respectively.
    • Use artificial or falsified data in test cases and put them under "test/input" or "test/scenario". Remember: SourceForge is public to everyone!

 So, to make it short: You are not allowed to add any data to the SourceForge repository except:

  • config.xml-files in your playground
  • files required for official JUnit test cases in "test/input/<name of your test>" or "test/scenario/…".

Test Cases

Why Tests?

Our main reason to have tests is to ensure we do not loose existing functionality when adding new functionality. Another reason, hopefully getting less important, is to figure out what influences bugs had, respectively what is influenced by a bugfix.

Possible Examples of Tests

The following list is not complete and likely never will. It is more to give you an idea, what could be tested:

  • readers and writers for data (Generating data, writing data to file. Reading the file and writing it out again should produce the same file as before).
  • calculating link travel times based on events
  • events-generation, e.g. from the transport simulation
  • calculation of plans' scores
  • are parameters correctly reflected in the execution (e.g. when replanning?)
  • ...

Automatic Run of the Tests

The tests are automatically run every night. When you log in on matsim.org, you'll find a link in the left navigation area ("developer info") where you can look at the nightly status of the tests. If errors or failures occur, an email is sent to Marcel Rieser who will then inform people as necessary.

More Information

Running the Tests

General Remarks

  • The tests currently require around 400 MB of RAM to run successfully on a 32-bit JVM (600 MB on 64-bit JVM).

In Eclipse

To run all tests, create a new Run-Configuration. Select to run all Tests in src/test/java with a JUnit 4 runner.

In the Arguments tab, do not forget to increase the available memory for the JVM (-Xmx600m), then click "Run".

With Maven on the Command Line

export MAVEN_OPTS=-Xmx600m
mvn test

Maven should output a summary, listing the number of all tests as well as the number of failed tests (if any).

Guidelines for Writing Tests

(The following list has been updated for JUnit 4.7. Many existing tests written for JUnit 3.8 still follow different guidelines.)

  • Name your class containing the test-methods such that it starts or ends with "Test", e.g. MyModuleTest.
    Otherwise, your class may not be recognized as test on the Build server.
  • Annotate your test methods with @Test and name your methods that contain your tests with a starting "test", e.g.: @Test public void testGetParameter();
  • Do not use the regular assert keyword from the Java language to check conditions, but use the methods provided by JUnit: Assert.assertEquals(x, y); Assert.assertTrue(x); Assert.assertNull(x); Assert.assertNotNull(y);
  • Provide a short description in the assert*-statements of what is being checked or what failed. JUnit will display that info when an assertion failes. This helps to find problems faster. Example:
    Assert.assertEquals("different events files.", checksum1, checksum2);
    Assert.assertNotNull("did not find person 1.", population.getPersons().get(1));
  • Note that when you compare two double values, also provide the precision. Example:
    double d1, d2;
    Assert.assertEquals(d1, d2); // this matches to assertEquals(Object, Object); likely not what you wanted...
    Assert.assertEquals(d1, d2, MatsimTestUtils.EPSILON); // this is the right way to test for double values
  • If your test reads or writes data from/to files, use @Rule MatsimTestRule, see Mini-Introduction to JUnit 4.7.
    You have then the following methods at your convenience:
    • Config loadConfig(String filename);
      automatically sets the correct output-directory for your tests.
    • getOutputDirectory(); getInputDirectory(); getClassInputDirectory(); getPackageInputDirectory();
      return the corresponding filesystem paths to easily read and write test-data.
    • Reset the global state of MATSim (Gbl, MatsimRandomNumber, ...) so that your test is not influenced by other tests.
    • Provide the constant EPSILON for comparing double values (see above).
    • Cleans the output-directory before running the test, so you're test doesn't get mixed up by old data.
  • Load config files with MatsimTestUtils.loadConfig().
  • Write any output to the directory specified by MatsimTestUtils.getOutputDirectory().
  • Files containing test-data must be located in src/test/resources/test/input/<package>/<class>/<test>/. Example:
    src/test/resources/test/input/org/matsim/mymodule/MyModuleUtils/testUtilMethod/config.xml
    is a configuration file for the test org.matsim.mymodule.MyModuleUtils.testUtilMethod().
    If some files are used by more than one test, they can be located in the directory corresponding to the class or the package. Test files in your playgrounds are organized the exactly same way.
  • Do not use test-classes from other projects. While Eclipse may happily compile your code, Maven does not allow that test-classes are used outside their own project.

[deprecated] Mini-Introduction to JUnit 3.8

This information is out-dated. Newer tests should be written with JUnit 4.7.

JUnit is a framework for writing tests in Java. We currently use JUnit 4.7 for our tests, but many older tests are still written as JUnit 3.8. Thus, the following information is retained only for better understanding of existing tests.

JUnit 3.8 uses three main concepts:

  • Tests: the effective Tests, implemented as methods in a class. The method-name must start with "test".
  • TestCases: group several tests, implemented as a class containing severeal test-methods
  • TestSuites: group several testcases or other testsuites

A small example of a test and testcase:

 public class MyTests extends TestCase {
     protected void setUp() throws Exception {
         super.setUp();
         // your code here...
     }
     protected void tearDown() throws Exception {
         super.tearDown();
         // your code here...
     }
     public final void testOne() {
         // your code here...
         assertEquals(expected, actual);
     }
     public final void testTwo() {
         // your code here...
         assertNotNull(someObject);
     }
 }

This code defines two tests (testOnetestTwo). Additionally, there are two methods setUp() and tearDown(), which are automatically called by JUnit when executing the TestCase. Make sure to call Gbl.reset() in tearDown() when you use the class Gbl or Config within your tests, so that the following TestCases are not influenced by your TestCase.
JUnit offers many different assert-statements which should be used to verify the results of your tests. Do not use the standardassert() offered by Java, as this must especially be enabled to be executed!

When writing Tests for MATSim, do not extend the class TestCase, but extend MatsimTestCase, as that one offers some convenient methods related to MATSim (see Guidelines for more details).

Mini-Introduction to JUnit 4.7

JUnit is a framework for writing tests in Java. We currently use JUnit 4.7 for our tests, which still supports the older JUnit 3.8 syntax.

A simple example of a testcase:

 import org.junit.Assert;
 import org.junit.Test;

 public class MyTests {
     @Test
     public final void testOne() {
         // your code here...
         Assert.assertEquals(expectedValue, actualValue);
     }
     @Test
     public final void testTwo() {
         // your code here...
         Assert.assertNotNull(someObject);
     }
     @Test @Ignore("not yet fully implemented")
     public final void testThree() {
         // your code here...
         // TODO complete test
     }
 }

This code defines three tests (testOne, testTwo, testThree). JUnit offers many different assert-statements which should be used to verify the results of your tests. Do not use the standard assert() offered by Java, as this must especially be enabled to be evaluated! If a test is not yet fully implemented but you still want to commit the code, add the annotation @Ignore to the test. In that case, the test will not be executed. Note that your code must still compile when committing ignored tests.

If you need to read in or write out files to disk, use MatsimTestUtils as a rule:

 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;

 public class MyTests {
     @Rule public MatsimTestUtils utils = new MatsimTestUtils();
     @Test
     public final void testOne() {
         String inputFile = utils.getInputDirectory() + "myFile.txt";
         // your code here...
         String outputFile = utils.getOutputDirectory() + "myFile.txt";
         Assert.assertEquals(expectedValue, actualValue);
     }
 }

Please note that many methods of MatsimTestUtils can only be used in the actual test (marked with @Test), but not in a constructor or other initialization methods (e.g. in @Before).

 

Adding a dependency

Introduction

Maven maintains an explicit dependency graph, which code uses which other code in order to compile. If your code requires code from other developers, either from a different playground or in form of an external java library, this dependency must be manually registered in order to keep the code compiling.

Adding another playground as a dependency

Imagine you want to write code that relies on classes in someone else's playground. To do this, you have to specify this dependency on the playground of the other person:

  • First make sure you have the playground of the other person loaded in Eclipse (see Creating Eclipse Projects from Maven Modules).
  • Open the pom.xml file in your playground
  • Switch to the dependencies view (second tab at the bottom of the editor window)
  • Click on "Add Dependency"
  • In the dialog, type in the name of the other playground you want to use
  • Select the playground from the list and click ok.
  • Save the pom.xml.

Adding another library as a dependency

First, make sure the library has a license that is compatible with the GPL that MATSim uses. Gnu.org has an extensive list of compatible and non-compatible licenses. If the license is not compatible, do not use it. Also, do not use SNAPSHOT-versions of libraries as a dependeny. Only use stable versions.

  • Open the pom.xml file in your playground
  • Switch to the dependencies view (second tab at the bottom of the editor window)
  • Click on "Add Dependency"
  • In the dialog, type in the name of the other library you want to use
  • If the library is available by Maven, it will be listed with the available versions.
  • Select the library and the correct version from the list and click ok (Do not select a SNAPSHOT-version!).
  • Save the pom file.
If the library is not available, please contact me (mrieser).

Notes

Maven prevents reusing test code between different modules, i.e. moduleA cannot use code in moduleB/src/test/java. There are some fancy tricks to circumvent this limitation, please contact me (mrieser) if you really need this feature.

Adding a playground / contrib

Note: The following text will always mention "playground", but the same steps can also be used to create a new contrib-project inside "contribs".

In the playgrounds-project, there exists a directory _template which can be used as a starting point. This template already contains the directory structure and svn meta data for a typical playground. Best is, to copy the template using svn commands. That is:

  • on the command line, go to the playgrounds-project: cd /path/to/workspace/playgrounds/
  • execute svn copy _template nameOfNewPlayground
  • in Eclipse, refresh the playgrounds-project (right-click on project > Refresh, or F5)
  • in nameOfNewPlayground/pom.xml, change the Artifact Id and the project name from "_template" to the name of the new playground.
  • add the name of the new playground as a module in playgrounds/pom.xml
Important

Do not copy the _template directory in Eclipse or in the Explorer! In every case except "svn copy", the metadata will not be correctly updated, resulting in a corrupt svn checkout!

 

 

Configuration conventions

For non-programmers, MATSim is configured via the config file.  (For extensions, we have not yet found a good solution.)  If you make your code configurable, please observe the following hints.

Avoid automagic

Examples for automagic are:

  • If the code finds a file of a certain type, then do something special.
  • If the code finds a config module of a certain type, then do something special.
  • If some values are overwritten then some other values are cleared.

The problem with such automagic is that it is nearly impossible to write code that is robust against typoes.  As a result, one gets warnings such as

  • "File of certain type not found, thus assuming ..."  (This may either be a deliberate user decision, or a typo on the filename.)
  • "Config module of a certain type not found, thus assuming ..." (This may either be a deliberate user decision, or a type in the module name.)
  • "Config module of a certain type found, thus assuming ..." (This may be a leftover module from some other experiments.)
  • "When you are overwriting value X please remember that this also affects values Y and Z." (Which may be what the user wants, or not.)

If a user is not able to switch off warnings, she or he will eventually start to ignore them.  Which is not good. In that sense:

Avoid warnings that cannot be switched off

If a user is not able to switch off warnings, she or he will eventually start to ignore them.  Two aspects:

  • Automagic should be avoided (see above).
  • If the user is doing something non-standard/not-recommended, this may lead to a warning.  It would make sense to provide a switch to disable such warnings.  (Makes the configuration file a lot longer, though.)

 

Core Contributions - Review Process

Contributions to the core of MATSim (packages org.matsim.*) require a high quality and stability. Thus, it is usually not desired to develop now concepts directly in a org.matsim-package, even if the code should later be located there. Instead, contributions to the core should go the following way:

  • Draft of the proposed functionality by one or more developers in a playground
  • informing MATSim-Core developers of new code, request for comments and reviews
  • if the code is considered as finished, inform MATSim-Committee (currently mrieser, mzilske, wrashid) of new code
  • MATSim-Committee checks the new code/functionality
  • If the code is considered as useful/good by the Committee, the code is moved to org.matsim.core.api.experimental or another appropriate package.
  • Usage of the new code at least in the existing core-code. Smaller changes to the new code are still okay in this phase.
  • If the new code was proven to be stable/useful in the core, the new code will be moved to org.matsim.api (or other package) on the request of the MATSim Committee.

 

Developer Mailing List

If you're writing code in MATSim and have a playground or contrib-project, make sure to sign up to the matsim-developers mailing list. On the mailing list, we'll inform you about major refactorings of the code or other important changes related to the development of the MATSim project.

Documenting your code

Every public class should have the following items:

  • For every class, a statement what it is meant for.
  • For every class, a very rough description of what it does.
  • For every class, the author should be specified with the @author-tag

All these items should be written in a Javadoc block atop of the class.

 

Eclipse Configuration

MATSim is developed by several persons on different platforms. So we need a basic set of settings to work successfully together.

Text File Encoding

In the Eclipse Preferences, please set the Text File Encoding to "UTF-8", and the New Text File Line Delimiter to "Unix" (in General > Workspace).

Exception Handling

Exceptions are an important concept of Java, as they allow to signal special conditions that need special handling. Java differentiates between two types of Exceptions, checked and unchecked exceptions. Checked exceptions need to be declared in a method and code calling it needs to handle the possible exceptions, for example with a try-catch block:

public void readFile(final String filename) throws IOException {
  // IOException is a checked exception, it needs to be declared as "throws"
  if (!(new File(filename).exists()) {
    throw new IOException("File not found!");
  }
  // continue with normal code if file exists
}

public void doCalculation(final int a, final int b) {
  if (b == 0) {
    // a RuntimeException is an unchecked exception, it does not have to be declared
    throw new RuntimeException("b cannot be zero!");
  }
}

public void someMethod() {
  try {
    readFile("foo.bar");
    // a checked exception must be handled, either with try-catch or by declaring a "throws" on this method
  } catch (IOException e) {
    // handle exception
  }
  doCalculation(3, 0);
}

Java itself makes use of checked exceptions in many places, most notably in many I/O related methods (IOException). As many programmers dislike to handle checked exceptions correctly (to either handle them or declare them and move the handling further up the caller chain), one can often observe code like the following:

try {
  readFile("foo.bar");
} catch (IOException e) {
  e.printStackTrace(); // DO NOT DO IT LIKE THIS!
}

Do not do it like this, as then your code will continue to run as if there was no problem, but you may be missing data in your code, or data was not written out, etc. So you'll spend a lot of time wondering why your application did not do what it should have been.

Better wrap the checked exception in an unchecked exception and re-throw it:

try {
  readFile("foo.bar");
} catch (IOException e) {
  throw new RuntimeException("Could not read the file foo.bar.", e); // This is better
}

In addition, you can still declare the RuntimeException, such that other people using your method know that there could be an exception and optionally handle it:

/**
 * Does some calculation with a and b.
 *
 * @throws RuntimeException if b is zero
 */
public void doCalculation(final int a, final int b) throws RuntimeException {
  if (b == 0) {
    throw new RuntimeException("b cannot be zero!");
  }
  // continue calculation
}

Optionally, you could even create your own (unchecked) Exception:

public class MyCustomException extends RuntimeException {
  public MyCustomException(final String message) {
    super(message);
  }
}

 

Java-related Information

Most of MATSim-T is written in Java and requires Java 1.5 to run. While Java is widely known, we stumble from time to time over certain features or specialities we'd like to highlight. So this is the place to collect interesting and informative stuff about Java which might (or might not) have some relation to our code.

Memory usage, object pools and String.intern()

Memory usage is a critical point in multi agent simulations, just because there usually are so many of them. Thus, every single byte that is used to describe a single agent enlarges the memory consumption of the whole system massively.
Our agents have several attributes (like sex, car-availability, employment status), their plans contain activities with a type and legs with a mode. Each of these attributes are stored as Strings. Considering that even an empty String takes up to 40 bytes in Java and characters in Java are always 16bit, even a small string like "f' (for Person.sex) or "car" (for Leg.mode) takes a lot of memory—and that's for every single agent, leg and activity!
It is quite obvious that it does not make sense to have more than one string with the same content multiple times, especially when every instance uses so much memory. This is where object pools are often used: a so called pool stores commonly used objects exactly once, and other objects can refer to these objects instead of holding their own, identical, instances. In our case this means that instead of having separate instances of String for every "f", "car" or other attribute, each occurring value exists only once as a String-object, and all the agents, legs and activities only reference the corresponding pool object instead of storing their own instance. Having a population of 200k agents with 5 attributes would contain 1mio strings—that would be more than 40MB of RAM alone, not yet counting the memory used by plans, leg-modes, activity-types. But when using our "object pool" we only need about 10 or 15 different Strings (depending on the number of different values in the attributes), instead of 1mio!
The class String offers already such an internal object pool, so that this optimization can be used without much additional code:

String.intern();

The documentation to String.intern() reads as follows:

Returns a canonical representation for the string object.
A pool of strings, initially empty, is maintained privately by the class String.
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.

So, the setters for such string-attributes can now be written like the following one:

class Act {
  String type = null;
  ...
  public void setType(String type) {
    this.type = type.intern();
  }
}

Using this simple trick, the memory consumption was reduced by over 25%  when reading in 160k agents, while the time used for reading the agents did not change significantly (50secs vs 49secs). Reading larger populations should result in even larger memory savings, as most likely no additional strings have to be added to the pool, and all attributes can just reference to them.

Out of memory in Java 1.6

Using Java 1.6.0 can evoke OutOfMemoryErrors while parsing huge xml files. For details see: bugs.sun.com/bugdatabase/view_bug.do?bug_id=6536111

Problems with HashMap / HashSet and Iterator

HashSet/HashMap do not specify in which order elements are iterated. Testing such structures are very difficult (sorting is always necessary for comparison). Even more tricky it gets, if tests randomly fail. Debugging will be very hard. Use LinkedHashSet/LinkedHashMap instead. It can be iterated over insertion order.

Random numbers

Introduction to random numbers

Our simulations depend heavily on random numbers. But despite using random numbers, we still want the simulations to be deterministic, so that results can be reproduced by running the same scenario a second time.
Usually, random numbers in Java are generated by calling Math.random():

 double d = Math.random();

While this method returns a random number, the number is indeed random such as that in a second run of the same scenario, other random numbers would result and the simulation would no longer be deterministic. To overcome this problem, an instance of java.util.Random can be generated and initialized with a custom random seed:

 Random random = new Random();
random.setSeed(1234);
...
double d = random.nextDouble();

In this case, everytime the code is run, we get the same random numbers. As drawing random numbers is widely used in the code, MATSim-T offers a global instance of Random, which is automatically initialized with the seed specified in the configuration file:

 import org.matsim.core.gbl.MatsimRandom;
...
double d = MatsimRandom.random.nextDouble();

Choosing a random seed

What value should be used as random seed? Is a value of 1 better than the value 86294? As both numbers have the same probability to be chosen in the range from 0 to Integer.MAX_VALUE, any value is equally good for a random seed.
But this is only half of the story. We all know, that these random numbers are only pseudo-random—and they depend on the chosen seed!

Using Random numbers in PlanAlgorithms

PlanAlgorithms could be executed in parallel in multiple threads, e.g. during replanning. As the exact order of execution with multiple threads is not deterministic, the usage of MatsimRandom.random would lead to non-deterministic results. Instead, every instance of a PlanAlgorithm should have its own random number generator. Best way to realize that is that PlanAlgorithms that use Random numbers have a constructor where an object of type java.util.Random can be passed. When instantiating PlanAlgorithms, one can use MatsimRandom.getLocalInstance() to obtain a Random-object that can be passed to the PlanAlgorithm. A Random object received by getLocalInstance() is already correctly initialized to return useful random numbers (see below, Problems when setting the random seed).

Problems when setting the random seed

In our code, we set the random seed at the start of every iteration, so that we can restart a simulation at any iteration. The code was similar to the example code below:

 int baseSeed; // the random seed specified in the configuration file
...
for (int iteration = 0; iteration < 1000; iteration++) {
  MatsimRandom.random.setSeed(baseSeed + iteration);
  ...
}

After running several iterations we realized that the first agent was never chosen for re-planning (remember, they get "randomly" chosen for re-planning). A little bit of research revealed, that the first random number drawn after setting the random seed depends heavily on the random seed! Only a slight change in the random seed (in our case always +1 for each iteration) resulted in only a slight change in the value of the random number. The following figure shows the distribution of the first and second drawn random number after setting different random seeds. As can be clearly seen, the first drawn number only moves in a very small range. The second drawn numbers have a better distribution when the seed is only changed a little.
distribution of random numbers with differrent random seed
To overcome this problem, we decided that after setting a random seed, we draw one random number and immediately throw it away, as it seems not enough random.

int, Integer and Collections

Note: I consider the following as a rather advanced topic / optimization. I stumbled upon it while testing a new Java-profiler and thought I document it, 'cause others may be interested in it.  – Cheers, Marcel
While the Collections in Java are really nice and useful, they are not always the best solution performance-wise. In a recent case, a TreeMap<Integer, Integer> was used for travel time lookups. Each link in the network had such a map, storing a (departure) time and the corresponding travel time at that departure time. When searching for routes in the network, this map was accessed really a lot of times. As the queried time was not necessarily a key in the map, often the first entry of a tailmap (a map containing all objects whose key is equal or larger than a certain value) was requested to get the travel time at the next possible departure time.
When testing a profiler, I realized that a Integer.getValue() was called a crazy number of times, using a lot of time in total, even if I had this function-call nowhere explicitly in my method. Well, to find the correct entry in the map, the Integer-keys had to be compared, which was done by accessing their basic type values. That explained the many calls to this function, which made me think of how to implement the travel time lookup without using Integer-objects, but using the basic type int.
Replacing the map (sorted by key) with two int-arrays (int[]), one containing the keys, the other the corresponding values, allowed to use a binary search on the key-array (Arrays.binarySearch()) to find the correct array-index and thus to easily access the corresponding travel time in the value-array. With this change, no Integers were used, thus no (un-)boxing had to be done, and the accessed memory in the array should not be so scattered around then the single map-entry objects, leading to faster access. Finally the code ran in 25% less time!

So, what did we learn from this?
  1. Collections are not always the fastest way to do things. (Well, that's hopefully no surprise)
  2. Auto-Boxing and -Unboxing of basic types is a hidden performance leak.
I do not say that we should no longer use Collections, but in certain places where they are accessed really a lot of times, it may help to think a bit further and maybe try some other data structure for an additional speed-up. A profiler (such was YourKit) may clearly help to find such places.

MATSim Extensions

Introduction

As a lot of functionality in MATSim is created by PhD students, there is often a problem maintaining this functionality after the respective students finished their work and leave university.  In order to better communicate which features are "standard MATSim" which will (and have to) be maintained by the MATSim core developers, and which features are just "single-developer functionality", MATSim introduces the concept of "MATSim core" and "MATSim extensions".

The core will be maintained by the core developers, and should contain central functionality which is likely to stay in MATSim forever. Extensions can provide new, but stable, functionality developed to solve specific problems which can be of interest to others in the MATSim community.

Extensions will—as long as they compile and pass all tests—also be packaged for releases and be thus optional parts of MATSim releases. This requires that extensions follow certain guidelines, also in order to keep code maintenance and user support in reasonable bounds.

Requirements

  • You feel responsible for your extension
  • Document the functionality of your extension on the website
  • Document the usage of your extension on the website. This documentation should cover topics like (a) How to use it, (b) How to configure it, (c) if it has any special system requirements, (d) optionally have a small tutorial with sample data to demonstrate the functionality.
  • If your code offers one or more main classes, make sure to provide useful error message to the user in the case the user submits no or wrong arguments
  • If your code offers functionality to other code (e.g. special algorithms and data structures), such classes/interfaces should be well-documented using Javadoc comments.
  • You will maintain the code in the case that some updates in MATSim-Core break some functionality in your extension
  • You are wiling to assist interested users in the case something is not working as described by your documentation.

Creating your own extension

  • Create the code in your playground
  • Make sure you meet the code requirements outline above
  • Talk to a member of the MATSim committee to request a new contrib-project for your code.
  • If the committee agrees to your request, they will create a contrib-project for you, where you can move your code to.
  • Write documentation on the website about your extension to comply with the above-mentioned documentation requirements. To do this, add a Child Page to the "Using Extensions" page.
  • Once all the code and documentation requirements are met, your extension will be included in future releases and nightly builds will be created for it.

 

Prefer composition/delegation over inheritance

INHERITANCE NOT VERY ROBUST

There are numerous hints that inheritance is not very stable under refactoring; see, for example, Bloch, "Effective Java".

THE SHORT VERSION

  • If you think you need to use inheritance, restrict it to a package.  This can be achieved by making classes and methods only package-visible (no public/protected).  Having it within a package makes the situation very local, and thus much better to manage.
  • If you think you need to use inheritance beyond package limits, observe the following rule of thumb: Public or protected methods should be final or empty.
    (Which implies: If you are extending a class from elsewhere, you should make all of your public or protected methods final.)

THE LONG VERSION

The problem

The problem has something to do with the sequence of program execution.  Assume

class Base {
run() {
   partA() ;
   partB() ;
}
partA() {
   do1() ;
   do2() ;
}
partB() {
   do3() ;
   do4() ;
}
...

and some derived code

class Derived extends Base {
partA() {
   do1() ;
   doMyOwnStuff() ;
   do2() ;
}
...

Now assume that the maintainer of the base class decides that do3() should be done before do2().  Thus (for example):

class Base {
...
partA() {
   do1() ;
   do3() ;
   do2() ;
}
partB() {
   do4() ;
}
...

Now the derived code will not execute do3() at all.

One may argue that this is a consequence of bad design of the base class, e.g. that run() should call the doX() methods directly, or the designer should know beforehand in which sequence something needs to be done.  In practice, these arguments do not work: Levels of abstraction are difficult to get right from the start; and there may be situations where sequences of execution originally do not matter, and when it later turns out that they matter, they may be in the wrong sequence.

One may also argue that this is a consequence of bad design of the derived class, i.e. the programmer who overrides methods that have content should always call the super-method. That is

class Derived extends Base {
partA() {
   super.partA() ;
   doMyOwnStuff() ;
}
...

(Note that this is not the same thing as above.)

However, the base class maintainers cannot enforce that class users (those who extend the base class) do this.  One may argue that this is the problem of the class users, but in our setup  test failures resulting from such issues are, as a tendency, the responsibility of the base class maintainer (since her or his code change broke the tests).

Use delegation in eclipse

We therefore suggest to prefer composition (=delegation) over inheritance where this is possible.  It is only possible when the class that one wants to inherit from implements an interface.  In that case, the following is possible (with eclipse):

1. Write a class skeleton as follows:

class MyClass implements XXXInterface {
   private XXXInterface delegate = new XXXImplementation(...) ;
}

2. In eclipse, go to "source"/"generate delegate methods" and follow the instructions.

[[Somebody please add a screenshot here. thanks. kai]]

This will delegate all method calls to MyClass to the delegate.  Now you can modify some of the delegate methods as you like.

(This sometimes seems to provide less access than inheritance, but I don't think this is true as long as you assume that internal variables/fields are always private.)

The typical example

It is called "composition" since you can do this with more than one interface/delegate.  The classical example is something like

class MyCar implements HasSteering, HasBrakes, HasGears {
   private HasSteering steeringDelegate = new PowerSteering(...) ;
   private HasBrakes   brakesDelegate   = new SimpleBrakes(...) ;
   private HasGears    gearsDelegate    = new ElectronicGears(...) ;
}

where the eclipse generate delegate methods will produce methods such as

   public void steerToRight( double value ) {
      steeringDelegate.steerToRight( value ) ;
   }
   ...
   public void brake( double value ) {
      brakesDelegate.brake( value ) ;
   }
 

As one can see, this now allows operations such as

   MyCar car ...
   ...
   car.brake( 3. ) ;
   car.steerToRight( 0.3 ) ;
 

that is, the car is now composed of its internals.

Exposing the delegates

In MATSim, we often expose the delegation, that is, the syntax is

  car.getBrakes().brake( 3. ) ;
  car.getSteering().steerToRight( 0.3 ) ;
 

This has the advantage that, if you extend the interfaces, you do not need to adapt every implementation.  It is, clearly, not an option if you want to write a class (such as a PlanStrategy) that is later inserted into the code – that has to fulfill the contract defined by the interface.

Using Generics

Generics can be quite powerful, but also very cumbersome if used wrongly. Thus, respect the following rules:

  • Using Generics: that's okay, e.g. when using the Java collection classes
  • Providing Generics (i.e. introducing Generics in our own classes): only sparingly if you know exactly what you do. If you are not sure, do not use Generics!

Modules / Features / Projects

Documentation about the following MATSim Modules / Features / Projects is available:

Controler Structure

Structure of the Controler and its extension points

The figure shows the main structure of the MATSim Controler. Easily recognizable is the iteration loop consisting of plans-execution, scoring and replanning. At each one of the eight marked points, modules can easily add additional functionality to MATSim.

 

Counts

'package org.matsim.counts:'

  • Using xml-schema: 

    <counts xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="[SOME URL]/counts_v1.xsd"
    name="[SOME NAME]" desc="[SOME DESC]" year="[SOME YEAR]" layer="[SOME LAYER]">

  • Automated graph creation is available using the LGPL library JFreeChart (+ the LGPL library jCommon), the MPL and LGPL library  iText (for pdf output), overlib.js (for tooltips) (licence conditions to check) and stylesheets:
          • To create our own graphs you can derive them from the abstract class CountsGraph and plug them into CountsGraphWriter (in the run method).
          • The simulation values can be scaled with a user supplied scaling factor.
          • CountsGraphWriter creates either pdf files or linked html output (formated with css).
          • The html output provides tooltips (using overlib.js) and links on the graphs.
          • All needed helper files (e.g. stylesheets etc.) are automatically copied into the folder div of the iteration output folder, that is, the graph output folder can be used standing alone.

     Contact:

    In case of questions or comments, please contact: horni(at)ivt.baug.ethz.ch

Emissions

Emissions

Monetarizing car or HDV emissions can be done quite straightforward using the MATSim simulation results. This includes the following steps:

  • Modeling air pollution emissions on a micro scale for every link in the network (such as PM10, PM2,5, NOx, NO2, NMVOC and CO2).
  • Modeling noise emissions on a micro scale for every link in the network.
  • Modeling the resulting immissions based on land use data.
  • Calculating the marginal social costs of transport for every link in the network.
  • Proposing second-best pricing schemes in order to internalize the calculated external effects.

Making this operational is planned within the context of the "detailed evaluation" project (DFG).

 

Hybrid Electric Vehicles and Smart Grid

Overview

One of the main goals of the project is to model the electric demand of Plug-in Hybrid Electric Vehicles (PHEVs) and Electric Vehicles (EVs) and to find out, if the underlying electricity network can support such demand.

For doing this, MATSim has been coupled with a simulation model of the electricity network, which is called PHEV Management and Power System Simulation (PMPSS) [1]. Furthermore a charging module was added to MATSim, which decides the policy, when and how charging is performed by the vehicles. After relaxation of the MATSim Iterations, the charging information is given to PMPSS which finds out, if certain grid constraints have been violated (e.g. transformer capacities). This information is given back to MATSim and the charging module. As such, MATSim and PMPSS form an outer loop around the original MATSim loop.

 

Three type of charging schemes have been implemented in [1]: Dumb Charging, Dual Tariff Charging and Smart Charging. They are shortly described in the PDF poster, here.

Developer Infos

  • The energy consumption of vehicles is calculated based on the average speed they drive along a link. Event handlers are used to capture this information.
  • Controller listeners are used to implement the charging module and the scoring, which happens after the simulation.
  • As PMPSS is implemented in MATLAB, it is invoked from Java after a specified number of iterations, where the MATSim demand is assumed to be relaxed (e.g. 100 iterations).

 Reference

 [1] Waraich, R.A., M.D. Galus, C. Dobler, M. Balmer, G. Andersson and K.W. Axhausen (2009) Plug-in Hybrid Electric Vehicles and Smart Grid: Investigations Based on a Micro-Simulation, paper presented at the 12th International Conference on Travel Behaviour Research (IATBR), Jaipur, December 2009.
(http://www.ivt.ethz.ch/vpl/publications/reports/ab592.pdf)

 

AttachmentSize
electric-flowdiag.png112.43 KB
Plug-in Hybrid16.pdf3.28 MB

Matrices

Maintenance and Questions:

Marcel Rieser and Michael Balmer, senozon AG ({rieser, balmer}_at_senozon.com)

Javadoc:

http://www.matsim.org/javadoc/org/matsim/matrices/package-summary.html

In Brief:

This was used to store things like OD matrices inside matsim. Since we prefer to disaggregate such things right away into individual trips, this module was not maintained. It is not clear if maybe it should be re-surrected.

[mrieser] I recently cleaned the package up a bit, in that it no longer requires Locations (from the deprecated World concept) but just Ids, and that they work more stand-alone. Matrices are used mostly in demand modelling. As such, they are useful, but would probably need more cleanup to come up to standards.

 - think about interface Matrix to have different implementations, also backed by matrix-package (e.g. Jama, ...).
 - mostly used in initial demand modeling. MATSim needs *some* kind of matrix support for idm.
 - probably rename matrices/Matrix to odmatrices/ODMatrix to make clear it's not a general matrix impl?

Micro-simulation

Documentations for the following micro-simulations currently available:

JDQSim: I moved this to the user part of the documentation since I think it can be used from the config file only.  kai, apr'11

Modeling collective taxis in MATSim

Main concepts/features

Large Scale

The service is available 24h per day, 7 days a week.

The vehicles are ranging from minivans to minibuses (approximately 6 to 12 passengers)

The service works without fixed stations

Taxis can be taken on the fly (smart phones)

Modeling Hypothesis

Price and utility parameters based on those of other modes in MATSim-T

Available to all agents at every point in time and space

No capacity restrictions (unlimited capacity)

Bibliographic reference:

Ciari, F., M. Balmer and K.W. Axhausen (2009) Large scale use of collective taxis: a multi-agent approach, paper presented at the 12th International Conference on Travel Behaviour Research, Jaipur, December 2009.

Possible future developments

Michal Maciejewski is looking into using MATSim to generate realistic instances of the dynamic vehicle routing problem (DVRP). If one wants to avoid that the DVRP program can "cheat", requests for service should not come out of MATSim before their time.  There seem to be the following types of requests:

  1. Get me a taxi/courier as soon as possible.
  2. Get me a taxi/courier for a specified departure time.
  3. Get me a taxi/courier for a specified arrival time.

Let me first look at taxis (i.e. persons make requests for themselves).

The first seems to be relatively easy to model: The leg mode would be "taxi"; the person would end its activity, go into the corresponding departure handler, which would request a taxi and then put the person into the departure queue (presumably, the same as there is for pt, although I am not sure if there is one per link or just one per pt stop).

The second is more difficult.  Sending out the request when the activity starts is too early, and the DVRP may use that to its advantage.  Possibilities that come to my (kn's) mind:

  1. We add something like "prescheduled event" to matsim.  Then, an agent starting an activity at time t, could pre-schedule an event for time t + tau.
  2. Sending a request during an activity will only be implemented together with within-day replanning.
  3. The agent ends its activity when it makes the request, and then just sits in the departure queue.
  4. The agent can state when it wants to be woken up, but does not necessarily have to perform a departure.  It could instead send out the taxi request and go back to sleep.
  5. Activities of the same type, without intervening leg, may be "stitched together".

Option 1 seems plausible at first glance.  Yet, it looks like it will cause additional headaches if this is ever combined with within-day replanning (because matsim would need to check which pre-scheduled events an agent has left around when it changes its plan).  Given our past experiences with such "quick fixes", this does not sound like a great idea.

Option 2 seems plausible (to me).  Within-day agents might be contacted, say once a minute, and asked if they want to call taxi for a pre-scheduled time in the future.  A disadvantage, however, is that these requests would all come at the same time, and the DVRP optimizer might take (unwarranted) advantage of that fact.

Option 3 seems a plausible fix for the meantime (to me).  It will produce wrong results with respect to agent scoring, but at least it will generate correct taxi requests.

Option 4 looks attractive (to me).  A remaining question is how this should look in the plans file.  My current (apr'12) intuition would be that there could be additional stuff during the activity, i.e.

<act type="leisure" end_time="20:00:03">
   <subact type="taxirequest" time="19:23:33/>
</act>

A clear disadvantage would be the necessary modification of the plans file.  One could, however, initially keep the necessary data structure until the problem is sorted out.

Option 5:

<act type="leisure" end_time="19:23:33/>
<act type="taxirequest" duration="00:00:00"/>
<act type="leisure" end_time="20:00:03" />

This would be more consistent with the approach that we took with the legs ... i.e. leave the hierarchy of the xml file intact and sort it out somewhere else.  With the legs, it seemed a bit easier since for legs the utilities are just linear in the durations, but in the end the "removePtInteractionActivities" is also an instance of "sorting it out somewhere else".

Now courier service

Seems to me that I don't know enough about this.  Freight, at this point, is planned to be plugged into matsim by using "truck drivers".  I.e. from the point of view of matsim, the transportation of goods will just be a side effect of a driver moving a vehicle from A to B, and that vehicle being loaded with certain goods.

Clearly, we can still make up courier requests without following the goods.  For this, once more the within-day agents seems like the most consistent option.

Taxis in MATSim

Once there are requests, there need to be taxis.  Personally, I would start with a single taxicab.  In terms of implementation, this would probably inherit from what is currently (may'11) called ExperimentalBasicWithindayAgent.

(Using delegation/composition instead of inheritance is difficult with matsim agents, since "this" inside some delegated logic points to the delegate, not to the composing object.  Yet, the "this" is used to remove the agent from data structures, and insert it into others (e.g. at-activity data structure, wait data structure, in-vehicle data structure).)

As a first step, I would make the taxi agent, every time it arrives somewhere, generate a next activity location and then drive there.

As a second step, I would try to make that taxi agent pick up a waiting passenger and deliver it.

After some thinking, my intuition is that I would stay away from the pt code.  Picking up passengers can as well be done with regular arrival, I would think, and that would be much less intrusive.

Update (jul'11): There is an "AdapterAgent" in Michael Z.'s playground, and Michal M. has started using that for his taxicab prototype.

Router

There are now 3 least-cost path algorithms in package org.matsim.router:
- Dijkstra
- AStarEuclidean
- AStarLandmarks

For every router, there exists a class which computes some preprocessing data and is passed to the router class constructor in order to accelerate the routing procedure. The preprocessing classes are located in org.matsim.demandmodeling.router.util:
- PreProcessDijkstra
- PreProcessEuclidean
- PreProcessLandmarks

Dijkstra:
Condition: The link cost must be non-negative, otherwise Dijkstra does not work.

The new version is much faster on short routes than the former version (50 times as fast, if the start and end node of the route are ~1km away from each other) and diminutively faster on long routes (~1.5 times faster with preprocessing). Dijkstra can be used with or without preprocessing data (the preprocessing just marks all nodes that are in dead ends). Preprocessing does not take long (2 seconds on a network with 400'000 nodes on our computer leibnitz) and does not require much additional memory (~ 1 pointer per node) either, therefore it should be used where possible. Invoking Dijkstra may then look like this:

PreProcessDijkstra preProcessData = new PreProcessDijkstra();
preProcessData.run(network);
TravelCostI costFunction = ...
LeastCostPathCalculator routingAlgo = new Dijkstra(network, costFunction, preProcessData);
routingAlgo.calcLeastCostPath(fromNode, toNode, startTime);

If you don't want to preprocess the network, you can invoke Dijkstra as follows:

LeastCostPathCalculator routingAlgo = new Dijkstra(network, costFunction);

AStarEuclidean:
Is about 3 times faster than the above Dijkstra.
Conditions:
    - The same as  for Dijkstra: The link cost must be non-negative, otherwise Dijkstra does not work.
    - The length stored in the links must be greater or equal to the euclidean distance of the link's start and end node, otherwise the algorithm is not guaranteed to deliver least-cost paths. In this case PreProcessEuclidean gives out a warning message.
    - The CostCalculator which calculates the cost for each link must implement the TravelMinCostI interface, i.e. it must implement the function getLinkMinimumTravelCost(Link link). The TravelTimeCalculator class does implement it.

PreProcessEuclidean.run() is very fast and needs (almost) no additional memory.
Example invocation:
TravelMinCostI costFunction = ...
PreProcessEuclidean preProcessData = new PreProcessEuclidean(costFunction);
preProcessData.run(network);
...
LeastCostPathCalculator routingAlgo = new AStarEuclidean(network, preProcessData);
...

A note about the so-called overdo factor: You can drastically accelerate the routing of AStarEuclidean by providing an overdo factor > 1 (e.g. 1.5, 2 or 3). In this case, AStarEuclidean does not calculate least-cost paths anymore but tends to deliver distance-minimal paths. The greater the overdo factor, the faster the algorithm but the more the calculated routes diverge from the least-cost ones.
A typical invocation then looks like this: LeastCostPathCalculator routingAlgo = new AStarEuclidean(network, preProcessData, 2);

AStarLandmarks:
About double as fast as AStarEuclidean. PreProcessLandmarks.run() takes about 1 minute on 400'000 nodes on leibnitz and requires 2*X double values per node, where X is the number of landmarks. Currently, it is set to 16 (but can be set to another value, as 12 or 8 for example), so with 400'000 nodes we would need 2*8*16*400'000 bytes = about 100MB of additional memory.
Conditions: The same as for AStarEuclidean.
Example invocation:

TravelMinCostI costFunction = ...
PreProcessLandmarks preProcessData = new PreProcessLandmarks(costFunction);
preProcessData.run(network);
...
LeastCostPathCalculator routingAlgo = new AStarLandmarks(network, preProcessData);
...

Scoring

Currently the following documentation for scoring is available:

Implementing Scoring Functions

Overview

This article describes how originally scoring functions were implemented and how it works now.

Originally, each scoring function needed to implement the ScoringFunction interface. The interface contains the following method signatures: startActivity,endActivity, startLeg, endLeg, agentStuck, addMoney, finish, getScore and reset. The documentation of these methods can be found in the source code of the ScoringFunction interface.

This implementation functions fine, but has a few shortcomings. The most important is, that the scoring functions based on this interface are not resuable and often not extendable.

The New Approach

Inorder not to change the current interface, the following approach was taken to make modular scoring functions possible: Five Interfaces have been introduced, which just subdivide the original ScoringFunction interface. These interface together with the methods are listed:

  • ActivityScoring: startActivity, endActivity
  • AgentStuckScoring: agentStuck
  • BasicScoring: reset, finish, getScore
  • LegScoring: startLeg, endLeg
  • MoneyScoring: addMoney

The basic idea is, that a scoring function can consist of an arbitrary number of summand terms. For example you can have scoring terms just depending on a static properties of agents or depnding on Activities. Furthermore a leg part could consist of several summand terms itself.

Every scoring term must implement the BasicScoring interface. A class called ScoringFunctionAccumulator is at the heart of this approach: The scores of all scoring terms registered with this accumulator, are summed up at the end of the iteration, making both reusable and extensible scoring functions easy to implement.

Scoring Function Example

Please look at the package org.matsim.scoring.charyparNagel for an example, which contains the following elements:

  • All scoring terms which make up the CharyparNagelScoringFunction
  • A ScoringFunctionFactory, for wiring up all scoring terms using the ScoringFunctionAccumulator

Although it would be possible to just put all scoring terms into one class by implementing all scoring term interfaces, this approach is not advisable, as it runs counter to the modularity principle (which was the reason for providing this new approach).

Hints and Pitfalls

  • The final score of an agent is the sum of all scoring terms (all getScoring methods are invoked at the end of the iteration, which are registered with the ScoringFunctionAccumulator).
  • Note: Although all ScoringFunction could have just inherited from this interface, this different approach was choosen for making it explicit what needs to be implemented.

Trip structure analysis of activity plans

For a description of the algorithms see the respective child pages.

Configuring location type for trip structure analysis

The subtour analysis functionality can use either link or facility as the definition of a "location". The default is to use links. When using TripStructureUtils in code, this can be changed by passing true as the "useFacilitiesInsteadOfLinks" parameter. When using subtour mode choice, this can only be changed programmatically by using the setAnchorSubtoursAtFacilitiesInsteadOfLinks( boolean ) method of ChooseRandomLegModeForSubtour.

 

Subtour analysis

Description

The different variants of TripStructureUtils.getSubtours( ... ) provide a convenient way to access the subtour structure of a Plan.

Subtour is defined like the following:

  • A tour is the smallest sequence of consecutive trips where the origin activity of the first trip and the destination activity of the last trip have the same location.
  • This common location is called anchor point.
  • A tour may contain several "children" subtours if other tours can be identified within it. Thus a subtour can be defined as a tour within another tour.

Examples

  1. Imagine an activity plan with the location sequence A-B-C-A. All trips belong to the same tour with the anchor point A.
  2. Imagine the location sequence A-B-A-B-A. Two tours exist with the anchor point A. The location sequence A-B-A-C-A has the same subtour structure.
  3. Imagine the location sequence A-B-B-B-B-A. Each trip between the locations B and B constitutes a subtour of the father tour with anchor point A.
  4. Note that there may be plans without tours: the sequence A-B-C-D doesn't contain any tour; the sequence A-B-C-B-D contains a subtour of anchor point B, but the "father" sequence of this subtour is not a tour. In the results of the getSubtours(...) methods, those sequences are identified as "open" subtours (Subtour.isClosed() returns false).

Usage in MATSim

For up-to-date information about the way to use those methods, the reader is refered to the javadocs.

Subtour level mode choice

Description

The ChooseRandomLegModeForSubtour algorithm, used in the SubtourModeChoice module, provides a mode choice procedure inspired by Miller et al.'s (2005) individual trip maker mode choice. It computes a choice set of feasible trip mode combinations given

  • the subtour structure of a home-based activity plan,
  • the set of modes available to the agent, and
  • the set of chain-based modes, i.e. modes an agent is bound to when chosen for a subtour (default: car, bike). Chain-based modes are opposed to trip-based modes for which no such commitment exists (such as public transport modes or walk). This means, chain-based modes are interpreted of the actual means of transportation the agent owns/has access to (the agent's car, the agent's bike). A boundary condition for the choice set generation is that the chain-based modes must be at home again at the end of the home-based activity plan.

This section provides a basic description of the idea behind subtour analysis and subtour-level mode choice.

Examples

Consider the following scenario:

  • Activity plan with location sequence A-B-A-C-A, with A being the location identifier of the home activity.
  • Modes available to the agent: car, pt, walk
  • chain-based modes: car

The plan consists of two subtours, each of which might be performed with one of the car. Alternatively, each trip might be performed woth a trip-based mode (walk, pt). The resulting choice set is:

car-car-car-car

car-car-pt-pt
car-car-walk-walk
car-car-walk-pt
car-car-pt-walk

pt-pt-car-car
walk-walk-car-car
walk-pt-car-car
pt-walk-car-car

pt-pt-pt-pt
pt-pt-pt-walk
pt-pt-walk-pt
pt-pt-walk-walk
pt-walk-pt-pt
pt-walk-pt-walk
pt-walk-walk-pt
pt-walk-walk-walk

walk-pt-pt-pt
walk-pt-pt-walk
walk-pt-walk-pt
walk-pt-walk-walk
walk-walk-pt-pt
walk-walk-pt-walk
walk-walk-walk-pt
walk-walk-walk-walk

See also attached Figure 1 from Miller et al. (2005).

Using subtour level mode choice in MATSim

The subtour-level mode choice algorithm is used in the SubtourModeChoice replanning strategy. The behavior of this strategy can be configured by the subtourModeChoice config group, which allows to define the different parameters of the algorithm as defined above:

<module name="subtourModeChoice" >

     <!-- Defines the chain-based modes, seperated by commas -->
     <param name="chainBasedModes" value="car,bike" />

     <!-- Defines whether car availability must be considered or not. A agent has no car only if it has no license, or never access to a car -->
     <param name="considerCarAvailability" value="false" />

      <!-- Defines all the modes available, including chain-based modes, seperated by commas -->
      <param name="modes" value="car,pt,bike,walk" />
 </module>
 

References

Miller, E. J., M. J. Roorda und J. A. Carrasco (2005) A tour-based model of travel mode choice, Transportation, 32 (4) 399–422.

Within-day replanning. Status: experimental

There are (at least) two versions:

  • One approach, put forward by Christoph Dobler, which takes existing agents with plans and modifies future parts of their plans.
  • Another approach, put forward by Kai Nagel and Michael Zilske, which re-programms the agent from the inside out.

In the end, each approach will be able to emulate the other one, so it may come down to a matter of taste.

For general conceptual material see

If any of these links are not working, check for packages with "withinDay" in their name in the tutorial section of the matsim javadoc or the matsim code.

Reference for the first variant:

Some links to related material:

Policy Measures

Possible policy measures, and how they might be implemented in MATSim. A classification with respect to the "four E" (Economy, Engineering, Education, Enforcement) will follow.

Access / speed limitations to some areas for special types of vehicles

For example:

HDVs (heavy duty vehicles) / cars in general are not allowed to enter the city center.

 

Modelling options in MATSim:

  • Either by editing the network file and changing the "mode=car" and/or "freespeed" for a bunch of links.
  • Time dependend freespeed changes could in principle be modeled with the help of "networkChangeEvents".
  • Or by changing "mode=car" to something like "vehicleType=passengerCar, walk, ..." and others to "vehicleType=passengerCar, publicTransitVehicle, heavyDutyVehicle,...); This would probably be easier when configuring the router?!
  • Or by defining a list of links where some "vehicle types" are not allowed (additional network-like xml file); here the router needs to know this additional file. For the state of the art regarding "vehicle types" see here. :)
  • Different freespeed for different vehicle types on the same network is not possible with the actual QueueSim / QSim.

 

Changes of the spatial structure

For example

  • increase of mixed land use areas
  • increasing the density
  • decentral services (shopping, schools, medical facilities, ...)
  • changes in the tax system (commuting, property)

Modelling options in MATSim:

  • changing the land use is possible in principle, but needs to be done by other tools or manually
  • sensitivity does only exist if location choice is switched on; as of now, there is no useable model for "primary" activity (work, education) location choice; there is a model for "secondary" activity (shopping, leisure, ...) location choice but we do not know how realistic the sensitivies will be

Changes of user costs

For example changes in transportation costs due to...

  1. higher fuel costs
  2. road pricing schemes
  3. lower public transit ticket prizes
  4. ...

Modelling options in MATSim:

  1. This can easily be set in the config under the module "planCalcScore" >> "monetaryDistanceCostRateCar" [unit_of_money / m]
  2. Global distance based road pricing schemes can be modeled as in 1. Lokal distance based road pricing schemes have already been modeled for Zurich (for an overview of the publications see here), using the module "roadpricing" with a XML-file for defining the tolled links. Cordon and Area pricing schemes are implemented, but, (as far as I know) not tested! Cordon might work, whereas for Area, there are methodological issues that are not solved. For further information please see here in the JavaDoc.
  3. When assuming costs per km for public transit, this can also be set in the module "planCalcScore" >> "monetaryDistanceCostRatePt" [unit_of_money / m]; it should work quite well as an approximation; otherwise, e.g. in the case of modeling step function like cost curves, this needs to be implemented.
  4. ...

Remark: make sure that (i) the router and (ii) the scoring function do perform the distance cost / utility calculations appropriately!

Evacuation of Tokyo?

This is not a policy evaluation, but a rule-of-thumb estimate how long it would take to evacuate a large city, in this case Tokyo.  It is not meant as any kind of policy advice but it is a very simple combination of numbers that seem plausible in the situation.

Assumptions (to get started):

  • We evacuate to the south only.
  • There are 35 million persons in the Tokyo area.

Evacuation by car.  Assumptions (to get started):

  • 2 persons per car
  • 2000 cars per hour per lane (optimistic)
  • 2 x 2 freeway lanes going through to the south (we have never been there; from the maps, this looks rather optimistic)

==> 16'000 persons / hr

Evacuation by bus.  Assumptions (to get started):

  • 30 persons per bus
  • 1000 buses per hour per lane
  • 2 x 2 freeway lanes towards the south (see above; for buses, this looks even more optimistic)

==> 120'000 persons / hr

Evacuation by train.  Assumptions (to get started):

  • 1000 persons per train
  • 24 trains per hour (this seems rather optimistic)

==> 24'000 persons / hr

Taking the bus and train numbers together, one obtains 150'000 persons / hr.  Dividing the 35 million inhabitants by that number results in 233 hours or approximately 10 days of evacuation times.

Sensitivities:

  • using the return lanes ("contraflow evacuation") would in theory double the road capacity.  In practice, this seems hopeless because (1) presumably this was never tried in these locations, and (2) it seems unrealistic to keep this up for 10 days.
  • the evacuation by bus could probably not be maintained because Tokyo would run out of buses.  Buses would need to return to pick up additional passengers.
  • cars/buses will break down/run out of gas while on the way
  • in theory, buses could be loaded with more than 30 passengers in the average.  In practice, evacuated persons want to bring some belongings plus their pets, and so this seems hopeless.  (The number comes from H. Klüpfel, who takes it from German evacuation procedures.)
  • in theory, cars could be loaded with more than 2 passengers in the average.  In practice, the same argument as with buses holds.  In addition, it seems difficult to have the management capabilities to organize more persons into a car.

Overall: the 10 days look rather optimistic

Things that we cannot judge:

  • It is not enough to get those persons out of Tokyo; they must be placed somewhere, provided with water, food, health services, etc.  Our own intuition is that the only solution would be to place them with other persons, i.e. every household in the south must accept a certain number of evacuees.
  • In case of a nuclear cloud, people might be safer inside a buildup city, and with a surrounding and functional infrastructure, than in a bus or car on the way.
  • Many others ...

This text came out of a telephone and email exchange between H. Klüpfel (www.traffgo-ht.com) and K. Nagel (www.vsp.tu-berlin.de), with input from K. Axhausen (www.ivt.ethz.ch).

Improvements of non-motorized transport modes

For example:

  • better bicycle network; network rental stations
  • improvements at the signals
  • safety improvements
  • pedestrian zones
  • improvements of the spatial quality

Modelling options in MATSim:

  • one can use "teleportation" of the "other" modes.  This is always an option.  It is not completely clear (to me) how the speeds and generalized costs are set for this (more specifically: one can set them in the config, but I do not know how they are used)
  • one can use a microscopic simulation of the "other" modes.  This is experimental, and there is no interaction between the modes.

With teleportation:

  • changing the behavioral parameters ("betas") for non-motorized modes is possible (as a placeholder for system-wide improvements)
  • it would not be clear which improvements correspond to what changes of the "betas"

Improvements of the public transit mode

Changes to the public transit mode, e.g.:

  1. Shortening system-wide travel times ("teleport mode").
  2. Changing individual lines.
  3. Public transit acceleration at intersections.
  4. ...

Modelling options in MATSim:

  1. In teleportation mode: module "planscalcroute" >> ptSpeedFactor. This has been done e.g. here.
  2. This has been done here (chapter 8.2). One could also think about raising the public transit capacities for some connections while reducing car capacities at the same time. This, obviously, would have to be done in the network.
  3. Not yet implemented.
  4. ...

 

Parking space management

For example:

People need to pay for public parking lots.

 

Modelling options in MATSim:

  • A monetary prize for parking in some areas could probably be modeled.
  • Modelling traffic due to people looking for a parking lot is currently not possible (parking location choice neccessary - but not withinday replanning!).
  • But: people could in principle be forced to park their car at a random location around their activity location; splitting the leg into a car and a walk part would then need to be implemented.

Raising awareness for environmentally friendly transport modes

A policy often discussed in practice:

Trying to convince people to change their mobility behaviour towards environmentally friendly modes. Therefore people have to try out this alternative.

 

Modelling options in MATSim:

Forcing people to use a bike / public transit / ride sharing / walk plan and fix it in the choice set.

Technical changes to the vehicle fleet

For example:

Due to technical changes and (monetary) incentives set up by the state, environmentally friendly and low emission cars (and busses) become more attractive. Thus, the vehicle fleet and its distribution of emission levels changes.

 

Modelling options in MATSim:

In order to model this, "vehicle types" have to be distributed to persons or households, e.g. based on survey data. One could now set a certain percentage of electric / low emission cars and that substitute either randomly chosen cars or older cars.

Therefore we need:

  • input data from a survey
  • an idea on how to set the substitution effect
  • vehicle types in the simulation (see here)
  • some kind of car-usership model within the households, since car-ownership is usually household-fine...