Molecular orbital diagrams in LaTeX?

This question led to a new package:
modiagram

I'm wondering if anyone has seen a package for drawing (qualitative) molecular orbital splitting diagrams in LaTeX? Or if there exist any packages that can be easily re-purposed to this task?

Otherwise, I think I'll have a go at it in TikZ.

Example

(Cropped from a graphic on Wikipedia by 'orci' - I suspect it was drawn manually due to the slight misalignment of various elements)

Having a go at it in TikZ

I decided to try doing this in TikZ and have prepared a MO diagram for dioxygen (prior attempt at much simpler dihydrogen below) - this is the kind of scheme I'm going for.

There are at least three problems with this approach:

• It's not very general and I don't know any strategies to make it arbitrarily extensible (e.g. stacking energy levels etc like in the example diagram.) Partially addressed
• The H, H_{2} labels are not aligned at the baseline of each H, so the H_{2} is slightly higher than the other two. Solved, thanks @Matthew Leingang
• The coordinates, whilst text-proportionate, are all hard coded and I would like to know how to make this diagram scalable in terms of a total width, total height and separation of the split levels. Addressed using (probably too many) variables and in-coordinate calculation

Specification

MO diagrams can be drawn in a variety of different ways. In the simplest case, such as for either O2 or H2 here, the left column represents the orbitals of one atom as horizontal lines, arranged vertically in order of their relative energies. The right column does the same for the other atom. In this case the example picture represents orbitals as boxes for clarity as several orbitals can have the same energy, which is what occurs in the case of the 3x 2p orbitals and the pi_x, pi_y orbitals. In this situation they are shown side by side. Orbitals may have zero, one or two (antiparallel) electrons. It is fairly common to simply see orbitals represented as horizontal lines rather than boxes. Lines connect the orbitals to indicate the contribution of the atomic orbitals to a molecular orbital.

The center column shows the molecular orbitals generated from the combination of the atomic orbitals, which can either be additive (in which case the relative energy drops, giving a bonding orbital) or subtractive (in which case the relative energy increases with respect to the atomic orbitals, i.e. an antibonding orbital). As this diagram is qualitative only, the splitting can be treated as symmetric.

Source

\documentclass{article}
\usepackage{tikz}
\usepackage{textcomp}
\usepackage[version=3]{mhchem}

\newcommand{\moup}{\textuparrow}
\newcommand{\modown}{\textdownarrow}
\newcommand{\moupdown}{\textuparrow\textdownarrow}

\begin{document}

\begin{tikzpicture}[scale=1]

\def\sbaseline{0em};
\def\pbaseline{14em};
\def\ssplit{6em};
\def\psplit{12em};
\def\pextend{5em};
\def\psso{4em};
\def\pxyoffset{1em};
\def\mwidth{3em};
\def\hsep{2em};

\tikzstyle{split} = [densely dashed,draw=gray]
\tikzstyle{orbital} = [rectangle, rounded corners, fill=white, draw=black, minimum width=3.5ex, minimum height=3.5ex]
\tikzstyle{label}   = [rectangle, minimum width=3.5ex, node distance=3.5ex]

%1s splitting
\draw        (\mwidth/-2-\hsep*2,\sbaseline)            -- (\mwidth/-2-\hsep  ,\sbaseline);
\draw[split] (\mwidth/-2-\hsep  ,\sbaseline)            -- (\mwidth/-2        ,\sbaseline+\ssplit/2);
\draw        (\mwidth/-2        ,\sbaseline+\ssplit/2)  -- (\mwidth/2         ,\sbaseline+\ssplit/2);
\draw[split] (\mwidth/2         ,\sbaseline+\ssplit/2)  -- (\mwidth/2+\hsep   ,\sbaseline);
\draw        (\mwidth/2+\hsep   ,\sbaseline)            -- (\mwidth/+2+\hsep*2,\sbaseline);
\draw[split] (\mwidth/-2-\hsep  ,\sbaseline)            -- (\mwidth/-2        ,\sbaseline+\ssplit/-2);
\draw        (\mwidth/-2        ,\sbaseline+\ssplit/-2) -- (\mwidth/2         ,\sbaseline+\ssplit/-2);
\draw[split] (\mwidth/2         ,\sbaseline+\ssplit/-2) -- (\mwidth/2+\hsep   ,\sbaseline);

%left 1s
\draw[] (-\mwidth-\hsep,0em) node[orbital] (l1s) {\moupdown};
\node[label, below of=l1s] (l1sl) {$2s$};

%right 1s
\draw[] (\mwidth+\hsep,0em) node[orbital] (r1s) {\moupdown};
\node[label, below of=r1s] (r1sl) {$2s$};

%sigma bonding
\draw[] (0em,\ssplit/-2) node[orbital] (sb) {\moupdown};
\node[label, below of=sb]  (sbl) {$\sigma$};
\node[label, left of=sb, node distance = 9ex] {\tiny{\color{gray}{$\Psi_{a}+\Psi_{b}$}}};

%sigma antibonding
\draw[] (0em,\ssplit/2) node[orbital] (sa) {\moupdown};
\node[label, below of=sa] (sal) {$\sigma^{*}$};
\node[label, left of=sa, node distance = 9ex] {\tiny{\color{gray}{$\Psi_{a}-\Psi_{b}$}}};

%orbital labels
\node[label, below of=l1sl, node distance=6em]   (a)    {\smash[b]{\ce{O_{a}}}};
\node[label, right of=a   , node distance=\mwidth+\hsep]   (ab)   {\smash[b]{\ce{{O2}}}};
\node[label, right of=a   , node distance=\mwidth*2+\hsep*2]  (b)    {\smash[b]{\ce{O_{b}}}};

%Title
\node[label, below of=ab  , node distance=3em]   (desc) {Dioxygen ($|S|=1$)};

%2p splitting
\draw        (\mwidth/-2-\hsep*2-\pextend,\pbaseline)            -- (\mwidth/-2-\hsep  ,\pbaseline);
\draw[split] (\mwidth/-2-\hsep  ,\pbaseline)            -- (\mwidth/-2        ,\pbaseline+\psplit/2);
\draw        (\mwidth/-2        ,\pbaseline+\psplit/2)  -- (\mwidth/2         ,\pbaseline+\psplit/2);
\draw[split] (\mwidth/2         ,\pbaseline+\psplit/2)  -- (\mwidth/2+\hsep   ,\pbaseline);
\draw        (\mwidth/2+\hsep   ,\pbaseline)            -- (\mwidth/+2+\hsep*2+\pextend,\pbaseline);
\draw[split] (\mwidth/-2-\hsep  ,\pbaseline)            -- (\mwidth/-2        ,\pbaseline+\psplit/-2);
\draw        (\mwidth/-2        ,\pbaseline+\psplit/-2) -- (\mwidth/2         ,\pbaseline+\psplit/-2);
\draw[split] (\mwidth/2         ,\pbaseline+\psplit/-2) -- (\mwidth/2+\hsep   ,\pbaseline);

\draw[split] (\mwidth/-2-\hsep  ,\pbaseline)            -- (\mwidth/-2        ,\pbaseline-\psso+\psplit/2);
\draw        (\mwidth/-2        ,\pbaseline-\psso+\psplit/2)  -- (\mwidth/2         ,\pbaseline-\psso+\psplit/2);
\draw[split] (\mwidth/2         ,\pbaseline-\psso+\psplit/2)  -- (\mwidth/2+\hsep   ,\pbaseline);
\draw[split] (\mwidth/-2-\hsep  ,\pbaseline)            -- (\mwidth/-2        ,\pbaseline+\psso+\psplit/-2);
\draw        (\mwidth/-2        ,\pbaseline+\psso+\psplit/-2) -- (\mwidth/2         ,\pbaseline+\psso+\psplit/-2);
\draw[split] (\mwidth/2         ,\pbaseline+\psso+\psplit/-2) -- (\mwidth/2+\hsep   ,\pbaseline);

%left 2p
\draw[] (-\mwidth-\hsep,\pbaseline) node[orbital] (l2pa) {\moupdown};
\node[orbital, left of=l2pa] (l2pb) {\moup};
\node[orbital, left of=l2pb] (l2pc) {\moup};

\node[label, below of=l2pb] (l2pl) {$2p$};

%right 2p

\draw[] (\mwidth+\hsep,\pbaseline) node[orbital] (r2pa) {\moupdown};
\node[orbital, right of=r2pa] (r2pb) {\moup};
\node[orbital, right of=r2pb] (r2pc) {\moup};

\node[label, below of=r2pb] (r2pl) {$2p$};

%sigmap bonding
\draw[] (0em,\pbaseline+\psplit/-2) node[orbital] (spb) {\moupdown};
\node[label, below of=spb]  (spbl) {$\sigma$};

%sigmap antibonding
\draw[] (0em,\pbaseline+\psplit/2) node[orbital] (spab) {};
\node[label, below of=spab]  (spabl) {$\sigma^{*}$};

%pi antibonding levels
\draw[] (-\pxyoffset,\pbaseline+\psso-\psplit/2) node[orbital] (ppabx) {\moupdown};
\node[label, below of=ppabx]  (ppabxl) {$\pi_{x}$};
\draw[] (+\pxyoffset,\pbaseline+\psso-\psplit/2) node[orbital] (ppaby) {\moupdown};
\node[label, below of=ppaby]  (ppabyl) {$\pi_{y}$};

%pi antibonding levels
\draw[] (-\pxyoffset,\pbaseline-\psso+\psplit/2) node[orbital] (ppbx) {\moup};
\node[label, below of=ppbx]  (ppbxl) {$\pi^{*}_{x}$};
\draw[] (+\pxyoffset,\pbaseline-\psso+\psplit/2) node[orbital] (ppby) {\moup};
\node[label, below of=ppby]  (ppbyl) {$\pi^{*}_{y}$};

\end{tikzpicture}

\end{document}

-
Could you give a description of these diagrams explaining their syntax? It's hard to look at the included graphic and your example and understand exactly what the specification is. Do the paths connecting the squares need to be horizontal as they enter the square and then dashed? –  Matthew Leingang Mar 19 '11 at 11:11
You can get the H's to align by using \smash[b]{H_2}, etc. –  Matthew Leingang Mar 19 '11 at 11:12
@Matthew Leingang - I've added a specification section to my question. In response to your specific queries, the horizontal paths would ordinarily represent orbitals if I weren't using boxes instead. The faint dashed lines connect these orbitals. Regarding \smash, that solved it, though that particular problem became irrelevant after I gave all of those labels subscripts - I didn't think to update the question. –  Richard Terrett Mar 19 '11 at 12:54
An approach for a more traditional diagram would be to use nodes with draw=none, fill=white and a horizontal line almost bisecting them - not sure how to do the horizontal line though. –  Richard Terrett Mar 19 '11 at 13:22
Clarifying comment: it isn't obvious from this page that cgnieder actually wrote the package modiagram and even though he wasn't one of the original answerers (only adding his answer once the package was written) it was motivated by this question (this is stated in the documentation on CTAN). –  Loop Space Mar 12 '12 at 8:52

I started doing an example on the basis of your first example picture, but hopefully you can adapt the ideas.

When constructing TikZ figures, I often find the libraries matrix and chains very helpful. And also thinking about the picture one small piece at a time.

So while waiting for our resident TikZ-deity Jake to show up with something much more elegant, I'd like to present my take on the first example picture (Plain-TeX):

\input tikz
\let\up\uparrow \let\down\downarrow % just to shorten a little
\usetikzlibrary{chains,matrix}
\tikzpicture[
a/.style={on chain,join,draw,rounded corners,minimum size=1.5em,inner sep=1pt},
r/.style={a,text=red},
every scope/.style={start chain,node distance=1mm}
]
\matrix[matrix of nodes,column sep=1.5em,row sep=1.5ex] (mx) {
&\scope[xshift=1em]\coordinate[a](A);
\node[a,label=below:$\sigma_\rho^*$]{};
\coordinate[a](C);\endscope\\
&\scope\coordinate[a](D);
\node[r,label=below:$\pi_x^*$]{$\up$};
\node[r,label=below:$\pi_y^*$]{$\up$};
\coordinate[a](G);\endscope\\
\scope\node[a]{$\up$}; \node[a]{$\up$}; \node[a]{$\up\,\down$};
\coordinate[a](H);\endscope&&
\scope\coordinate[a](I);
\node[a]{$\up\,\down$}; \node[a]{$\down$}; \node[a]{$\down$};\endscope\\
&\scope\coordinate[a](J);
\node[a,label=below:$\pi_x$]{$\up\,\down$};
\node[a,label=below:$\pi_y$]{$\up\,\down$};
\coordinate[a](K);\endscope\\
&\scope[xshift=1em]\coordinate[a](L);
\node[a,label=below:$\sigma_\rho$]{$\up\,\down$};
\coordinate[a](N);\endscope\\
};

\draw (H)--(A) (H)--(D) (H)--(J) (H)--(L)
(I)--(C) (I)--(G) (I)--(K) (I)--(N);

\endtikzpicture
\bye


I think you could separate the drawing of the chain to outside of the matrix, and be able to branch things.

-
That looks fantastic. I persevered with my experimentation and got something workable, but your approach looks much more flexible. I note that the diagram isn't totally symmetric about the 2p orbital baseline, but you don't appear to use any explicit positioning on the vertical axis. Is the asymmetry due to justification within the matrix? I feel embarrassed for not knowing about label=below - handy :D I will leave the question 'unanswered' for a while in case the Jake you mention takes a look at this, but in the meantime you have my sincere thanks. –  Richard Terrett Mar 19 '11 at 15:20
@eutactic: For centering the "2p-Orbitale" you could append ,nodes={anchor=center} to the definition of \matrix (after the matrix of nodes) –  morbusg Mar 19 '11 at 16:51
do not discount your own tikz-deism. –  Matthew Leingang Mar 19 '11 at 17:39
Wow, talk about pressure! I love your approach, all I managed to do was make it a bit more complicated to gain slightly more flexibility. So much for the deism... –  Jake Mar 19 '11 at 23:11
@Jake: oops, didn't mean to pressure, only compliment. :-) –  morbusg Mar 20 '11 at 17:03

I'm wondering if anyone has seen a package for drawing (qualitative) molecular orbital splitting diagrams in LaTeX?

Since the end of September 2011 there is the new package modiagram which provides an easy syntax for molecular orbital diagrams.

Two examples:

\documentclass{article}
\usepackage{modiagram,chemfig}
\usepackage[version=3]{mhchem}
\begin{document}

\begin{MOdiagram}[labels,names,style=square]
\atom[N]{left}{
2p = {0;up,up,up}
}
\atom[O]{right}{
2p = {2;pair,up,up}
}
\molecule[NO]{
2pMO  = {1.8,.4;pair,pair,pair,up} ,
color = {2piy* = red}
}
\end{MOdiagram}

\begin{MOdiagram}[names]
\atom[\lewis{0.,F}\hspace*{5mm}\lewis{4.,F}]{left}{
1s = .2;up,
up-el-pos = {1sleft=.5}
}
\atom[Xe]{right}{
1s = 1.25;pair
}
\molecule[\ce{XeF2}]{
1sMO = {1/.25;pair}
}
\AO(1cm){s}{0;up}
\AO(3cm){s}{0;pair}
\connect{ AO1 & AO2 }
\node[right,xshift=4mm] at (1sigma) {\footnotesize bonding};
\node[above] at (AO2.90) {\footnotesize non-bonding};
\node[above] at (1sigma*.90) {\footnotesize anti-bonding};
\end{MOdiagram}

\end{document}


-

morbusg's approach is awesome, and for most molecular orbitals that can sensibly be drawn with such pretty rectangles, it should be all one could wish for.

In some cases, however, it can become necessary to have finer control over the vertical position of the atom/molecule orbitals (for example, in nitric oxide the 2p-orbitals of oxygen have a higher energy level than those of nitrogen, according to a chemistry textbook). Having all orbitals in one matrix makes it a bit hard to adjust vertical positions.

Building on morbusg's approach, here's one that uses individual matrices for each energy level. The matrices aren't used for actually placing the orbitals, but rather in order to access the nice \execute at begin cell={<some code>} functionality that allows us to enclose the orbitals in scopes that in turn start chains. The horizontal spacing is done using those chains, the vertical positioning happens by using yshifts.

\documentclass{minimal}
\usepackage{tikz}
\usetikzlibrary{chains,matrix}

\newcommand{\moup}{$\uparrow$}
\newcommand{\modown}{$\downarrow$}
\newcommand{\moupdown}{$\uparrow\,\downarrow$}
\begin{document}

\begin{tikzpicture}[
a/.style={on chain,join,draw,rounded corners,minimum size=1.5em,inner sep=1pt},
r/.style={a,text=red},
% Style for molecular orbital matrices
mo/.style={inner sep=-\pgflinewidth,label distance=0.3em,label position=below},
left atom/.style={execute at begin cell={\begin{scope}},
execute at end cell={\coordinate[a];\end{scope}},mo,xshift=-1.5cm,matrix anchor=base east},
right atom/.style={execute at begin cell={\begin{scope}\coordinate[a];},
execute at end cell={\end{scope}},mo,xshift=1.5cm,matrix anchor=base west},
molecule/.style={execute at begin cell={\begin{scope}\coordinate[a,inner sep=2cm];},
execute at end cell={\coordinate[a];\end{scope}},mo,anchor=base},
% Morbusg's scope-chain magic
every scope/.style={start chain,node distance=1mm},
]

\matrix[molecule,yshift=2cm] (as) { % Antibonding Sigma
\node[a,label=$\sigma_\rho^*$]{}; \\};

\matrix[molecule,yshift=0.8cm] (ap) {  % Antibonding Pi
\node[a,label=$\pi_x^*$]{\moup};
\node[a,label=$\pi_y^*$]{}; \\};

\matrix[molecule,yshift=-0.8cm] (bp) { % Bonding Pi
\node[a,label=$\pi_x$]{\moupdown};
\node[a,label=$\pi_y$]{\moupdown}; \\};

\matrix[molecule,yshift=-2cm] (bs) { % Bonding Sigma
\node[a,label=$\sigma_\rho$]{\moupdown}; \\};

\matrix [left atom,yshift=-0.4cm] (la){ % Left Atom
\node[a]{\moup}; \node[a]{\moup}; \node[a]{\moup};\\};

\matrix [right atom,yshift=0.5cm] (ra) { % Right Atom
\node[a]{\moupdown}; \node[a]{\modown}; \node[a]{\modown}; \\};

\draw [densely dashed] (la.base east) -- (bs.base west)
(bs.base east) -- (ra.base west) -- (as.base east)
(as.base west) -- (la.base east) -- (bp.base west)
(bp.base east) -- (ra.base west) -- (ap.base east)
(ap.base west) -- (la.base east);
\end{tikzpicture}

\end{document}


-
A-ha! Separate matrices makes so much sense! –  morbusg Mar 20 '11 at 17:01
You don't disappoint. The tweakable orbital levels make this truly useful for both simplified examples and real systems, because with your approach it should be trivial to substitute real scaled energies for the vertical offsets in all three columns, as well as to add extra columns for other atoms. I'll give morbusg the answer as he got the ball rolling on this one, but you certainly perfected it. Thanks so much for your time! –  Richard Terrett Mar 21 '11 at 1:44