Pages

A Java Calculator for Oxide Growth

I created this Java applet while employed as a high school intern at Rogue Valley Microdevices (RVM). I was a lab tech in the foundry and we used a calculator on RVM's website to calculate our run times for the oxide furnaces. This proved problematic one week when, for some reason, the Internet connection in the lab kept cutting out (plus, the website was just slow sometimes). I created this applet so we would not have to rely on a good Internet connection and it was used for a few years at RVM (last time I asked about this was around a year ago, I think). This program also proved useful later in a class at MIT where we were given the pointless task of calculating oxide growth times by hand in a problem set. It was also the first time I had created something that was useful in "the real world".

You can download the .jar file here. Please attribute my code if you use it in your own work. Below is a screenshot of the interface.


I owe a lot to RVM and the skills they taught me. The knowledge I acquired there helped me get my first research internship at MIT in Karen Gleason's group working on organic CVD and polymeric conductors.

Quantum Espresso Molecular Dynamics Animation

I've been using Quantum Espresso for some projects and I created this animation using XCrySDen on a molecular dynamics relaxation job I ran. It is a fairly interesting animation: One can make out many of the vibrational modes in the molecule, particularly those of the hydrogen atoms (light blue), even though this was not the goal I had in mind. Sometimes using the method with the least sophistication can still produce some insight into the physics or at least make some fun animations.


In quantum chemistry, the first step of most simulations will be to "relax" a molecular structure; this means to search the potential energy surface to find the minimal energy structure (i.e., the most stable structure). The relaxed structure is assumed to be an accurate model of the physical compound. Higher quality relaxations, typically those using a higher level of theory such as perturbation or coupled-cluster, make for a more realistic geometry, in principle. However, higher quality always translates to more "expensive" which, in scientific computation, refers to the amount of resources (time and computational hardware, usually) one must throw at a particular simulation.

Molecular dynamics is regarded as a very "cheap" method because it does not use an algorithm to search the energy landscape for a path to the minimal energy structure. Instead, the straight-forward approach of molecular dynamics is to integrate the forces applied to each atom directly using something like a Verlet or damped-Newtonian model. This is mathematically inefficient since you might not converge to the minimal energy very quickly but the method is computationally "cheap" so it is a good starting point, especially if you know your initial structure is very far from the correct geometry as I assumed for my calculation: Algorithms like conjugate gradient or BFGS are only most efficient when the structure is already close to a minimum in the energy landscape.

There is a lot more to be said about structure relaxation, the theory and the best way to do it in practice, and vibrational modes but I will leave that for another time.

Muting the Startup Tone in OSX

This is a hack that I have found infinitely useful due to the amount of annoyance it saves. No one appreciates the person who comes to a lecture (maybe a few minutes late), opens their MacBook, hits the power button, and treats everyone to the Mac startup tone at full volume. This method ensures this will never happen again. Sadly, I do not remember now where I first read it as it was some years ago.

The idea is to create two scripts, one that mutes and one that unmutes: When the Mac is shut down, one script mutes the system so that the next startup will not produce the tone and the second script unmutes the system at login (following the usual occurrence of the tone, which happens at startup but before login) so that the system functions as normal.

Below, the contents of mute-on.sh
#!/bin/bash
osascript -e 'set volume with output muted'

Below, the contents of mute-off.sh
#!/bin/bash
osascript -e 'set volume without output muted'

Put these two scripts in a location of your choosing and run the following to create the appropriate Login Hooks
sudo chmod u+x /Library/Scripts/mute-on.sh
sudo chmod u+x /Library/Scripts/mute-off.sh
sudo defaults write com.apple.loginwindow LogoutHook /Library/Scripts/mute-on.sh
sudo defaults write com.apple.loginwindow LoginHook /Library/Scripts/mute-off.sh

To remove the Login Hooks so you can hear the login tone again
sudo defaults delete com.apple.loginwindow LoginHook
sudo defaults delete com.apple.loginwindow LogoutHook

One deficiency with this hack that I've noticed is that when one uses the headphone jack and shuts down the system with the plug still in the jack (removing the plug after shutdown) sometimes the next startup will produce the hated tone. This effect is rare enough though (I do not think it happens every time) that I have not bothered to try and find a further solution.

Fourier Transform Miscellanea

The Fourier Transform in Circular Symmetries

The Bessel equation of the first-kind, zero order is defined as
    \begin{equation}
        J_0(a) = \frac{1}{2\pi} \int_{0}^{2\pi} e^{-ia \cos(\theta - \phi)} d\theta
    \end{equation}
We thus define the Fourier Transform
    \begin{equation}
        G_0(\rho, \phi) = G_0(\rho) = 2\pi \int_{0}^{\infty} r g(r) J_0(2\pi r \rho) d\rho
    \end{equation}
and its inverse transform
    \begin{equation}
        g(r) = 2\pi \int_{0}^{\infty} \rho G_0(\rho) J_0(2\pi r \rho) d\rho
    \end{equation}
  

Discretizing the Fourier Transform

Discretizing the Fourier Transform allows us to use the Fast Fourier Transform (FFT) to quickly acquire the Fourier Transform of a continuous function in Python.

Discretize time and frequency
    \begin{equation}
        t = m\Delta t + t_0 \qquad
        \omega = k \Delta \omega \qquad
        \Delta t \Delta \omega = \frac{2 \pi}{N}
    \end{equation}
where \(m,k \in \mathbb{Z}\) and \(N\) is the number of samples. Using the definition of the Fourier Transform
    \begin{equation}
           F(\omega) = \frac{1}{\sqrt[]{2\pi}} \int_{-\infty}^{\infty} e^{-i\omega t} f(t) dt
    \end{equation}
we can substitute the previously defined quantities to get
    \begin{align}
        F(k\Delta \omega) &\approx \frac{1}{\sqrt[]{2\pi}} \sum_{m=1}^{N} \Delta t f(t_0 + m\Delta t) e^{-i k \Delta \omega (t_0+m\Delta t)} \\&= \frac{1}{\sqrt[]{2\pi}} \Delta t e^{-i t_0 k \Delta \omega} \sum_{m=1}^{N} e^{-2\pi i \frac{mk}{N}} f(t_0 + m\Delta t)
    \end{align}
Now notice that, in the final result, the constant phase factor is being multiplied by the discrete Fourier Transform (DFT) on the right. We may now use the FFT to calculate the DFT, keeping in mind that we must multiply by the phase factor to get an approximation of the continuous Fourier Transform.

We can define the inverse transform in exactly the same way
    \begin{equation}
        \omega = n \Delta \omega + \omega_0 \qquad
        t = l \Delta t \qquad
        \Delta t \Delta \omega = \frac{2 \pi}{N}
    \end{equation}
where \(n,l \in \mathbb{Z}\) and \(N\) is defined as before. Now the inverse transform is
    \begin{equation}
           f(t) = \frac{1}{\sqrt[]{2\pi}} \int_{-\infty}^{\infty} e^{i\omega t} F(\omega) dt
    \end{equation}\begin{align}
        f(l \Delta t) &\approx \frac{1}{\sqrt[]{2\pi}} \sum_{m=1}^{N} \Delta \omega F(\omega_0 + n\Delta \omega) e^{-i l \Delta t (\omega_0+n\Delta \omega)} \\&= \frac{1}{\sqrt[]{2\pi}} \Delta \omega e^{-i \omega_0 l \Delta t} \sum_{m=1}^{N} e^{-2\pi i \frac{nl}{N}} F(\omega_0 + n\Delta \omega)
    \end{align}

Python Code

This code works well for messing around with Fourier Transforms.
import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack

# Number of samplepoints
N = 600
# sample spacing
T = 1.0 / 800.0
x = np.linspace(0.0, N*T, N)
y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)
yf = scipy.fftpack.fft(y)
xf = np.linspace(0.0, 1.0/(2.0*T), N/2)

fig, ax = plt.subplots()
ax.plot(xf, 2.0/N * np.abs(yf[:N//2]))
plt.show()

Friedel's Law

Given a real function, its Fourier transform \begin{equation} F(k) = \int_{-\infty}^{\infty} f(x) e^{ikx} dx \end{equation} has the following properties. 
  • \(F(k) = F^*(-k) \)
  • \(|F(k)|^2 = |F(-k)|^2\)
  • The phase of F, however, is antisymmetric: \(\phi(k) = -\phi(-k)\)
Centrosymmetric points \((k, -k)\) are called Friedel or Bijvoet pairs.