H2+ Matlab
H2+ Matlab
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%
PHY.F20 Molecular and Solid State Physics: Molecular orbitals of the
molecular ion H2+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%
Then one can define the atomic orbitals to be used for the
approximation of the molecular orbitals. This is done inside a cell
called orb. It contains one cell for each nuclei with strings giving
the name of the orbitals we want to use for this nuclei.
Then one also has to set the limits of the finite integration area.
This is done via a single variable called universallimit. The
integration will be done inside a shape at least as big as a sphere
with that radius.
Integration will be much faster for linear molecules where all the
nuclei are on the x-axis and only s and px orbitals are used. This
will be detected automatically and the code switches from the full
3d integration to an equivalent 2d integration over a cylinder with
radius universallimit.
Most of the files can be called with the parameters explained above:
orb, Z, xAtom, yAtom, zAtom and universallimit
constants.m:
This file can be run to load some useful constants.
Dividing variables in SI units by ec or a0 will give the energy and
distance in eV and bohr respectively.
e.g:
-2.1799e-18 J / ec = -13.6057 eV
1.27e-10 m / a0 = 2.4 bohr
atorbit.m:
Defines the first few atomic orbitals. It is used by the other
files.
calcHamiltonian.m:
function [H,S] =
calcHamiltonian(orb,Z,xAtom,yAtom,zAtom,universallimit)
As one can see in the definition, this function calculates the two
matrices H and S.
You can see if the area of integration is large enough be checking
the diagonal entries of S. They should be very close to 1. If they
are considerably smaller your results mighthave errors and you
should increase the integration area.
calcDensity.m:
function ZZ = calcDensity(orb, Z, xAtom, yAtom, zAtom, V, XX, YY)
This function calculates the electron density defined by a given
LCAO coefficient vector V for a xy-grid XX, YY. Alter this script
if you want the wavefunctions of a calculated orbital.
plot_molecule.m:
function plot_molecule(orb, Z, xAtom, yAtom, zAtom, V_min,
plotlimit)
This function plots the xy-plane density of the given orbital
defined by the LCAO coefficients V. The area that is plotted is a
square defined by plotlimit.
plot_S.m, plot_H.m:
function plot_X(orb, Z, xAtom, yAtom, zAtom, plotlimit)
These functions are helpful to visualize the integrals done when
calculating thematrices S and H.
h2_plus.m:
An example how to use the files to calculate the dissociation energy
of H2+ is given with this file. After calculation finish it will
save the results in a results.mat file. This file can be used by
plot_animation.m to visualize all the densities for all given
distances of the protons.
ATORBIT
function [ result ] =
atorbit(xlocal,ylocal,zlocal,Zlocal,laplace,type)
%ATORBIT Atomic orbital centered at specified coordinates
%
% xlocal ... x-coordinate of the center of the atom (in m)
% ylocal ... y-coordinate (in m)
% zlocal ... z-coordinate (in m)
% Zlocal ... atomic number of the atom
% laplace ... boolean. true - laplace operator is appled to atomic
orbital
% false - "pure" atomic orbital is returned
% type ... string specifying the orbital (1s, 2s, 2px, 2py, 2pz)
result = [];
%[x_mesh,xAtom_mesh] = meshgrid(x,xAtom);
%xlocal = x - xAtom;
%[y_mesh,yAtom_mesh] = meshgrid(y,yAtom);
%ylocal = y - yAtom;
%[z_mesh,zAtom_mesh] = meshgrid(z,zAtom);
%zlocal = z - zAtom;
%Zlocal = repmat(Z,length(x),1);
calDensity.m
ZZ = zeros(size(XX));
k = 1;
for atom = 1:numel(Z)
for orbital = 1:numel(orb{atom})
ZZ = ZZ + V(k)*atorbit(XX-xAtom(atom), YY-yAtom(atom),
zeros(size(XX))-zAtom(atom), Z(atom), false, orb{atom}{orbital});
k = k + 1;
end
end
ZZ = ZZ.^2;
calcHamiltonian.m
constants
if nargin<6
universallimit = a0*50; %a0*50
end
if nargin<8
RTol = 1E-6;
end
x_lim_l = -universallimit;
x_lim_u = universallimit;
y_lim_l = -universallimit;
y_lim_u = universallimit;
z_lim_l = -universallimit;
z_lim_u = universallimit;
r_lim = universallimit;
num_orbs_per_atom = cellfun('size',orb,2);
nopa_cumsum = cumsum([0; num_orbs_per_atom]);
N_atom = length(Z);
N = sum(num_orbs_per_atom);
orblist = {};
for k = 1:length(orb)
orblist = [orblist orb{k}];
end
H = NaN(N);
S = H;
for k = 1:N
for l = k:N
atom_k = find(k > nopa_cumsum,1,'last');
atom_l = find(l > nopa_cumsum,1,'last');
x_lim_l,x_lim_u,0,r_lim,'AbsTol',ATol,'RelTol',RTol);
else % do the full 3d integral
S(k,l) = integral3(@(x,y,z) atorbit(x-xAtom(atom_k),y-
yAtom(atom_k), z-zAtom(atom_k),Z(atom_k),false,orblist{k}).* ...
atorbit(x-xAtom(atom_l),y-yAtom(atom_l),z-
zAtom(atom_l),Z(atom_l),false,orblist{l}), ...
x_lim_l,x_lim_u,y_lim_l,y_lim_u,z_lim_l,z_lim_u,'AbsTol',ATol,'RelTo
l',RTol);
end
%end
%fprintf('Done S(%i,%i): %i-%s, %i-%s\n', k, l, atom_k,
orblist{k}, atom_l, orblist{l});
end
end
S = triu(S) + triu(S,1)';
for k = 1:N
for l = 1:N
atom_k = find(k > nopa_cumsum,1,'last');
atom_l = find(l > nopa_cumsum,1,'last');
orb1 = orblist{k};
orb2 = orblist{l};
%n1 = str2double(orb1(1));
n2 = str2double(orb2(1));
%eigenE1 = -me*ec^4/(2*(4*pi*eps0)^2*hbar^2)/n1^2*Z1^2;
eigenE2 = -
me*ec^4/(2*(4*pi*eps0)^2*hbar^2)/n2^2*Z(atom_l)^2;
H(k,l) = eigenE2*S(k,l);
x_lim_l,x_lim_u,0,r_lim+sqrt(yAtom(j)^2+zAtom(j)^2),0,2*pi,'AbsTol',
ATol,'RelTol',RTol);
end
%fprintf('Done H(%i,%i) - Atom %i\n',k,l,j);
end
end
end
end
calcHamiltonian.m
constants
if nargin<6
universallimit = 5.2917721E-11*50; %a0*50
end
if nargin<8
RTol = 1E-6;
end
x_lim_l = -universallimit;
x_lim_u = universallimit;
y_lim_l = -universallimit;
y_lim_u = universallimit;
z_lim_l = -universallimit;
z_lim_u = universallimit;
num_orbs_per_atom = cellfun('size',orb,2);
nopa_cumsum = cumsum([0; num_orbs_per_atom]);
N_atom = length(Z);
N = sum(num_orbs_per_atom);
orblist = {};
for k = 1:length(orb)
orblist = [orblist orb{k}];
end
H = NaN(N);
S = H;
for k = 1:N
for l = k:N
atom_k = find(k > nopa_cumsum,1,'last');
atom_l = find(l > nopa_cumsum,1,'last');
x_lim_l,x_lim_u,y_lim_l,y_lim_u,z_lim_l,z_lim_u,'AbsTol',ATol,'RelTo
l',RTol);
%end
fprintf('Done S(%i,%i): %i-%s, %i-%s\n', k, l, atom_k,
orblist{k}, atom_l, orblist{l});
end
end
S = triu(S) + triu(S,1)';
for k = 1:N
for l = 1:N
atom_k = find(k > nopa_cumsum,1,'last');
atom_l = find(l > nopa_cumsum,1,'last');
orb1 = orblist{k};
orb2 = orblist{l};
%n1 = str2double(orb1(1));
n2 = str2double(orb2(1));
%eigenE1 = -me*ec^4/(2*(4*pi*eps0)^2*hbar^2)/n1^2*Z1^2;
eigenE2 = -
me*ec^4/(2*(4*pi*eps0)^2*hbar^2)/n2^2*Z(atom_l)^2;
H(k,l) = eigenE2*S(k,l);
x_lim_l,x_lim_u,y_lim_l,y_lim_u,z_lim_l,z_lim_u,'AbsTol',ATol,'RelTo
l',RTol);
fprintf('Done H(%i,%i) - Atom %i\n',k,l,j);
end
end
end
end
constants.m
a0 = 5.2917721E-11;
hbar = 1.05457266E-34;
me = 9.1093897E-31;
eps0 = 8.854187817E-12;
ec = 1.60217733E-19;
Eh = hbar^2/(me*a0^2);
k1 = 1/2*hbar^2/me;
k2 = ec^2/(4*pi*eps0);
h2+.m
constants
% these arrays will hold the energies and LCAO coefficients for all
d
E_list = [];
V_list = [];
for d = d_list
fprintf('\ndistance: %f\n', d/a0)
xAtom = xAtom_d(d);
yAtom = yAtom_d(d);
zAtom = zAtom_d(d);
% find the distance with the lowest energy and set some variables
with it
[E_min, min_index] = min(real(E_total(1, :)));
d_min = d_list(min_index);
V_min = V_list(:, min_index);
xAtom_min = xAtom_d(d_min);
yAtom_min = yAtom_d(d_min);
zAtom_min = zAtom_d(d_min);
% figure 1 plots the energies over distance with the bonding energy
figure(1)
plot(d_list/a0, E_total/ec)
hold on
plot([0, max(d_list)]/a0, E_inf/ec*[1, 1], '--k')
hold off
title('H_2^+ bonding energy')
ylim([-17, 0])
xlabel('d / a_0 distance between protons')
ylabel('Energy / eV')
%legend('plus, bonding', 'minus, antibonding')
fprintf('\nLCAO coefficients:\n')
disp(V_min)
fprintf('dissociation energy: %f eV\n', (E_inf - E_min)/ec)
plot_animation.m
load('results.mat')
constants
plotlimit = universallimit;
figure
x = linspace(-universallimit, universallimit, 1000);
y = linspace(-universallimit, universallimit, 1000);
[XX, YY] = meshgrid(x, y);
ZZ = zeros(size(XX));
frame = 1;
for d = d_list
xAtom = [-d/2; d/2];
yAtom = [0; 0];
zAtom = [0; 0];
ZZ = calcDensity(orb, Z, xAtom, yAtom, zAtom, V_list(:, frame),
XX, YY);
s = surf(XX, YY, ZZ);
s.EdgeColor = 'none';
xlim([-plotlimit, plotlimit])
ylim([-plotlimit, plotlimit])
axis off
%zlim([0, 3E30])
view(25,60)
plot_h.m
num_orbs_per_atom = cellfun('size',orb,2);
nopa_cumsum = cumsum([0; num_orbs_per_atom]);
N_atom = length(Z);
N = sum(num_orbs_per_atom);
orblist = {};
for k = 1:length(orb)
orblist = [orblist orb{k}];
end
figure
for k = 1:N
for l = 1:N
atom_k = find(k > nopa_cumsum,1,'last');
atom_l = find(l > nopa_cumsum,1,'last');
orb1 = orblist{k};
orb2 = orblist{l};
subplot(N, N, N*(k-1)+l)
plot_molecule.m
figure
x = linspace(-plotlimit, plotlimit, 1000);
y = linspace(-plotlimit, plotlimit, 1000);
[XX, YY] = meshgrid(x, y);
ZZ = zeros(size(XX));
k = 1;
for atom = 1:numel(Z)
for orbital = 1:numel(orb{atom})
ZZ = ZZ + V_min(k)*atorbit(XX-xAtom(atom), YY-yAtom(atom),
zeros(size(XX))-zAtom(atom), Z(atom), false, orb{atom}{orbital});
k = k + 1;
end
end
plot_S.m
num_orbs_per_atom = cellfun('size',orb,2);
nopa_cumsum = cumsum([0; num_orbs_per_atom]);
N_atom = length(Z);
N = sum(num_orbs_per_atom);
orblist = {};
for k = 1:length(orb)
orblist = [orblist orb{k}];
end
for k = 1:N
for l = k:N
atom_k = find(k > nopa_cumsum,1,'last');
atom_l = find(l > nopa_cumsum,1,'last');
subplot(N, N, N*(k-1)+l)
ZZ = atorbit(XX-xAtom(atom_k),YY-yAtom(atom_k),-
zAtom(atom_k),Z(atom_k),false,orblist{k}).* ...
atorbit(XX-xAtom(atom_l),YY-yAtom(atom_l),-
zAtom(atom_l),Z(atom_l),false,orblist{l});