Browse Source

wip, interactions

- metal coordination
- Features.Provider() ctor
- Features.Provider, multiple types
Alexander Rose 5 years ago
parent
commit
5813840e17

+ 3 - 3
src/mol-model-props/computed/interactions/charged.ts

@@ -371,9 +371,9 @@ function testCationPi(structure: Structure, infoA: Features.Info, infoB: Feature
 
 //
 
-export const NegativChargeProvider = { type: FeatureType.NegativeCharge, add: addUnitNegativeCharges }
-export const PositiveChargeProvider = { type: FeatureType.PositiveCharge, add: addUnitPositiveCharges }
-export const AromaticRingProvider = { type: FeatureType.AromaticRing, add: addUnitAromaticRings }
+export const NegativChargeProvider = Features.Provider([FeatureType.NegativeCharge], addUnitNegativeCharges)
+export const PositiveChargeProvider = Features.Provider([FeatureType.PositiveCharge], addUnitPositiveCharges)
+export const AromaticRingProvider = Features.Provider([FeatureType.AromaticRing], addUnitAromaticRings)
 
 export const IonicProvider: LinkProvider<IonicParams> = {
     name: 'ionic',

+ 4 - 1
src/mol-model-props/computed/interactions/features.ts

@@ -128,9 +128,12 @@ namespace Features {
     }
 
     export interface Provider {
-        type: FeatureType
+        types: Set<FeatureType>
         add: (structure: Structure, unit: Unit.Atomic, featuresBuilder: FeaturesBuilder) => void
     }
+    export function Provider(types: FeatureType[], add: Provider['add']): Provider {
+        return { types: new Set(types), add }
+    }
 }
 
 export { FeaturesBuilder }

+ 5 - 5
src/mol-model-props/computed/interactions/halogen-bonds.ts

@@ -30,7 +30,7 @@ const halBondElements = [Elements.CL, Elements.BR, Elements.I, Elements.AT] as E
 /**
  * Halogen bond donors (X-C, with X one of Cl, Br, I or At) not F!
  */
-export function addUnitHalogenDonors (structure: Structure, unit: Unit.Atomic, builder: FeaturesBuilder) {
+function addUnitHalogenDonors(structure: Structure, unit: Unit.Atomic, builder: FeaturesBuilder) {
     const { elements } = unit
     const { x, y, z } = unit.model.atomicConformation
 
@@ -48,7 +48,7 @@ const Y = [Elements.C, Elements.N, Elements.P, Elements.S] as ElementSymbol[]
 /**
  * Halogen bond acceptors (Y-{O|N|S}, with Y=C,P,N,S)
  */
-export function addUnitHalogenAcceptors (structure: Structure, unit: Unit.Atomic, builder: FeaturesBuilder) {
+function addUnitHalogenAcceptors(structure: Structure, unit: Unit.Atomic, builder: FeaturesBuilder) {
     const { elements } = unit
     const { x, y, z } = unit.model.atomicConformation
 
@@ -68,7 +68,7 @@ export function addUnitHalogenAcceptors (structure: Structure, unit: Unit.Atomic
     }
 }
 
-function isHalogenBond (ti: FeatureType, tj: FeatureType) {
+function isHalogenBond(ti: FeatureType, tj: FeatureType) {
     return (
         (ti === FeatureType.HalogenAcceptor && tj === FeatureType.HalogenDonor) ||
         (ti === FeatureType.HalogenDonor && tj === FeatureType.HalogenAcceptor)
@@ -112,8 +112,8 @@ function testHalogenBond(structure: Structure, infoA: Features.Info, infoB: Feat
 
 //
 
-export const HalogenDonorProvider = { type: FeatureType.HalogenDonor, add: addUnitHalogenDonors }
-export const HalogenAcceptorProvider = { type: FeatureType.HalogenAcceptor, add: addUnitHalogenAcceptors }
+export const HalogenDonorProvider = Features.Provider([FeatureType.HalogenDonor], addUnitHalogenDonors)
+export const HalogenAcceptorProvider = Features.Provider([FeatureType.HalogenAcceptor], addUnitHalogenAcceptors)
 
 export const HalogenBondsProvider: LinkProvider<HalogenBondsParams> = {
     name: 'halogen-bonds',

+ 3 - 3
src/mol-model-props/computed/interactions/hydrogen-bonds.ts

@@ -303,9 +303,9 @@ function testWeakHydrogenBond(structure: Structure, infoA: Features.Info, infoB:
 
 //
 
-export const HydrogenDonorProvider = { type: FeatureType.HydrogenDonor, add: addUnitHydrogenDonors }
-export const WeakHydrogenDonorProvider = { type: FeatureType.WeakHydrogenDonor, add: addUnitWeakHydrogenDonors }
-export const HydrogenAcceptorProvider = { type: FeatureType.HydrogenAcceptor, add: addUnitHydrogenAcceptors }
+export const HydrogenDonorProvider = Features.Provider([FeatureType.HydrogenDonor], addUnitHydrogenDonors)
+export const WeakHydrogenDonorProvider = Features.Provider([FeatureType.WeakHydrogenDonor], addUnitWeakHydrogenDonors)
+export const HydrogenAcceptorProvider = Features.Provider([FeatureType.HydrogenAcceptor], addUnitHydrogenAcceptors)
 
 export const HydrogenBondsProvider: LinkProvider<HydrogenBondsParams> = {
     name: 'hydrogen-bonds',

+ 6 - 6
src/mol-model-props/computed/interactions/hydrophobic.ts

@@ -15,18 +15,18 @@ import { Elements } from '../../../mol-model/structure/model/properties/atomic/t
 import { FeatureType, FeatureGroup, InteractionType } from './common';
 import { LinkProvider } from './links';
 
-export const HydrophobicParams = {
+const HydrophobicParams = {
     distanceMax: PD.Numeric(4.0, { min: 1, max: 5, step: 0.1 }),
 }
-export type HydrophobicParams = typeof HydrophobicParams
-export type HydrophobicProps = PD.Values<HydrophobicParams>
+type HydrophobicParams = typeof HydrophobicParams
+type HydrophobicProps = PD.Values<HydrophobicParams>
 
 /**
  * Hydropbobic atoms
  * - Carbon only bonded to carbon or hydrogen
  * - Fluorine
  */
-export function addHydrophobicAtom(structure: Structure, unit: Unit.Atomic, builder: FeaturesBuilder) {
+function addHydrophobicAtom(structure: Structure, unit: Unit.Atomic, builder: FeaturesBuilder) {
     const { elements } = unit
     const { x, y, z } = unit.model.atomicConformation
 
@@ -49,7 +49,7 @@ export function addHydrophobicAtom(structure: Structure, unit: Unit.Atomic, buil
     }
 }
 
-function isHydrophobicContact (ti: FeatureType, tj: FeatureType) {
+function isHydrophobicContact(ti: FeatureType, tj: FeatureType) {
     return ti === FeatureType.HydrophobicAtom && tj === FeatureType.HydrophobicAtom
 }
 
@@ -68,7 +68,7 @@ function testHydrophobic(structure: Structure, infoA: Features.Info, infoB: Feat
 
 //
 
-export const HydrophobicAtomProvider = { type: FeatureType.HydrophobicAtom, add: addHydrophobicAtom }
+export const HydrophobicAtomProvider = Features.Provider([FeatureType.HydrophobicAtom], addHydrophobicAtom)
 
 export const HydrophobicProvider: LinkProvider<HydrophobicParams> = {
     name: 'hydrophobic',

+ 7 - 3
src/mol-model-props/computed/interactions/interactions.ts

@@ -10,7 +10,7 @@ import { RuntimeContext } from '../../../mol-task';
 import { Features, FeaturesBuilder } from './features';
 import { ValenceModelProvider } from '../valence-model';
 import { InteractionsIntraLinks, InteractionsInterLinks, FeatureType } from './common';
-import { IntraLinksBuilder, InterLinksBuilder } from './builder';
+import { IntraLinksBuilder, InterLinksBuilder } from './links-builder';
 import { IntMap } from '../../../mol-data/int';
 import { Vec3 } from '../../../mol-math/linear-algebra';
 import { addUnitLinks, LinkTester, addStructureLinks, LinkProvider } from './links';
@@ -18,6 +18,8 @@ import { HalogenDonorProvider, HalogenAcceptorProvider, HalogenBondsProvider } f
 import { HydrogenDonorProvider, WeakHydrogenDonorProvider, HydrogenAcceptorProvider, HydrogenBondsProvider, WeakHydrogenBondsProvider } from './hydrogen-bonds';
 import { NegativChargeProvider, PositiveChargeProvider, AromaticRingProvider, IonicProvider, PiStackingProvider, CationPiProvider } from './charged';
 import { HydrophobicAtomProvider, HydrophobicProvider } from './hydrophobic';
+import { SetUtils } from '../../../mol-util/set';
+import { MetalCoordinationProvider, MetalProvider, MetalBindingProvider } from './metal';
 
 export { Interactions }
 
@@ -105,6 +107,7 @@ const FeatureProviders = [
     NegativChargeProvider, PositiveChargeProvider, AromaticRingProvider,
     HalogenDonorProvider, HalogenAcceptorProvider,
     HydrophobicAtomProvider,
+    MetalProvider, MetalBindingProvider,
 ]
 
 const LinkProviders = {
@@ -115,6 +118,7 @@ const LinkProviders = {
     'hydrogen-bonds': HydrogenBondsProvider,
     'weak-hydrogen-bonds': WeakHydrogenBondsProvider,
     'hydrophobic': HydrophobicProvider,
+    'metal-coordination': MetalCoordinationProvider,
 }
 type LinkProviders = typeof LinkProviders
 
@@ -133,7 +137,7 @@ export const InteractionsParams = {
         'hydrogen-bonds',
         'halogen-bonds',
         // 'hydrophobic',
-        // 'metal-coordination',
+        'metal-coordination',
         'weak-hydrogen-bonds',
     ], PD.objectToOptions(LinkProviders)),
     ...getProvidersParams()
@@ -153,7 +157,7 @@ export async function computeInteractions(runtime: RuntimeContext, structure: St
 
     const requiredFeatures = new Set<FeatureType>()
     linkProviders.forEach(l => { for (const f of l.requiredFeatures) requiredFeatures.add(f) })
-    const featureProviders = FeatureProviders.filter(f => requiredFeatures.has(f.type))
+    const featureProviders = FeatureProviders.filter(f => SetUtils.areIntersecting(requiredFeatures, new Set(f.types)))
 
     const unitsFeatures = IntMap.Mutable<Features>()
     const unitsLinks = IntMap.Mutable<InteractionsIntraLinks>()

+ 0 - 0
src/mol-model-props/computed/interactions/builder.ts → src/mol-model-props/computed/interactions/links-builder.ts


+ 1 - 1
src/mol-model-props/computed/interactions/links.ts

@@ -8,7 +8,7 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { Structure, Unit } from '../../../mol-model/structure';
 import { Features } from './features';
 import { InteractionType, FeatureType } from './common';
-import { IntraLinksBuilder, InterLinksBuilder } from './builder';
+import { IntraLinksBuilder, InterLinksBuilder } from './links-builder';
 import { Mat4, Vec3 } from '../../../mol-math/linear-algebra';
 import { altLoc, connectedTo } from '../chemistry/util';
 

+ 165 - 0
src/mol-model-props/computed/interactions/metal.ts

@@ -0,0 +1,165 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ *
+ * based in part on NGL (https://github.com/arose/ngl)
+ */
+
+import { ParamDefinition as PD } from '../../../mol-util/param-definition';
+import { Structure, Unit, StructureElement } from '../../../mol-model/structure';
+import { FeaturesBuilder, Features } from './features';
+import { typeSymbol, compId, atomId } from '../chemistry/util';
+import { Elements, isTransitionMetal, isHalogen } from '../../../mol-model/structure/model/properties/atomic/types';
+import { FeatureType, FeatureGroup, InteractionType } from './common';
+import { LinkProvider } from './links';
+import { ElementSymbol, AminoAcidNames, BaseNames, ProteinBackboneAtoms, NucleicBackboneAtoms } from '../../../mol-model/structure/model/types';
+
+export const MetalCoordinationParams = {
+    distanceMax: PD.Numeric(3.0, { min: 1, max: 5, step: 0.1 }),
+}
+export type MetalCoordinationParams = typeof MetalCoordinationParams
+export type MetalCoordinationProps = PD.Values<MetalCoordinationParams>
+
+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
+] as ElementSymbol[]
+
+function addMetal(structure: Structure, unit: Unit.Atomic, builder: FeaturesBuilder) {
+    const { elements } = unit
+    const { x, y, z } = unit.model.atomicConformation
+
+    for (let i = 0 as StructureElement.UnitIndex, il = elements.length; i < il; ++i) {
+        const element = typeSymbol(unit, i)
+
+        let type = FeatureType.None
+        if (IonicTypeMetals.includes(element)) {
+            type = FeatureType.IonicTypeMetal
+        } else if (isTransitionMetal(element) || element === Elements.ZN || element === Elements.CD) {
+            type = FeatureType.TransitionMetal
+        }
+
+        if (type) {
+            builder.add(type, FeatureGroup.None, x[elements[i]], y[elements[i]], z[elements[i]], i)
+        }
+    }
+}
+
+function isProteinSidechain(atomname: string) {
+    return !ProteinBackboneAtoms.has(atomname)
+}
+
+function isProteinBackbone(atomname: string) {
+    return ProteinBackboneAtoms.has(atomname)
+}
+
+function isNucleicBackbone(atomname: string) {
+    return NucleicBackboneAtoms.has(atomname)
+}
+
+/**
+ * Metal binding partners (dative bond or ionic-type interaction)
+ */
+function addMetalBinding(structure: Structure, unit: Unit.Atomic, builder: FeaturesBuilder) {
+    const { elements } = unit
+    const { x, y, z } = unit.model.atomicConformation
+
+    for (let i = 0 as StructureElement.UnitIndex, il = elements.length; i < il; ++i) {
+        const element = typeSymbol(unit, i)
+        const resname = compId(unit, i)
+        const atomname = atomId(unit, i)
+        let dative = false
+        let ionic = false
+
+        const isStandardAminoacid = AminoAcidNames.has(resname)
+        const isStandardBase = BaseNames.has(resname)
+
+        if (!isStandardAminoacid && !isStandardBase) {
+            if (isHalogen(element) || element === Elements.O || element === Elements.S) {
+                dative = true
+                ionic = true
+            } else if (element === Elements.N) {
+                dative = true
+            }
+        } else if (isStandardAminoacid) {
+            // main chain oxygen atom or oxygen, nitrogen and sulfur from specific amino acids
+            if (element === Elements.O) {
+                if (['ASP', 'GLU', 'SER', 'THR', 'TYR', 'ASN', 'GLN'].includes(resname) && isProteinSidechain(atomname)) {
+                    dative = true
+                    ionic = true
+                } else if (isProteinBackbone(atomname)) {
+                    dative = true
+                    ionic = true
+                }
+            } else if (element === Elements.S && 'CYS' === resname) {
+                dative = true
+                ionic = true
+            } else if (element === Elements.N) {
+                if (resname === 'HIS' && isProteinSidechain(atomname)) {
+                    dative = true
+                }
+            }
+        } else if (isStandardBase) {
+            // http://pubs.acs.org/doi/pdf/10.1021/acs.accounts.6b00253
+            // http://onlinelibrary.wiley.com/doi/10.1002/anie.200900399/full
+            if (element === Elements.O && isNucleicBackbone(atomname)) {
+                dative = true
+                ionic = true
+            } else if (['N3', 'N4', 'N7'].includes(atomname)) {
+                dative = true
+            } else if (['O2', 'O4', 'O6'].includes(atomname)) {
+                dative = true
+                ionic = true
+            }
+        }
+
+        if (dative) {
+            builder.add(FeatureType.DativeBondPartner, FeatureGroup.None, x[elements[i]], y[elements[i]], z[elements[i]], i)
+        }
+        if (ionic) {
+            builder.add(FeatureType.IonicTypePartner, FeatureGroup.None, x[elements[i]], y[elements[i]], z[elements[i]], i)
+        }
+    }
+}
+
+function isMetalCoordination(ti: FeatureType, tj: FeatureType) {
+    if (ti === FeatureType.TransitionMetal) {
+        return (
+            tj === FeatureType.DativeBondPartner ||
+            tj === FeatureType.TransitionMetal
+        )
+    } else if (ti === FeatureType.IonicTypeMetal) {
+        return (
+            tj === FeatureType.IonicTypePartner
+        )
+    }
+}
+
+function testMetalCoordination(structure: Structure, infoA: Features.Info, infoB: Features.Info, distanceSq: number): InteractionType | undefined {
+    const typeA = infoA.types[infoA.feature]
+    const typeB = infoB.types[infoB.feature]
+
+    if (!isMetalCoordination(typeA, typeB) && !isMetalCoordination(typeB, typeA)) return
+
+    return InteractionType.MetalCoordination
+}
+
+//
+
+export const MetalProvider = Features.Provider([FeatureType.IonicTypeMetal, FeatureType.TransitionMetal], addMetal)
+export const MetalBindingProvider = Features.Provider([FeatureType.IonicTypePartner, FeatureType.DativeBondPartner], addMetalBinding)
+
+export const MetalCoordinationProvider: LinkProvider<MetalCoordinationParams> = {
+    name: 'metal-coordination',
+    params: MetalCoordinationParams,
+    requiredFeatures: [FeatureType.IonicTypeMetal, FeatureType.TransitionMetal, FeatureType.IonicTypePartner, FeatureType.DativeBondPartner],
+    createTester: (props: MetalCoordinationProps) => {
+        return {
+            maxDistanceSq: props.distanceMax * props.distanceMax,
+            getType: (structure, infoA, infoB, distanceSq) => testMetalCoordination(structure, infoA, infoB, distanceSq)
+        }
+    }
+}