# Creating Additional Plugins

&kst; has a simple and standardized interface that facilitates easy creation of additional plugins. In addition to detailing basic requirements for plugins, the following sections describe how to make use of pre-written header files to create certain types of plugins.

## Creating a Basic Plugin

A &kst; plugin consists of two files—a KDE desktop service file and a shared object file.

### The KDE Desktop Service File

The KDE desktop service file provides information about the plugin to the &kst; plugin loading infrastructure. The following is an example of a KDE desktop service file for a &kst; plugin:

    [Desktop Entry]
    Encoding=UTF-8
    Type=Service
    ServiceTypes=Kst Data Object
    X-KDE-ModuleType=Plugin
    X-KDE-Library=kst_FOO_plugin
    X-Kst-Plugin-Author=FOO
    Name=FOO Plugin
    Comment=The FOO algorithm for Kst.

Generally, you can use the example above as a template and modify the FOO entries to fit your plugin. As can be seen from the example, the desktop service file consists of a series of key value pairs. The `ServiceTypes` entry should be left as seen above. This key indicates that the plugin inherits the KstDataObject class. See the API documentation for the interfaces this class exposes. The `X-KDE-Library` key points to the shared object file that implements your plugin. Do not include the shared object's file extension.

Once you have completed the desktop file, save it as `[X-KDE-LIBRARY].desktop`, where `[X-KDE-LIBRARY]` is the value of the key in the desktop file.

### The Shared Object File

The shared object file contains the actual functionality of the plugin. The following are the requirements for the shared object file:

- The object must inherit the KstDataObject class:

      #ifndef FOOPLUGIN_H
      #define FOOPLUGIN_H

      #include <kstdataobject.h>

      class FooPlugin : public KstDataObject {
        Q_OBJECT
      public:
          FooPlugin(QObject *parent, const char *name, const QStringList &args);
          virtual ~FooPlugin();

          virtual KstObject::UpdateType update(int);
          virtual QString propertyString() const;
          virtual KstDataObjectPtr makeDuplicate(KstDataObjectDataObjectMap&);

      protected slots:
          virtual void _showDialog();
      };

      #endif

The following is an example of the shared object file source code for a simple plugin:

### Compiling the Plugin

If you are using &gcc; to compile your plugin, simply compile the object file:

    cc -Wall -c -o myplugin.o myplugin.c -fPIC -DPIC

and then create the shared library:

    ld -o myplugin.so -shared myplugin.o

The resulting `*.so` file and `*.xml` file must be put in the same directory. When you use &kst;'s Plugin Manager to load the XML file, it will automatically look for the shared object file in the same directory.

## Creating Linear Fit Plugins

To create a linear fit plugin, you could implement your own fitting algorithms and output the appropriate vectors. However, &kst; already comes with header files that make it easy for you to implement linear least-squares fit plugins by just providing a few functions. This section will describe how to take advantage of these files.

### Header Files

Two header files are provided for performing linear fits, `linear.h` (for unweighted linear fits) and `linear_weighted.h` (for weighted linear fits). They are both located under `kst/plugins/fits/` in the &kst; source tarball. To use these files, include only one of them in the source code for your plugin:

    #include <../linear.h>

or

    #include <../linear_weighted.h>

(by convention, we will place the source code for the plugin one directory below where the header files are).

### Implementing Required Functions

Given a general linear model:

where `y` is a vector of `n` observations, `X` is an `n` by `p` matrix of predictor variables, and `c` is the vector of `p` best-fit parameters that are to be estimated, the header files provide functions for estimating `c` for a given `y` and `X`. To provide `X`, the following function needs to be implemented in the source code for the plugin:

    double calculate_matrix_entry( double dX, int iPos )

This function should return the value of the entry in column `iPos` of the matrix of predictor variables, using `x` value `dX`. This function will be called by linear.h or linear_weighted.h. The implementation of this function depends on the model you wish to use for the fit, and is unique to each linear fit plugin. For example, to fit to a polynomial model, `calculate_matrix_entry` could be implemented as follows:

    double calculate_matrix_entry( double dX, int iPos ) {
      double dY;
      dY = pow( dX, (double)iPos );
      return dY;
    }

### Calling the Fitting Functions

Once the appropriate header file has been included and `calculate_matrix_entry` has been implemented, call the appropriate fitting function included from the header file:

    kstfit_linear_unweighted( inArrays, inArrayLens,
                              outArrays, outArrayLens,
                              outScalars, iNumParams );

or

    kstfit_linear_weighted( inArrays, inArrayLens,
                            outArrays, outArrayLens,
                            outScalars, iNumParams );

Each function will return `0` on success, or `-1` on error, so it is a good idea to set the return value of the exported C function to be equal to the return value of the fitting function. To maintain simplicity, the code for the plugin can simply pass the arguments given to the exported C function to the fitting function. Note, however, that inArrays must be structured as follows:

- `inArrays[0]` must contain the array of x coordinates of the data points

- `inArrays[1]` must contain the array of y coordinates of the data points

- `inArrays[2]` only exists if `kstfit_linear_weighted` is being called, and must contain the array of weights to use for the fit.

The easiest way to ensure that inArrays is structured correctly is to specify the correct order of input vectors in the XML file for the plugin.

`iNumParams` is the number of parameters in the fitting model used, which should be equal to the number of columns in the matrix `X` of predictor variables. `iNumParams` must be set correctly before the fitting function is called.

After `kstfit_linear_unweighted` or `kstfit_linear_weighted` is called, `outArrays` and `outScalars` will be set as follows:

- `outArrays[0]` will contain the array of fitted y values.

- `outArrays[1]` will contain the array of residuals.

- `outArrays[2]` will contain the array of best-fit parameters that were estimated.

- `outArrays[3]` will contain the covariance matrix, returned row after row in an array.

- `outScalars[0]` will contain chi^2/nu, where chi^2 is the weighted sum of squares of the residuals, and nu is the degrees of freedom.

`outArrayLens` will be correctly set to indicate the length of each output array.

Ensure that the specified outputs in the XML file match those that the exported C function returns (which in most cases will simply be the outputs returned by the fitting function).

### Example

The following is an example of the source code for a linear fit plugin.

    /*
     *  Polynomial fitting plugin for KST.
     *  Copyright 2004, The University of British Columbia
     *  Released under the terms of the GPL.
     */

    #include "../linear.h"

    double calculate_matrix_entry( double dX, int iPos ) {
      double dY;

      dY = pow( dX, (double)iPos );

      return dY;
    }

    extern "C" int kstfit_polynomial_unweighted(
      const double *const inArrays[],
      const int inArrayLens[],
      const double inScalars[],
      double *outArrays[], int outArrayLens[],
      double outScalars[]);

    int kstfit_polynomial_unweighted(
      const double *const inArrays[],
      const int inArrayLens[],
    	const double inScalars[],
    	double *outArrays[], int outArrayLens[],
    	double outScalars[])
    {
      int iRetVal = -1;
      int iNumParams;

      iNumParams = 1 + (int)floor( inScalars[0] );
      if( iNumParams > 0 ) {
        iRetVal = kstfit_linear_unweighted( inArrays, inArrayLens,
                                            outArrays, outArrayLens,
                                            outScalars, iNumParams );
      }

      return iRetVal;
    }

## Creating Non-linear Fit Plugins

&kst; provides header files designed to simplify the creation of non-linear least-squares fit plugins. The following sections detail the use of the header files.

### Header Files and Definitions

The non-linear fit header files are located in `kst/plugins/fits_nonlinear` of the &kst; source tarball. The files are named `non_linear.h` and `non_linear_weighted.h` for unweighted and weighted fits, respectively. To use these files, include only one of them in the source code for your plugin:

    #include <../non_linear.h>

or

    #include <../non_linear_weighted.h>

(by convention, we will place the source code for the plugin one directory below where the header files are).

As non-linear fitting is an iterative process, you must also define the maximum number of iterations that should be performed. The non-linear fitting algorithm will stop when at least one of the following conditions is true:

- The maximum number of iterations has been reached.

- A precision of 10-4 has been reached.

In addition, you need to define the number of parameters in the model, as it is not passed to the fitting function explicitly. To define these two values, include the following at the top of your source code:

    #define NUM_PARAMS [num1]
    #define MAX_NUM_ITERATIONS [num2]

replacing `[num1]` with the number of parameters in the model, and `[num2]` with the maximum number of iterations to perform.

### Implementing Required Functions

To use the header files for non-linear fits, you must provide the function to use as the model, the partial derivatives of the function with respect to each parameter, and initial estimates of the best-fit parameters. To do this, three functions must be implemented. These functions are described below.

`double function_calculate( double `dX`, double* `pdParameters` )`

  This function calculates the y value of the fitting model for a given x value `dX`, using the supplied array of parameters `pdParameters`. The order of parameters in `pdParameters` is arbitrary, but should be consistent with the other two implemented functions. For example, for an exponential model, `function_calculate` could be implemented as follows:

      double function_calculate( double dX, double* pdParameters ) {
        double dScale	 = pdParameters[0];
        double dLambda = pdParameters[1];
        double dOffset = pdParameters[2];
        double dY;

        dY  = ( dScale * exp( -dLambda * dX ) ) + dOffset;

        return dY;
      }

`void function_derivative( double `dX`, double* `pdParameters`, double* `pdDerivatives` )`

  This function calculates the partial derivatives of the model function for a give value of x `dX`. The partial derivatives should be returned in `pdDerivatives`. The order of the partial derivatives in the array `pdDerivatives` should correspond to the order of the parameters in `pdParameters` (i.e. if `pdParameters[0]` contains the parameter lambda for an exponential model, `pdDerivatives[0]` should contain the derivative of the model with respect to lambda).

`void function_initial_estimate( const double* `pdX`, const double* `pdY`, int `iLength`, double* `pdParameterEstimates` )`

  This function provides an initial estimate of the best-fit parameters to the fitting function. The array of x values and y values of the data points are provided in `pdX` and `pdY` respectively, and the number of data points is provided by `iLength`. You can use any or none of these parameters at your discretion to calculate the initial estimate. The function should put the calculated initial estimates in `pdParameterEstimates`, with the order of the estimates corresponding to the order of the parameters in `pdParameters` of `function_calculate` and `function_derivative`. Keep in mind that the initial estimate is important in determining whether or not the fitting function converges to a solution.

### Calling the Fitting Functions

Once all the required functions have been implemented, the fitting function from the included header file can be called:

    kstfit_nonlinear( inArrays, inArrayLens,
    		  inScalars, outArrays,
    		  outArrayLens, outScalars );

or

    kstfit_nonlinear_weighted( inArrays, inArrayLens,
                               inScalars, outArrays,
                               outArrayLens, outScalars );

depending on whether you are implementing a non-weighted fit or a weighted fit.

The function will return `0` on success, or `-1` on error, so it is simplest to set the return value of the exported C function to be equal to the return value of the fitting function. To maintain simplicity, the code for the plugin can simply pass the arguments given to the exported C function to the fitting function. Note, however, that inArrays must be structured as follows:

- `inArrays[0]` must contain the array of x coordinates of the data points

- `inArrays[1]` must contain the array of y coordinates of the data points

- `inArrays[2]` only exists if `kstfit_linear_weighted` is being called, and must contain the array of weights to use for the fit.

The easiest way to ensure that inArrays is structured correctly is to specify the correct order of input vectors in the XML file for the plugin.

After `kstfit_linear_unweighted` or `kstfit_linear_weighted` is called, `outArrays` and `outScalars` will be set as follows:

- `outArrays[0]` will contain the array of fitted y values.

- `outArrays[1]` will contain the array of residuals.

- `outArrays[2]` will contain the array of best-fit parameters that were estimated.

- `outArrays[3]` will contain the covariance matrix, returned row after row in an array.

- `outScalars[0]` will contain chi^2/nu, where chi^2 is the weighted sum of squares of the residuals, and nu is the degrees of freedom.

`outArrayLens` will be correctly set to indicate the length of each output array.

Ensure that the specified outputs in the XML file match those that the exported C function returns (which in most cases will simply be the outputs returned by the fitting function).

### Example

The following is an example of a non-linear fit plugin that performs a fit to an exponential model.

    /*
     *  Exponential fit plugin for KST.
     *  Copyright 2004, The University of British Columbia
     *  Released under the terms of the GPL.
     */

    #define NUM_PARAMS 3
    #define MAX_NUM_ITERATIONS 500

    #include "../non_linear.h"

    void function_initial_estimate( const double* pdX, const double* pdY,
                                    int iLength, double* pdParameterEstimates ) {
      KST_UNUSED( pdX )
      KST_UNUSED( pdY )
      KST_UNUSED( iLength )

      pdParameterEstimates[0] =  1.0;
      pdParameterEstimates[1] =  0.0;
      pdParameterEstimates[2] =  0.0;
    }

    double function_calculate( double dX, double* pdParameters ) {
      double dScale	 = pdParameters[0];
      double dLambda = pdParameters[1];
      double dOffset = pdParameters[2];
      double dY;

      dY  = ( dScale * exp( -dLambda * dX ) ) + dOffset;

      return dY;
    }

    void function_derivative( double dX, double* pdParameters, double* pdDerivatives ) {
      double dScale	 = pdParameters[0];
      double dLambda = pdParameters[1];
      double dExp;
      double ddScale;
      double ddLambda;
      double ddOffset;

      dExp     = exp( -dLambda * dX );
      ddScale  = dExp;
      ddLambda = -dX * dScale * dExp;
      ddOffset = 1.0;

      pdDerivatives[0] = ddScale;
      pdDerivatives[1] = ddLambda;
      pdDerivatives[2] = ddOffset;
    }

    extern "C" int kstfit_exponential(const double *const inArrays[], const int inArrayLens[],
    		const double inScalars[],
    		double *outArrays[], int outArrayLens[],
    		double outScalars[]);

    int kstfit_exponential(const double *const inArrays[], const int inArrayLens[],
    		const double inScalars[],
    		double *outArrays[], int outArrayLens[],
    		double outScalars[])
    {
      return kstfit_nonlinear( inArrays, inArrayLens,
                               inScalars, outArrays,
    			   outArrayLens, outScalars );
    }

## Creating Pass Filter Plugins

&kst; provides header files to simplify the implementation of pass filter plugins. The use of these header files is described below.

### Header Files

The pass filter header file is located in `kst/plugins/pass_filters` of the &kst; source tarball. The file is named `filters.h` To use this file, include it in the source code for your plugin:

    #include <../filters.h>

(by convention, we will place the source code for the plugin one directory below where the header files are).

### Required Functions

The `filters.h` header file contains a single function that calculates the Fourier transform of a supplied function, applies the supplied filter to the Fourier transform, and then calculates the inverse Fourier transform of the filtered Fourier transform. To supply the filter, the following function needs to be implemented in the source code for your plugin:

`double filter_calculate( double `dFreqValue`, const double `inScalars[]` )`

This function should calculate the filtered amplitude for the frequency `dFreqValue`. `inScalars[]` will contain the unaltered input scalars for the plugin, specified in the XML file. Most likely `inScalars[]` will contain cutoff frequencies or other properties of the filter. For example, to implement a Butterworth high-pass filter, `filter_calculate` could be implemented as follows:

    double filter_calculate( double dFreqValue, const double inScalars[] ) {
      double dValue;
      if( dFreqValue > 0.0 ) {
        dValue = 1.0 / ( 1.0 +
        		pow( inScalars[1] / dFreqValue, 2.0 * (double)inScalars[0] ) );
      } else {
        dValue = 0.0;
      }
      return dValue;
    }

### Calling the Filter Function

Once the required `filter_calculate` has been implemented, the filter function from the header file can be called:

    kst_pass_filter( inArrays,
                     inArrayLens,
                     inScalars,
                     outArrays,
                     outArrayLens,
                     outScalars );

The arguments supplied to the exported C function can usually be passed to `kst_pass_filter` without modification. However, there are a few restrictions on the arguments:

- `inArrays[0]` must contain the array of data to filter.

- `inScalars` should contain the filter-specific parameters to be used by the `filter_calculate` function.

After the function call, `outArrays[0]` will contain the filtered array of data, and `outArrayLens` will be set appropriately. The `kst_pass_filter` function does not use `outScalars`.

### Example

The following is an example of a pass filter plugin that implements the Butterworth high-pass filter.

    /*
     *  Butterworth low pass filter plugin for KST.
     *  Copyright 2004, The University of British Columbia
     *  Released under the terms of the GPL.
     */

    #include <stdlib.h>
    #include <math.h>
    #include "../filters.h"

    extern "C" int butterworth_highpass(const double *const inArrays[], const int inArrayLens[],
    		const double inScalars[],
    		double *outArrays[], int outArrayLens[],
    		double outScalars[]);

    int butterworth_highpass(const double *const inArrays[], const int inArrayLens[],
    		const double inScalars[],
    		double *outArrays[], int outArrayLens[],
    		double outScalars[])
    {
      int iReturn;

      iReturn = kst_pass_filter( inArrays,
                                 inArrayLens,
                                 inScalars,
                                 outArrays,
                                 outArrayLens,
                                 outScalars );

      return iReturn;
    }

    double filter_calculate( double dFreqValue, const double inScalars[] ) {
      double dValue;

      if( dFreqValue > 0.0 ) {
        dValue = 1.0 / ( 1.0 + pow( inScalars[1] / dFreqValue, 2.0 * (double)inScalars[0] ) );
      } else {
        dValue = 0.0;
      }

      return dValue;
    }