bool Element::calcValence()

in core/indigo-core/molecule/src/elements.cpp [457:937]


bool Element::calcValence(int elem, int charge, int radical, int conn, int& valence, int& hyd, bool to_throw)
{
    int groupno = Element::group(elem);
    int rad = radicalElectrons(radical);

    valence = conn;
    hyd = 0;

    if (groupno == 1)
    {
        if (elem == ELEM_Li || elem == ELEM_Na || elem == ELEM_K || elem == ELEM_Rb || elem == ELEM_Cs || elem == ELEM_Fr)
        {
            valence = 1;
            hyd = 1 - rad - conn - abs(charge);
        }
        if (elem == ELEM_H)
        {
            valence = 1;
            if (charge == 1 && conn == 0)
                hyd = 0;
            else if (charge == -1 && conn == 0)
                hyd = 0;
            else if (charge == 0 && conn == 1)
                hyd = 0;
            else if (charge == 0 && conn == 0)
                hyd = 1; // elemental hydrogen, hmm... well, OK -- behaviour changed
                         // Allow implicit H for H, so single H is considered as molecule H2 now
                         // in accordance with Biovia Draw model
            else
                hyd = -1;
        }
    }
    else if (groupno == 2)
    {
        if (elem == ELEM_Be || elem == ELEM_Mg || elem == ELEM_Ca || elem == ELEM_Sr || elem == ELEM_Ba || elem == ELEM_Ra)
        {
            valence = 2;
            if (conn != 0)
            {
                if (rad > 0 || abs(charge) > 0)
                    hyd = -1;
                else
                    hyd = 2 - conn;
            }
            else if (rad > 0 || abs(charge) > 0)
            {
                hyd = 2 - rad - abs(charge);
            }
            else
            {
                hyd = 0;
            }

            if (hyd != 0)
                hyd = -1;
        }
    }
    else if (groupno == 3)
    {
        if (elem == ELEM_B || elem == ELEM_Al || elem == ELEM_Ga || elem == ELEM_In)
        {
            if (charge == -1)
            {
                valence = 4;
                hyd = 4 - rad - conn;
            }
            else if (charge == -3 && elem != ELEM_B && rad + conn <= 6)
            {
                valence = rad + conn;
                hyd = 0;
            }
            else if (elem == ELEM_Al && charge == -2)
            {
                if (rad + conn == 5)
                {
                    valence = 5;
                    hyd = 0;
                }
                else
                    hyd = -1;
            }
            else
            {
                valence = 3;
                hyd = 3 - rad - conn - abs(charge);
            }
        }
        else if (elem == ELEM_Tl)
        {
            if (charge == -1)
            {
                if (rad + conn <= 2)
                {
                    valence = 2;
                    hyd = 2 - rad - conn;
                }
                else
                {
                    valence = 4;
                    hyd = 4 - rad - conn;
                }
            }
            else if (charge == -2)
            {
                if (rad + conn <= 3)
                {
                    valence = 3;
                    hyd = 3 - rad - conn;
                }
                else
                {
                    valence = 5;
                    hyd = 5 - rad - conn;
                }
            }
            else if (charge == -3 && rad + conn == 6)
            { // ISIS Draw and Marvin allow this
                valence = 6;
                hyd = 0;
            }
            else
            {
                if (rad + conn + abs(charge) <= 1)
                {
                    valence = 1;
                    hyd = 1 - rad - conn - abs(charge);
                }
                else
                {
                    valence = 3;
                    hyd = 3 - rad - conn - abs(charge);
                }
            }
        }
    }
    else if (groupno == 4)
    {
        if (elem == ELEM_C)
        {
            valence = 4;
            hyd = 4 - rad - conn - abs(charge);
        }
        else if (elem == ELEM_Si || elem == ELEM_Ge || elem == ELEM_Sn || elem == ELEM_Pb)
        {
            if (charge == -2 && conn == 6 && rad == 0)
            {
                // Zinc fluorosilicate, hexafluorogermanium
                valence = 6;
                hyd = 0;
            }
            else if (charge == -1 && conn + rad == 5)
            {
                // with radical:    [Ge-]: CID 18503269
                // without radical: [Si-]: CID 358631
                //                  [Ge-]: CID 19891516
                valence = 5;
                hyd = 0;
            }
            else if (charge == -1 && conn + rad == 4 && elem == ELEM_Si)
            {
                valence = 5; // CID 438107
                hyd = 1;
            }
            else if ((elem == ELEM_Sn || elem == ELEM_Pb) && conn + rad + abs(charge) <= 2)
            {
                // [SnH2]: CID 23962
                // [PbH2]: CID 23927
                valence = 2;
                hyd = 2 - rad - conn - abs(charge);
            }
            else
            {
                // 4-valent Pb with H: CID 24003
                // 4-valent Sn with H: CID 5948
                // 4-valent Ge with H2: CID 66239
                // [GeH4]: CID 23984
                valence = 4;
                hyd = 4 - rad - conn - abs(charge);
            }
        }
    }
    else if (groupno == 5)
    {
        if (elem == ELEM_N || elem == ELEM_P)
        {
            if (charge == 1)
            {
                valence = 4;
                hyd = 4 - rad - conn;
            }
            else if (charge == 2)
            {
                valence = 3;
                hyd = 3 - rad - conn;
            }
            else if (charge == -1 && elem == ELEM_P)
            {
                if (rad + conn <= 2) // phosphanide
                {
                    valence = 2;
                    hyd = 2 - rad - conn;
                }
                else if (rad + conn == 3) // no known examples with a hydrogen
                    hyd = -1;
                else if (rad + conn == 4)
                {
                    valence = 4;
                    hyd = 0;
                }
                else if (rad + conn <= 6)
                {
                    // w/ hydrogen: CID 3084356, CID 2784547
                    // w/o hydrogen: hexachlorophosphate
                    valence = 6;
                    hyd = 6 - rad - conn;
                }
            }
            else
            {
                if (elem == ELEM_N || rad + conn + abs(charge) <= 3)
                {
                    valence = 3;
                    hyd = 3 - rad - conn - abs(charge);
                }
                else // ELEM_P && rad + conn + abs(charge) > 3
                {
                    valence = 5;
                    hyd = 5 - rad - conn - abs(charge);
                }
            }
        }
        else if (elem == ELEM_Bi || elem == ELEM_Sb || elem == ELEM_As)
        {
            if (charge == -1 && rad + conn == 6)
            {
                valence = 6;
                hyd = 0;
            }
            else if (charge == 1)
            {
                if (rad + conn <= 2 && elem != ELEM_As)
                {
                    valence = 2;
                    hyd = 2 - rad - conn;
                }
                else
                {
                    valence = 4;
                    hyd = 4 - rad - conn;
                }
            }
            else if (charge == 2)
            {
                valence = 3;
                hyd = 3 - rad - conn;
            }
            else if (charge == -2 && rad + conn == 5)
            {
                // Bi: CID 45158489
                valence = 5;
                hyd = 0;
            }
            else
            {
                if (rad + conn + abs(charge) <= 3)
                {
                    valence = 3;
                    hyd = 3 - rad - conn - abs(charge);
                }
                else
                {
                    valence = 5;
                    hyd = 5 - rad - conn - abs(charge);
                }
            }
        }
    }
    else if (groupno == 6)
    {
        if (elem == ELEM_O)
        {
            if (charge >= 1)
            {
                valence = 3;
                hyd = 3 - rad - conn;
            }
            else
            {
                valence = 2;
                hyd = 2 - rad - conn - abs(charge);
            }
        }
        else if (elem == ELEM_S || elem == ELEM_Se || elem == ELEM_Po)
        {
            if (charge == 1)
            {
                if (conn <= 3)
                {
                    valence = 3;
                    hyd = 3 - rad - conn;
                }
                else
                {
                    valence = 5;
                    hyd = 5 - rad - conn;
                }
            }
            else if (charge == -1)
            {
                if (conn + rad <= 1)
                {
                    valence = 1;
                    hyd = 1 - rad - conn;
                }
                else if (conn + rad <= 3)
                {
                    valence = 3;
                    hyd = 3 - rad - conn;
                }
                // no real examples for the other two cases, just following ISIS/Draw logic
                else if (conn + rad <= 5)
                {
                    valence = 5;
                    hyd = 5 - rad - conn;
                }
                else
                {
                    valence = 7;
                    hyd = 7 - rad - conn;
                }
            }
            else
            {
                if (conn + rad + abs(charge) <= 2)
                {
                    valence = 2;
                    hyd = 2 - rad - conn - abs(charge);
                }
                else if (conn + rad + abs(charge) <= 4)
                // See examples in PubChem
                // [S] : CID 16684216
                // [Se]: CID 5242252
                // [Po]: no example, just following ISIS/Draw logic here
                {
                    valence = 4;
                    hyd = 4 - rad - conn - abs(charge);
                }
                else
                // See examples in PubChem
                // [S] : CID 46937044
                // [Se]: CID 59786
                // [Po]: no example, just following ISIS/Draw logic here
                {
                    valence = 6;
                    hyd = 6 - rad - conn - abs(charge);
                }
            }
        }
        else if (elem == ELEM_Te)
        {
            if (charge == -1)
            {
                if (rad + conn == 7) // CID 4191414
                {
                    valence = 7;
                    hyd = 0;
                }
                else if (rad + conn == 5)
                { // no example, but both Marvin and ISIS are OK with this configuration
                    valence = 5;
                    hyd = 0;
                }
                else
                {
                    valence = 1;
                    hyd = 1 - rad - conn;
                }
            }
            else if (charge == 1)
            {
                valence = 3;
                hyd = 3 - rad - conn;
                // no known cases of 5-connected [Te+]
            }
            else if (charge == 2)
            {
                if (conn + rad == 4)
                {
                    valence = conn + rad;
                    hyd = 0;
                }
                else // ISIS Draw logic
                {
                    hyd = 2 - conn - rad;
                    valence = 2;
                }
            }
            else if (charge == 0)
            {
                if (conn + rad <= 2)
                {
                    hyd = 2 - conn - rad;
                    valence = 2;
                }
                else if (conn + rad <= 4)
                {
                    hyd = 4 - conn - rad; // with hydrogen: CID 11968228
                    valence = 4;
                }
                else
                {
                    hyd = 6 - conn - rad; // with hydrogen: CID 5231555, CID 6418860
                    valence = 6;
                }
            }
        }
    }
    else if (groupno == 7)
    {
        if (elem == ELEM_F)
        {
            valence = 1;
            hyd = 1 - rad - conn - abs(charge);
        }
        else if (elem == ELEM_Cl || elem == ELEM_Br || elem == ELEM_I || elem == ELEM_At)
        {
            if (charge == 1)
            {
                if (conn <= 2)
                {
                    valence = 2;
                    hyd = 2 - rad - conn;
                }
                else if (conn == 3 || conn == 5 || conn >= 7)
                    hyd = -1;
            }
            else if (charge == 0)
            {
                if (conn <= 1)
                {
                    valence = 1;
                    hyd = 1 - rad - conn;
                }
                // While the halogens can have valence 3, they can not have
                // hydrogens in that case.
                else if (conn == 2 || conn == 4 || conn == 6)
                {
                    if (rad == 1)
                    {
                        valence = conn;
                        hyd = 0;
                    }
                    else
                        hyd = -1; // will throw an error in the end
                }
                else if (conn > 7)
                    hyd = -1; // will throw an error in the end
            }
        }
    }
    else if (groupno == 8)
    {
        if (elem == ELEM_He || elem == ELEM_Ne || elem == ELEM_Ar || elem == ELEM_Kr || elem == ELEM_Xe || elem == ELEM_Rn || elem == ELEM_Og)
        {
            valence = 0;
            hyd = 0 - rad - conn - abs(charge);
            if (hyd > 0)
                hyd = 0;
        }
    }

    if (hyd < 0)
    {
        if (to_throw)
            throw Error("bad valence on %s having %d drawn bonds, charge %d, and %d radical electrons", toString(elem), conn, charge, rad);
        valence = conn;
        hyd = 0;
        return false;
    }
    return true;
}