[Ifeffit] Rebinning

Carlo U. Segre segre at iit.edu
Tue Mar 11 12:16:24 CST 2003


Matt and Bruce:

Following our previous discussion of rebinning continuous scan data, I am
attaching a python code fragment which we use to perform this function.
You are free to use it as you like.  It was written by Ken McIvor, a
student at IIT as part of a larger project to manipulate and preview
MR-CAT XAFS data.  We simply pulled out the code and annotated it
somewhat.

Carlo

-- 
Carlo U. Segre -- Professor of Physics
Associate Dean for Research, Armour College
Illinois Institute of Technology
Voice: 312.567.3498            Fax: 312.567.3494
Carlo.Segre at iit.edu    http://www.iit.edu/~segre
-------------- next part --------------
# Name: rebin-alg.py
# Purpose: An algorithm to perform XAFS data reduction.
# Author: Ken McIvor <mcivken at iit.edu>
#
# Copyright 2003 Illinois Institute of Technology
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL ILLINOIS INSTITUTE OF TECHNOLOGY BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of Illinois Institute
# of Technology shall not be used in advertising or otherwise to promote
# the sale, use or other dealings in this Software without prior written
# authorization from Illinois Institute of Technology.


import math
import bisect
import Numeric


def grid(start, stop, stepSize):
	"""Create an array which can be used as an abscissa for interpolation.

	Returns an array of regular values, increasing by 'stepSize', which go from
	'start' to 'stop' inclusively.
	"""
	r = Numeric.arange(start, stop + stepSize, stepSize)
	while r[-1] > stop:
		r = r[:-1]
	if r[-1] < stop:
		r = Numeric.resize(r, (r.shape[0]+1, ) )
		r[-1] = stop
	return r


def rebin(data, eColumn, Eo, after, kstep, file='', msgStream=None):
	"""XAFS data reduction.

	'data' is a Numerical Python matrix (rank 2 array) which contains the XAFS
	data to be reduced.  'eColumn' is the column index of the energy values of
	each point.  'Eo' is the edge energy of the data.

	All points for which the energy is greater than 'Eo'+'after' are
	reduced to a new set of points in which the energy varies in
	equally-spaced steps in k-space, defined by 'kstep'.

	'file' is the file name corresponding to this data set, and if specified
	will be used in any exceptions raised by this functions.

	If 'msgStream' is specified it must be an output stream (an object
	implementing a write() method),	which will used to print status
	information.
	"""

	# if file is specified, reformat it for use in error messages
	if file:
		file = '[%s] ' % file

	# acquire the energy vector of the data and find its minimum and maximum
	E = data[:,eColumn]
	Min, Max = min(E), max(E)

	if Max <= Eo:
		raise RebinError, (
			'%sno energy values larger than Eo (incomplete data set?)'
			% file)

	# start rebinning points at Eo+after
	start = Eo + after

	if Max <= start:
		raise RebinError, '%sthe value of "after" is too large' % file

	# find the index of the energy vector which corresponds to the start point
	startPoint = bisect.bisect_left(E, start)

	# slice the energy vector and data matrix to get the points for rebinning
	eRange = E[startPoint:]
	dataRange = data[startPoint:, :]

	if msgStream:
		msgStream.write('%s%d points in E from %.4f to %.4f (Eo = %.4f)\n' %
			(file, eRange.shape[0], start, Max, Eo))

	def k(E, Eo=Eo):
		"""Calculate K for some energy level E, using the edge energy argument
		passed to rebin().
		"""
		return 0.512 * math.sqrt(E - Eo)

	# Generate the regular k-space abscissa that will be rebined to.
	# grid(start, end, step) returns a vector of values from 'start' to 'end'
	# by 'step', inclusive.
	kgrid = grid(k(start), k(Max), kstep)

	if msgStream:
		msgStream.write(
			'%srebinning to %d points in k-space from %.4f to %.4f\n'
			% (file, kgrid.shape[0], kgrid[0], kgrid[-1]))

	# newData is matrix which is BINCOUNT-1 rows long and contains the same
	# number of columns as the data matrix.  It accumulates the sums of the
	# points which fall in each bin
	newData = Numeric.zeros((kgrid.shape[0]-1, data.shape[1]), data.typecode())

	# binCounts is a vector of BINCOUNT elements, which accumulates the number
	# of points that fall in each bin
	binCounts = Numeric.zeros( (newData.shape[0],) , data.typecode())

	for i in range(0, eRange.shape[0]):
		# locate the index of the bin in which the current energy level falls
		where = bisect.bisect_right(kgrid, k(eRange[i])) - 1
		if where == newData.shape[0]:
			where = where - 1

		# bin the data
		newData[where] += dataRange[i]
		binCounts[where] += 1

	# check that all of the bins contain data
	for i in range(0, newData.shape[0]):
		if binCounts[i] == 0:
			raise RebinError, ('%sbin %d (%.4f < k < %.4f) is empty'
				% (file, i, kgrid[i], kgrid[i+1]))

	# average the binned points
	for i in range(0, newData.shape[0]):
		newData[i,:] /= binCounts[i]

	# The length of E[0:startPoint] is the number of points which were not
	# rebinned.  The result matrix will contain that many rows plus one row for
	# each bin.
	Len = E[0:startPoint].shape[0] + newData.shape[0]

	# create a new matrix to hold the final result
	result = Numeric.zeros((Len, data.shape[1]), data.typecode())	

	# copy unrebinned and rebinned data into the result matrix
	result[0:startPoint, :] = data[0:startPoint, :]
	result[startPoint:, :] = newData

	return result


More information about the Ifeffit mailing list