msspec_python3/doc/source/tutorials/temperature/Cu_temperature.py

154 lines
6.3 KiB
Python

# coding: utf-8
from msspec.calculator import MSSPEC, XRaySource
from msspec.utils import *
from msspec.iodata import Data
from ase.build import bulk
import numpy as np
import sys
a0 = 3.6 # The lattice parameter in angstroms
phi = np.arange(0, 100) # An array of phi angles
all_T = np.arange(300, 1000, 100) # All temperatures used for the calculation
all_theta = np.array([45, 83]) # 2 polar angles, 83° is grazing detection
eps = 0.01 # a useful small value
DATA_FNAME = 'all_data.hdf5' # Where to store all the data
ANALYSIS_FNAME = 'analysis.hdf5'
def compute(filename):
"""Will compute a phi scan for an emitter in the first, second and third plane
of a copper substrate for various polar angles and temperatures.
In a second step (outside this function), intensities from all these emitters
are added to get the signal of a substrate."""
calc = MSSPEC(spectroscopy='PED')
calc.source_parameters.energy = XRaySource.AL_KALPHA
calc.muffintin_parameters.interstitial_potential = 14.1
calc.calculation_parameters.vibrational_damping = 'averaged_tl'
calc.calculation_parameters.use_debye_model = True
calc.calculation_parameters.debye_temperature = 343
calc.calculation_parameters.vibration_scaling = 1.2
calc.detector_parameters.average_sampling = 'high'
calc.detector_parameters.angular_acceptance = 5.7
filters = ['forward_scattering', 'backward_scattering']
calc.calculation_parameters.path_filtering = filters
calc.calculation_parameters.RA_cutoff = 3
# You can also choose a real potential and manually define the
# electron mean free path
#
# calc.tmatrix_parameters.exchange_correlation = 'hedin_lundqvist_real'
# calc.calculation_parameters.mean_free_path = 10.
data = None # init an empty data object
for temperature in all_T:
for plane in range(3):
# We create a cylindrical cluster here with one plane below the emitter
# and 0, 1 or to planes above the emitter
cluster = bulk('Cu', a=a0, cubic=True)
cluster = cluster.repeat((20, 20, 8))
center_cluster(cluster)
cluster = cut_cylinder(cluster, radius=1.5 * a0 + eps)
cluster = cut_plane(cluster, z=-( a0/2 + eps))
cluster = cut_plane(cluster, z=(plane) * a0 / 2 + eps)
cluster.absorber = get_atom_index(cluster, 0, 0, 0)
calc.calculation_parameters.temperature = temperature
# the scattering order depends on the number of planes above
# the emitter to speed up calculations
calc.calculation_parameters.scattering_order = 1 + plane
calc.set_atoms(cluster)
# Here starts the calculation
data = calc.get_phi_scan(level='2p3/2', theta=all_theta, phi=phi,
kinetic_energy=560, data=data)
data.save(filename)
def process_data(datafile, outputfile):
"""Will create another Data file with some phi-scans corresponding to 3
planes at different temperatures and the anisotropy curve for 45° and
grazing detection.
"""
def get_signal(datafile, T=300, theta=45):
data = Data.load(datafile)
total = None
for dset in data:
p = {_['group'] + '.' + _['name']: _['value'] for _ in dset.parameters()}
temperature = np.float(p['CalculationParameters.temperature'])
if temperature != T: continue
i = np.where(dset.plane == -1)
j = np.where(dset.theta[i] == theta)
signal = dset.cross_section[i][j]
try:
total += signal
except:
total = signal
phi = dset.phi[i][j]
return phi, total
analysis = Data('Temperature tutorial')
scans_dset = analysis.add_dset('Phi scans')
scans_view = scans_dset.add_view('Figure 1',
title=r'Cu(2p) Azimuthal scan for $\theta = 83\degree$',
xlabel=r'$\Phi (\degree$)',
ylabel='Signal (a.u.)')
anisotropy_dset = analysis.add_dset('Anisotropies')
anisotropy_view = anisotropy_dset.add_view('Figure 2',
title='Relative anisotropies for Cu(2p)',
marker='o',
xlabel='T (K)',
ylabel=r'$\frac{\Delta I / I_{max}(T)}{\Delta I_{300} / I_{max}(300)} (\%)$')
for theta in all_theta:
for T in all_T:
PHI, SIGNAL = get_signal(datafile, T=T, theta=theta)
for phi, signal in zip(PHI, SIGNAL):
scans_dset.add_row(phi=phi, signal=signal, theta=theta, temperature=T)
middleT = all_T[np.abs(all_T - np.mean(all_T)).argmin()]
if theta == 83 and T in [np.min(all_T), middleT, np.max(all_T)]:
scans_view.select('phi', 'signal',
where='temperature == {:f} and theta == {:f}'.format(T, theta),
legend='{:.0f} K'.format(T))
PHI, SIGNAL0 = get_signal(datafile, T=np.min(all_T), theta=theta)
Imax = np.max(SIGNAL)
Imax0 = np.max(SIGNAL0)
dI = Imax - np.min(SIGNAL)
dI0 = Imax0 - np.min(SIGNAL0)
ani = (dI / Imax) / (dI0 / Imax0)
anisotropy_dset.add_row(temperature=T, anisotropy=ani, theta=theta)
anisotropy_view.select('temperature', 'anisotropy',
where='theta == {:f}'.format(theta),
legend=r'$\theta = {:.0f} \degree$'.format(theta))
analysis.save(outputfile)
# A convenient way to run the script, just specify one or more of these calc, analyse or
# view keywords as arguments
# ... to calculate all the data, analyse the data and view the results, run
# python Cu_temperature.py calc analyse view
# ... to just view the results, simply run
# python Cu_temperature.py view
if 'calc' in sys.argv:
compute(DATA_FNAME)
if 'analyse' in sys.argv:
process_data(DATA_FNAME, ANALYSIS_FNAME)
if 'view' in sys.argv:
data = Data.load(ANALYSIS_FNAME)
data.view()