rapodaca / molecule.rs

Implementation of a minimal Molecule API in Rust
MIT License
2 stars 1 forks source link

Hypervalent N/O/F don't return `HypervalentAtom` #2

Closed thesketh closed 4 years ago

thesketh commented 4 years ago

I've been thinking about corner cases because I've been putting together the unit tests for oxmol, and atom::Atom::build happily accepts NH5, OH6 and FH7 without returning HypervalentAtom.

I have a fix that works, but I'm not sure if it's the best way to handle it. This preserves the ability to represent PF5, SF6 and IF7.

in element:.rs, adjust the valence electron counts for the offending atoms:

impl Element {
    pub fn valence_electrons(&self) -> u8 {
        match self {
            // ...
            Element::N =>  3, // 5
            Element::O =>  2, // 6
            Element::F =>  1, // 7
            // ...

in atom::Atom::build, re-add the missing electrons after adding hydrogens:

        match element {
            Element::N => nonbonding_electrons += 2,
            Element::O => nonbonding_electrons += 4,
            Element::F => nonbonding_electrons += 6,
            _ => ()
        };

I don't know how neon is supposed to behave, but I think anyone representing noble gasses is likely to know their quirks anyway.

rapodaca commented 4 years ago

The valence electron count is designed to count all electrons in the valence shell. For nitrogen bound to three carbons, the count should be 2, for example.

This is to ensure that all molecular properties can be computed in a consistent way. For example, if you wanted to know whether a nitrogen was a lone pair donor, it would be difficult to do that if it had zero nonbonding electrons.

What you're getting at is worthwhile. Nitrogen with 5 hydrogens is weird. But it doesn't break any rules - other than regularly observed bonding behavior.

That said, a function called validate_hydrogens could work. It would accept a Molecule and for each atom check that the hydrogen count conformed to a particular view of bonding regularity.

It might not be universally applicable, however. Each research group may have a different idea of what represents bonding regularity.

The tradeoff I made in Molecule.rs was to allow anything up to and including consumption of all valence electrons. Past that, and you get an error.

thesketh commented 4 years ago

That makes sense, it's a good idea to leave the valence electron counts alone, it was just the first solution that came to mind. I might emit a warning for these three in Python. A validation function could be useful, but you're right that deciding what is 'normal' might be difficult

As alternative solutions, I think enforcing the octet rule or checking the hybridisation state would work:

Both of these feel like heavy-handed solutions for only three exceptions, though. In line with 'be liberal in what you accept', the current behaviour is preferable. I'll close this for now, if hybridisation/VSEPR shape are implemented later and the code for this is in place it might be worth revisiting.