Example: O2 PES PADΒΆ

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import numpy as np
import abel

import matplotlib.pylab as plt
from scipy.ndimage.interpolation import shift

# This example demonstrates Hansen and Law inverse Abel transform
# of an image obtained using a velocity map imaging (VMI) photoelecton
# spectrometer to record the photoelectron angular distribution resulting
# from photodetachement of O2- at 454 nm.
# Measured at  The Australian National University
# J. Chem. Phys. 133, 174311 (2010) DOI: 10.1063/1.3493349

# image file
filename = 'data/O2-ANU1024.txt.bz2'
# numpy handles .gz or plain .txt extensions

# Load image as a numpy array
print('Loading ' + filename)
IM = np.loadtxt(filename)
# use scipy.misc.imread(filename) to load image formats (.png, .jpg, etc)

rows, cols = IM.shape    # image size

# Image center should be mid-pixel, i.e. odd number of colums
if cols % 2 != 1:
    print ("HL: even pixel width image, re-adjusting image centre")
    IM = shift(IM, (-1/2, -1/2))[:-1, :-1]
    rows, cols = IM.shape   # new image size

r2 = rows//2   # half-height image size
c2 = cols//2   # half-width image size
print ('image size {:d}x{:d}'.format(rows, cols))

# Hansen & Law inverse Abel transform
print('Performing Hansen and Law inverse Abel transform:')

AIM = abel.transform(IM, method="hansenlaw", direction="inverse",
                     symmetry_axis=None)['transform']

# PES - photoelectron speed distribution  -------------
print('Calculating speed distribution:')

r, speed  = abel.tools.vmi.angular_integration(AIM)

# normalize to max intensity peak
speed /= speed[200:].max()  # exclude transform noise near centerline of image

# PAD - photoelectron angular distribution  ------------
print('Calculating angular distribution:')
# radial ranges (of spectral features) to follow intensity vs angle
# view the speed distribution to determine radial ranges
r_range = [(93, 111), (145, 162), (255, 280), (330, 350), (350, 370),
           (370, 390), (390, 410), (410, 430)]

# map to intensity vs theta for each radial range
intensities, theta = abel.tools.vmi.calculate_angular_distributions(AIM,
                                                     radial_ranges=r_range)

print("radial-range      anisotropy parameter (beta)")
for rr, intensity in zip(r_range, intensities):
    # evaluate anisotropy parameter from least-squares fit to
    # intensity vs angle
    beta, amp = abel.tools.vmi.anisotropy_parameter(theta, intensity)
    result = "    {:3d}-{:3d}        {:+.2f}+-{:.2f}".format(*rr+beta)
    print(result)

# plots of the analysis
fig = plt.figure(figsize=(15, 4))
ax1 = plt.subplot(131)
ax2 = plt.subplot(132)
ax3 = plt.subplot(133)

# join 1/2 raw data : 1/2 inversion image
vmax = IM[:, :c2-100].max()
AIM *= vmax/AIM[:, c2+100:].max()
JIM = np.concatenate((IM[:, :c2], AIM[:, c2:]), axis=1)
rr = r_range[-3]
intensity = intensities[-3]
beta, amp = abel.tools.vmi.anisotropy_parameter(theta, intensity)
# draw a 1/2 circle representing this radial range
# for rw in range(rows):
#   for cl in range(c2,cols):
#       circ = (rw-r2)**2 + (cl-c2)**2
#       if circ >= rr[0]**2 and circ <= rr[1]**2:
#           JIM[rw,cl] = vmax

# Prettify the plot a little bit:
# Plot the raw data
im1 = ax1.imshow(JIM, origin='lower', aspect='auto', vmin=0, vmax=vmax)
fig.colorbar(im1, ax=ax1, fraction=.1, shrink=0.9, pad=0.03)
ax1.set_xlabel('x (pixels)')
ax1.set_ylabel('y (pixels)')
ax1.set_title('velocity map image| inverse Abel             ')

# Plot the 1D speed distribution
ax2.plot(speed)
ax2.plot((rr[0], rr[0], rr[1], rr[1]), (1, 1.1, 1.1, 1), 'r-')  # red highlight
ax2.axis(xmax=450, ymin=-0.05, ymax=1.2)
ax2.set_xlabel('radial pixel')
ax2.set_ylabel('intensity')
ax2.set_title('Speed distribution')

# Plot anisotropy variation
ax3.plot(theta, intensity, 'r',
         label="expt. data r=[{:d}:{:d}]".format(*rr))


def P2(x):   # 2nd order Legendre polynomial
    return (3*x*x-1)/2


def PAD(theta, beta, amp):
    return amp*(1 + beta*P2(np.cos(theta)))


ax3.plot(theta, PAD(theta, beta[0], amp[0]), 'b', lw=2, label="fit")
ax3.annotate("$\\beta = ${:+.2f}+-{:.2f}".format(*beta), (-2, -1.1))
ax3.legend(loc=1, labelspacing=0.1, fontsize='small')

ax3.axis(ymin=-2, ymax=12)
ax3.set_xlabel("angle $\\theta$ (radians)")
ax3.set_ylabel("intensity")
ax3.set_title("anisotropy parameter")


# Plot the angular distribution
plt.subplots_adjust(left=0.06, bottom=0.17, right=0.95, top=0.89,
                    wspace=0.35, hspace=0.37)

# Save a image of the plot
# plt.savefig(filename[:-7]+"png", dpi=150)

# Show the plots
plt.show()

(Source code, png, hires.png, pdf)

_images/example_O2_PES_PAD.png