Skip to content
Joris Borgdorff edited this page Jul 11, 2016 · 10 revisions

Installing the SIM-CITY framework

The command-line tools to the SIM-CITY framework consists of SIM-CITY client. The JSON-REST interface is called SIM-CITY webservice. If you have any questions, please submit an issue.

HTTP server

All services will be served over HTTP. To allow multiple services on the same host and port, we use nginx as a proxy server.

Install it with

sudo apt-get install nginx

and add proxies to /etc/nginx/sites-enabled/0-default, e.g.

      location /couchdb {
          proxy_pass http://127.0.0.1:5984;
      }

      location ~ /\.ht {
          deny all;
      }

CouchDB service

CouchDB is used to store the input and output of simulations, and keep track of where they are running. It has its own authentication system.

Unless you already have access to a CouchDB installation, install CouchDB, either as a system package:

sudo apt-get install couchdb

or with docker:

docker install klaemo/couchdb    

It can be administered at http://localhost:5984/_utils/index.html. Set up an admin user here. Once it is configured, add a proxy to it with nginx. The database will be initialised with the SIM-CITY client.

Geoserver

Geographic data will be stored in a PostGIS database and served with a Geoserver. There is a howto for installing these: https://nlesc.gitbooks.io/geospatial-handbook/content/geoserver-howto.html.

SIM-CITY client

The SIM-CITY client manages starting jobs, and assigning tasks. See the README therein to see its usage.

It needs to be installed at two locations: your laptop and any cluster you want to run on. For example, assume you're using the <lisa.surfsara.nl> cluster. First, add lisa to your ssh path, by adding the following lines to ~/.ssh/config:

Host lisa
HostName lisa.surfsara.nl
User myuser

and copy your public SSH key to Lisa:

$ scp ~/.ssh/id_rsa.pub lisa:.
$ ssh lisa
lisa$ mkdir -p .ssh
lisa$ cat id_rsa.pub >> .ssh/authorized_keys
lisa$ rm id_rsa.pub

On your laptop and on Lisa, make the following ~/.simcity_client file:

[task-db]
# CouchDB URL
url = https://myhost/couchdb/
# CouchDB username
username = myuser
# CouchDB password
password = mypassword
# CouchDB database
database = simcity
    
[Execution]
# Base execution directory for local working files
tmp_dir = $TMPDIR
# Base directory for output files that need to be stored
output_dir = $HOME/input
# Base directory for input files
input_dir = $HOME/output

[lisa-host]
# where the run script is located
path = sim-city-client/scripts
script = lisaRun.sh
host = torque://lisa
method = xenon

See sim-city-client/config.ini.dist for additional configuration examples.

On lisa, run:

mkdir $HOME/input $HOME/output $HOME/tmp
git clone https://github.com/indodutch/sim-city-client.git
module load python/2.7
pip install --user virtualenv
~/.local/bin/virtualenv simcity

And add the following to ~/.bashrc:

export TMPDIR=${TMPDIR:-$HOME/tmp}
module load python/2.7
. simcity/bin/activate

Then run

source ~/.profile
make install

On your own machine, run the same commands except module load python/2.7.

Initialise the CouchDB database for the SIM-CITY client by running:

python sim-city-client/scripts/createDatabase.py myadmin

Now you can install any command or model that you want on lisa, and run it with

sim-city-client/scripts/submitJob.py ~/command.sh lisa

To run it locally as well, install exactly the same command ~/command.sh on your own machine. You can then process jobs locally with

sim-city-client/scripts/run.py -eP `hostname`-`date +%F%T`

If a command had an error and you have fixed the reason for the error, you can run

sim-city-client/scripts/scrub.py error

If you don't want to process the commands with errors anymore, run

sim-city-client/scripts/deleteFromView.py error

If jobs were deleted before they started, or ended before they could register this to the database, run

sim-city-client/scripts/deleteFromView.py pending_jobs

and

sim-city-client/scripts/scrub.py active_jobs

Then running

sim-city-client/scripts/startJob.py lisa

will succeed for sure.

SIM-CITY web service

To access these functionalities from a web service, install sim-city-webservice:

git clone https://github.com/indodutch/sim-city-webservice.git
cd sim-city-webservice
pip install -U .

To the ~/.simcity_client file, add a few new lines:

[Simulations]
# the maximum number of concurrent jobs that the service has
max_jobs = 4
# default host to submit to
default_host = lisa

And then serve the service with

 make serve

To start the web service automatically, create a new daemon that does these steps using your local daemon provider (e.g., upstart or systemd).

SIM-CITY explore

SIM-CITY client can also be used to make a scenario exploration. For example, in a fire response simulation, a fire is started in every ward, and for each the fire response time is measured. First the job is submitted in python:

import csv
import simcity
import sys
import os
import geojson

if len(sys.argv) != 2:
    sys.exit("Usage: {} ensemble_name".format(sys.argv[0]))

host = "lisa"
command = "~/bangalore-matsim-0.4/matsim.sh"
version = "0.4"
simulation = 'matsim'
ensemble = sys.argv[1]
max_jobs = 16

# starting a fire in the center of each ward
with open('input/blr/gis/wards.csv') as f:
    for row in csv.DictReader(f):
        fire = {'id': row['id'], 'x': row['lat'], 'y': row['lon']}

        simcity.add_task({
            'command': command,
            'name': simulation,
            'version': version,
            'ensemble': ensemble,
            'input': {
                'numberOfThreads': 16,
                'fires': [fire],
                'populationSampleFactor': 0.01,
            },
        })

for i in range(max_jobs):
    simcity.submit_if_needed(hostname=host, max_jobs=max_jobs)

If some jobs have gotten an error, evaluate why, and scrub them with

python sim-city-client/scripts/scrub.py error
python sim-city-client/scripts/submitJob.py lisa

After the simulations have finished, analyse the output in python:

def add_responsetime(wards):
    """
    Add response times to a dict with geojson wards.

    In the ward properties, a first_responder and second_responder
    property are added, with response time in seconds. This data is
    retrieved from the ensemble, which is assumed to start a single
    fire in each ward.
    """
    db = simcity.get_task_database()
		
    design_doc = simcity.ensemble_view(
        db, simulation, version,
        '/couchdb/' + simcity.get_config().section('task-db')['database'], ensemble)
		
    tasks = db.get_from_view('all_docs', design_doc=design_doc)
		
    for task in tasks:
        if task.done == 0:
            print("skipping ward {0}, its simulation is not done"
                  .format(task.input['fires'][0]['id']))
        elif task.done == -1:
            print("skipping ward {0}, its simulation has errors: {1}"
                  .format(task.input['fires'][0]['id'], task.error))
        else:
            try:
                # Get the fire engine paths data from the database
                firepaths_str = simcity.download_attachment(task, task.id, 'GeoFirePaths.json')
                # Parse it
                with open(os.path.join(task.id, 'GeoFirePaths.json')) as f:
                    firepaths = geojson.load(f)
                collection = geojson.FeatureCollection.to_instance(firepaths)
                # Collect response times and put it in the relevant wards.
                responsetime = sorted([path.properties['responsetime'] for path in collection.features])
                ward = wards[task['input']['fires'][0]['id']]
                ward['properties']['first_responder'] = responsetime[0]
                ward['properties']['second_responder'] = responsetime[1]
            except (KeyError, IndexError) as ex:
                print(ex)
Clone this wiki locally