calculateValence()

in packages/ketcher-core/src/domain/entities/CoreAtom.ts [203:483]


  calculateValence() {
    if (this.hasExplicitValence) {
      const valence = this.properties.explicitValence as number;
      const hydrogenAmount = valence - this.valenceWithoutHydrogen;

      return {
        valence,
        hydrogenAmount,
      };
    }

    const label = this.label;
    const element = Elements.get(label);
    const elementGroupNumber = element?.group;
    const connectionAmount = this.calculateConnections();
    const radicalAmount = this.radicalAmount;
    const charge = this.properties.charge || 0;
    const absCharge = Math.abs(charge);
    let valence = connectionAmount;
    let hydrogenAmount = 0;

    if (connectionAmount === -1) {
      return {
        valence,
        hydrogenAmount,
      };
    }

    if (elementGroupNumber === undefined) {
      if (label === AtomLabel.D || label === AtomLabel.T) {
        valence = 1;
        hydrogenAmount = 1 - radicalAmount - connectionAmount - absCharge;
      } else {
        // this.implicitH = 0;
        // return true;
      }
    } else if (elementGroupNumber === 1) {
      if (
        label === AtomLabel.H ||
        label === AtomLabel.Li ||
        label === AtomLabel.Na ||
        label === AtomLabel.K ||
        label === AtomLabel.Rb ||
        label === AtomLabel.Cs ||
        label === AtomLabel.Fr
      ) {
        valence = 1;
        hydrogenAmount = 1 - radicalAmount - connectionAmount - absCharge;
      }
    } else if (elementGroupNumber === 2) {
      if (
        connectionAmount + radicalAmount + absCharge === 2 ||
        connectionAmount + radicalAmount + absCharge === 0
      ) {
        valence = 2;
      } else hydrogenAmount = -1;
    } else if (elementGroupNumber === 3) {
      if (
        label === AtomLabel.B ||
        label === AtomLabel.Al ||
        label === AtomLabel.Ga ||
        label === AtomLabel.In
      ) {
        if (charge === -1) {
          valence = 4;
          hydrogenAmount = 4 - radicalAmount - connectionAmount;
        } else {
          valence = 3;
          hydrogenAmount = 3 - radicalAmount - connectionAmount - absCharge;
        }
      } else if (label === AtomLabel.Tl) {
        if (charge === -1) {
          if (radicalAmount + connectionAmount <= 2) {
            valence = 2;
            hydrogenAmount = 2 - radicalAmount - connectionAmount;
          } else {
            valence = 4;
            hydrogenAmount = 4 - radicalAmount - connectionAmount;
          }
        } else if (charge === -2) {
          if (radicalAmount + connectionAmount <= 3) {
            valence = 3;
            hydrogenAmount = 3 - radicalAmount - connectionAmount;
          } else {
            valence = 5;
            hydrogenAmount = 5 - radicalAmount - connectionAmount;
          }
        } else if (radicalAmount + connectionAmount + absCharge <= 1) {
          valence = 1;
          hydrogenAmount = 1 - radicalAmount - connectionAmount - absCharge;
        } else {
          valence = 3;
          hydrogenAmount = 3 - radicalAmount - connectionAmount - absCharge;
        }
      }
    } else if (elementGroupNumber === 4) {
      if (
        label === AtomLabel.C ||
        label === AtomLabel.Si ||
        label === AtomLabel.Ge
      ) {
        valence = 4;
        hydrogenAmount = 4 - radicalAmount - connectionAmount - absCharge;
      } else if (label === AtomLabel.Sn || label === AtomLabel.Pb) {
        if (connectionAmount + radicalAmount + absCharge <= 2) {
          valence = 2;
          hydrogenAmount = 2 - radicalAmount - connectionAmount - absCharge;
        } else {
          valence = 4;
          hydrogenAmount = 4 - radicalAmount - connectionAmount - absCharge;
        }
      }
    } else if (elementGroupNumber === 5) {
      if (label === AtomLabel.N || label === AtomLabel.P) {
        if (charge === 1) {
          valence = 4;
          hydrogenAmount = 4 - radicalAmount - connectionAmount;
        } else if (charge === 2) {
          valence = 3;
          hydrogenAmount = 3 - radicalAmount - connectionAmount;
        } else if (
          label === AtomLabel.N ||
          radicalAmount + connectionAmount + absCharge <= 3
        ) {
          valence = 3;
          hydrogenAmount = 3 - radicalAmount - connectionAmount - absCharge;
        } else {
          // ELEM_P && rad + conn + absCharge > 3
          valence = 5;
          hydrogenAmount = 5 - radicalAmount - connectionAmount - absCharge;
        }
      } else if (
        label === AtomLabel.Bi ||
        label === AtomLabel.Sb ||
        label === AtomLabel.As
      ) {
        if (charge === 1) {
          if (radicalAmount + connectionAmount <= 2 && label !== AtomLabel.As) {
            valence = 2;
            hydrogenAmount = 2 - radicalAmount - connectionAmount;
          } else {
            valence = 4;
            hydrogenAmount = 4 - radicalAmount - connectionAmount;
          }
        } else if (charge === 2) {
          valence = 3;
          hydrogenAmount = 3 - radicalAmount - connectionAmount;
        } else if (radicalAmount + connectionAmount <= 3) {
          valence = 3;
          hydrogenAmount = 3 - radicalAmount - connectionAmount - absCharge;
        } else {
          valence = 5;
          hydrogenAmount = 5 - radicalAmount - connectionAmount - absCharge;
        }
      }
    } else if (elementGroupNumber === 6) {
      if (label === AtomLabel.O) {
        if (charge >= 1) {
          valence = 3;
          hydrogenAmount = 3 - radicalAmount - connectionAmount;
        } else {
          valence = 2;
          hydrogenAmount = 2 - radicalAmount - connectionAmount - absCharge;
        }
      } else if (
        label === AtomLabel.S ||
        label === AtomLabel.Se ||
        label === AtomLabel.Po
      ) {
        if (charge === 1) {
          if (connectionAmount <= 3) {
            valence = 3;
            hydrogenAmount = 3 - radicalAmount - connectionAmount;
          } else {
            valence = 5;
            hydrogenAmount = 5 - radicalAmount - connectionAmount;
          }
        } else if (connectionAmount + radicalAmount + absCharge <= 2) {
          valence = 2;
          hydrogenAmount = 2 - radicalAmount - connectionAmount - absCharge;
        } else if (connectionAmount + radicalAmount + absCharge <= 4) {
          // See examples in PubChem
          // [S] : CID 16684216
          // [Se]: CID 5242252
          // [Po]: no example, just following ISIS/Draw logic here
          valence = 4;
          hydrogenAmount = 4 - radicalAmount - connectionAmount - absCharge;
        } else {
          // See examples in PubChem
          // [S] : CID 46937044
          // [Se]: CID 59786
          // [Po]: no example, just following ISIS/Draw logic here
          valence = 6;
          hydrogenAmount = 6 - radicalAmount - connectionAmount - absCharge;
        }
      } else if (label === AtomLabel.Te) {
        if (charge === -1) {
          if (connectionAmount <= 2) {
            valence = 2;
            hydrogenAmount = 2 - radicalAmount - connectionAmount - absCharge;
          }
        } else if (charge === 0 || charge === 2) {
          if (connectionAmount <= 2) {
            valence = 2;
            hydrogenAmount = 2 - radicalAmount - connectionAmount - absCharge;
          } else if (connectionAmount <= 4) {
            valence = 4;
            hydrogenAmount = 4 - radicalAmount - connectionAmount - absCharge;
          } else if (charge === 0 && connectionAmount <= 6) {
            valence = 6;
            hydrogenAmount = 6 - radicalAmount - connectionAmount - absCharge;
          } else {
            hydrogenAmount = -1;
          }
        }
      }
    } else if (elementGroupNumber === 7) {
      if (label === AtomLabel.F) {
        valence = 1;
        hydrogenAmount = 1 - radicalAmount - connectionAmount - absCharge;
      } else if (
        label === AtomLabel.Cl ||
        label === AtomLabel.Br ||
        label === AtomLabel.I ||
        label === AtomLabel.At
      ) {
        if (charge === 1) {
          if (connectionAmount <= 2) {
            valence = 2;
            hydrogenAmount = 2 - radicalAmount - connectionAmount;
          } else if (
            connectionAmount === 3 ||
            connectionAmount === 5 ||
            connectionAmount >= 7
          ) {
            hydrogenAmount = -1;
          }
        } else if (charge === 0) {
          if (connectionAmount <= 1) {
            valence = 1;
            hydrogenAmount = 1 - radicalAmount - connectionAmount;
            // While the halogens can have valence 3, they can not have
            // hydrogens in that case.
          } else if (
            connectionAmount === 2 ||
            connectionAmount === 4 ||
            connectionAmount === 6
          ) {
            if (radicalAmount === 1) {
              valence = connectionAmount;
              hydrogenAmount = 0;
            } else {
              hydrogenAmount = -1; // will throw an error in the end
            }
          } else if (connectionAmount > 7) {
            hydrogenAmount = -1; // will throw an error in the end
          }
        }
      }
    } else if (elementGroupNumber === 8) {
      if (connectionAmount + radicalAmount + absCharge === 0) valence = 1;
      else hydrogenAmount = -1;
    }

    // if (Atom.isHeteroAtom(label) && this.implicitHCount !== null) {
    //   hydrogenAmount = this.implicitHCount;
    // }
    // this.valence = valence;
    // this.implicitH = hydrogenAmount;
    // if (this.implicitH < 0) {
    //   this.valence = connectionAmount;
    //   this.implicitH = 0;
    //   this.badConn = true;
    //   return false;
    // }

    return {
      valence,
      hydrogenAmount,
    };
  }