A customer posed a good question to me the other day:  outside of relational databases, what good is LINQ?  As an example, he suggested a chemistry drawing application.

I couldn't help him directly on the GUI aspects, but I decided to figure out, given a graph of atoms and bonds representing a molecule, how to find patterns in the structure.  In the specific example, I decided to locate hydroxyl ions (-OH).

The query boils down to this:  find the hydrogen atoms with a single bond, which goes to an oxygen atom, which has only one other bond not going to the original hydrogen.

The following is a working example, and compiles against the CTP release of LINQ. Obviously, with some more thought put into the chemistry object model, the code could be simplified, and potentially more sophisticated queries executed.  One early (and as yet untested) speculation had me writing something like:

from atom in molecule.Atoms
where atom.Element == Element.Hydrogen
and atom.Bonds.Count == 1
from atom2 in atom.Bonds[0].FindAtom(a => a != atom && a.Element == Element.Oxygen)
where atom2.FindBonds(b => b != atom.Bonds[0]).Count == 1
select atom2.FindBonds(b => b != atom.Bonds[0])[0].FindAtom(a => a != atom2)

Code follows:

using System;
using System.Collections.Generic;
using System.Text;
using System.Query;
using System.Xml.XLinq;
using System.Data.DLinq;
using System.Collections.ObjectModel;

namespace ChemLinq
{
    class Program
    {
        enum Element
        {
            Hydrogen = 1,
            Oxygen = 8,
            Carbon = 12
        }

        class Atom
        {
            public Element Element;

            public Collection<Bond> Bonds;

            public Atom(Element element)
            {
                this.Element = element;
                Bonds = new Collection<Bond>();
            }
        }

        class Bond
        {
            public Collection<Atom> Atoms;

            public Bond(params Atom[] atoms)
            {
                Atoms = new Collection<Atom>(atoms);

                foreach (Atom a in atoms)
                {
                    a.Bonds.Add(this);
                }
            }
        }

        static void Main(string[] args)
        {
            // create Carbon Ring -- a MoleculeBuilder class would be useful here

            var c1 = new Atom(Element.Carbon);
            var c2 = new Atom(Element.Carbon);
            var c3 = new Atom(Element.Carbon);
            var c4 = new Atom(Element.Carbon);
            var c5 = new Atom(Element.Carbon);
            var c6 = new Atom(Element.Carbon);

            var bond12 = new Bond(c1, c2);
            var bond23 = new Bond(c2, c3);
            var bond34 = new Bond(c3, c4);
            var bond45 = new Bond(c4, c5);
            var bond56 = new Bond(c5, c6);
            var bond61 = new Bond(c6, c1);

            // create Hydroxyl ions

            var o1 = new Atom(Element.Oxygen);
            var o3 = new Atom(Element.Oxygen);
            var o5 = new Atom(Element.Oxygen);

            var h1 = new Atom(Element.Hydrogen);
            var h3 = new Atom(Element.Hydrogen);
            var h5 = new Atom(Element.Hydrogen);

            var bondOh1 = new Bond(o1, h1);
            var bondOh3 = new Bond(o3, h3);
            var bondOh5 = new Bond(o5, h5);

            // bond the ions to the ring

            var bond1 = new Bond(o1, c1);
            var bond3 = new Bond(o3, c3);
            var bond5 = new Bond(o5, c5);

            // bundle these into a molecule
            var molecule = new[] { c1, c2, c3, c4, c5, c6, o1, o3, o5, h1, h3, h5 };

            // query the structure to locate the hydroxyls

            // this could be cleaned up with some appropriate helper methods
            // on Atom and Bond

            var query = 
                from hAtom in molecule                          // search the molecule
                where hAtom.Element == Element.Hydrogen         // for hydrogen atoms
                && hAtom.Bonds.Count == 1                       // with a single bond;
                    from hBond in hAtom.Bonds                   // search those bonds
                    where hBond.Atoms.Count == 2                // which have only 2 atoms
                        from oAtom in hBond.Atoms               // and find those where
                        where oAtom.Element == Element.Oxygen   // the other atom is oxygen
                        && oAtom.Bonds.Count == 2               // and which has only 2 bonds;
                            from oBond in oAtom.Bonds           // then take the bond
                            where oBond.Atoms.Count == 2        // that go to only 1 other atom
                            && !oBond.Atoms.Contains(hAtom)     // but not to the original hAtom
                            select oAtom;                       // and select that oxygen atom


            Console.WriteLine(query.Count()); // outputs 3

            Console.ReadKey(true);
        }
    }
}