pysrim

Table of contents

  1. Introduction
  2. Example: a multi-layered heterostructure
  3. Caveats

Introduction

The Python package pysrim provides a slick and convenient way of scripting some of the tedious aspects involed with running many similar SRIM calculations. Its key strength is it provides a convenient interface to programatically define the calculation input. This is particularly advantageous as it:

  • allows for easy “batch” calculations where a few simulation parameters are systematically varied (e.g., the ion implantation energy).
  • allows the use of for loops when creat multilayered heterostructures, which is arduous otherwise.
  • makes the record of the calculation much more readable than SRIM’s own custom (and dated) input format.

It even works well when running on Linux (i.e., it automatically calls wine SRIM.exe, wine TRIM.exe, etc.)!

As a bonus, it also has a short paper that can be cited:


Title
pysrim: automation, analysis, and plotting of SRIM calculations
Author
C. Ostrouchov, Y. Zhang, W. J. Weber
Journal
J. Open Source Software
Volume
3
Issue
28
Pages
829
Year
2018
10.21105/joss.00829
costrouc/pysrim

Example: a multi-layered heterostructure

Here I give an example showcasing pysrim’s capabilities. The script below creates a target with a complex layered structure (one that would be particularly unpleasent construct “by hand”) and runs several TRIM calculations for a single ion at a few different implantation energies. Conveniently, the script takes care of moving all the results to their own (new) folder after each calculation completes.

#!/usr/bin/python3

import os
import numpy as np
import matplotlib.pyplot as plt
from srim import TRIM, Ion, Layer, Target
from srim.output import Results, Range


# desired implantation energies (eV)
Energy_eV = 1e3 * np.array([1.0, 3.0, 5.0, 7.0])

# number of simulated ions
N_Ions = 1e3

# mass of the implanted ion 8Li (amu)
m_8Li = 8.02248625

# specify the directory of SRIM.exe
# for Windows users the path will be of the form "C://..."
srim_executable_directory = "/path/to/srim-2013"

# create a heterostructure consisting of n_repetitions of alternating layers of
# the perovskites LaNiO3 and LaAlO3
# these have the (approximate) cubic lattice constants:
a_LaNiO3 = 3.857
a_LaAlO3 = 3.787

# use an empty list to hold each layer
layers = []

# number of layer repetitions
n_repetions = 3

# loop over the repetions to create the heterostructure!
for i in range(n_repetions):

    # 2 unit cell thick lanthanum nickelate layer
    LaNiO3 = Layer(
        {
            "La": {"stoich": 1.0},
            "Ni": {"stoich": 1.0},
            "O": {"stoich": 3.0},
        },
        density=7.11,
        width=2 * a_LaNiO3,
        name="LaNiO3(%d)" % i,
    )
    layers.append(LaNiO3)

    # 5 unit cell thick lanthanum aluminate layer
    LaAlO3 = Layer(
        {
            "La": {"stoich": 1.0},
            "Al": {"stoich": 1.0},
            "O": {"stoich": 3.0},
        },
        density=6.52,
        width=5 * a_LaAlO3,
        name="LaAlO3(%d)" % i,
    )
    layers.append(LaAlO3)

# use a 0.5 mm sapphire layer as the bottom "substrate"
Al2O3 = Layer(
    {
        "Al": {"stoich": 2.0},
        "O": {"stoich": 3.0},
    },
    density=3.95,
    width=50000.0,
    name="Al2O3",
)
layers.append(Al2O3)


# construct the mulitlayer target using the layers list
target = Target(layers)

# loop over implantation energies
for E_eV in Energy_eV:

    # Construct the implanted 8Li ion
    ion = Ion("Li", energy=E_eV, mass=m_8Li)

    # Initialize a TRIM calculation with the ion & target
    trim = TRIM(
        target,
        ion,
        calculation=2,
        number_ions=N_Ions,
        description="%.0f eV 8Li implanted in heterostructure" % E_eV,
        # reminders="",
        # autosave=1000,
        plot_mode=5,
        # plot_xmin=0,
        # plot_xmax=0,
        ranges=True,
        backscattered=True,
        transmit=True,
        sputtered=True,
        collisions=True,
        angle_ions=0,
    )

    # run the TRIM calculation
    # - this may take a few seconds to start (especially using wine)
    # - if all went well, a TRIM window will pop up!
    results = trim.run(srim_executable_directory)

    # move all the results for each implantation energy to a new directory
    output_directory = "results/%.0f_eV" % E_eV
    os.makedirs(output_directory, exist_ok=True)
    TRIM.copy_output_files(srim_executable_directory, output_directory)

Try it out yourself!

Download heterostructure.py.

Caveats

pysrim, unfortunately, isn’t perfect and I ran into the following issues while using it:

  • Everytime it runs, it complains that the .yaml file it’s reading isn’t done safely. This is due to a recent change in pyYAML, requiring a Loader to be specified as a kwarg. There is currently a merge request on the project’s GitLab page (https://gitlab.com/costrouc/pysrim) to fix this, but until this gets officially patched it can be mended by editing line 10 of srim/core/elemementdb.py so that it reads:
return yaml.load(open(dbpath, "r"), Loader=yaml.SafeLoader)
  • It fails to parse IONIZ.txt output when the ion energy is less than 1 keV. The problem is with the regex expression used to parse the output. As a simple workaround, rather than fixing the problem, it is sufficient to just comment out line 36 of srim/output.py so that it reads:
# raise SRIMOutputParseError("unable to extract ion from file")
  • The autosave input in TRIM setup does not appear to work; the calculation won’t run if the kwarg is specified. This is relatively minor, so my workaround is to just avoid providing the parameter.

  • SRIM’s default values for (element specific) displacement, lattice, and surface binding energies do not appear to be used automatically and need to specified manually.

  • Bragg corrections are not implemented on a per-layer basis. This is relatively easy to fix by editing lines 42-48 in srim/core/layer.py to read:

    def __init__(self, elements, density, width, phase=0, name=None, bragg_correction=1.0):
        """Creation of Layer from elements, density, width, phase, and
name"""
        self.width = width
        self.name = name
        self.bragg_correction = bragg_correction
        super(Layer, self).__init__(elements, density, phase)

as well as lines 150-153 in srim/input.py to read:

    def _write_bragg_correction(self):
        return (
            'Target Compound Corrections (Bragg)'
        ) + self.newline + ' ' + ' '.join([str(layer.bragg_correction) for layer in self._trim.target.layers]) + self.newline
  • pysrim fails to parse results where no ions were stopped in the target. At least the fix is easy - simply comment out the exception raised on line 72 in srim.py.

These issues/shortcomings are rectified in my custom fork of pysrim; it can be obtained from: https://github.com/rmlmcfadden/pysrim


Copyright © 2020-2023 Ryan M. L. McFadden.