UCVM Model Integration Guide

From SCECpedia
Jump to navigationJump to search

Introduction

UCVM 14.7.0 introduced a new interface designed to make installing and adding new models easier. Unlike previous versions of UCVM, starting with UCVM 14.7.0, UCVM will not need to know about the model at compile-time in order to make use of it. This means that model developers can more readily use UCVM's plotting utilities, meshing utilities, and other capabilities with their models.

Please note that this guide is only for systems that support dynamic linking, which is the vast majority of Linux and Mac OS X systems. Static linking is more complex and beyond the scope of this guide.

Interface Description

Directory Structure

UCVM searches and reads models that are installed in a standardized format. Suppose that you have UCVM installed in /home/user/ucvm-14.6.0. All models are installed in the "model" directory and must follow this format to be included:

/home/user/ucvm-14.7.0/model/[name]/lib/lib[name].so

So, if we are trying to install a model named "acme", we would need our shared object library to be at:

/home/user/ucvm-14.7.0/model/acme/lib/libacme.so

Basic Structures

All UCVM models work in the following basic manner:

  1. Take as input latitude, longitude, and depth, with spherical earth co-ordinates using the WGS84 ellipsoid.
  2. Return material properties for that point. The material properties consist of one or more of Vp (m/s), Vs (m/s), Density (g/cm^3), Qp, and/or Qs.

UCVM passes the input latitude, longitude, and depth through a structure which is defined as follows:

typedef struct basic_point_t {
    double longitude;    // Longitude in degrees
    double latitude;    // Latitude in degrees
    double depth;    // Depth in meters
} basic_point_t;

All models need to then read in points in the above format and return material properties in the following format:

typedef struct basic_properties_t {
    double vp;    // Vp in meters per second
    double vs;    // Vs in meters per second
    double rho;    // Density in grams per cubic centimeter
    double qp;    // Qp
    double qs;    // Qs
} basic_properties_t;

Model Operation

Models called from UCVM undergo the following lifecycle:

  1. Initialization - during this period, the model is initialized and should load any necessary data to memory as disk can be relatively slow. It's also recommended that the model pre-compute as much as possible with regards to projections, coefficients, and so on.
  2. Query - after models are initialized they must be ready to accept queries. Queries are arrays of the basic_point_t structure, as described in the structures section, and a pre-malloced pointer to an array of basic_properties_t, which will contain the material properties. If no properties are available, models are advised to return -1 for each of the entries in the basic_properties_t structure.
  3. Finalize - models who are called to finalize must free up their resources.

Function Definitions

There are four functions that must be implemented:

int model_init(const char *dir, const char *label)
Description: Called to initialize the model and load whatever contents are necessary into memory.
Parameters:

  • dir - The directory in which UCVM is located (e.g. /home/user/ucvm-14.7.0).
  • label - The model name (e.g. acme). So the model's full directory is always [dir]/model/[label].

Returns: 0 if the model initialization worked, 1 if it didn't.

int model_query(basic_point_t *points, basic_properties_t *data, int numpts)
Description: Gives an array of numpts points and writes material properties to an equal number of basic_properties_t structures in data.
Parameters:

  • points - The array of points, in WGS84 ellipsoid, latitude, longitude format for which the model should retrieve material properties.
  • data - The array of material properties that are returned.
  • numpts - The number of points, and material properties, to use.

Returns: 0 if query was successful, 1 if there was an error encountered (note an error in this case does not mean outside of the model region, rather it means an unrecoverable issue such as a bad projection, or something like that).

int model_finalize()
Description: Frees up all used memory and shuts the model down.
Returns: 0 if the free was successful, 1 if not.

int model_version(char *ver, int len)
Description: Returns a unique version identifier for your model (e.g. "Acme 1.0").
Parameters:

  • ver - The version string buffer to which the version identifier should be written.
  • len - The maximum number of characters to return.

Returns: 0 if the version was written successfully, 1 if not.

Basic Tutorial Model

Code Description

This tutorial will show how to integrate a simple, fictitious model into UCVM. Let's suppose that we have a very simple model which simply returns Vp = (2000 + latitude)m/s, Vs = (1000 + longitude)m/s, and density = (2000 + depth)g/cm^3, for every point within the model boundaries. Of course, this is a completely fake model, but it will suffice to show the general idea of implementation within UCVM.

We would require no initialization for this model, so our model_init would be something like:

int model_init(const char *dir, const char *label) {
    return 0;
}

For our query function, we would need to loop through each point and return back our fake material properties:

int model_query(basic_point_t *points, basic_properties_t *data, int numpts) {
    int i = 0;
    for (i = 0; i < numpts; i++) {
        data[i].vp = 2000 + points[i].latitude;    // Set Vp for this point.
        data[i].vs = 1000 + points[i].longitude;    // Set Vs for this point.
        data[i].rho = 2000 + points[i].depth;    // Set density for this point.
        data[i].qp = -1;    // Model does not have Qp.
        data[i].qs = -1;    // Model does not have Qs.
    }
    return 0;
}

We also require no memory clean-up, so our finalize function is very simple:

int model_finalize() {
    return 0;
}

Finally, let's call our model "Acme":

int model_ver(char *ver, int len) {
    int verlen;
    verlen = strlen("Acme");
    if (verlen > len - 1) {
        verlen = len - 1;
    }
    memset(ver, 0, len);
    strncpy(ver, "Acme", verlen);
    return 0;
}

Compiling and Installing

The entire code is as follows:

acme.c
#include <string.h>
typedef struct basic_point_t {
    double longitude;    // Longitude in degrees
    double latitude;    // Latitude in degrees
    double depth;    // Depth in meters
} basic_point_t;

typedef struct basic_properties_t {
    double vp;    // Vp in meters per second
    double vs;    // Vs in meters per second
    double rho;    // Density in grams per cubic centimeter
    double qp;    // Qp
    double qs;    // Qs
} basic_properties_t;

int model_init(const char *dir, const char *label) {
    return 0;
}

int model_query(basic_point_t *points, basic_properties_t *data, int numpts) {
    int i = 0;
    for (i = 0; i < numpts; i++) {
        data[i].vp = 2000 + points[i].latitude;    // Set Vp for this point.
        data[i].vs = 1000 + points[i].longitude;    // Set Vs for this point.
        data[i].rho = 2000 + points[i].depth;    // Set density for this point.
        data[i].qp = -1;    // Model does not have Qp.
        data[i].qs = -1;    // Model does not have Qs.
    }
    return 0;
}

int model_finalize() {
    return 0;
}

int model_version(char *ver, int len) {
    int verlen;
    verlen = strlen("Acme");
    if (verlen > len - 1) {
        verlen = len - 1;
    }
    memset(ver, 0, len);
    strncpy(ver, "Acme", verlen);
    return 0;
}

To compile your code, please run:
gcc -shared -o libacme.so acme.c

Now, installing your new model is very simple. Simply copy your shared object to your UCVM's model directory following the conventions described at the beginning of the page.

mkdir -p /home/user/ucvm-14.7.0/model/acme/lib
cp libacme.so /home/user/ucvm-14.7.0/model/acme/lib

To test the model, run ucvm_query:

$ ./ucvm_query -f ../conf/ucvm.conf -m acme
Using Geo Depth coordinates as default mode.
-118 34 0
-118.0000 34.0000 0.000 280.896 390.000 acme 2034.000 882.000 2000.000 none 0.000 0.000 0.000 crust 2034.000 882.000 2000.000

Note that this is correct (2034 = 2000 + latitude, 882 = 1000 + longitude, and 2000 = 2000 + depth).

You can now use your model with other components of UCVM (e.g. Vs30 calculations, Z1.0 and Z2.5 calculations, and so on).

Limitations

Advanced functionality will require other components than the basic model code. For example, to query by elevation, UCVM requires that an appropriate digital elevation model be installed. This guide is intended to show how most, but not necessarily all, models can be implemented into UCVM.