Back to Starlab home

Creating your own Starlab tools

It is straightforward to create your own standalone tools for use within the Starlab environment. In order to take full advantage of existing Starlab modules and the standard data structure, we recommend that you program in C++. However, it is also possible to work in C or even FORTRAN (using existing tools such as readp and dumbp to translate the data into usable format).

Numerous programming aids and conventions have become established during the development of Starlab. While we do not impose any particular style, we describe here a general format which we have found useful. As an example, here is a simple program (based on and equivalent to the Starlab to_com tool) that reads in a dyn snapshot from stdin (by inheritance, it also will work with _dyn_, hdyn, etc. data), shifts to the center-of-mass frame, and writes the result to stdout. For simplicity, we assume a flat (i.e. single-level) tree. An annotated version (see the "//--" comments) of the program follows:

//// Sample Starlab tool:  Bring all positions and velocities
////                       to the center-of-mass frame.
////
//// Options:     -c    add a comment to the output snapshot [false]

                                                  //-- initial "////" lines
                                                  //-- serve as documentation
                                                  //-- for the program

#include "dyn.h"                                  //-- tool will operate
                                                  //-- on dyn data

local void shift_to_com(dyn *b)                   //-- local is a Starlab
                                                  //-- synonym for static
{
    // Compute the center of mass.

    real total_mass = 0;                          //-- "real" is double

    vec com_pos  = 0;                             //-- "vec" is an array
    vec com_vel  = 0;                             //-- of 3 reals, with all
                                                  //-- arithmetic operations
                                                  //-- properly defined

    for_all_daughters(dyn, b, d) {                //-- Starlab macro to
                                                  //-- loop over all dyn
                                                  //-- daughters d of base
                                                  //-- node b; also have:
                                                  //--    for_all_nodes
                                                  //--    for_all_leaves

        total_mass += d->get_mass();              //-- real member function
                                                  //-- get_mass() accesses
                                                  //-- dyn mass

        com_pos    += d->get_mass()               //-- similarly for vector
                           * d->get_pos();        //-- member functions
        com_vel    += d->get_mass()               //-- get_pos() and get_vel()
                           * d->get_vel();

    }   

    com_pos /= total_mass;
    com_vel /= total_mass;

    // Shift all positions and velocities.

    for_all_daughters(dyn, b, d) {
        d->inc_pos(-com_pos);                     //-- equivalently, could use
        d->inc_vel(-com_vel);                     //--
    }                                             //-- d->set_pos(d->get_pos()
                                                  //--             - com_pos);
                                                  //--
                                                  //-- etc.

    // Add an entry to the root log story.        //-- conventional to
                                                  //-- document such changes

    char tmp[128];
    sprintf(tmp, "  modified system center of mass at time %f",
            b->get_system_time());

    b->log_comment(tmp);                          //-- places the string in
                                                  //-- the log story of the
                                                  //-- system root node

    putvq(b->get_log_story(),                     //-- places a line of the
          "old_com_pos", com_pos);                //-- form
                                                  //--
                                                  //--   old_com_pos  =  x y z
                                                  //--
                                                  //-- in the root log story
}

main(int argc, char *argv[])
{
    check_help();                                 //-- if "--help" appears on
                                                  //-- the command line, print
                                                  //-- verbatim any line in
                                                  //-- this file beginning
                                                  //-- with "////"

    // Parse the command line.

    extern char *poptarg;
    int c;
    char* param_string = "c:";                    //-- list of legal command-
                                                  //-- line arguments; a colon
                                                  //-- (":") indicates that a
                                                  //-- value must be supplied
                                                  //-- on the command line

    bool c_flag = false;
    char *comment;

    while ((c = pgetopt(argc, argv, param_string)) != -1)
        switch(c) {

            case 'c': c_flag = TRUE;              //-- poptarg points to the
                      comment = poptarg;          //-- relevant item on the
                      break;                      //-- argument list

            case '?': params_to_usage(cerr, argv[0], param_string);
                      get_help();
                      exit(1);
        }            

    dyn *b;                                       //-- pointer to the root node

    while (b = get_dyn(cin)) {                    //-- read the next input
                                                  //-- snapshot from stdin

        if (c_flag) b->log_comment(comment);      //-- conventional to
        b->log_history(argc, argv);               //-- document program use

        shift_to_com(b);                          //-- do the work!

        put_dyn(b, cout);                         //-- write snapshot to stdout

        rmtree(b);                                //-- recursively delete the
                                                  //-- tree structure
    }
}
(This example has quite a few extra bells and whistles. A minimal ``stripped-down'' version is given here.)

Compilation

In order to build your own Starlab tool, you will need to link it with the Starlab header files and libraries. As of version 4.0, the simplest way to do this is to use make with the following lines in your Makefile:

CXXFLAGS = -I$(STARLAB_INSTALL_PATH)/include/starlab -DHAVE_CONFIG_H
LDLIBS   = -L$(STARLAB_INSTALL_PATH)/lib/starlab \
                -lhdyn -l_dyn_ -ldyn -lsstar -lnode -lstd -lm
Then, to build program from program.C or program.cc, just say
        make  program
and the rest is automatic. You may have to experiment with the libraries depending on your application. Some of those listed above may not be necessary -- for example, you won't need the star libraries for pure dynamics, you won't need -lhdyn for dyn applications, etc.