next up previous contents
Next: 3 Reading Arrays from Data Files Up: IFEFFIT Tutorial Previous: 1 Introduction

Subsections



2 Data, Commands, and Simple Data Manipulation

IFEFFIT uses a simple set of data that you can access directly at the command prompt through high-level commands. There are three types of data that IFEFFIT knows about: scalars (which contain a single floating point number), arrays (which contains a list of floating point numbers, or a vector), and strings (which contains a set of characters). If you've done any programming, these data types should be familiar to you. In keeping with the language of computer programming, I'll refer to the data in IFEFFIT as Variables. These are not necessarily the quantities varied in a fit: I'll call those Fitting Variables when there's room for confusion.


2.1 Data Types and Naming Conventions

Variables in IFEFFIT are named, and you can create and manipulate your own data. This makes IFEFFIT a fairly general purpose calculator and data plotter. That is, you can type something like this at the IFEFFIT command line:

  Ifeffit> a =  5
  Ifeffit> phi =  (sqrt(a) + 1 ) /2
  Ifeffit> print a, phi
     5.00000000     1.61803399
  Ifeffit> print sin(10)
   -0.544021111
Well, that only shows how to use scalars, not arrays or strings. IFEFFIT distinguishes its three data types by name. Here are the naming rules:

Scalars must have names that begin with a letter, ampersand '&', or underscore '_', and then contain letters, numbers, ampersands, and underscores after that. The names are not sensitive to case: A is the same as a.

Arrays have names that always have exactly one dot ('.'). This gives array names a prefix and suffix. The prefix of the array name is associated with the array Group, which is a simple and effective way to make several arrays related to each other. The naming rules for the prefix or group name are the same as for scalars. The suffix of the array name is associated with the array contents. The naming rules for the suffix are similar to those for scalars, but relaxed to allow it to begin with numbers.

Thus, 'data.energy' and 'data.xmu' are array names, and are in the group 'data'. When we get to discussing commands for doing background removal, Fourier transforms, and the like, we'll see that arrays created by IFEFFIT commands will use the same group name as the input data, which make it easy to keep a group of data together. Other valid array names are 'cu.1' and '_XX_.001'.

Strings have names that always begin with a dollar sign '$', and contain letters, numbers, ampersands, and underscores after that. You can define a string like this:

  Ifeffit> $string = Gosh, this is easy!
  Ifeffit> print $string
    Gosh, this is easy!
In fact, '$1' and '$99'' are valid string names, but their use is discouraged: '$1' ... '$9' may be internally overwritten whenever you invoke a macro, so it's not a good idea to rely on their values.

There's one more thing to note on names for variables. By convention, ``system variables'' begin with an ampersand '&' (or '$&' for system strings). This convention is not enforced in any way, but IFEFFIT tends to use such system variables for things that effect its behavior (such as how output is written to the screen). Unusual behavior may result if you write over system variables without knowing what you're doing.


2.2 Data Manipulation

As shown in the brief example at the beginning of the previous section, working with scalar variables in IFEFFIT is easy. You can create and use variables with normal algebraic syntax:

  Ifeffit> a   =  5
  Ifeffit> phi =  (sqrt(a) + 1 ) /2
  Ifeffit> x   = pi / phi
  Ifeffit> y   = cos(7*x)
  Ifeffit> print a, phi, x, y
   5.00000000    1.61803399    1.94161104   0.519178666
All scalars are floating point numbers (16 bits of precision). The usual mathematical operators (sin, tan, log, exp, coth, and so on) are supported, and a few operators not often found are supported as well1. The variables you define can be used anywhere in the mathematical expressions and assignment statements for other variables.

Manipulating arrays is just as easy as manipulating scalars, though creating arrays of data is a bit more work. One very common way to create arrays is to read them in from data files - that's covered in the next section3. You can also create arrays from scratch using the built-in functions indarr(), ones(), and zeros(). For example

  Ifeffit> test.index = indarr(10)
will create an array with elements (1,2,3,...,10). You can make other evenly spaced arrays:
  Ifeffit> npts = 100
  Ifeffit> step = 0.01
  Ifeffit> test.index = step * indarr(npts)
which will create an array with elements (0.01,0.02,...,1.0). (Starting with version 1.0053 you can also say
  Ifeffit> test.ones = range(0.01,1.0, 0.01)
to get the same effect. The range function takes "start, stop, step" as it's arguments). In addition, you can create arrays using
  Ifeffit> data.ones = ones(10)
  Ifeffit> data.null = zeros(1000)
which will create first an array with 10 elements, all set to 1: (1,1,1,...,1) and then an array of 1000 zeros.

Once you have arrays created or read in from data files, manipulating them is easy:

  Ifeffit> test.index = indarr(100)
  Ifeffit> test.sqrt  = sqrt( test.index / 10)
will fill test.sqrt with square-roots of the numbers (0.1, 0.2, .... 10.0). Note that the assignment of test.sqrt is automatically done element-by-element, without looping over elements needed. In fact, IFEFFIT doesn't even allow looping over the elements of an array.


2.3 Commands and their conventions

The operations you type at the IFEFFIT command line are interpreted as commands. In general, IFEFFIT commands consist of a name, followed by a set of arguments, usually with a keyword/value syntax:

   Ifeffit> command(key= value, key= value, key= value, ...)

The parentheses are optional, but if an opening parenthesis is used just after the command name, the closing one is required even if that means the command has to extend over multiple lines. We'll see that many commands will become quite long, so this ability will become convenient. Though they are optional, I'll use the parentheses when talking about commands, so you can tell I mean a command when I say print(). The keywords are usually short descriptive names describing some parameter the command may need. The value is often a number, but can often be a variable, string, or even a mathematical expression - a typical command would look like this:

   Ifeffit> spline(energy=data.e, xmu =data.xmu, rkbg=1, kweight="2")
The keyword/value syntax is not universal, and some commands (like the print() command shown earlier) take simple lists of arguments separated by commas. Some commands even mix lists and keyword/value pairs:
   Ifeffit> command(argument1, argument2, argument2)
   Ifeffit> command(argument1, argument2, key= value, 
                    key= value, key=value)
This may seem a little surprising, especially since in the previous section we just used
   Ifeffit> a = 2
which appears to have no command at all! The truth is that IFEFFIT always expects a command to be the first word typed at the command line, but if the first word is not a known command, it uses the default command def() - short for define, not default - to define a variable. That is, the above definition was translated to
   Ifeffit> def( a = 2 )
As we'll see in the next section, this can have some profound consequences, so it is often useful to keep in mind that the def() command is the default. I'll continue to use the simpler ``a = 2'' syntax throughout this tutorial, and expect that you will too.


2.4 Storing Definitions of Scalars and Arrays: show() and def()

Because IFEFFIT is primarily an XAFS modeling program, it is important to be able to set up both simple and complex models for XAFS path parameters that can be adjusted during a fit. To allow a flexible modeling environment, a principle feature of IFEFFIT is to allow you to define Program Variables by formula and have the values automatically updated when the values of variables in the formula change.

An example will probably help. Let's consider the case of entering this seemingly innocent set of assignments (which, we now know, will use the def() command):

  Ifeffit> a = 1
  Ifeffit> b = a + 1
  Ifeffit> a = 2
What value should b have: 2 or 3? In most computer languages and programs, b is 2, because the formula for it has not been stored, only the value at the time of its assignment. For IFEFFIT the value will be 3 - the formula is stored, not just the value.

The main advantage for this is that you could tell IFEFFIT that a is a fitting variable (by saying guess a = 1, and use both a and b for parameters in the fitting model. No matter what value the fitting engine decides a should have, b will always obey the formula you specified. When we get to fitting XAFS and non-XAFS data, you'll find (at least, eventually) this somewhat unique behavior to be very useful.

Sometimes, however. you really want b to stay as 2, not be dependent on the future value of a. That is, you sometimes want to turn off the 'store the formula' aspect of IFEFFIT. To do this, all you need to do is use the set() command as an alternative to def():

  Ifeffit> a = 1
  Ifeffit> set(b = a + 1)
  Ifeffit> a = 2
Now the formula for b will not be saved, and it will remain 2 no matter how a changes. Again, it is often useful to remember:

The default command is def(), which will save a variables definition.


2.5 The show() command

At some point you're going to want to get information back from IFEFFIT such 'what exactly is the value of e0, anyway?' and 'what are the names of all the arrays I have?'. There are two main commands for showing such information about program variables, and there's no better place to introduce them then right now. The first command is show(), which will show information about Program Variables and other IFEFFIT objects like macros and paths (which we haven't gotten to yet, but which you'll find useful soon). To follow the example of the previous section, we can see the value and definitions of the scalars a and b like this:

  Ifeffit> a = 2
  Ifeffit> b = a + 1
  Ifeffit> show a
   a              =       2.000000000
  Ifeffit> show b
   b              =       3.000000000 := a+1
Note that not only the values are shown, but also the definitions, where appropriate. Although a wasn't actually set(), it was defined as an obviously constant value that didn't depend on any program variables, so FEFFIT knew to treat it as a set value. The show() command takes a list of things (scalars, strings, arrays, etc) to show. We could have said something like this:
  Ifeffit> a = 2,  b = a + 1
  Ifeffit> $doc_string = "here is a simple definition"
  Ifeffit> show $doc_string, a, b
   $doc_string    = here is a simple definition
   a              =       2.000000000
   b              =       3.000000000 := a+1
For arrays, show() doesn't show all the data points, but a one-line summary of the data:
  Ifeffit> test.ones = ones(10)
  Ifeffit> test.index = 0.1 * indarr(100)
  Ifeffit> show test.ones, test.index
   test.ones      =   10 pts [ 1.000 : 1.000 ] := ones(10)
   test.index     =  100 pts [0.1000 : 10.00 ] := 0.1*indarr(100)
which shows test.index to have 100 point, with a minimum value of 0.1 and a maximum value of 10, for example. As for defined scalars, the definition is shown after the ``:='' characters.

It's often necessary to show all the scalars, arrays, or string variables. The show() has several modifiers to tell it to show entire classes of program variables. All the modifiers begin with the @ symbol, so to see the values and definitions of arrays, you'd say show @arrays. To see all the scalars and strings, you'd say show @scalars and show @strings.

If you try show @scalars or show @strings, you'll notice several scalars and strings that you didn't define, but are loaded in to the program as it starts. These include pi and etok2and several ``system variables'' that begin with a & (or $& for system string variables). As mentioned at the end of section 2.1, these ``system variables'' are used internally by IFEFFIT, and though you can change their values, this is not necessarily recommended. For the most part these ``system variables'' can be ignored during normal use, and won't be discussed into detail in this tutorial.

You may also notice that the order the scalars shown by show @scalars is not the same order you put them in. The order may even change over time. This reflects the fact IFEFFIT tries to manage the scalars and definitions for its own internal efficiency, and will attempt to arrange it so that the set() values are listed before the def() values. Since many commands can change the list of scalars, the order of listing may change at any time. The same behavior applies to arrays: IFEFFIT will rearrange the list of arrays to suit its own needs and to try to list the ``constant'' arrays before the defined arrays.

Speaking of array data, it's useful to see information about the groups of arrays, as analysis threads are generally done according to group. To show all the arrays in a particular group, you'd say show @group=data, which will show all the arrays in the group data as if you had said show data.energy, data.xmu and so forth. To get a list of the array groups, type show @groups.

The show() command can take other ``@'' modifiers for FEFF paths, macros, and fitting variables. These will be discussed when the time comes to discuss feff paths, writing macros, and fitting. The show() command has a modifier to show a brief description of all the commands: show @commands will list of all commands.


2.6 The print() command

We used the print() command before, but haven't really explained what it's doing. Unlike the show() command, which tends to show information about the data type, the print() command is a more literal command. That is, print e0 will simply print the values of the scalar e0. No definitions will be shown. For array data, the entire array will be printed - hardly ever what you really want, but sometimes it's necessary. At it's simplest, then, the print() command prints the values of variables listed:

 
  Ifeffit> number = 99.0 
  Ifeffit> print number 
   99.0000000 
  Ifeffit> print pi, number, $doc_string 
   3.14159265 99.0000000 here is a string
In addition to this simple behavior, the print() command can print literal strings and also evaluate expressions in place. Thus, you can use print() to write simple messages:
  Ifeffit> print " the square root of ", number, " is ", sqrt(number)
   the square root of    99.0000000  is    9.94987437
  Ifeffit> $descrip = " # of seconds per year"
  Ifeffit> value    = 365*24*60*60
  Ifeffit> print  $descrip, " = ", value
   # of seconds per year =    31536000.0
In addition to the print() command, there's also an echo() command that simply prints a string:
 
  Ifeffit> echo "Hi Mom!"
   Hi Mom!
This is not incredibly useful when typing at the command line, but does become useful when you load files of IFEFFIT commands, as we'll see next.


2.7 Command Files

Typing at the command line is all well and good until you have to do it the third or fourth time, at which point it becomes pretty tedious. More importantly, it's not convenient for processing lots of data. For that, you'd like to be able to edit text files of IFEFFIT commands and run them all at once. You can. A file of commands can be loaded with the load() command, which will run through all the commands in the file. A command file show_bkg.iff that looks like this

 # File  show_bkg.iff 
 read_data(file=Cu.dat, type=raw, group= cu)
 cu.energy  = cu.1 * 1000.0
 cu.xmu     = ln(cu.2 / cu.3)
 spline(energy = cu.energy, xmu = cu.xmu, 
        rbkg=1.1, kweight=1., kmin=0)

 plot(cu.energy, cu.xmu)
 plot(cu.energy, cu.bkg, xmin=8850, xmax=9300,  
                color=red)
 #
can be loaded as
 
  Ifeffit> load show_bkg.iff
More than that, the history mechanism of the ifeffit command-line program saves a list of the 500 most recent IFEFFIT commands run to the file .ifeffit_hist in your home directory. This file can be used as a starting point for creating and editing command files. These topics will be discussed further in section 8


next up previous contents
Next: 3 Reading Arrays from Data Files Up: IFEFFIT Tutorial Previous: 1 Introduction
Matt Newville
2001-10-05