C-Munipack library (API)

The C-Munipack library provides an extensive set of functions with a simple application programming interface (API) for reduction of images carried out by a CCD or DSLR cameras, aimed at observation of variable stars.

The library has been developed as a part of the C-Munipack software. See the project home page for more information about the project and other interfaces.

Sample program

The following text describes implementation of a very simple application, which performs photometry of a single CCD frame using functions from the C-Munipack library. It is supposed, that you have got the C-Munipack library and its headers installed.

The source code

Let’s start - make a new project in your favorite IDE and make a big mug of coffee for yourself. First of all, we need to include some standard headers:

#include <stdio>
#include <stdlib>

The declarations from the C-Munipack library are sorted into several header files, but all we need to include just one header file, which in turn includes all other public header files:

#include <cmunipack>

We will use command-line arguments to specify name of an input CCD frame and name of an output file. Because of this, our declaration of the main function looks like this:

int main(int argc, char *argv[])
{
        CmpackPhot *lc;

The lc variable is called a context. The context stores the configuration parameters and keeps internal data used during photometry process. It allows a caller to process multiple frames in different threads without interference between each other. The context is a trick that makes all functions from the library re-entrant; you can safely call functions from different threads without any synchronization or locking features provided that those threads uses different contexts. There are two exceptions to that rule. The initialization routine must be called before any other call from the C-Munipack library and the clean-up routine must be called as the last call.

At the beginning of our sample program, we call the initialization routine:

/* Library initialization */
cmpack_init();

The next piece of code checks the command line parameters. This demo expects two parameters, the first one is a name of an input file with a source frame, the second one is a name of an output file:

/* Command line checking */
if (argc!=3) {
             fprintf(stderr, "Syntax: test <ccd frame> <photometry file>");
             return 1;
}

Before we do any real work, we need to create a new photometry context. This is a opaque data structure that keeps the configuration parameters required to perform a photometry on a frame. The context is created by calling the cmpack_phot_init routine. This function creates a new photometry context, sets all parameters to default values, sets the reference counter to one. A pointer to the context is returned. The caller becomes an owner of the context and when we don’t need it anymore, we should release the reference by calling the cmpack_phot_free function which decrements the reference counter and destroys the context.

Let’s set up at least two most important configuration parameters – the filter half-width and the detection threshold. We let all other parameter to the default values.

/* Create context */
lc = cmpack_phot_init();
cmpack_phot_set_fwhm(lc, 2.5);
cmpack_phot_set_thresh(lc, 4.0);

Now everything is ready to do a real work. The photometry is executed by calling the cmpack_phot, which takes the context as its first parameter, the names of the input and output files as the second and third parameter. The fourth parameter is NULL.

cmpack_phot(lc, argv[1], argv[2], NULL);

Before we finish the program, we should destroy our reference to the photometry context and since this is the last reference, the context and all data that are stored within the context is destroyed as well.

/* Destroy context */
cmpack_unref(lc);

Before terminating the program, you should call the library clean-up function.

        /* Library cleanup */
        cmpack_cleanup();

        return 0;
}

Compiling and linking

The C-Munipack library comes with a configuration file for pkg-config. If your system supports pkg-config, this is the easiest way how to pass all options that are necessary to compile and link an application against the C-Munipack library.

Otherwise, you have to set up all the options on the command line. Here is an example that builds our source code on Debian 4 using the gcc compiler.

gcc main.c -I -lcmunipack-1.2 -lexpat -lcfitsio -lm

Memory allocation

In the C-Munipack library, all dynamic memory allocation are performed by means of a group of routines which correspond to the C standard library memory handling function.

When you build your own application using the C-Munipack library, please check the API Reference to make sure when the caller is responsible to free the allocated memory blocks. To do so, you have to call the cmpack_free routine, otherwise, the behavior of the program is unpredictable.

Detecting memory leaks

When the C-Munipack library is compiled with _DEBUG symbol defined, the memory handling function keep track of blocks allocated on the heap. When the application calls the cmpack_clean routine, the list of blocks that are still allocated is printed to the standard output. This feature is designed to detect memory blocks that were allocated but not freed.

Detecting out-of-block modifications

When the C-Munipack library is compiled with _DEBUG symbol defined, the memory handling function check for out-of-block modifications. When a memory block is requested, the function allocates 8 bytes more and writes a 4 bytes of constant data at the beginning of the block and 4 bytes of constant data at the end of the block. The function returns a pointer of a memory after the first four bytes, so from caller’s perspective, everything is transparent.

When a memory block is freed or reallocated, the program checks if the leading and trailing data were not modified. In such case, an assertion is issued to stop execution of the program.

Objects and reference counting

Most of the structures that are published by the C-Munipack library are opaque. They can be referenced by pointers, but their internal structure and content can be accessed only by calling appropriate functions. This slows down an execution of the resulting program, but provides a compatibility of binary code that were dynamically compiled against the library.

To help binding into other languages, the structures contain reference counters reference counting that can be incremented and decremented and when the last reference to a structure is lost, the structure is freed automatically. For each structure that support reference counting, there are two functions:

A function that has the reference suffix increments the reference counter of an object given as an argument. Its return value is a copy of the argument. A function that has the free suffix decrements the reference counter of an object given as an argument and when the reference counter reaches zero it destroys the object and frees allocated memory.

Initialization and clean-up

The library initialization routine cmpack_init must be called prior to any other call to the library. It initializes the static data and when the library was compiled with _DEBUG symbol defined, the data required by the memory leak detection is also initialized.

The library initialization routine cmpack_cleanup can be called before the program terminates, though it is not necessary, if you don’t care about memory leaks, which is a bad idea in general. The clean-up code releases any memory allocated in static data. When the library was compiled with _DEBUG symbol defined, it prints out to the standard output a report about any memory blocks that were allocated but not freed. Please note that only memory blocks that were handled by library’s allocation/free routines are threated by the leak detector.

Thread safety

Functions from the C-Munipack library are re-entrant. It means, that you can call them from different threads without any external synchronization and locking if they are called on different data. The data that are used inside a function call are stored on a stack, the data that are passed between function calls are stored in an memory allocated on a heap, called a context.

On the other hand, functions from the library are not thread-safe. When you call a function on the same context (data) from two threads at the same time, the behavior of the program and the results are unpredictable.

For example, it is safe to perform a photometry on two frames in two threads simultaneously, but you have to make two photometry contexts (instances of CmpackPhot type).

There are two exceptions to this rule, the library initialization routine cmpack_init and the clean-up routine cmpack_cleanup. These routines are not re-entrant nor thread-safe.