Personal tools
You are here: Home BlueSky Framework Running BlueSky through Web Services
BlueSky Framework

USFS LogoNational Fire Plan logoNASA logoJoint Fire Science Program LogoEPA logoBlueSky is a framework for model management. It facilitates the use of predictive models that simulate the cumulative impacts of smoke on air quality from forest, agricultural, and range fires.

BlueSky is maintained by the U.S. Forest Service AirFire Team and Sonoma Technology, Inc.
AirFire LogoSonoma Technology, Inc. Logo

 

Running BlueSky through Web Services

last modified Jul 30, 2009 08:44 PM

How to run BlueSky on our servers using web services calls.

Overview

Since version 3.1, the BlueSky Framework now has built-in support for remote access using web services.  The framework provides a consistent interface to the models distributed with BlueSky.  Currently, this interface is accessible using the XML-RPC protocol.  Other protocols may be supported in the future.

Steps of a BlueSky web services call

Essentially, calling a BlueSky model using web services is a request-response process.  Your computer (known as the client) constructs an XML-RPC message, called a request.  The request contains the name of the model you want to call, and information about a fire or fires of interest.  The client sends the request to the BlueSky server, using the HTTP protocol (the same network protocol that web browsers use to communicate with web servers).  At the server, the BlueSky Framework unpacks the request and builds a FireInformation data structure.  This data structure is a software object that contains everything BlueSky knows about a given fire or set of fires.  Next, the framework uses the FireInformation structure to initialize a BlueSky module for the model you have selected.  The BlueSky module uses information from the FireInformation structure to set up a model run (e.g. by creating model configuration files, constructing data arrays, etc.) and then runs the model.  Then the BlueSky module takes the output from the model and uses it to update the FireInformation structure.  The BlueSky server repacks the FireInformation data structure into an XML-RPC message, called the response.  BlueSky returns this response back to the client.  The client (your computer) then unpacks this response and uses the results.

A program or script that uses a BlueSky web service will generally need to follow these steps:

  1. Collect information about the fire(s)
  2. Build a local data structure that resembles the FireInformation object
  3. Use an XML-RPC library to translate your local data structure into an XML-RPC request
  4. Use an XML-RPC or HTTP library to send your XML-RPC request to the BlueSky server and get a response back
  5. Use an XML-RPC library to translate the XML-RPC response back into a local data structure
  6. Read the results from the local data structure

The format of the call

The actual "wire protocol" or format of data passed between the client and server are described by the XML-RPC specification (BlueSky also uses the <nil/> value extension).

The format of the data structure is actually determined by the wrapper module, not by the Framework itself.  However, nearly all web service calls will take a single FireInformation object as their only parameter.  For nodes that require more than one input structure (that is, for nodes that have more than one input "plug" when connected in a BlueSky graph), you must pass a structure for each of its inputs.

The structure of the FireInformation object and its sub-objects is described by the $BS_DIR/base/etc/types.ini file.  The BlueSky Framework will attempt to infer the correct structure if it is simply given a flat mapping of field names to values.  For example, if the input is a structure that just contains

{"latitude": 45.46, "longitude": -114.961, "date_time": "20090728", "area": 100}

then the framework will infer the structure:

/*FireInformation*/ {
    "fire_locations": /*array*/ [
        /*FireLocationData*/ {
            "id": "UNKNOWN",
            "owner": null,
            "latitude": 45.46,
            "longitude": -114.961,
            "fips": null,
            "elevation": null,
            "slope": null,
            "state": null,
            "county": null,
            "country": null,
            "date_time": "200907280000+00:00",
            "duration": null,
            "snow_month": null,
            "rain_days": null,
            "wind": null,
            "fuel_moisture_10hr": null,
            "fuel_moisture_1khr": null,
            "type": null,
            "scc": null,
            "area": 100.0,
            "time_profile": null,
            "fuels": null,
            "consumption": null,
            "emissions": null,
            "plume_rise": null,
            "metadata": /*struct*/ { }
        }
    ],
    "fire_events": /*array*/ [ ],
    "dispersion": null,
    "start_date": "200907280000+00:00",
    "hours_to_run": 24,
    "emissions_offset": 0,
    "dispersion_offset": 0,
    "emissions_start": "200907280000+00:00",
    "emissions_end": "200907290000+00:00",
    "dispersion_start": "200907280000+00:00",
    "dispersion_end": "200907290000+00:00",
    "metadata": /*struct*/ { }
}

Note that the structure has been expanded into a FireInformation object, containing a "fire_locations" list, which contains a FireLocationData object, which in turn contains the values passed in.  A few other values (mostly date/time data) are given reasonable default values, but most values not explicitly provided in the input are inferred to be null. 

Expected output

Since BlueSky Framework nodes can have more than one output structure, the return value from the XML-RPC call will always be a <struct> element.  This <struct> will contain an entry for each output from the node, indexed by name.

For example, if the above structure is passed into the "FCCS" fuel-loading model, using the BlueSky web service, the response structure will contain a single element named "fires".  The "fires" structure will look like this:

/*FireInformation*/ {
    "fire_locations": /*array*/ [
        /*FireLocationData*/ {
            "id": "UNKNOWN",
            "owner": null,
            "latitude": 45.46,
            "longitude": -114.961,
            "fips": null,
            "elevation": null,
            "slope": null,
            "state": null,
            "county": null,
            "country": null,
            "date_time": "200907280000+00:00",
            "duration": null,
            "snow_month": null,
            "rain_days": null,
            "wind": null,
            "fuel_moisture_10hr": null,
            "fuel_moisture_1khr": null,
            "type": null,
            "scc": null,
            "area": 100.0,
            "time_profile": null,
            "fuels": /*FuelsData*/ {
                "fuel_1hr": 0.4,
                "fuel_10hr": 2.2,
                "fuel_100hr": 2.8,
                "fuel_1khr": 8.3,
                "fuel_10khr": 0.7,
                "fuel_gt10khr": 0.5,
                "shrub": 0.0,
                "grass": 0.14,
                "rot": 1.0,
                "duff": 1.92,
                "litter": 1.0,
                "canopy": 4.16,
                "metadata": /*struct*/ {
                    "VEG": "Lodgepole pine forest",
                    "fccs_number": 22
                }
            },
            "consumption": null,
            "emissions": null,
            "plume_rise": null,
            "metadata": /*struct*/ { }
        },
    ],
    "fire_events": /*array*/ [ ],
    "dispersion": null,
    "start_date": "200907280000+00:00",
    "hours_to_run": 24,
    "emissions_offset": 0,
    "dispersion_offset": 0,
    "emissions_start": "200907280000+00:00",
    "emissions_end": "200907290000+00:00",
    "dispersion_start": "200907280000+00:00",
    "dispersion_end": "200907290000+00:00",
    "metadata": /*struct*/ { }
}

Example scripts

Here is an example XML-RPC client written in Python.  This is a fully-functional utility script that takes latitude and longitude on the command line, queries the FCCS fuel loading module, and writes the output fuelbed information to the screen:

#!/usr/bin/env python

import os
import sys
import xmlrpclib
import datetime

WEB_SERVICE_URL = "http://blueskyweb.sonomatech.com/xml-rpc.py"

def main():
    # Parse command line arguments
    try:
        latitude, longitude = sys.argv[1:]
    except ValueError:
        print "Usage: %s <latitude> <longitude>" % os.path.basename(sys.argv[0])
        sys.exit(1)
    
    # Construct request structure
    requestData = {
        "latitude": float(latitude),
        "longitude": float(longitude),
        "area": 100.0,
        "date_time": datetime.date.today().strftime("%Y%m%d")
        }

    # Construct XML-RPC proxy
    bluesky = xmlrpclib.ServerProxy(WEB_SERVICE_URL, allow_none=True)

    # Send request, and retrive response
    print "Sending request to %s..." % WEB_SERVICE_URL
    responseData = bluesky.FCCS(requestData)

    # Extract FireInformation from response
    fires = responseData["fires"]

    # Write output
    print "Got response, %d fires returned:" % len(fires["fire_locations"])
    for i, fireLoc in enumerate(fires["fire_locations"]):
        print
        print "Fire #%d: %s" % (i + 1, fireLoc["id"])
        print "  Latitude: %1.5f" % fireLoc["latitude"]
        print "  Longitude: %1.5f" % fireLoc["longitude"]
        if fireLoc["fuels"]:
            print
            if "VEG" in fireLoc["fuels"]["metadata"]:
                print "  Vegetation type:", fireLoc["fuels"]["metadata"]["VEG"]
            print "  1-hr fuels: %1.2f" % fireLoc["fuels"]["fuel_1hr"]
            print "  10-hr fuels: %1.2f" % fireLoc["fuels"]["fuel_10hr"]
            print "  100-hr fuels: %1.2f" % fireLoc["fuels"]["fuel_100hr"]
            print "  1,000-hr fuels: %1.2f" % fireLoc["fuels"]["fuel_1khr"]
            print "  10,000-hr fuels: %1.2f" % fireLoc["fuels"]["fuel_10khr"]
            print "  >10,000-hr fuels: %1.2f" % fireLoc["fuels"]["fuel_gt10khr"]
            print "  Duff: %1.2f" % fireLoc["fuels"]["duff"]
            print "  Grass: %1.2f" % fireLoc["fuels"]["grass"]
            print "  Litter: %1.2f" % fireLoc["fuels"]["litter"]
            print "  Rotten fuels: %1.2f" % fireLoc["fuels"]["rot"]
            print "  Canopy: %1.2f" % fireLoc["fuels"]["canopy"]

if __name__ == '__main__':
    main()

Creating a web page tool that uses web-services

An example JavaScript implementation is available at http://blueskyweb.sonomatech.com/webservicetest.html.

This uses the JavaScript XML-RPC library from http://phpxmlrpc.sourceforge.net/jsxmlrpc/.  (I made a small change to the library to add support for the <nil/> value extension to the XML-RPC spec.)  A copy of this library, with the patch applied, is also distributed with the BlueSky Framework, under $BS_DIR/base/wwwroot/xmlrpc_lib.js.

BlueSky Playground

The BlueSky Playground is a tool for exploring the effects of different combinations of models.  It uses XML-RPC web services to communicate with the BlueSky Framework, enabling users to run models on demand, as well as compare results from different models.

Document Actions