Author |
Topic |
|
Stefan.E.S
Germany
11 Posts |
Posted - 04/23/2010 : 09:11:19 AM
|
Origin Ver. and Service Release : 8.1G SR2 Operating System: WinXP
In a fit function I need to access data which are contained in an Origin worksheet. The fit function is programmed as using Microsoft Visual C++.
Can I use e.g. lParam1 or LParam2 from the FIT_PARA_LIST below for access to an origin worksheet?
#define FIT_PARA_LIST short cntrl, DWORD lpProc, short nParam, DWORD lParam1, DWORD lParam2, LPDOUBLE p, LPDOUBLE c, LPDOUBLE x, LPDOUBLE y, LPDOUBLE dy
Furthermore, I would like to use the number (index) of the current x-axis data point in my fit function.
How can this be retrieved in an external DLL fit function?
|
|
Stefan.E.S
Germany
11 Posts |
Posted - 04/29/2010 : 04:03:30 AM
|
I forgot to mention that access to origin worksheets from external DLL fitting functions was possible with Origin 7.5. I just wonder how this functionality can be used in Origin 8.1. Below a copy of a working orgin 7.5 example. A response from OriginLab would be appreaciated.
Thanks,
Stefan
#include <windows.h>
/* The following entry function
* related to Windows
*/
#ifndef _WIN32
int FAR PASCAL LibMain(hModule, wDataSeg, cbHeapSize, lpszCmdLine)
HANDLE hModule;
WORD wDataSeg;
WORD cbHeapSize;
LPSTR lpszCmdLine;
{
return 1;/* Nothing is done, but it is necessary */
}
// ANU v4.134 9/30/96 32_BIT_COMPATIBLE
#else //_WIN32
BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
{
// The return value is only used for DLL_PROCESS_ATTACH; all other
// conditions are ignored.
return TRUE; // successful DLL_PROCESS_ATTACH
}
#endif
///end 32_BIT_COMPATIBLE
/* Your DLL code starts here */
#include <math.h>
#include <stdio.h>
#include "orgdll.h"
///Function names have to be upper case so that origin can
//recognize the functions.
int FAR PASCAL THEOFIT(
HWND hWnd, /* Origin's main window */
double FAR * lpValue,/* input (x) ,output (y)*/
short nParam, /* number of parameters */
double FAR * lpParam,/* parameter array */
LPCALLBK lpfn)
{
/* Fitting of a weighted sum of theoretical spectra to an experimental spectrum.
The theoretical spectra are assumed to be contained in a workshhet named "Theory"
and to have a common, equidistant energy axis that is col. no. 1 in the worksheet.
The spectra are assumed to be in the subsequent columns. Column names can be arbitrary.
The number of parameters to be given in the fdf-file is 3 + number of spectra) */
/* Fit parameters are
* lpParam[0] : overall scale factor
* lpParam[1..2] : linear background (subtracted)
* lpParam[3..nspec+3] : individual scale factor for each spectrum
* lpParam[nspec+4..2*nspec+3] : energy shift for each spectrum
* nspec, npts and theory[npts][nspec+1] are defined in Theospec.h
* with the theoretical energy scale stored in theory[npts][0]
*/
double x = *lpValue;
if (x<=0) {*lpValue=0;return (0);}
/* lpValue point to a temperary location
* that contains the X value on input
*/
int nspec = (nParam-3)/2;
char TheoryWksName[80], colname[80], cstr[80];
typedef char SpecName[80];
SpecName Theory_E, *Theory_Spectrum = new SpecName[nspec];
strcpy(TheoryWksName,"Theory");
// get name of 1st column in theory worksheet (energy)
lpfn(hWnd,WCB_EXECUTE,"%A=Theory!WKS.COL1.NAME$",0L);
lpfn(hWnd,WCB_GET_STRING,(LPSTR)colname,0);
strcpy(Theory_E,TheoryWksName);
strcat(Theory_E,"_");
strcat(Theory_E,colname);
int n;
for (n=1;n<=nspec;n++)
{
// get name of n+1st column in theory worksheet (spectra)
sprintf(cstr,"%%A=Theory!WKS.COL%d.NAME$",n+1);
lpfn(hWnd,WCB_EXECUTE,cstr,0L);
lpfn(hWnd,WCB_GET_STRING,(LPSTR)colname,0);
strcpy(Theory_Spectrum[n-1],TheoryWksName);
strcat(Theory_Spectrum[n-1],"_");
strcat(Theory_Spectrum[n-1],colname);
// output to script window for debugging purposes
// sprintf(cstr,"type -a $(%d) %s",n,Theory_Spectrum[n-1]);
// lpfn(hWnd,WCB_EXECUTE,(LPSTR)cstr,0L);
}
// variables needed for reading data from worksheets
long range[4];
DWORD data_id;
DATAELEMENT data;
data.index = 0;
data_id = lpfn(hWnd, WCB_DATA_GET_ID, (LPSTR)Theory_E, (LPSTR)range);
lpfn(hWnd, WCB_DATA_GET_VALUE, (LPSTR)data_id, (LPSTR)(&data));
double x0 = data.value;
long int npts = range[1];
data.index = 1;
data_id = lpfn(hWnd, WCB_DATA_GET_ID, (LPSTR)Theory_E, (LPSTR)range);
lpfn(hWnd, WCB_DATA_GET_VALUE, (LPSTR)data_id, (LPSTR)(&data));
double x1 = data.value;
double dx = x1-x0;
double y=0;
int i;
for (int j=0;j<nspec;j++)
{
double eshift = lpParam[3+nspec+j];
i = int((x-x0-eshift)/dx);
/*
// in case of non equidistant x-values use the following instructions
for (i=npts-1;i>=0;i--)
{
data.index = i;
data_id = lpfn(hWnd, WCB_DATA_GET_ID, (LPSTR)Theory_E, (LPSTR)range);
lpfn(hWnd, WCB_DATA_GET_VALUE, (LPSTR)data_id, (LPSTR)(&data));
double xi = data.value+eshift;
if (x<xi) break;
}
*/
if ((i>0) && (i<npts-2))
{
data.index = i;
data_id = lpfn(hWnd, WCB_DATA_GET_ID, (LPSTR)Theory_E, (LPSTR)range);
lpfn(hWnd, WCB_DATA_GET_VALUE, (LPSTR)data_id, (LPSTR)(&data));
double x1 = data.value+eshift;
data.index = i;
data_id = lpfn(hWnd, WCB_DATA_GET_ID, (LPSTR)Theory_Spectrum[j], (LPSTR)range);
lpfn(hWnd, WCB_DATA_GET_VALUE, (LPSTR)data_id, (LPSTR)(&data));
double y1 = data.value;
data.index = i+1;
data_id = lpfn(hWnd, WCB_DATA_GET_ID, (LPSTR)Theory_Spectrum[j], (LPSTR)range);
lpfn(hWnd, WCB_DATA_GET_VALUE, (LPSTR)data_id, (LPSTR)(&data));
double y2 = data.value;
y += lpParam[j+3]*(y1 + (x-x1)*(y2-y1)/dx);
}
}
y *= lpParam[0]; // overall scale factor
y -= lpParam[1]+x*lpParam[2]; // subtract background
*lpValue = y; // result of the function is stored back to lpValue
delete[] Theory_Spectrum;
return(0);
/* You must return zero if there is no error
* otherwise you can return any number other than
* zero to signal an error
*/
}
StSch |
|
|
Stefan.E.S
Germany
11 Posts |
Posted - 04/29/2010 : 04:45:18 AM
|
I just found out that I simply had to recompile the DLL using the Origin 8.1 header file "OriginLab\Orgin81\ATI\include\ORGDLL.H" instead of "FitFuncDef.H". Now the fitting works.
I suggest to supply documentation for fitting with fit functions from an external DLL using ORGDLL.H. Currently there is only documentation for "FitFuncDef.h".
Below I attach the fdf-file that I use for running the example from my previous post
[General Information]
Function Name = Theofit4
Brief Description = linear combination of theoretical spectra
Function Source = Theofit.1
Function Type = External DLL
Function Form = Expression
Number Of Parameters = 11
Number Of Independent Variables = 1
Number Of Dependent Variables = 1
Analytical Derivatives for User-Defined = 0
FunctionPrev = Theofit4
[Fitting Parameters]
Naming Method = User-Defined
Names = yscale,a0,a1,c1S,c3P0,c3P1,c3P2,es1S,es3P0,es3P1,es3P2
Meanings = xxx,xxx,xxx,xxx
Initial Values = 1.0(F),0.0(F),0.0(F),0.25(V),0.25(V),0.25(V),0.25(V),0(F),0(F),0(F),0(F)
Lower Bounds = 0.0,--,--,0.0,0.0,0.0,0.0,--,--,--,--
Upper Bounds = --,--,--,1.0,1.0,1.0,1.0,--,--,--,--
Number Of Significant Digits = 8,8,8,8,8,8,8,8,8,8,8
[Formula]
formula goes here;
[Constraints]
c1s+c3P0+c3P1+c3P2=1;
es3P1=es3P0;
es3P2=es3P0;
[Constants]
[Parameters Initialization]
[Initializations]
[After Fitting]
[Independent Variables]
x =
[Dependent Variables]
y =
[Controls]
General Linear Constraints = 0
Initialization Scripts = 1
Scripts After Fitting = 0
Number Of Duplicates = N/A
Duplicate Offset = N/A
Duplicate Unit = N/A
Generate Curves After Fitting = 1
Curve Point Spacing = Same X as Fitting Data
Generate Peaks After Fitting = 0
Generate Peaks During Fitting = 0
Generate Peaks with Baseline = 0
Paste Parameters to Plot After Fitting = 1
Paste Parameters to Notes Window After Fitting = 1
Generate Residuals After Fitting = 0
Keep Parameters = 1
Enable Parameters Initialization = 0
Compile On Param Change Script = 0
[Compile Function]
Compile = 0
Compile Parameters Initialization = 0
OnParamChangeScriptsEnabled = N/A
[Origin C Function Header]
[Origin C Parameter Initialization Header]
[References]
StSch |
|
|
|
Topic |
|
|
|