How To Component: Difference between revisions
(Initial CCA component how to) |
m (Replace geshi with syntaxhighlight) |
||
(3 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
== Subsidence Port == | === Subsidence Port === | ||
Create a port that interacts with a subsidence component. For now, I declare two port methods. One to initialize (or reinitalize) the component, and one the get deflections (in meters). | Create a port that interacts with a subsidence component. For now, I declare two port methods. One to initialize (or reinitalize) the component, and one the get deflections (in meters). | ||
< | <syntaxhighlight lang=bash>bocca create port subsidePort</syntaxhighlight> | ||
This is done by editing the appropriate SIDL file. The best way to do this is with the bocca edit command. A normal array is able to access the underlying data as well as its length and rank. It is more like a FORTRAN array where a raw array is more like a c pointer. | This is done by editing the appropriate SIDL file. The best way to do this is with the bocca edit command. A normal array is able to access the underlying data as well as its length and rank. It is more like a FORTRAN array where a raw array is more like a c pointer. | ||
< | <syntaxhighlight lang=bash>bocca edit port subsidePort</syntaxhighlight> | ||
A snippet from the sidl file that defines the port. | A snippet from the sidl file that defines the port. | ||
< | |||
<syntaxhighlight lang=sidl> | |||
interface subsidePort extends gov.cca.Port { | interface subsidePort extends gov.cca.Port { | ||
// DO-NOT-DELETE bocca.splicer.begin(csdms.subsidePort.methods) | // DO-NOT-DELETE bocca.splicer.begin(csdms.subsidePort.methods) | ||
Line 14: | Line 15: | ||
int get_deflection_in_m( inout rarray<double,1> dz(len) , in rarray<double,1> x(len) , in rarray<double,1> load(len) , in int len ); | int get_deflection_in_m( inout rarray<double,1> dz(len) , in rarray<double,1> x(len) , in rarray<double,1> load(len) , in int len ); | ||
} | } | ||
</ | </syntaxhighlight > | ||
Note the way that arrays are handled in the SIDL language. I'll add a section about this later. These are called "raw arrays". The SIDL language also has "normal" arrays, which are declared as `array`. | Note the way that arrays are handled in the SIDL language. I'll add a section about this later. These are called "raw arrays". The SIDL language also has "normal" arrays, which are declared as `array`. | ||
==Subsidence Component== | ===Subsidence Component=== | ||
Create a component that wraps an existing subsidence model. The model predicts the subsidence of Earth's crust due to vertical loading. | Create a component that wraps an existing subsidence model. The model predicts the subsidence of Earth's crust due to vertical loading. | ||
< | <syntaxhighlight lang=bash> | ||
bocca create component subside --language=c --provides=subsidePort | bocca create component subside --language=c --provides=subsidePort | ||
</ | </syntaxhighlight> | ||
This will create a component that has a single port that provides data to the caller. The way that the new component implements this functionality is defined in the appropriate Impl file. Once again use the edit command, | This will create a component that has a single port that provides data to the caller. The way that the new component implements this functionality is defined in the appropriate Impl file. Once again use the edit command, | ||
< | <syntaxhighlight lang=bash> | ||
bocca edit component subside --impl | bocca edit component subside --impl | ||
</ | </syntaxhighlight> | ||
without the impl option, bocca would edit the component's SIDL file. Allowed options are: sidl (the default), impl, and head. To go to a particular function, you can specify it at the end. For instance, in this case use, | without the impl option, bocca would edit the component's SIDL file. Allowed options are: sidl (the default), impl, and head. To go to a particular function, you can specify it at the end. For instance, in this case use, | ||
< | <syntaxhighlight lang=bash> | ||
bocca edit component subside --impl get_deflection_in_m | bocca edit component subside --impl get_deflection_in_m | ||
</ | </syntaxhighlight> | ||
Remove the code between the DO-DELETE tags and add your own code. Just to get things going I've added the following: | Remove the code between the DO-DELETE tags and add your own code. Just to get things going I've added the following: | ||
< | <syntaxhighlight lang=c> | ||
{ | { | ||
int32_t status = 0; | int32_t status = 0; | ||
Line 45: | Line 46: | ||
return status; | return status; | ||
} | } | ||
</ | </syntaxhighlight> | ||
==The Driver Component== | ===The Driver Component=== | ||
Although we've created a component, it isn't much good by itself. Let's now create a component that calls subside. This will be the project's driver component. | Although we've created a component, it isn't much good by itself. Let's now create a component that calls subside. This will be the project's driver component. | ||
< | <syntaxhighlight lang=bash> | ||
bocca create component subsideDriver --go=start --uses=subsidePort --language=c | bocca create component subsideDriver --go=start --uses=subsidePort --language=c | ||
bocca edit component subsideDriver --impl go | bocca edit component subsideDriver --impl go | ||
</ | </syntaxhighlight> | ||
This function will have a significant amount of auto-generated code. You'll have to scroll down to the next 'Insert-UserCode-Here' section. Remove the code in the 'REMOVE ME' block. I've added the following, | This function will have a significant amount of auto-generated code. You'll have to scroll down to the next 'Insert-UserCode-Here' section. Remove the code in the 'REMOVE ME' block. I've added the following, | ||
< | <syntaxhighlight lang=c> | ||
if ( bocca_status==0 ) | if ( bocca_status==0 ) | ||
{ | { | ||
Line 91: | Line 92: | ||
if ( dz ) free( dz ); | if ( dz ) free( dz ); | ||
} | } | ||
</ | </syntaxhighlight> | ||
After all of those changes we are now ready to configure and build the project. First run configure in the top-level directory, | After all of those changes we are now ready to configure and build the project. First run configure in the top-level directory, | ||
< | <syntaxhighlight lang=bash> | ||
./configure --prefix=/path/to/install/dir | ./configure --prefix=/path/to/install/dir | ||
</ | </syntaxhighlight> | ||
This configure script is the same as any other (use configure --help for a full list of options). By default, configure will install in ./install. Now make and install the project, | This configure script is the same as any other (use configure --help for a full list of options). By default, configure will install in ./install. Now make and install the project, | ||
make all install | make all install | ||
If you don't want to install the project (it can take a lot of time), a simple make should set things up to run some tests. If everything compiled without errors, you can run a test using the ccafe gui, | If you don't want to install the project (it can take a lot of time), a simple make should set things up to run some tests. If everything compiled without errors, you can run a test using the ccafe gui, | ||
< | <syntaxhighlight lang=bash> | ||
utils/run-gui.sh | utils/run-gui.sh | ||
</ | </syntaxhighlight> | ||
Connect the two components and click 'start'. The deflections should print to the screen. | Connect the two components and click 'start'. The deflections should print to the screen. | ||
==Link to External Libraries== | ===Link to External Libraries=== | ||
Now change the above implementation to use functions from external libraries. To implement the subsidence model, we'll need two functions: `get_flexure_parameter`, and `subside_point_load_1d`. These are both part of the sedflux installation. On my machine, I've installed sedflux in `/usr/local/ew/2.0.38`. | Now change the above implementation to use functions from external libraries. To implement the subsidence model, we'll need two functions: `get_flexure_parameter`, and `subside_point_load_1d`. These are both part of the sedflux installation. On my machine, I've installed sedflux in `/usr/local/ew/2.0.38`. | ||
The new implementation code for the subside component becomes | The new implementation code for the subside component becomes | ||
< | <syntaxhighlight lang=c> | ||
{ | { | ||
/* DO-NOT-DELETE splicer.begin(csdms.subside.get_deflection_in_m) */ | /* DO-NOT-DELETE splicer.begin(csdms.subside.get_deflection_in_m) */ | ||
Line 130: | Line 131: | ||
/* DO-NOT-DELETE splicer.end(csdms.subside.get_deflection_in_m) */ | /* DO-NOT-DELETE splicer.end(csdms.subside.get_deflection_in_m) */ | ||
} | } | ||
</ | </syntaxhighlight> | ||
In addition, include the header file `sed.h` at the beginning of the file. | In addition, include the header file `sed.h` at the beginning of the file. | ||
< | <syntaxhighlight lang=c> | ||
/* Insert-UserCode-Here {csdms.subside._includes} (includes and arbitrary code) */ | /* Insert-UserCode-Here {csdms.subside._includes} (includes and arbitrary code) */ | ||
#include <sed.h> | #include <sed.h> | ||
</ | </syntaxhighlight> | ||
The compiler needs to know where the libraries are that define these new functions. This is done by setting `INCLUDES` and `LIBS` in the appropriate make.vars.user file. In this case, edit `components/csdms.subside/make.vars.user`, | The compiler needs to know where the libraries are that define these new functions. This is done by setting `INCLUDES` and `LIBS` in the appropriate make.vars.user file. In this case, edit `components/csdms.subside/make.vars.user`, | ||
< | <syntaxhighlight lang=bash> | ||
INCLUDES = -I/usr/local/ew/2.0.38/include/ew-2.0 -I/usr/local/gtk/include/glib-2.0 -I/usr/local/gtk/lib/glib-2.0/include | INCLUDES = -I/usr/local/ew/2.0.38/include/ew-2.0 -I/usr/local/gtk/include/glib-2.0 -I/usr/local/gtk/lib/glib-2.0/include | ||
# Library paths and names, binaries | # Library paths and names, binaries | ||
LIBS = -L/usr/local/gnu/lib -L/usr/local/ew/2.0.38/lib -L/usr/local/gtk/lib -lsedflux -lutils -lm -lglib-2.0 -lintl -liconv -lsedflux-2.0 | LIBS = -L/usr/local/gnu/lib -L/usr/local/ew/2.0.38/lib -L/usr/local/gtk/lib -lsedflux -lutils -lm -lglib-2.0 -lintl -liconv -lsedflux-2.0 | ||
</ | </syntaxhighlight> | ||
Once again, in the top-level directory, | Once again, in the top-level directory, | ||
< | <syntaxhighlight lang=bash> | ||
make all install ; utils/run-gui.sh | make all install ; utils/run-gui.sh | ||
</ | </syntaxhighlight> | ||
==Editing Configure.in== | ===Editing Configure.in=== | ||
There should is a better way to do the above. The above requires the user to edit by hand the `LIBS` and `INCLUDES` variables to match their particular setup. This can be done automatically by configure. First edit configure.in, | There should is a better way to do the above. The above requires the user to edit by hand the `LIBS` and `INCLUDES` variables to match their particular setup. This can be done automatically by configure. First edit configure.in, | ||
< | <syntaxhighlight lang=bash> | ||
# insert user-autoconf-here | # insert user-autoconf-here | ||
PKG_CONFIG=pkg-config | PKG_CONFIG=pkg-config | ||
Line 158: | Line 159: | ||
AC_SUBST(SEDFLUX_CFLAGS) | AC_SUBST(SEDFLUX_CFLAGS) | ||
AC_SUBST(SEDFLUX_LIBS) | AC_SUBST(SEDFLUX_LIBS) | ||
</ | </syntaxhighlight> | ||
If `pkg-config` is installed and `PKG_CONFIG_PATH` contains the directory that holds sedflux.pc, the sedflux include and lib flags will be set correctly. So that these variables are given to make, they are set in make.project.in | If `pkg-config` is installed and `PKG_CONFIG_PATH` contains the directory that holds sedflux.pc, the sedflux include and lib flags will be set correctly. So that these variables are given to make, they are set in make.project.in | ||
< | <syntaxhighlight lang=bash> | ||
# Insert configure output variables here | # Insert configure output variables here | ||
SEDFLUX_CFLAGS = @SEDFLUX_CFLAG@ | SEDFLUX_CFLAGS = @SEDFLUX_CFLAG@ | ||
SEDFLUX_LIBS = @SEDFLUX_LIBS@ | SEDFLUX_LIBS = @SEDFLUX_LIBS@ | ||
</ | </syntaxhighlight> | ||
Now we use these variables in the component's make.vars.user file (components/csdms.subside/make.vars.user, in this case), | Now we use these variables in the component's make.vars.user file (components/csdms.subside/make.vars.user, in this case), | ||
< | <syntaxhighlight lang=bash> | ||
# Include path directives, including paths to Fortran modules | # Include path directives, including paths to Fortran modules | ||
INCLUDES = $(SEDFLUX_CFLAGS) | INCLUDES = $(SEDFLUX_CFLAGS) | ||
# Library paths and names, binaries | # Library paths and names, binaries | ||
LIBS = $(SEDFLUX_LIBS) -lsubside | LIBS = $(SEDFLUX_LIBS) -lsubside | ||
</ | </syntaxhighlight> | ||
Note that libsubside is the particular sedflux library that contains the symbols used in our example. | Note that libsubside is the particular sedflux library that contains the symbols used in our example. | ||
==Download An Existing Project== | ===Download An Existing Project=== | ||
I've uploaded a version of the above test to the downloads section. After downloading and unpacking it, go to the project's top level directory (`cd csdms`, in this case). Because the new machine may be configured differently than the one I used to create the project, the project must be configured, | I've uploaded a version of the above test to the downloads section. After downloading and unpacking it, go to the project's top level directory (`cd csdms`, in this case). Because the new machine may be configured differently than the one I used to create the project, the project must be configured, | ||
< | <syntaxhighlight lang=bash> | ||
bocca config -u | bocca config -u | ||
</ | </syntaxhighlight> | ||
Now things should be set to build and test the project, | Now things should be set to build and test the project, | ||
< | <syntaxhighlight lang=bash> | ||
make clean all install ; ./utils/run-gui.sh | make clean all install ; ./utils/run-gui.sh | ||
</ | </syntaxhighlight> | ||
==Create a River Component== | ===Create a River Component=== | ||
Create a port for a river component, | Create a port for a river component, | ||
< | <syntaxhighlight lang=bash> | ||
bocca create port riverPort | bocca create port riverPort | ||
</ | </syntaxhighlight> | ||
< | <syntaxhighlight lang=java> | ||
interface riverPort extends gov.cca.Port | interface riverPort extends gov.cca.Port | ||
{ | { | ||
Line 200: | Line 201: | ||
int pop_event ( ); | int pop_event ( ); | ||
} | } | ||
</ | </syntaxhighlight> | ||
Create a river component, | Create a river component, | ||
< | <syntaxhighlight lang=bash> | ||
bocca create component river --provides=riverPort --language=c | bocca create component river --provides=riverPort --language=c | ||
</ | </syntaxhighlight> | ||
This particular river component will use the sedflux type `Sed_hydro_file` to read in either a sedflux river file or a HydroTrend file and then provide river data as needed. To begin with, provide the component with some extra data to remember, namely the `Sed_hydro_file` info. This is done in the component's header file, | This particular river component will use the sedflux type `Sed_hydro_file` to read in either a sedflux river file or a HydroTrend file and then provide river data as needed. To begin with, provide the component with some extra data to remember, namely the `Sed_hydro_file` info. This is done in the component's header file, | ||
< | <syntaxhighlight lang=bash> | ||
bocca edit component river --header | bocca edit component river --header | ||
</ | </syntaxhighlight> | ||
< | <syntaxhighlight lang=c> | ||
struct csdms_river__data { | struct csdms_river__data { | ||
/* DO-NOT-DELETE splicer.begin(csdms.river._data) */ | /* DO-NOT-DELETE splicer.begin(csdms.river._data) */ | ||
Line 224: | Line 225: | ||
/* DO-NOT-DELETE splicer.end(csdms.river._data) */ | /* DO-NOT-DELETE splicer.end(csdms.river._data) */ | ||
}; | }; | ||
</ | </syntaxhighlight> | ||
Don't forget to include `sed.h`, | Don't forget to include `sed.h`, | ||
< | <syntaxhighlight lang=c> | ||
/* Insert-Code-Here {csdms.river._includes} (include files) */ #include <sed.h> | /* Insert-Code-Here {csdms.river._includes} (include files) */ #include <sed.h> | ||
</ | </syntaxhighlight> | ||
Write the implementation of the port methods. | Write the implementation of the port methods. | ||
< | <syntaxhighlight lang=bash> | ||
bocca config CLASSNAME --var=VARUSER --value=VALUE | bocca config CLASSNAME --var=VARUSER --value=VALUE | ||
</ | </syntaxhighlight> |
Latest revision as of 16:08, 16 July 2009
Subsidence Port
Create a port that interacts with a subsidence component. For now, I declare two port methods. One to initialize (or reinitalize) the component, and one the get deflections (in meters).
bocca create port subsidePort
This is done by editing the appropriate SIDL file. The best way to do this is with the bocca edit command. A normal array is able to access the underlying data as well as its length and rank. It is more like a FORTRAN array where a raw array is more like a c pointer.
bocca edit port subsidePort
A snippet from the sidl file that defines the port.
interface subsidePort extends gov.cca.Port {
// DO-NOT-DELETE bocca.splicer.begin(csdms.subsidePort.methods)
// Insert-UserCode-Here {csdms.subsidePort.methods} (Insert your port methods here)
// Read init data to set constants. If file is empty, use defaults. int init( in string file );
// Get the deflection (in meters) due to the applied loads.
int get_deflection_in_m( inout rarray<double,1> dz(len) , in rarray<double,1> x(len) , in rarray<double,1> load(len) , in int len );
}
Note the way that arrays are handled in the SIDL language. I'll add a section about this later. These are called "raw arrays". The SIDL language also has "normal" arrays, which are declared as `array`.
Subsidence Component
Create a component that wraps an existing subsidence model. The model predicts the subsidence of Earth's crust due to vertical loading.
bocca create component subside --language=c --provides=subsidePort
This will create a component that has a single port that provides data to the caller. The way that the new component implements this functionality is defined in the appropriate Impl file. Once again use the edit command,
bocca edit component subside --impl
without the impl option, bocca would edit the component's SIDL file. Allowed options are: sidl (the default), impl, and head. To go to a particular function, you can specify it at the end. For instance, in this case use,
bocca edit component subside --impl get_deflection_in_m
Remove the code between the DO-DELETE tags and add your own code. Just to get things going I've added the following:
{
int32_t status = 0;
if ( dz && x && load && len>0 )
{
int32_t i;
for ( i=0 ; i<len ; i++ )
dz[i] = load[i]*5.; status = 0;
}
else
status = -1;
return status;
}
The Driver Component
Although we've created a component, it isn't much good by itself. Let's now create a component that calls subside. This will be the project's driver component.
bocca create component subsideDriver --go=start --uses=subsidePort --language=c
bocca edit component subsideDriver --impl go
This function will have a significant amount of auto-generated code. You'll have to scroll down to the next 'Insert-UserCode-Here' section. Remove the code in the 'REMOVE ME' block. I've added the following,
if ( bocca_status==0 )
{
int32_t i;
int32_t len = 100; // Number of grid nodes
double dx = 1000.; // Grid spacing in meters
double* x = (double*)malloc( sizeof(double)*len );
double* v = (double*)malloc( sizeof(double)*len );
double* dz = (double*)malloc( sizeof(double)*len );
if ( x && v && dz )
{ /* Set the initial data and get the deflection */
for ( i=0 ; i<len ; i++ )
{
x[i] = i*dx;
v[i] = 0.;
dz[i] = 0.;
}
v[len/2] = 1.;
bocca_status = csdms_subsidePort_get_deflection_in_m( subsidePort , dz , x , v , len , &throwaway_excpt );
if ( bocca_status==0 )
{ /* Print the result */
for ( i=0 ; i<len ; i++ )
fprintf( stdout , "%f ; %f ; %f\n" , x[i] , dz[i] , v[i] );
fflush( stdout );
}
}
else
bocca_status = -1;
if ( x ) free( x );
if ( v ) free( v );
if ( dz ) free( dz );
}
After all of those changes we are now ready to configure and build the project. First run configure in the top-level directory,
./configure --prefix=/path/to/install/dir
This configure script is the same as any other (use configure --help for a full list of options). By default, configure will install in ./install. Now make and install the project, make all install If you don't want to install the project (it can take a lot of time), a simple make should set things up to run some tests. If everything compiled without errors, you can run a test using the ccafe gui,
utils/run-gui.sh
Connect the two components and click 'start'. The deflections should print to the screen.
Link to External Libraries
Now change the above implementation to use functions from external libraries. To implement the subsidence model, we'll need two functions: `get_flexure_parameter`, and `subside_point_load_1d`. These are both part of the sedflux installation. On my machine, I've installed sedflux in `/usr/local/ew/2.0.38`.
The new implementation code for the subside component becomes
{
/* DO-NOT-DELETE splicer.begin(csdms.subside.get_deflection_in_m) */
int32_t status = 0;
if ( dz && x && load && len>0 )
{
int32_t i;
double alpha = get_flexure_parameter( 10000. , 7e10 , 1 );
fprintf( stderr , "alpha = %f\n" , alpha );
fflush( stderr );
for ( i=0 ; i<len ; i++ ) dz[i] = 0.;
for ( i=0 ; i<len ; i++ )
if ( load[i]>0 )
subside_point_load_1d( dz , x , len , load[i] , x[i] , alpha );
status = 0;
}
else
status = -1;
return status;
/* DO-NOT-DELETE splicer.end(csdms.subside.get_deflection_in_m) */
}
In addition, include the header file `sed.h` at the beginning of the file.
/* Insert-UserCode-Here {csdms.subside._includes} (includes and arbitrary code) */
#include <sed.h>
The compiler needs to know where the libraries are that define these new functions. This is done by setting `INCLUDES` and `LIBS` in the appropriate make.vars.user file. In this case, edit `components/csdms.subside/make.vars.user`,
INCLUDES = -I/usr/local/ew/2.0.38/include/ew-2.0 -I/usr/local/gtk/include/glib-2.0 -I/usr/local/gtk/lib/glib-2.0/include
# Library paths and names, binaries
LIBS = -L/usr/local/gnu/lib -L/usr/local/ew/2.0.38/lib -L/usr/local/gtk/lib -lsedflux -lutils -lm -lglib-2.0 -lintl -liconv -lsedflux-2.0
Once again, in the top-level directory,
make all install ; utils/run-gui.sh
Editing Configure.in
There should is a better way to do the above. The above requires the user to edit by hand the `LIBS` and `INCLUDES` variables to match their particular setup. This can be done automatically by configure. First edit configure.in,
# insert user-autoconf-here
PKG_CONFIG=pkg-config
SEDFLUX_CFLAGS=`$PKG_CONFIG --cflags sedflux`
SEDFLUX_LIBS=`$PKG_CONFIG --libs sedflux`
AC_SUBST(SEDFLUX_CFLAGS)
AC_SUBST(SEDFLUX_LIBS)
If `pkg-config` is installed and `PKG_CONFIG_PATH` contains the directory that holds sedflux.pc, the sedflux include and lib flags will be set correctly. So that these variables are given to make, they are set in make.project.in
# Insert configure output variables here
SEDFLUX_CFLAGS = @SEDFLUX_CFLAG@
SEDFLUX_LIBS = @SEDFLUX_LIBS@
Now we use these variables in the component's make.vars.user file (components/csdms.subside/make.vars.user, in this case),
# Include path directives, including paths to Fortran modules
INCLUDES = $(SEDFLUX_CFLAGS)
# Library paths and names, binaries
LIBS = $(SEDFLUX_LIBS) -lsubside
Note that libsubside is the particular sedflux library that contains the symbols used in our example.
Download An Existing Project
I've uploaded a version of the above test to the downloads section. After downloading and unpacking it, go to the project's top level directory (`cd csdms`, in this case). Because the new machine may be configured differently than the one I used to create the project, the project must be configured,
bocca config -u
Now things should be set to build and test the project,
make clean all install ; ./utils/run-gui.sh
Create a River Component
Create a port for a river component,
bocca create port riverPort
interface riverPort extends gov.cca.Port
{
int get_width ( out double w );
int get_depth ( out double d );
int get_velocity ( out double v );
int get_discharge( out double q );
int pop_event ( );
}
Create a river component,
bocca create component river --provides=riverPort --language=c
This particular river component will use the sedflux type `Sed_hydro_file` to read in either a sedflux river file or a HydroTrend file and then provide river data as needed. To begin with, provide the component with some extra data to remember, namely the `Sed_hydro_file` info. This is done in the component's header file,
bocca edit component river --header
struct csdms_river__data {
/* DO-NOT-DELETE splicer.begin(csdms.river._data) */
/* Bocca generated code. bocca.protected.begin(csdms.river._data) */
/* Handle to framework services object */
gov_cca_Services d_services;
/* Bocca generated code. bocca.protected.end(csdms.river._data) */
/* Put other private data members here... */
Sed_hydro_file hydro_file;
/* DO-NOT-DELETE splicer.end(csdms.river._data) */
};
Don't forget to include `sed.h`,
/* Insert-Code-Here {csdms.river._includes} (include files) */ #include <sed.h>
Write the implementation of the port methods.
bocca config CLASSNAME --var=VARUSER --value=VALUE