fitref.5
- Reflectivity Fitting for C-Plot
The following is a comprehensive
set of notes describing how I wrote the original version of fitref.5.c.
I've included any relavent code to further explain how it was written.
-- Michael Kelley
4-27-98 fitref.5.c has been updated,
the following web page has also been updated to reflect those changes.
-- Michael Kelley
6-19-98 Three
functions have been added to fitref.5: pr - Prefilter, po - Postfilter,
and p - Print. They are self explanitory functions, so I won't add
them to this page.
-- Mike
6-15-2005 Recent
Adaptations have been made to the fitref function, in hopes that we may
better fit our experimental data.
-- Clay Schumacher
This page is divided into the following sections:
-
The Main Program - Not much to say here.
-
The Setup Function - Prepares the program.
-
The Parameters - How are the parameters created.
(What
do the parameters mean?)
-
The Model - What is the model function and how is
it used.
-
The Added Functions - These are the functions I have
added.
-
Initialize Parameters
-
Save Parameters
-
Let (Set Parameter)
-
Vary Parameter
-
Print
-
Postfilter
-
Prefilter
The Main Program -
First of all, I started with prototype.5.c found
in the <cplothome>/prototypes directory. MAXPAR
was changed to 36. I included cplx.h
for complex functions (rquired for the reflectivity calculations) and stdio.h
for the file input/output. There were some independent variables
not needed for this funciton (only one is necessary) so I deleted the others,
leaving:
#define X (M_flag? Make_x[0]:dp->d_xx[0])
I also removed many of the comments as I didn't think
they helped understand the program more, but just were programming aids.
4-27-98 Four constants have been
added: firstP, lastP, firstC, lastC to correspond to the first/last index
values of each parameter.
To Top
The Setup Function -
This function sets the prompts:
setup() {
set_prompt(0, "FitRef (? for help)");
/* Main prompt */
set_prompt(1, "FitRef"); /* Command-file
prompt */
And then assigns addresses to the parameter pointers
(see The Parameters):
/* These next arrays are pointers to the parameters
to make user defined
functions easier to write */
parameterP[1]=&p1;
parameterP[2]=&p2;
parameterP[3]=&p3;
etc...
To Top
The Parameters -
Next is the parameter list. The 36 parameters
are P(1) through P(28),
and C(1) through C(8).
These are placed in the initial[] variable:
struct init_4 initial[] = {
/* Name
Deriv? Fit? Initial Limit? Low High */
{ "P(1)", 0, 0,
1, 0, 0, 0,
},
{ "P(2)", 0, 1,
1, 1, -88, 88, },
{ "P(3)", 0, 0,
1, 0, 0, 0,
},
{ "P(4)", 0, 1, 0.334,
1, 0, 3, },
{ "P(5)", 0, 0,
0, 0, 0, 0,
},
{ "P(6)", 0, 1, 17.5,
1, 0, 100, },
{ "P(7)", 0, 1, .35,
1, 0, 3, }, etc.
(All these attributes are merely initial values and can be changed by
the user, except for Deriv and Initial)
-
Deriv - 0 because the analytic-derivative is not supplied.
-
Fit - 0 for hold constant, 1 for variable.
-
Initial - The initial value for the parameter.
-
Limit - 0 for no limit, 1 for lower limit, 2 for upper limit, 3 for both.
-
Low - The lower limit.
-
High - The upper limit.
Next a mnemonic is assigned to the variables:
#define p1 fpar[0].p_b
#define fp1 fpar[0].p_fit
#define dp1 fpar[0].p_p
#define c1 fpar[28].p_b
#define fc1 fpar[28].p_fit
#define dc1 fpar[28].p_p
-
p# (or c#)
- the value of the parameter.
-
fp# (or fc#)
- the fit flag (0 for constant, 1 for variable).
-
dp# (or dc#)
- the analytic-derivative flag.
After the definitions, two global pointer arrays are defined: *parameterP[29]
and *parameterC[8]. In setup()
these are assigned to the addresses of the parameters. I believe
doing this makes user functions easier to write and read, but that is up
to you to decide (see The Setup Function);
parameterP[1]=&p1;
parameterP[2]=&p2;
parameterP[3]=&p3;
parameterP[4]=&p4;
parameterP[5]=&p5;
... etc. ...
parameterC[5]=&c5;
parameterC[6]=&c6;
parameterC[7]=&c7;
What
do the parameters mean?
To Top
The Model -
The model is the function to fit the data.
model()
returns the value of the model equation at the current point with the current
parameters.
My model() first declares
two arrays, P and C,
and lets these equal the parameters' current values:
for (i=1; i<29;
i++)
P[i]=*parameterP[i];
for (i=1; i<8; i++)
C[i]=*parameterC[i];
It then calculates the reflectivity using the function
calculateReflec()
which returns yfit, the value of the model.
X is the dependent variable from C-Plot:
calculateReflec(P,
C, X, &yfit);
calculateReflec() uses the same reflectivity
function ref1.4.c
uses.
4-27-98 The
previous for statements now read:
for (i=firstP; i<=lastP; i++)
P[i]=*parameterP[i];
for (i=firstC; i<=lastC; i++)
C[i]=*parameterC[i];
To Top
The Added Functions -
These functions are those that I have added to improve
the functionality of C-Plot's fitting program.
First the function prototypes are declared.
C-Plot requires they be type int, but the value returned means nothing:
int initParam();
int setParam();
int newhelp();
int saveParam();
int varyParam();
void toggle(int *param, char name[]);
Next they are assigned a mnemonic in the structure
user_cmds[]:
struct user_cmds
{
char
c_one;
/* The first letter of the command */
char
c_two;
/* The second letter (or 0) */
int
(*c_func)();
/* The name of the function */
} user_cmds[] = {
{ 'i', 'p', initParam
},
{ 'l', 't', setParam
},
{ '?', '\0', newhelp
},
{ 'S', 'P', saveParam
},
{ 'v', 'a', varyParam
},
0,
/* must be terminated with a zero */
};
-
ip - Initialize Parameters: Reads the parameters
from a file.
-
SP - Save Parameters: Saves the parameters to a
file readable by ip.
-
lt - Let: Changes the value of a parameter.
-
va - Vary Parameter: Toggles the vary flag for
a parameter.
-
? - Displays a simple help screen.
NOTE: toggle()
is used in varyParam().
To Top
Initialize Parameters -
Reads the parameters from a file.
First the variables are declared:
FILE *inf;
char ch, dummy, PfileName[255]="defaultparameters.dat";
int n;
/* The array index */
float val; /* The array
value */
Next the function get_snum()
is called to get the name of the file to open. get_snum()
is decribed in the C-Plot User Manual, Chapter 12:
get_snum("Name
of the parameter file to load", PfileName);
It opens the file (unless there is an error).
I will not describe the file processing algorithm here, but the file syntax
can be found in parameters.dat.
To Top
Let (Set Parameter) -
Changes the value of a parameter.
Define variables:
char *cmd = get_cmdbuf(); /*
This is a pointer to the command line */
char name[21]="\0", par;
double val;
int n, i, len;
cmd
is
a pointer to the command buffer, the string the user typed in to run the
function. If this string is longer than 3 characters then the name
of a parameter must have been entered (hopefully). E.g., compare
these two ways of acessing the function:"lt c[7]=2" and "lt". If
there is one, it copies the command line parameter (the string minus the
first three characters 'l', 't', and ' ') and finishes it with a null zero:
if ((len=strlen(cmd))>3)
{
for (i=3; i<=len &&
i<20; i++)
name[i-3]
= cmd[i]; /* Copy the cmdline to the name
array */
name[i+1]='\0';
} else {
Else the user must now supply the command string
(what parameter to change and what to change it to). Inspecting this
code and knowing that get_snum()
returns
a zero if the value of name is unchanged (in
this case from "i.e. C[7]=4.0") reveals that if nothing is entered at the
prompt, the function quits:
strcpy(name,
"i.e. C[7]=4.0");
printf("\nYou MUST use
the following format: p[n]=val or p(n)=val.");
printf("\n
Where p is the parameter, n is the index number, and val is the value.");
printf("\n
IMPORTANT: Do not add any spaces or other characters.");
if (!get_snum("\nCommand
string", name)) {
printf("\nNo
values changed.\n");
return 0;
}
}
Next, the parameter, index number, and new value
is read from the command string with sscanf():
if (name[1]=='[')
sscanf(name, "%c[%d]=%lf", &par, &n, &val);
if (name[1]=='(') sscanf(name, "%c(%d)=%lf",
&par, &n, &val);
If the index value and parameter
is correct, the parameter is changed:
switch (par) {
case 'P':
/* This is the parameter P */
if (n>0 && n<29)
*parameterP[n]=val;
else
printf("I
don't recognize or use %s. Reason: Wrong index value.\n", name);
break;
case 'C':
if (n>0 && n<8)
*parameterC[n]=val;
else
printf("I
don't recognize or use %s. Reason: Wrong index value.\n", name);
break;
default:
printf("I
don't recognize or use %s. Reason: Unrecognizable parameter.\n",
name);
break;
}
4-27-98 The previous if statements
now read:
case 'P':
/* This is the parameter P */
if (n>=firstP &&
n<lastP)
...
case 'C':
if (n>=firstC &&
n<lastC)
To Top
Save Parameters -
This saves the parameters to a file readable by
ip
and ref1.4.c
Define variables:
FILE * of;
char *cmd = get_cmdbuf(); /*
A pointer to the commmand buffer used to call the function */
char fileName[255]="parameters.dat";
int i;
double P[30], C[10];
The default value of "parameters.dat" is assigned
to fileName.
If the length of cmd
> 3, a file name must have been typed in (see Let), use
this one. Otherwise, prompt the user with get_snum()
(see C-Plot User Manual Chapter 12 for a description of this function):
if (strlen(cmd)>3)
/* There must be a file name typed */
sscanf(cmd, "SP %s", fileName);
else
get_snum("What is the
file name to save parameters to", fileName);
Open the file, and print the parameters.
To Top
Vary Parameters -
va toggles a parameter from variable/constant to
constant/variable.
First define the variables as every good C programmer
should:
char *cmd = get_cmdbuf(); /*
A pointer to the commmand buffer used to call the function */
char name[21], par;
int n, i, len;
cmd
is used the same way as in Save Parameters and Let.
If cmd > 3 assume
there is a parameter to be changed in the command line. Otherwise,
prompt for one with get_snum()
(which is found in the C-Plot User Manual Chapter 12):
if ((len=strlen(cmd))>3) {
/* If length > 3 the user must have type a parameter into cmd */
for (i=3; i<=len &&
i<20; i++)
name[i-3]
= cmd[i]; /* Copy the cmdline to the name
array */
name[i+1]='\0';
} else {
strcpy(name, "i.e. c(1)");
printf("\nYou MUST use
the following format: p[n] or p(n).");
printf("\n
Where n is a number and p is the parameter.");
if (!get_snum("\nWhat is
the parameter to toggle", name)) {
printf("\nNo
parameters toggled.\n");
return 0;
}
}
Get the parameter name and index value:
name[0]=toupper(name[0]);
if (name[1]=='[') sscanf(name, "%c[%d",
&par, &n);
if (name[1]=='(') sscanf(name, "%c(%d",
&par, &n);
Toggle its status using toggle():
switch (par) {
case 'P':
/* This is the parameter P */
switch (n)
{
case 1: toggle(&fp1, name); break;
case 2: toggle(&fp2, name); break;
case 3: toggle(&fp3, name); break;
Toggle -
A fairly simple function. It makes param
a pointer to the location of the fit flag (see The
Parameters above) and changes it's truth:
void toggle(int *param, char name[])
{
if (*param) {
*param=0;
printf("\n%s toggled from
fit to constant.\n", name);
} else {
*param=1;
printf("\n%s toggled from
constant to fit.\n", name);
}
}
To Top
Recent Adaptations -
Many new versions of fitref have been created in order to better fit new
data. These are detailed below, see source for more documentation:
fitref12.5: This function was adapted from fitref7,
which used a monolayer model, so that it would fit a bilayer model, such as
Sphingomyelin.
fitref13.5: Added convolution to fitref12.
fitref14.5: Added a linear term to the window
for convolution, and adapted the function to account for a non-uniform number of
layers throughout the sample by making c[1] the "average" last layer, and then
using two factors, alpha1 and alpha2, of the electron density of the average
last layer, and the extra partial layer, to account for their incompletion.
fitref16.5: Abandoned the factors model for a
more useful model with an independent section encompassing the last two bilayers.
fitref17.5: Added more interfaces to the bilayer,
making a total of 7. These two new interfaces account for a lower density
section of the chains due to their non-uniformity.
fitref18.5: A simplified model, with just two
repeated interfaces, one for the chains, the other for head groups/water. This
may help by providing approximations calculable from the parameters it returns,
while fitting the data accurately and quickly (relatively speaking).
fitref19.5: A version of fitref18 adapted for
a pure cholesterol model, where the interfaces are cholesterol and water,
respectively. The first section (which represented the first head group) was
removed, and it is recommended to vary P[2], the roughness between the subface
and first interface.
Clay Schumacher
To Top
Michael S Kelley
|