<commit_before>/**
 * @file Metal Binding
 * @author <NAME> <<EMAIL>>
 */

import { defaults } from '../../utils'
import Structure from '../../structure/structure'
// import { valenceModel } from '../../structure/data'
import { Elements } from '../../structure/structure-constants'
// import { hasAromaticNeighbour } from '../functional-groups'
import {
  Features, FeatureType,
  addAtom, addFeature, createFeatureState,
} from './features'
import { Contacts, ContactType, ContactDefaultParams, invalidAtomContact } from './contact'

const IonicTypeMetals = [
  Elements.LI, Elements.NA, Elements.K, Elements.RB, Elements.CS,
  Elements.MG, Elements.CA, Elements.SR, Elements.BA, Elements.AL,
  Elements.GA, Elements.IN, Elements.TL, Elements.SC, Elements.SN,
  Elements.PB, Elements.BI, Elements.SB, Elements.HG
]

/**
 * Metal binding partners (dative bond or ionic-type interaction)
 */
export function addMetalBinding (structure: Structure, features: Features) {
  structure.eachAtom(a => {
    let dative = false
    let ionic = false

    if (a.isProtein()){
      // main chain oxygen atom or oxygen, nitrogen and sulfur from specific amino acids
      if (a.number === Elements.O) {
        if(['ASP', 'GLU', 'SER', 'THR', 'TYR', 'ASN', 'GLN', 'CSO'].includes(a.resname) && a.isSidechain()) {
          dative = true
          ionic = true
        } else if (a.isBackbone()) {
          dative = true
          ionic = true
        }
      } else if (a.number === Elements.S && ['CYS', 'CSO'].includes(a.resname)) {
        dative = true
        ionic = true
      } else if (a.number === Elements.N) {
        if(a.resname === 'HIS' && a.isSidechain()) {
          dative = true
        }
      }
    } else if (a.isNucleic()){
      // http://pubs.acs.org/doi/pdf/10.1021/acs.accounts.6b00253
      // http://onlinelibrary.wiley.com/doi/10.1002/anie.200900399/full
      if (a.number === Elements.O && a.isBackbone()) {
        dative = true
        ionic = true
      } else if(['N3', 'N4', 'N7'].includes(a.atomname)) {
        dative = true
      } else if(['O2', 'O4', 'O6'].includes(a.atomname)) {
        dative = true
        ionic = true
      }
    } else if (!a.isPolymer()) {
      if (a.isHalogen() || a.number === Elements.O || a.number === Elements.S) {
        dative = true
        ionic = true
      } else if (a.number === Elements.N) {
        dative = true
      }
    }
    if (dative) {
      const state = createFeatureState(FeatureType.DativeBondPartner)
      addAtom(state, a)
      addFeature(features, state)
    }
    if (ionic) {
      const state = createFeatureState(FeatureType.IonicTypePartner)
      addAtom(state, a)
      addFeature(features, state)<commit_msg>fix nucleic metal coordination<commit_after>/**
 * @file Metal Binding
 * @author <NAME> <<EMAIL>>
 */

import { defaults } from '../../utils'
import Structure from '../../structure/structure'
// import { valenceModel } from '../../structure/data'
import { Elements } from '../../structure/structure-constants'
// import { hasAromaticNeighbour } from '../functional-groups'
import {
  Features, FeatureType,
  addAtom, addFeature, createFeatureState,
} from './features'
import { Contacts, ContactType, ContactDefaultParams, invalidAtomContact } from './contact'

const IonicTypeMetals = [
  Elements.LI, Elements.NA, Elements.K, Elements.RB, Elements.CS,
  Elements.MG, Elements.CA, Elements.SR, Elements.BA, Elements.AL,
  Elements.GA, Elements.IN, Elements.TL, Elements.SC, Elements.SN,
  Elements.PB, Elements.BI, Elements.SB, Elements.HG
]

/**
 * Metal binding partners (dative bond or ionic-type interaction)
 */
export function addMetalBinding (structure: Structure, features: Features) {
  structure.eachAtom(a => {
    let dative = false
    let ionic = false

    if (a.isProtein()){
      // main chain oxygen atom or oxygen, nitrogen and sulfur from specific amino acids
      if (a.number === Elements.O) {
        if(['ASP', 'GLU', 'SER', 'THR', 'TYR', 'ASN', 'GLN', 'CSO'].includes(a.resname) && a.isSidechain()) {
          dative = true
          ionic = true
        } else if (a.isBackbone()) {
          dative = true
          ionic = true
        }
      } else if (a.number === Elements.S && ['CYS', 'CSO'].includes(a.resname)) {
        dative = true
        ionic = true
      } else if (a.number === Elements.N) {
        if(a.resname === 'HIS' && a.isSidechain()) {
          dative = true
        }
      }
    } else if (!a.isPolymer()) {
      if (a.isHalogen() || a.number === Elements.O || a.number === Elements.S) {
        dative = true
        ionic = true
      } else if (a.number === Elements.N) {
        dative = true
      }
    } else if (a.isNucleic()){
      // http://pubs.acs.org/doi/pdf/10.1021/acs.accounts.6b00253
      // http://onlinelibrary.wiley.com/doi/10.1002/anie.200900399/full
      if (a.number === Elements.O && a.isBackbone()) {
        dative = true
        ionic = true
      } else if(['N3', 'N4', 'N7'].includes(a.atomname)) {
        dative = true
      } else if(['O2', 'O4', 'O6'].includes(a.atomname)) {
        dative = true
        ionic = true
      }
    }
    if (dative) {
      const state = createFeatureState(FeatureType.DativeBondPartner)
      addAtom(state, a)
      addFeature(features, state)
    }
    if (ionic) {
      const state = createFeatureState(FeatureType.IonicTypePartner)
      addAtom(state, a)
      addFeature(features, state)
{'fraction_non_alphanumeric': 0.15749770009199632, 'fraction_numerical': 0.012143514259429623, 'mean_word_length': 2.5207253886010363, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '517541', 'n_tokens_mistral': 1856, 'n_tokens_neox': 1726, 'n_words': 414}