Warning, /graphics/kst-plot/docbook/kst/creatingplugins-chapter.docbook is written in an unsupported language. File is not indexed.

0001 <appendix id="creatingplugins">
0002 <title>Creating Additional Plugins</title>
0003 <para>
0004 &kst; has a simple and standardized interface that facilitates easy creation of additional plugins.
0005 In addition to detailing basic requirements for plugins, the following sections describe how to make
0006 use of pre-written header files to create certain types of plugins.
0007 </para>
0008 
0009 <sect1 id="creatingbasicplugin">
0010 <title>Creating a Basic Plugin</title>
0011 <para>
0012 A &kst; plugin consists of two files&mdash;an XML file and a shared object file.
0013 </para>
0014 
0015 <sect2 id="creatingbasicpluginxmlfile">
0016 <title>The XML File</title>
0017 <para>
0018 The XML file provide information about the plugin and describes its
0019 inputs and outputs.  The following is an example of an XML
0020 file for a &kst; plugin:
0021 </para>
0022 
0023 <informalexample>
0024 <screen>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
0025 &lt;!DOCTYPE Module SYSTEM "file:/Repository/Level2/Soft/ProC/moduledef.dtd"&gt;
0026 
0027 &lt;module&gt;
0028 
0029 &lt;intro&gt;
0030 &lt;modulename name="testplugin"/&gt;    &lt;!-- The name of the module --&gt;
0031 &lt;author name="Rick Chern"/&gt; &lt;!-- The name of the author --&gt;
0032 &lt;description text="A test plugin for me"/&gt; &lt;!-- A description of the module --&gt;
0033 &lt;version minor="1" major="0"/&gt;  &lt;!-- The version number of the module --&gt;
0034 &lt;state devstate="release"/&gt;     &lt;!-- The development state of the module (optional)--&gt;
0035 &lt;/intro&gt;
0036 
0037 &lt;interface&gt;
0038 
0039 &lt;!--inputs here--&gt;
0040 &lt;input&gt;
0041 &lt;table type="float" name="Input Vector 1" descr="The first input vector" /&gt;
0042 &lt;/input&gt;
0043 
0044 &lt;input&gt;
0045 &lt;float name="Input Scalar 1" descr="The first input scalar" /&gt;
0046 &lt;/input&gt;
0047 
0048 &lt;!--outputs here--&gt;
0049 &lt;output&gt;
0050 &lt;table type="float" name="Output Vector 1" descr="The first output vector" /&gt;
0051 &lt;/output&gt;
0052 
0053 &lt;output&gt;
0054 &lt;float name="Output Scalar 1" descr="The first output scalar" /&gt;
0055 &lt;/output&gt;
0056 
0057 &lt;/interface&gt;
0058 
0059 &lt;/module&gt;
0060 </screen>
0061 </informalexample>
0062 
0063 <para>
0064 Generally, you can use the example above as a template and modify sections to fit your needs.
0065 As can be seen from the example, the XML file consists of one <literal>module</literal>
0066 node.  The <literal>module</literal> node has an <literal>intro</literal> node and an
0067 <literal>interface</literal> node.  You should modify the <literal>intro</literal> node
0068 appropriately using the comments in the above XML file as guides.  It is important that
0069 <literal>modulename</literal> has the <literal>name</literal> attribute set to the same name
0070 that your shared object file will use.
0071 </para>
0072 
0073 <para>
0074 The <literal>interface</literal> node describes the actual inputs and outputs of the plugin.
0075 Each input is described by an <literal>input</literal> node, and each output is described
0076 by an <literal>output</literal> node.  Each input or output should have either a
0077 <literal>table</literal> or a <literal>float</literal> node as a child.  The <literal>type</literal>
0078 attribute of a <literal>table</literal> must be set to <literal>&quot;float&quot;</literal>.
0079 Note that the order of the inputs and outputs matters&mdash;the order is used to determine
0080 the index values for each input and output array of the object file, and is the same order
0081 used to display the input and output fields in the &kst; plugin interface.
0082 </para>
0083 
0084 <para>
0085 Once you have completed the XML file, save it as <filename>[modulename].xml</filename>, where
0086 <filename>[modulename]</filename> is the value of the <literal>name</literal> attribute
0087 of the <literal>modulename</literal> node.
0088 </para>
0089 
0090 </sect2>
0091 
0092 <sect2 id="creatingbasicpluginobjectfile">
0093 <title>The Shared Object File</title>
0094 <para>
0095 The shared object file contains the actual functionality of the plugin.  In other words,
0096 it determines how to derive the outputs from the given inputs.  The following are the
0097 requirements for the shared object file:
0098 </para>
0099 
0100 <itemizedlist>
0101 
0102 <listitem>
0103 <para>
0104 The object must export the following C linkage symbol:
0105 <literallayout><function><returnvalue>int</returnvalue> symbol(const double *const <parameter>inArrays[]</parameter>,
0106            const int <parameter>inArrayLens[]</parameter>,
0107            const double <parameter>inScalars[]</parameter>,
0108            double *<parameter>outArrays[]</parameter>,
0109            int <parameter>outArrayLens[]</parameter>,
0110            double <parameter>outScalars[]</parameter>)</function></literallayout>
0111 </para>
0112 <para>
0113 where <replaceable>symbol</replaceable> must be the value of the <literal>name</literal> attribute
0114 of the <literal>modulename</literal> node in the XML file.  This is the only
0115 function that will be called by &kst; (although you may have other functions).
0116 The following describes each argument of this function:
0117 </para>
0118 
0119 <variablelist>
0120 <varlistentry>
0121 <term><varname>const double *const inArrays[]</varname></term>
0122 <listitem>
0123 <para>
0124 The array of input arrays.  Each input array corresponds to an input vector.
0125 The arrays are in the same order as the vectors are listed in the XML file, so
0126 <literal>inArrays[0]</literal> is the array representing the first input vector,
0127 <literal>inArrays[1]</literal> is the array representing the second input vector,
0128 and so on.
0129 </para>
0130 </listitem>
0131 </varlistentry>
0132 
0133 <varlistentry>
0134 <term><varname>const int inArraysLens[]</varname></term>
0135 <listitem>
0136 <para>
0137 The array containing array lengths for each input array.  The lengths are stored
0138 in the same order as the arrays in <literal>inArrays[]</literal> (e.g.
0139 <literal>inArrayLens[0]</literal> is the length of <literal>inArrays[0]</literal>).
0140 </para>
0141 </listitem>
0142 </varlistentry>
0143 
0144 <varlistentry>
0145 <term><varname>const double inScalars[]</varname></term>
0146 <listitem>
0147 <para>
0148 The array of input scalars.  The scalars are stored in the same order as they
0149 are listed in the XML file.
0150 </para>
0151 </listitem>
0152 </varlistentry>
0153 
0154 <varlistentry>
0155 <term><varname>double *outArrays[]</varname></term>
0156 <listitem>
0157 <para>
0158 The array of output arrays.  Each output array corresponds to an output vector,
0159 and the arrays should be in the same order as the output vectors are listed in the
0160 XML file.
0161 </para>
0162 </listitem>
0163 </varlistentry>
0164 
0165 <varlistentry>
0166 <term><varname>int outArrayLens[]</varname></term>
0167 <listitem>
0168 <para>
0169 The array that should contain lengths of the output arrays.  The lengths should be
0170 stored in the same order as the arrays in <literal>outArrays[]</literal>.
0171 </para>
0172 </listitem>
0173 </varlistentry>
0174 
0175 <varlistentry>
0176 <term><varname>double outScalars[]</varname></term>
0177 <listitem>
0178 <para>
0179 The array of output scalars.  The scalars should be in the same order they are
0180 listed in the XML file.
0181 </para>
0182 </listitem>
0183 </varlistentry>
0184 </variablelist>
0185 
0186 
0187 </listitem>
0188 
0189 <listitem>
0190 <para>
0191 The function must return <literal>0</literal> if it executed successfully, and
0192 <literal>-1</literal> otherwise.
0193 </para>
0194 </listitem>
0195 
0196 <listitem>
0197 <para>
0198 The code for the object file must handle unexpected inputs, such as empty input arrays
0199 (in most cases a return value of <literal>-1</literal> would be sufficient when such
0200 situations are encountered).
0201 </para>
0202 </listitem>
0203 
0204 <listitem>
0205 <para>
0206 The number and type of outputs must be exactly as specified by the XML file.
0207 </para>
0208 </listitem>
0209 
0210 <listitem>
0211 <para>
0212 You will probably need to resize the arrays in <varname>outArrays[]</varname>.
0213 To do so, use the <function>realloc()</function> function.  E.g.,
0214 </para>
0215 <informalexample>
0216 <screen>
0217 outArrays[0]=(double*)realloc(outArrays[0], 5*sizeof(double));
0218 </screen>
0219 </informalexample>
0220 <para>
0221 will allocate space for 5 doubles for <varname>outArrays[0]</varname>.  Do not
0222 use any memory allocator other than <function>realloc()</function>.
0223 </para>
0224 </listitem>
0225 
0226 <listitem>
0227 <para>
0228 The input arguments must remain constant.  Do not cast them to non-constant types.
0229 </para>
0230 </listitem>
0231 
0232 </itemizedlist>
0233 
0234 <para>
0235 The following is an example of the shared object file source code for a simple
0236 plugin:
0237 </para>
0238 <informalexample>
0239 <screen>
0240 #include &lt;stdlib.h&gt;
0241 
0242 extern "C" int testplugin(const double *const inArrays[], const int inArrayLens[],
0243                 const double is[],
0244                 double *outArrays[], int outArrayLens[],
0245                 double outScalars[]);
0246 
0247 int testplugin(const double *const inArrays[], const int inArrayLens[],
0248                 const double is[],
0249                 double *outArrays[], int outArrayLens[],
0250                 double outScalars[])
0251 
0252 //Accept 1 vector and 1 scalar. Multiply all elements of the vector by the
0253 //scalar, and output the resulting vector. Also output the original scalar.
0254 {
0255         //Set the outputs
0256         outArrayLens[0]=inArrayLens[0];
0257 
0258         //resize the output arrays
0259         outArrays[0]=(double*)realloc(outArrays[0], inArrayLens[0]*sizeof(double));
0260 
0261         //multiply each element of the input vector
0262         //by the scalar
0263         for (int i=0; i&lt;inArrayLens[0]; i++)
0264         {
0265                 outArrays[0][i]=inArrays[0][i] * is[0];
0266         }
0267 
0268         //now set the output scalar
0269         outScalars[0]=is[0];
0270 
0271         return 0;
0272 }
0273 </screen>
0274 </informalexample>
0275 </sect2>
0276 
0277 
0278 <sect2 id="compilingplugin">
0279 <title>Compiling the Plugin</title>
0280 <para>
0281 If you are using &gcc; to compile your plugin, simply compile the object file:
0282 <screen><userinput><command>cc -Wall -c -o myplugin.o myplugin.c -fPIC -DPIC</command></userinput></screen>
0283 </para>
0284 <para>and then create the shared library:
0285 <screen><userinput><command>ld -o myplugin.so -shared myplugin.o</command></userinput></screen>
0286 </para>
0287 <para>
0288 The resulting <filename>*.so</filename> file and <filename>*.xml</filename> file must be put in the same
0289 directory.  When you use &kst;'s Plugin Manager to load the XML file, it will automatically look for the
0290 shared object file in the same directory.
0291 </para>
0292 
0293 </sect2>
0294 </sect1>
0295 
0296 <sect1 id="creatinglinearfittingplugins">
0297 <title>Creating Linear Fit Plugins</title>
0298 <para>
0299 To create a linear fit plugin, you could implement your own fitting algorithms and output the appropriate
0300 vectors.  However, &kst; already comes with header files that make it easy for you to implement linear
0301 least-squares fit plugins by just providing a few functions.
0302 This section will describe how to take advantage of these files.
0303 </para>
0304 
0305 <sect2 id="headerslinearfittingplugins">
0306 <title>Header Files</title>
0307 <para>
0308 Two header files are provided for performing linear fits, <filename>linear.h</filename>
0309  (for unweighted linear fits) and
0310 <filename>linear_weighted.h</filename> (for weighted linear fits).  They are both located under
0311 <filename>kst/plugins/fits/</filename> in the &kst; source tarball.  To use these files, include only one
0312 of them in the source code for your plugin:
0313 <screen>
0314 #include &lt;../linear.h&gt;
0315 </screen>
0316 or
0317 <screen>
0318 #include &lt;../linear_weighted.h&gt;
0319 </screen>
0320 (by convention, we will place the source code for the plugin one directory below where the header files
0321 are).
0322 </para>
0323 
0324 </sect2>
0325 
0326 <sect2 id="reqfunctionsfittingplugins">
0327 <title>Implementing Required Functions</title>
0328 <para>
0329 Given a general linear model:
0330 </para>
0331 <para>
0332 <inlinemediaobject>
0333 <imageobject>
0334 <imagedata fileref="Formula-kst-generallinearmodel.png" format="PNG"/>
0335 </imageobject>
0336 </inlinemediaobject>
0337 </para>
0338 <para>
0339 where <literal>y</literal> is a vector of <literal>n</literal> observations, <literal>X</literal>
0340 is an <literal>n</literal> by <literal>p</literal> matrix of predictor variables, and <literal>c</literal>
0341 is the vector of <literal>p</literal> best-fit parameters that are to be estimated, the header files
0342 provide functions for estimating <literal>c</literal> for a given <literal>y</literal> and
0343 <literal>X</literal>.  To provide <literal>X</literal>, the following function needs to be
0344 implemented in the source code for the plugin:
0345 <literallayout><function><returnvalue>double</returnvalue> calculate_matrix_entry( double <parameter>dX</parameter>, int <parameter>iPos</parameter> )</function></literallayout>
0346 </para>
0347 <para>
0348 This function should return the value of the entry in column <literal>iPos</literal>
0349 of the matrix of predictor variables, using <literal>x</literal> value <literal>dX</literal>.
0350 This function will be called by linear.h or linear_weighted.h.  The implementation of this function
0351 depends on the model you wish to use for the fit, and is unique to each linear fit plugin.
0352 For example, to fit to a polynomial model, <function>calculate_matrix_entry</function> could
0353 be implemented as follows:
0354 <informalexample>
0355 <screen>
0356 double calculate_matrix_entry( double dX, int iPos ) {
0357   double dY;
0358   dY = pow( dX, (double)iPos );
0359   return dY;
0360 }
0361 </screen>
0362 </informalexample>
0363 </para>
0364 
0365 </sect2>
0366 
0367 <sect2 id="callingfittingfunctionslinearfittingplugins">
0368 <title>Calling the Fitting Functions</title>
0369 <para>
0370 Once the appropriate header file has been included and <function>calculate_matrix_entry</function>
0371 has been implemented, call the appropriate fitting function included from the header file:
0372 <screen>
0373 <function>kstfit_linear_unweighted( <parameter>inArrays</parameter>, <parameter>inArrayLens</parameter>,
0374                           <parameter>outArrays</parameter>, <parameter>outArrayLens</parameter>,
0375                           <parameter>outScalars</parameter>, <parameter>iNumParams</parameter> )</function>;
0376 </screen>
0377 or
0378 <screen>
0379 <function>kstfit_linear_weighted( <parameter>inArrays</parameter>, <parameter>inArrayLens</parameter>,
0380                         <parameter>outArrays</parameter>, <parameter>outArrayLens</parameter>,
0381                         <parameter>outScalars</parameter>, <parameter>iNumParams</parameter> )</function>;
0382 </screen>
0383 </para>
0384 <para>
0385 Each function will return <literal>0</literal> on success, or <literal>-1</literal> on
0386 error, so it is a good idea to set the return value of the exported C function to be equal to the return
0387 value of the fitting function. To maintain simplicity, the code for the plugin can simply pass the
0388  arguments given to the exported C function to the fitting function. Note, however, that inArrays must
0389 be structured as follows:
0390 </para>
0391 <itemizedlist>
0392 <listitem>
0393 <para>
0394 <varname>inArrays[0]</varname> must contain the array of x coordinates of the data points
0395 </para>
0396 </listitem>
0397 
0398 <listitem>
0399 <para>
0400 <varname>inArrays[1]</varname> must contain the array of y coordinates of the data points
0401 </para>
0402 </listitem>
0403 
0404 <listitem>
0405 <para>
0406 <varname>inArrays[2]</varname> only exists if <function>kstfit_linear_weighted</function>
0407 is being called, and must contain the array of weights to use for the fit.
0408 </para>
0409 </listitem>
0410 </itemizedlist>
0411 <para>
0412 The easiest way to ensure that inArrays is structured correctly is to specify the correct
0413 order of input vectors in the XML file for the plugin.
0414 </para>
0415 <para>
0416 <varname>iNumParams</varname> is the number of parameters in the fitting model used, which
0417 should be equal to the number of columns in the matrix <literal>X</literal> of
0418 predictor variables.  <varname>iNumParams</varname> must be set correctly before the fitting
0419 function is called.
0420 </para>
0421 <para>
0422 After <function>kstfit_linear_unweighted</function> or <function>kstfit_linear_weighted</function>
0423 is called, <varname>outArrays</varname> and <varname>outScalars</varname>
0424 will be set as follows:
0425 </para>
0426 <itemizedlist>
0427 <listitem>
0428 <para>
0429 <varname>outArrays[0]</varname> will contain the array of fitted y values.
0430 </para>
0431 </listitem>
0432 
0433 <listitem>
0434 <para>
0435 <varname>outArrays[1]</varname> will contain the array of residuals.
0436 </para>
0437 </listitem>
0438 
0439 <listitem>
0440 <para>
0441 <varname>outArrays[2]</varname> will contain the array of best-fit parameters that were estimated.
0442 </para>
0443 </listitem>
0444 
0445 <listitem>
0446 <para>
0447 <varname>outArrays[3]</varname> will contain the covariance matrix, returned row after row in an array.
0448 </para>
0449 </listitem>
0450 
0451 <listitem>
0452 <para>
0453 <varname>outScalars[0]</varname> will contain chi^2/nu, where chi^2 is the weighted sum of squares of the residuals,
0454 and nu is the degrees of freedom.
0455 </para>
0456 </listitem>
0457 </itemizedlist>
0458 <para>
0459 <varname>outArrayLens</varname> will be correctly set to indicate the length of each output array.
0460 </para>
0461 
0462 <para>
0463 Ensure that the specified outputs in the XML file match those that the exported C function returns (which
0464 in most cases will simply be the outputs returned by the fitting function).
0465 </para>
0466 
0467 
0468 </sect2>
0469 
0470 <sect2 id="examplelinearfittingplugins">
0471 <title>Example</title>
0472 <para>
0473 The following is an example of the source code for a linear fit plugin.
0474 </para>
0475 <informalexample>
0476 <screen>
0477 /*
0478  *  Polynomial fitting plugin for KST.
0479  *  Copyright 2004, The University of British Columbia
0480  *  Released under the terms of the GPL.
0481  */
0482 
0483 #include "../linear.h"
0484 
0485 double calculate_matrix_entry( double dX, int iPos ) {
0486   double dY;
0487 
0488   dY = pow( dX, (double)iPos );
0489 
0490   return dY;
0491 }
0492 
0493 extern "C" int kstfit_polynomial_unweighted(
0494   const double *const inArrays[],
0495   const int inArrayLens[],
0496   const double inScalars[],
0497   double *outArrays[], int outArrayLens[],
0498   double outScalars[]);
0499 
0500 int kstfit_polynomial_unweighted(
0501   const double *const inArrays[],
0502   const int inArrayLens[],
0503         const double inScalars[],
0504         double *outArrays[], int outArrayLens[],
0505         double outScalars[])
0506 {
0507   int iRetVal = -1;
0508   int iNumParams;
0509 
0510   iNumParams = 1 + (int)floor( inScalars[0] );
0511   if( iNumParams &gt; 0 ) {
0512     iRetVal = kstfit_linear_unweighted( inArrays, inArrayLens,
0513                                         outArrays, outArrayLens,
0514                                         outScalars, iNumParams );
0515   }
0516 
0517   return iRetVal;
0518 }
0519 </screen>
0520 </informalexample>
0521 </sect2>
0522 
0523 </sect1>
0524 
0525 <sect1 id="creatingnonlinearfitplugin">
0526 <title>Creating Non-linear Fit Plugins</title>
0527 <para>
0528 &kst; provides header files designed to simplify the creation of non-linear least-squares fit plugins.
0529 The following sections detail the use of the header files.
0530 </para>
0531 
0532 <sect2 id="headersnonlinearfittingplugins">
0533 <title>Header Files and Definitions</title>
0534 <para>
0535 The non-linear fit header files are located in <filename>kst/plugins/fits_nonlinear</filename> of
0536 the &kst; source tarball.  The files are named <filename>non_linear.h</filename> and
0537 <filename>non_linear_weighted.h</filename> for unweighted and weighted fits, respectively.
0538 To use these files, include only one of them in the source code for your plugin:
0539 <screen>
0540 #include &lt;../non_linear.h&gt;
0541 </screen>
0542 or
0543 <screen>
0544 #include &lt;../non_linear_weighted.h&gt;
0545 </screen>
0546 (by convention, we will place the source code for the plugin one directory below where the header files
0547 are).
0548 </para>
0549 
0550 <para>
0551 As non-linear fitting is an iterative process, you must also define the maximum number of iterations
0552 that should be performed.  The non-linear fitting algorithm will stop when at least one of the following
0553 conditions is true:
0554 </para>
0555 <itemizedlist>
0556 <listitem>
0557 <para>
0558 The maximum number of iterations has been reached.
0559 </para>
0560 </listitem>
0561 <listitem>
0562 <para>
0563 A precision of 10<superscript>-4</superscript> has been reached.
0564 </para>
0565 </listitem>
0566 </itemizedlist>
0567 <para>
0568 In addition, you need to define the number of parameters in the model, as it is not passed to the fitting
0569 function explicitly.  To define these two values, include the following at the top of your source code:
0570 </para>
0571 <screen>
0572 #define NUM_PARAMS [num1]
0573 #define MAX_NUM_ITERATIONS [num2]
0574 </screen>
0575 <para>
0576 replacing <literal>[num1]</literal> with the number of parameters in the model, and <literal>[num2]</literal>
0577 with the maximum number of iterations to perform.
0578 </para>
0579 </sect2>
0580 
0581 <sect2 id="reqfunctionsnonlinearfittingplugins">
0582 <title>Implementing Required Functions</title>
0583 <para>
0584 To use the header files for non-linear fits, you must provide the function to use as the model,
0585 the partial derivatives of the function with respect to each parameter, and initial estimates
0586 of the best-fit parameters.
0587 To do this, three functions must be implemented. These functions
0588 are described below.
0589 </para>
0590 <variablelist>
0591 <varlistentry>
0592 <term><function><returnvalue>double</returnvalue> function_calculate( double <parameter>dX</parameter>, double* <parameter>pdParameters</parameter> )</function></term>
0593 <listitem>
0594 <para>
0595 This function calculates the y value of the fitting model for a given x value <literal>dX</literal>,
0596 using the supplied array of parameters <varname>pdParameters</varname>.  The order of parameters in
0597 <varname>pdParameters</varname> is arbitrary, but should be consistent with the other two
0598 implemented functions.
0599 For example, for an exponential model,
0600 <function>function_calculate</function> could be implemented as follows:
0601 </para>
0602 <informalexample>
0603 <screen>
0604 double function_calculate( double dX, double* pdParameters ) {
0605   double dScale  = pdParameters[0];
0606   double dLambda = pdParameters[1];
0607   double dOffset = pdParameters[2];
0608   double dY;
0609 
0610   dY  = ( dScale * exp( -dLambda * dX ) ) + dOffset;
0611 
0612   return dY;
0613 }
0614 </screen>
0615 </informalexample>
0616 </listitem>
0617 </varlistentry>
0618 
0619 <varlistentry>
0620 <term><function><returnvalue>void</returnvalue> function_derivative( double <parameter>dX</parameter>, double* <parameter>pdParameters</parameter>, double* <parameter>pdDerivatives</parameter> )</function></term>
0621 <listitem>
0622 <para>
0623 This function calculates the partial derivatives of the model function for
0624 a give value of x <literal>dX</literal>.  The partial derivatives should be returned in
0625 <varname>pdDerivatives</varname>.  The order of the partial derivatives in the array
0626 <varname>pdDerivatives</varname> should correspond to the order of the parameters
0627 in <varname>pdParameters</varname> (i.e. if <varname>pdParameters[0]</varname> contains
0628 the parameter lambda for an exponential model, <varname>pdDerivatives[0]</varname> should
0629 contain the derivative of the model with respect to lambda).
0630 </para>
0631 </listitem>
0632 </varlistentry>
0633 
0634 <varlistentry>
0635 <term><function><returnvalue>void</returnvalue> function_initial_estimate(
0636 const double* <parameter>pdX</parameter>, const double* <parameter>pdY</parameter>,
0637 int <parameter>iLength</parameter>, double* <parameter>pdParameterEstimates</parameter> )</function></term>
0638 <listitem>
0639 <para>
0640 This function provides an initial estimate of the best-fit parameters to the fitting function. The array of
0641 x values and y values of the data points are provided in <varname>pdX</varname> and <varname>pdY</varname>
0642 respectively, and the number of data points is provided by <varname>iLength</varname>.  You can use any or
0643 none of these parameters at your discretion to calculate the initial estimate.  The function should put the
0644 calculated initial estimates in <varname>pdParameterEstimates</varname>, with the order of the estimates
0645 corresponding to the order of the parameters in <varname>pdParameters</varname> of
0646 <function>function_calculate</function> and <function>function_derivative</function>.  Keep in mind that the
0647 initial estimate is important in determining whether or not the fitting function converges to a solution.
0648 </para>
0649 </listitem>
0650 </varlistentry>
0651 
0652 </variablelist>
0653 
0654 </sect2>
0655 
0656 <sect2 id="callingnonlinearfittingplugins">
0657 <title>Calling the Fitting Functions</title>
0658 <para>
0659 Once all the required functions have been implemented, the fitting function from the included header file
0660 can be called:
0661 <screen>
0662 kstfit_nonlinear( <parameter>inArrays</parameter>, <parameter>inArrayLens</parameter>,
0663                   <parameter>inScalars</parameter>, <parameter>outArrays</parameter>,
0664                   <parameter>outArrayLens</parameter>, <parameter>outScalars</parameter> );
0665 </screen>
0666 or
0667 <screen>
0668 kstfit_nonlinear_weighted( <parameter>inArrays</parameter>, <parameter>inArrayLens</parameter>,
0669                            <parameter>inScalars</parameter>, <parameter>outArrays</parameter>,
0670                            <parameter>outArrayLens</parameter>, <parameter>outScalars</parameter> );
0671 </screen>
0672 depending on whether you are implementing a non-weighted fit or a weighted fit.
0673 </para>
0674 
0675 <para>
0676 The function will return <literal>0</literal> on success, or <literal>-1</literal> on
0677 error, so it is simplest to set the return value of the exported C function to be equal to the return
0678 value of the fitting function. To maintain simplicity, the code for the plugin can simply pass the
0679  arguments given to the exported C function to the fitting function. Note, however, that inArrays must
0680 be structured as follows:
0681 </para>
0682 <itemizedlist>
0683 <listitem>
0684 <para>
0685 <varname>inArrays[0]</varname> must contain the array of x coordinates of the data points
0686 </para>
0687 </listitem>
0688 
0689 <listitem>
0690 <para>
0691 <varname>inArrays[1]</varname> must contain the array of y coordinates of the data points
0692 </para>
0693 </listitem>
0694 
0695 <listitem>
0696 <para>
0697 <varname>inArrays[2]</varname> only exists if <function>kstfit_linear_weighted</function>
0698 is being called, and must contain the array of weights to use for the fit.
0699 </para>
0700 </listitem>
0701 </itemizedlist>
0702 <para>
0703 The easiest way to ensure that inArrays is structured correctly is to specify the correct
0704 order of input vectors in the XML file for the plugin.
0705 </para>
0706 <para>
0707 After <function>kstfit_linear_unweighted</function> or <function>kstfit_linear_weighted</function>
0708 is called, <varname>outArrays</varname> and <varname>outScalars</varname>
0709 will be set as follows:
0710 </para>
0711 <itemizedlist>
0712 <listitem>
0713 <para>
0714 <varname>outArrays[0]</varname> will contain the array of fitted y values.
0715 </para>
0716 </listitem>
0717 
0718 <listitem>
0719 <para>
0720 <varname>outArrays[1]</varname> will contain the array of residuals.
0721 </para>
0722 </listitem>
0723 
0724 <listitem>
0725 <para>
0726 <varname>outArrays[2]</varname> will contain the array of best-fit parameters that were estimated.
0727 </para>
0728 </listitem>
0729 
0730 <listitem>
0731 <para>
0732 <varname>outArrays[3]</varname> will contain the covariance matrix, returned row after row in an array.
0733 </para>
0734 </listitem>
0735 
0736 <listitem>
0737 <para>
0738 <varname>outScalars[0]</varname> will contain chi^2/nu, where chi^2 is the weighted sum of squares of the residuals,
0739 and nu is the degrees of freedom.
0740 </para>
0741 </listitem>
0742 </itemizedlist>
0743 <para>
0744 <varname>outArrayLens</varname> will be correctly set to indicate the length of each output array.
0745 </para>
0746 
0747 <para>
0748 Ensure that the specified outputs in the XML file match those that the exported C function returns (which
0749 in most cases will simply be the outputs returned by the fitting function).
0750 </para>
0751 
0752 </sect2>
0753 
0754 <sect2 id="nonlinearfittingpluginexample">
0755 <title>Example</title>
0756 <para>The following is an example of a non-linear fit plugin that performs a fit to an exponential model.</para>
0757 <informalexample>
0758 <screen>
0759 /*
0760  *  Exponential fit plugin for KST.
0761  *  Copyright 2004, The University of British Columbia
0762  *  Released under the terms of the GPL.
0763  */
0764 
0765 #define NUM_PARAMS 3
0766 #define MAX_NUM_ITERATIONS 500
0767 
0768 #include "../non_linear.h"
0769 
0770 void function_initial_estimate( const double* pdX, const double* pdY,
0771                                 int iLength, double* pdParameterEstimates ) {
0772   KST_UNUSED( pdX )
0773   KST_UNUSED( pdY )
0774   KST_UNUSED( iLength )
0775 
0776   pdParameterEstimates[0] =  1.0;
0777   pdParameterEstimates[1] =  0.0;
0778   pdParameterEstimates[2] =  0.0;
0779 }
0780 
0781 double function_calculate( double dX, double* pdParameters ) {
0782   double dScale  = pdParameters[0];
0783   double dLambda = pdParameters[1];
0784   double dOffset = pdParameters[2];
0785   double dY;
0786 
0787   dY  = ( dScale * exp( -dLambda * dX ) ) + dOffset;
0788 
0789   return dY;
0790 }
0791 
0792 void function_derivative( double dX, double* pdParameters, double* pdDerivatives ) {
0793   double dScale  = pdParameters[0];
0794   double dLambda = pdParameters[1];
0795   double dExp;  
0796   double ddScale;
0797   double ddLambda;
0798   double ddOffset;
0799   
0800   dExp     = exp( -dLambda * dX );
0801   ddScale  = dExp;
0802   ddLambda = -dX * dScale * dExp;
0803   ddOffset = 1.0;
0804 
0805   pdDerivatives[0] = ddScale;
0806   pdDerivatives[1] = ddLambda;
0807   pdDerivatives[2] = ddOffset;
0808 }
0809 
0810 extern "C" int kstfit_exponential(const double *const inArrays[], const int inArrayLens[],
0811                 const double inScalars[],
0812                 double *outArrays[], int outArrayLens[],
0813                 double outScalars[]);
0814 
0815 int kstfit_exponential(const double *const inArrays[], const int inArrayLens[],
0816                 const double inScalars[],
0817                 double *outArrays[], int outArrayLens[],
0818                 double outScalars[])
0819 {
0820   return kstfit_nonlinear( inArrays, inArrayLens,
0821                            inScalars, outArrays,
0822                            outArrayLens, outScalars );
0823 }
0824 </screen>
0825 </informalexample>
0826 
0827 </sect2>
0828 </sect1>
0829 
0830 <sect1 id="creatingpassfilterplugins">
0831 <title>Creating Pass Filter Plugins</title>
0832 <para>
0833 &kst; provides header files to simplify the implementation of pass filter plugins. The use of these
0834 header files is described below.
0835 </para>
0836 <sect2 id="creatingpassfilterpluginsheaderfiles">
0837 <title>Header Files</title>
0838 <para>
0839 The pass filter header file is located in <filename>kst/plugins/pass_filters</filename> of
0840 the &kst; source tarball.  The file is named <filename>filters.h</filename>
0841 To use this file, include it in the source code for your plugin:
0842 <screen>
0843 #include &lt;../filters.h&gt;
0844 </screen>
0845 (by convention, we will place the source code for the plugin one directory below where the header files
0846 are).
0847 </para>
0848 </sect2>
0849 
0850 <sect2 id="creatingpassfilterpluginsrequirements">
0851 <title>Required Functions</title>
0852 <para>
0853 The <filename>filters.h</filename> header file contains a single function that calculates the Fourier
0854 transform of a supplied function, applies the supplied filter to the Fourier transform, and then calculates
0855 the inverse Fourier transform of the filtered Fourier transform.  To supply the filter, the following
0856 function needs to be implemented in the source code for your plugin:
0857 </para>
0858 <para><function><returnvalue>double</returnvalue> filter_calculate( double <parameter>dFreqValue</parameter>, const double <parameter>inScalars[]</parameter> )</function></para>
0859 <para>
0860 This function should calculate the filtered amplitude for the frequency <literal>dFreqValue</literal>.
0861 <literal>inScalars[]</literal> will contain the unaltered input scalars for the plugin, specified in the
0862 XML file.  Most likely <literal>inScalars[]</literal> will contain cutoff frequencies or other
0863 properties of the filter.  For example, to implement a Butterworth high-pass filter,
0864 <function>filter_calculate</function> could be implemented as follows:
0865 </para>
0866 <informalexample>
0867 <screen>
0868 double filter_calculate( double dFreqValue, const double inScalars[] ) {
0869   double dValue;
0870   if( dFreqValue > 0.0 ) {
0871     dValue = 1.0 / ( 1.0 +
0872                 pow( inScalars[1] / dFreqValue, 2.0 * (double)inScalars[0] ) );
0873   } else {
0874     dValue = 0.0;
0875   }
0876   return dValue;
0877 }
0878 </screen>
0879 </informalexample>
0880 </sect2>
0881 
0882 <sect2 id="creatingpassfilterpluginscallingfunction">
0883 <title>Calling the Filter Function</title>
0884 <para>
0885 Once the required <function>filter_calculate</function> has been implemented, the filter function
0886 from the header file can be called:
0887 </para>
0888 <literallayout><function>kst_pass_filter( <parameter>inArrays</parameter>,
0889                  <parameter>inArrayLens</parameter>,
0890                  <parameter>inScalars</parameter>,
0891                  <parameter>outArrays</parameter>,
0892                  <parameter>outArrayLens</parameter>,
0893                  <parameter>outScalars</parameter> );</function></literallayout>
0894 <para>
0895 The arguments supplied to the exported C function can usually be passed to
0896 <function>kst_pass_filter</function> without modification.  However, there are a few restrictions
0897 on the arguments:
0898 </para>
0899 <itemizedlist>
0900 <listitem>
0901 <para>
0902 <varname>inArrays[0]</varname> must contain the array of data to filter.
0903 </para>
0904 </listitem>
0905 
0906 <listitem>
0907 <para>
0908 <varname>inScalars</varname> should contain the filter-specific parameters to be used by
0909 the <function>filter_calculate</function> function.
0910 </para>
0911 </listitem>
0912 </itemizedlist>
0913 <para>
0914 After the function call, <varname>outArrays[0]</varname> will contain the filtered array of data, and
0915 <varname>outArrayLens</varname> will be set appropriately.  The <function>kst_pass_filter</function>
0916 function does not use <varname>outScalars</varname>.
0917 </para>
0918 </sect2>
0919 
0920 <sect2 id="creatingpassfilterpluginsexample">
0921 <title>Example</title>
0922 <para>
0923 The following is an example of a pass filter plugin that implements the Butterworth high-pass filter.
0924 </para>
0925 <informalexample>
0926 <screen>/*
0927  *  Butterworth low pass filter plugin for KST.
0928  *  Copyright 2004, The University of British Columbia
0929  *  Released under the terms of the GPL.
0930  */
0931 
0932 #include &lt;stdlib.h&gt;
0933 #include &lt;math.h&gt;
0934 #include "../filters.h"
0935 
0936 extern "C" int butterworth_highpass(const double *const inArrays[], const int inArrayLens[],
0937                 const double inScalars[],
0938                 double *outArrays[], int outArrayLens[],
0939                 double outScalars[]);
0940 
0941 int butterworth_highpass(const double *const inArrays[], const int inArrayLens[],
0942                 const double inScalars[],
0943                 double *outArrays[], int outArrayLens[],
0944                 double outScalars[])
0945 {
0946   int iReturn;
0947 
0948   iReturn = kst_pass_filter( inArrays,
0949                              inArrayLens,
0950                              inScalars,
0951                              outArrays,
0952                              outArrayLens,
0953                              outScalars );
0954 
0955   return iReturn;
0956 }
0957 
0958 double filter_calculate( double dFreqValue, const double inScalars[] ) {
0959   double dValue;
0960 
0961   if( dFreqValue &gt; 0.0 ) {
0962     dValue = 1.0 / ( 1.0 + pow( inScalars[1] / dFreqValue, 2.0 * (double)inScalars[0] ) );
0963   } else {
0964     dValue = 0.0;
0965   }
0966 
0967   return dValue;
0968 }</screen>
0969 </informalexample>
0970 </sect2>
0971 
0972 </sect1>
0973 </appendix>
0974 
0975 
0976 <!-- Keep this comment at the end of the file
0977 Local variables:
0978 mode: xml
0979 sgml-omittag:nil
0980 sgml-shorttag:nil
0981 sgml-namecase-general:nil
0982 sgml-general-insert-case:lower
0983 sgml-minimize-attributes:nil
0984 sgml-always-quote-attributes:t
0985 sgml-indent-step:0
0986 sgml-indent-data:true
0987 sgml-parent-document:("index.docbook" "book" "appendix")
0988 sgml-exposed-tags:nil
0989 sgml-local-catalogs:nil
0990 sgml-local-ecat-files:nil
0991 End:
0992 -->