wiki:BossaExampleOne

Version 12 (modified by davea, 16 years ago) (diff)

--

Bossa tutorial

Create a Bossa server

Install the BOINC software on a Linux system (or run the BOINC server virtual machine in a VMWare player on any computer).

Use make_project to create a BOINC project named "test":

> cd boinc/tools
> make_project --web_only test

Edit httpd.conf as directed (you'll need root access to do this). Let's say your server's domain name is "a.b.c".

Visit http://a.b.c/test/create_account.php and create an account for yourself.

Example application

We'll create an application in which volunteers view images, looking for ellipses on a noisy background. Their task is to click on the center of the ellipse, or to indicate that there is no ellipse. Here's an example:

(this has an ellipse slightly below/left of center).

Visit http://a.b.c/test_ops/bossa_ops.php, and create an application with short name "bossa_example".

The application is define by three scripts in ~/projects/test/html/:

  • ops/bossa_example_workgen.php: this generates more jobs.
  • user/bossa_example.php: show a job, and handle user response.
  • inc/bossa_example.inc: compare and handle completed jobs.

We'll go through these scripts and explain how they work. To develop your own Bossa applications you'll need to write corresponding scripts.

A script to generate jobs

First, let's generate some jobs. We'll do this with a PHP script, html/ops/bossa_example_workgen.php.

The first part of this script is code for generating an image; the key functions are make_test_case(), which generates a structure saying if and where there's an ellipse, and make_image(), which generates an image given this info.

Next we have

function make_job($app, $batch, $i, $config) {
    // create the image file;
    // store it in the download directory hierarchy
    //
    $jobname = "job_$batch_$i";
    $case = make_test_case();
    $filename = "$jobname.png";
    $path = dir_hier_path(
        $filename, $config->download_dir, $config->uldl_dir_fanout
    );
    $url = dir_hier_url(
        $filename, $config->download_url, $config->uldl_dir_fanout
    );
    imagepng(make_image($case), $path);
    $case->url = $url;

    // make a job record in the Bossa database
    //
    $job = new BossaJob;
    $job->app_id = $app->id;
    $job->batch = $batch;
    $job->time_estimate = 30;
    $job->time_limit = 600;
    $job->name = $jobname;
    $job->info = json_encode($case);

    if (!$job->insert()) {
        echo "BossaJob::insert failed: ", mysql_error(), "\n";
        exit(1);
    }
}

This function creates one job, as follows:

  • Choose a name for the job, and a name for the corresponding image file.
  • Decide where the file goes in the project's download hierarchy.
  • Generate a random case (ellipse presence and position)
  • Create the image file.
  • Create a job record in the Bossa database. Assign a time estimate (in seconds) and a time limit. Store a description of the job, encoded in JSON, in the job record.

Finally we have:

function make_jobs($njobs) {
    $c = get_config();
    $config = null;
    $config->download_dir = parse_config($c, "<download_dir>");
    $config->download_url = parse_config($c, "<download_url>");
    $config->uldl_dir_fanout = parse_config($c, "<uldl_dir_fanout>");
    $app = BossaApp::lookup_name("Find the ellipse");
    if (!$app) {
        echo "Application $appname not found\n";
        exit(1);
    }
    $batch = time();
    for ($i=0; $i<$njobs; $i++) {
        make_job($app, $batch, $i, $config);
    }
    echo "Created $njobs jobs";
}

$njobs = get_int('make_jobs', true);
if ($njobs) {
    make_jobs($njobs);
} else {
    header ("Content-type: image/png");
    imagepng(make_image(make_test_case()));
}

make_jobs() parses the project configuration file, looks up the application in the database, and creates some jobs. You can invoke this by visiting http://a.b.c/test_ops/bossa_example_workgen.php?make_jobs=10 (or use the link on the http://a.b.c/test_ops/bossa_ops.php).

Displaying jobs

Next we'll explain the script that displays a job to a volunteer and handles their response: bossa_example_display.php.

function show_job($bj, $bji) {
    $info = json_decode($bj->info);
    $img_url = $info->url;
    echo "
        <form method=get action='bossa_example_display.php'>
        Click on the center of the ellipse.
        If you don't see one, click here:
        <br><br><input type=submit name=submit value=None>
        <input type=hidden name=bji value=$bji->id>
        <input type=hidden name=completion value=1>
        <input type=image name=pic src='$img_url'>
        </form>
    ";
}

function handle_job_completion($bj, $bji) {
    $response = null;
    if (get_str('submit', true)) {
        $response->have_ellipse = 0;
    } else {
        $response->have_ellipse = 1;
        $response->cx = get_int('pic.x');
        $response->cy = get_int('pic.y');
    }
    $bji->info = json_encode($response);
    $bji->completed($bj);
    Bossa::show_next_job($bj);    // show another job immediately
}

Bossa::script_init($user, $bj, $bji);

if (isset($_GET['completion'])) {
    handle_job_completion($bj, $bji);
} else {
    show_job($bj, $bji);
}

The script calls Bossa::script_init() to get PHP objects describing the user, the job, and the job instance.

show_job() decodes the job description to get the image URL, and displays the image in an HTML page that lets the user click on the image or on a "No ellipse" button.

handle_job_completion() gets the user's response (from form variables). It calls the completed() method of the job, passing it a JSON encoding of the response. I then calls Bossa::show_next_job() to immediately display another job.

Handling completed results

Finally, we need to specify how results are handled. This is specified in bossa_example_backend.inc.

This defines two functions, which must have names X_compare and X_handle where X is the application's short name.

The first function compares two instances and decides if they are compatible:

function bossa_example_compare($r1, $r2) {
    if ($r1->have_ellipse) {
        if ($r2->have_ellipse) {
            $dx = ($r1->cx - $r2->cx);
            $dy = ($r1->cy - $r2->cy);
            $dsq = $dx*$dx + $dy*$dy;
            return ($dsq < 400);
        } else return false;
    } else {
        return !$r2->have_ellipse;
    }
}

In this case, two instances are considered compatible if either

  • neither of them found an ellipse, or
  • they both found an ellipse and the centers are within 20 pixels

The second function specifies what happens when a job has been completed, i.e. a consensus set has been found:

function bossa_example_handle($bj, $c) {
    $res = $c[0];
    if ($res->have_ellipse) {
        $res->cx = 0;
        $res->cy = 0;
        foreach ($c as $r) {
            $res->cx += $r->cx;
            $res->cy += $r->cy;
        }
        $res->cx /= count($c);
        $res->cy /= count($c);
    }

    $info = json_decode[$bj->info);
    $info->result = $res;
    $i = json_encode($info);
    $bj->update("info='$i'");
}

This function is called with the BossaJob? record ($bj) and an array of job instances in the consensus set ($c). In this case, we average the center positions (if an ellipse was found) and store the JSON-encoded result in the info field of the job record.

Attachments (1)

Download all attachments as: .zip