[Ifeffit] how can i call the function of Athena or Artemis in Python

Matt Newville newville at cars.uchicago.edu
Thu Dec 4 16:52:09 CST 2008


HI Jack,

> since i am not ever a software developer(as most people), i really suggest to do a function
> lib first(which is the key parts of Athena etc.and gap between ifeffit and user. then users
> can use them in python etc first), then GUI.

It's a little confusing to read "I'm not a software developer" and "I
want to run Athena from Python".  Nobody here is actually a software
developer... we're all scientists, and some of us write programs to
get stuff done.    It seems like you'd also like to write programs to
get stuff done.  The basic Ifeffit interface may seem fairly low level
at first glance, but it really does allow you to write fairly
high-level functions very easily:

Below is a primitive "Library" that does some of what you want
(merging data).  I often use and write such scripts and I don't think
it can ever get a lot simpler than this and still be generally useful.
   Put another way: writing a library that is all of "simple to use"
and "high level" and "generally useful" is hard.    Of course, Athena,
Artemis, and SixPack all have a lot of "higher level" functionality"
on top of Ifeffit, but (as far as I can tell) neither fully separated
processing approaches from the GUI interface, and also are not (yet)
intended for general reuse.  Again, creating such a general-purpose
library is not a small amount of work.

I do agree that it would be very nice to have a set of standard
functions and classes that were not tied to a particular GUI.   I
think Bruce agrees too, hence Demeter.   For now, if you'd like to
work on a higher level Python interface that did many of the "Athena
Steps", that would be great.   The code below might give a reasonable
start, though it is a set of functions, and not class-based.  I think
that defining a class for "DataGroup" would help a lot.

As Bruce mentioned, we've played with "Python-Perl" interaction with
XML-RPC and are planning on using more of this in the future, as
Ifeffit2 will be implemented in Python, Bruce's Perl codes will need
to interact with the base library through XML-RPC.  That's a ways off,
but if your (or anyone else) is interested in getting involved with
these developments, let us know.

--Matt

#!/usr/bin/python

from Ifeffit import Ifeffit
iff  = Ifeffit()

def run_iff(commands,debug=False):
    """basic wrapper around ifeffit commands:
    send a command string or a list of command strings
    """
    cmds = commands
    if isinstance(commands,(list,tuple)):
        cmds = "\n".join(commands)
    elif not isinstance(commands,str):
        print "cannot pass commands to Ifeffit:"
        print commands
    if debug: print cmds
    iff.ifeffit(cmds)

def show_arrays():  run_iff("show @arrays")
def show_scalars():  run_iff("show @scalars")
def show_group(group):  run_iff("show @group=%s"%group)

def plot(group,x,y, range=(None,None), new=False):
    """ simple plotting wrapper"""
    cmd = ["%s.%s, %s.%s" % (group,x, group,y)]
    if new:
        cmd.append("new=1,xlabel=%s,ylabel=%s" % (x,y))

    run_iff("plot(%s)" % ','.join(cmd))
    if range is not (None,None):
        opts = ''
        if range[0] is not None: opts = "%s,xmin=%s" % (opts,str(range[0]))
        if range[1] is not None: opts = "%s,xmax=%s" % (opts,str(range[1]))
        run_iff("plot %s" % opts)


def read_GSE_trans(fname,group='a'):
    """read transmission XAFS data from GSECARS """
    cmds = ["read_data(file=%s, group=%s)" % (fname,group)]
    cmds.append("set %s.energy = %s.p1" % (group,group))
    cmds.append("set %s.xmu    = -log(%s.d2/%s.d1)" % (group,group,group))
    run_iff(cmds)

def read_GSE_fluor(fname,group='a',i0=1,d=(3,16)):
    """Simple read of fluor XAFS data from GSECARS (see escan data for
more elaborate approach)
      i0 = detector column for i0 channel [default=1]
      d  = (c1, c2) detector column range for fluorescence channels to
add together
    """

    cmds = ["read_data(file=%s, group=%s)" % (fname,group)]

    cmds.append("set %s.energy  = %s.p1" % (group,group))
    cmds.append("set %s.i0  = %s.d1" % (group,group))

    fcols = range(d[0],d[1]+1)
    dcol = '+'.join(['%s.d%i' % (group,i) for i in fcols])
    cmds.append("set %s.fl = %s" % (group,dcol))
    cmds.append("set %s.xmu = %s.fl/%s.i0" % (group,group,group))

    run_iff(cmds)


def autobk(group,rbkg=1.0,kweight=2,kmin=0,kmax=0):
    """ simple autobk wrapper"""
    cmds = ["""spline(%s.energy, %s.xmu,
    rbkg=%f, kweight=%f,kmin=%f,kmax=%f)""" %
(group,group,rbkg,kweight,kmin,kmax)]
    cmds.append("set %s.chik = %s.chi* %s.k^2" % (group,group,group))

    run_iff(cmds)

def fftf(group,kmin=0,kmax=0,kweight=2,dk=2,window='kaiser',rmax=10):
    """ simple fftf wrapper"""
    cmds = ["""fftf(%s.chi,kweight=%f,kmin=%f,kmax=%f,
    dk=%f,kwindow=%s,rmax_out=%f)""" % (group,kweight,kmin,kmax,dk,window,rmax)]

    run_iff(cmds)

def pause(t=5):
    import time
    time.sleep(t)


def merge_start(group,type='xmu',output=None):
    cmds = [] ; add = cmds.append
    add("set $merge_type=%s" % type)
    add("set merge_count=1")
    if output is None: output='merge'
    add("set $merge_output=%s" % output)
    if type=='xmu':
        add("set __tmp.en  = %s.energy" % group)
        add("set __tmp.xmu = %s.xmu"    % group)
    elif type=='chi':
        add("set __tmp.k   = %s.k"    % group)
        add("set __tmp.chi = %s.chi"  % group)
    else:
        print "cannot merge data of type: ", mtype
        return
    run_iff(cmds)

def merge_add(group):
    mtype = iff.get_string("$merge_type")
    cmds = [] ; add = cmds.append
    if mtype=='xmu':
        add("set __tmp.xmu = __tmp.xmu +
lintrp(%s.energy,%s.xmu,__tmp.xmu)" % (group,group))
    elif mtype=='chi':
        add("set __tmp.chi = __tmp.chi +
lintrp(%s.k,%s.chi,__tmp.chi)" % (group,group))
    else:
        print "cannot merge data of type: ", mtype
        return
    add("set merge_count=merge_count+1")
    run_iff(cmds)


def merge_finish(group,output=None):
    merge_add(group)
    cmds = [] ; add = cmds.append
    mtype  = iff.get_string("$merge_type")
    mout   = iff.get_string("$merge_output")
    if output is not None: mout = output
    if mtype=='xmu':
        add("set %s.energy = __tmp.en" % mout)
        add("set %s.xmu = __tmp.xmu / merge_count" % mout)
    elif mtype=='chi':
        add("set %s.k   = __tmp.k" % mout)
        add("set %s.chi = __tmp.chi / merge_count" % mout)
    else:
        print "cannot merge data of type: ", mtype
        return
    run_iff(cmds)

if __name__ == '__main__':
    read_GSE_trans('as2o5_xafs.001',group='a5')
    autobk('a5',rbkg=0.9)

    plot('a5','energy','xmu',new=True)
    plot('a5','energy','bkg')
    pause(3)

    plot('a5','k','chik',new=True)
    pause(3)

    fftf('a5',kmin=2,kmax=11,dk=3)
    plot('a5','r','chir_mag',new=True,range=(0,7))

##
## Another Example Use: (assumes the file is saved as Ifflib.py)
# import Ifflib as IFL
#
# IFL.read_GSE_fluor('04_as_xafs.001', group='as04_1', d=(3,15))
# IFL.read_GSE_fluor('04_as_xafs.002', group='as04_2', d=(3,15))
# IFL.read_GSE_fluor('04_as_xafs.003', group='as04_3', d=(3,15))
# IFL.read_GSE_fluor('04_as_xafs.004', group='as04_4', d=(3,15))
#
# IFL.merge_start('as04_4')
# IFL.merge_add('as04_3')
# IFL.merge_add('as04_2')
# IFL.merge_finish('as04_1',output='as04_ave')
#
# IFL.run_iff("save as04.sav")
#
# IFL.plot('as04_ave','energy','xmu',new=True)
#
##



More information about the Ifeffit mailing list