Browse Source

add support for Beta and Gamma peptides

Alexander Rose 5 years ago
parent
commit
41bc74e543

+ 1 - 1
src/mol-model-formats/structure/common/entity.ts

@@ -30,7 +30,7 @@ export class EntityBuilder {
     }
 
     getEntityId(compId: string, moleculeType: MoleculeType, chainId: string): string {
-        if (moleculeType === MoleculeType.water) {
+        if (moleculeType === MoleculeType.Water) {
             if (this.waterId === undefined) {
                 this.set('water', 'Water')
                 this.waterId = `${this.count}`

+ 1 - 1
src/mol-model-formats/structure/gro.ts

@@ -36,7 +36,7 @@ function getCategories(atoms: GroAtoms) {
     let currentAsymIndex = 0
     let currentAsymId = ''
     let currentSeqId = 0
-    let prevMoleculeType = MoleculeType.unknown
+    let prevMoleculeType = MoleculeType.Unknown
     let prevResidueNumber = -1
 
     for (let i = 0, il = atoms.count; i < il; ++i) {

+ 1 - 1
src/mol-model-formats/structure/mmcif/parser.ts

@@ -180,7 +180,7 @@ function getSaccharideComponentMap(format: mmCIF_Format): SaccharideComponentMap
             const _type = type.value(i)
             if (SaccharideCompIdMap.has(_id)) {
                 map.set(_id, SaccharideCompIdMap.get(_id)!)
-            } else if (getMoleculeType(_type, _id) === MoleculeType.saccharide) {
+            } else if (getMoleculeType(_type, _id) === MoleculeType.Saccharide) {
                 map.set(_id, UnknownSaccharideComponent)
             }
         }

+ 2 - 1
src/mol-model/structure/model/properties/atomic/hierarchy.ts

@@ -8,7 +8,7 @@
 import { Column, Table } from '../../../../../mol-data/db'
 import { Segmentation } from '../../../../../mol-data/int'
 import { mmCIF_Schema as mmCIF } from '../../../../../mol-io/reader/cif/schema/mmcif'
-import { ElementSymbol, MoleculeType } from '../../types'
+import { ElementSymbol, MoleculeType, PolymerType } from '../../types'
 import { ChainIndex, EntityIndex, ResidueIndex, ElementIndex } from '../../indexing';
 import SortedRanges from '../../../../../mol-data/int/sorted-ranges';
 
@@ -116,6 +116,7 @@ export interface AtomicDerivedData {
         readonly directionFromElementIndex: ArrayLike<ElementIndex | -1>
         readonly directionToElementIndex: ArrayLike<ElementIndex | -1>
         readonly moleculeType: ArrayLike<MoleculeType>
+        readonly polymerType: ArrayLike<PolymerType>
     }
 }
 

+ 23 - 10
src/mol-model/structure/model/properties/utils/atomic-derived.ts

@@ -7,9 +7,10 @@
 import { AtomicData } from '../atomic';
 import { AtomicIndex, AtomicDerivedData } from '../atomic/hierarchy';
 import { ElementIndex, ResidueIndex } from '../../indexing';
-import { MoleculeType, getMoleculeType, getComponentType } from '../../types';
+import { MoleculeType, getMoleculeType, getComponentType, PolymerType, getPolymerType } from '../../types';
 import { getAtomIdForAtomRole } from '../../../../../mol-model/structure/util';
 import { ChemicalComponentMap } from '../common';
+import { isProductionMode } from '../../../../../mol-util/debug';
 
 export function getAtomicDerivedData(data: AtomicData, index: AtomicIndex, chemicalComponentMap: ChemicalComponentMap): AtomicDerivedData {
     const { label_comp_id, _rowCount: n } = data.residues
@@ -18,38 +19,49 @@ export function getAtomicDerivedData(data: AtomicData, index: AtomicIndex, chemi
     const directionFromElementIndex = new Int32Array(n)
     const directionToElementIndex = new Int32Array(n)
     const moleculeType = new Uint8Array(n)
+    const polymerType = new Uint8Array(n)
 
     const moleculeTypeMap = new Map<string, MoleculeType>()
+    const polymerTypeMap = new Map<string, PolymerType>()
 
     for (let i = 0 as ResidueIndex; i < n; ++i) {
         const compId = label_comp_id.value(i)
         const chemCompMap = chemicalComponentMap
+
         let molType: MoleculeType
+        let polyType: PolymerType
         if (moleculeTypeMap.has(compId)) {
             molType = moleculeTypeMap.get(compId)!
-        } else if (chemCompMap.has(compId)) {
-            molType = getMoleculeType(chemCompMap.get(compId)!.type, compId)
-            moleculeTypeMap.set(compId, molType)
+            polyType = polymerTypeMap.get(compId)!
         } else {
-            console.log('chemComp not found', compId)
-            molType = getMoleculeType(getComponentType(compId), compId)
+            let type: string
+            if (chemCompMap.has(compId)) {
+                type = chemCompMap.get(compId)!.type
+            } else {
+                if (!isProductionMode) console.info('chemComp not found', compId)
+                type = getComponentType(compId)
+            }
+            molType = getMoleculeType(type, compId)
             // TODO if unknown molecule type, use atom names to guess molecule type
+            polyType = getPolymerType(type, molType)
             moleculeTypeMap.set(compId, molType)
+            polymerTypeMap.set(compId, polyType)
         }
         moleculeType[i] = molType
+        polymerType[i] = polyType
 
-        const traceAtomId = getAtomIdForAtomRole(molType, 'trace')
+        const traceAtomId = getAtomIdForAtomRole(polyType, 'trace')
         let traceIndex = index.findAtomsOnResidue(i, traceAtomId)
         if (traceIndex === -1) {
-            const coarseAtomId = getAtomIdForAtomRole(molType, 'coarseBackbone')
+            const coarseAtomId = getAtomIdForAtomRole(polyType, 'coarseBackbone')
             traceIndex = index.findAtomsOnResidue(i, coarseAtomId)
         }
         traceElementIndex[i] = traceIndex
 
-        const directionFromAtomId = getAtomIdForAtomRole(molType, 'directionFrom')
+        const directionFromAtomId = getAtomIdForAtomRole(polyType, 'directionFrom')
         directionFromElementIndex[i] = index.findAtomsOnResidue(i, directionFromAtomId)
 
-        const directionToAtomId = getAtomIdForAtomRole(molType, 'directionTo')
+        const directionToAtomId = getAtomIdForAtomRole(polyType, 'directionTo')
         directionToElementIndex[i] = index.findAtomsOnResidue(i, directionToAtomId)
     }
 
@@ -59,6 +71,7 @@ export function getAtomicDerivedData(data: AtomicData, index: AtomicIndex, chemi
             directionFromElementIndex: directionFromElementIndex as unknown as ArrayLike<ElementIndex | -1>,
             directionToElementIndex: directionToElementIndex as unknown as ArrayLike<ElementIndex | -1>,
             moleculeType: moleculeType as unknown as ArrayLike<MoleculeType>,
+            polymerType: polymerType as unknown as ArrayLike<PolymerType>,
         }
     }
 }

+ 9 - 9
src/mol-model/structure/model/properties/utils/atomic-ranges.ts

@@ -7,7 +7,7 @@
 import { AtomicRanges, AtomicIndex, AtomicHierarchy, AtomicDerivedData } from '../atomic/hierarchy';
 import { Segmentation, Interval } from '../../../../../mol-data/int';
 import SortedRanges from '../../../../../mol-data/int/sorted-ranges';
-import { isPolymer } from '../../types';
+import { isPolymer, PolymerType } from '../../types';
 import { ElementIndex, ResidueIndex } from '../../indexing';
 import { getAtomIdForAtomRole } from '../../../util';
 import { AtomicConformation } from '../atomic/conformation';
@@ -16,18 +16,18 @@ import { Entities } from '../common';
 import StructureSequence from '../sequence';
 
 function areBackboneConnected(riStart: ResidueIndex, riEnd: ResidueIndex, conformation: AtomicConformation, index: AtomicIndex, derived: AtomicDerivedData) {
-    const { moleculeType, traceElementIndex, directionFromElementIndex, directionToElementIndex } = derived.residue
-    const mtStart = moleculeType[riStart]
-    const mtEnd = moleculeType[riEnd]
-    if (!isPolymer(mtStart) || !isPolymer(mtEnd)) return false
+    const { polymerType, traceElementIndex, directionFromElementIndex, directionToElementIndex } = derived.residue
+    const ptStart = polymerType[riStart]
+    const ptEnd = polymerType[riEnd]
+    if (ptStart === PolymerType.NA || ptEnd === PolymerType.NA) return false
     if (traceElementIndex[riStart] === -1 || traceElementIndex[riEnd] === -1) return false
 
-    let eiStart = index.findAtomsOnResidue(riStart, getAtomIdForAtomRole(mtStart, 'backboneStart'))
-    let eiEnd = index.findAtomsOnResidue(riEnd, getAtomIdForAtomRole(mtEnd, 'backboneEnd'))
+    let eiStart = index.findAtomsOnResidue(riStart, getAtomIdForAtomRole(ptStart, 'backboneStart'))
+    let eiEnd = index.findAtomsOnResidue(riEnd, getAtomIdForAtomRole(ptEnd, 'backboneEnd'))
 
     if (eiStart === -1 || eiEnd === -1) {
-        eiStart = index.findAtomsOnResidue(riStart, getAtomIdForAtomRole(mtStart, 'coarseBackbone'))
-        eiEnd = index.findAtomsOnResidue(riEnd, getAtomIdForAtomRole(mtEnd, 'coarseBackbone'))
+        eiStart = index.findAtomsOnResidue(riStart, getAtomIdForAtomRole(ptStart, 'coarseBackbone'))
+        eiEnd = index.findAtomsOnResidue(riEnd, getAtomIdForAtomRole(ptEnd, 'coarseBackbone'))
     }
 
     const { x, y, z } = conformation

+ 92 - 26
src/mol-model/structure/model/types.ts

@@ -40,30 +40,49 @@ export const enum EntityType {
 }
 
 export const enum MoleculeType {
-    /** the molecule type is not known */
-    unknown,
-    /** a known, but here not listed molecule type */
-    other,
-    /** water molecule */
-    water,
-    /** small ionic molecule */
-    ion,
-    /** protein, e.g. component type included in `ProteinComponentTypeNames` */
-    protein,
+    /** The molecule type is not known */
+    Unknown,
+    /** A known, but here not listed molecule type */
+    Other,
+    /** Water molecule */
+    Water,
+    /** Small ionic molecule */
+    Ion,
+    /** Protein, e.g. component type included in `ProteinComponentTypeNames` */
+    Protein,
     /** RNA, e.g. component type included in `RNAComponentTypeNames` */
     RNA,
     /** DNA, e.g. component type included in `DNAComponentTypeNames` */
     DNA,
     /** PNA, peptide nucleic acid, comp id included in `PeptideBaseNames` */
     PNA,
-    /** sacharide, e.g. component type included in `SaccharideComponentTypeNames` */
-    saccharide
+    /** Saccharide, e.g. component type included in `SaccharideComponentTypeNames` */
+    Saccharide
+}
+
+export const enum PolymerType {
+    /** not applicable */
+    NA,
+    Protein,
+    GammaProtein,
+    BetaProtein,
+    RNA,
+    DNA,
+    PNA,
 }
 
 export type AtomRole = 'trace' | 'directionFrom' | 'directionTo' | 'backboneStart' | 'backboneEnd' | 'coarseBackbone'
 
-export const MoleculeTypeAtomRoleId: { [k: number]: { [k in AtomRole]: Set<string> } } = {
-    [MoleculeType.protein]: {
+export const PolymerTypeAtomRoleId: { [k in PolymerType]: { [k in AtomRole]: Set<string> } } = {
+    [PolymerType.NA]: {
+        trace: new Set(),
+        directionFrom: new Set(),
+        directionTo: new Set(),
+        backboneStart: new Set(),
+        backboneEnd: new Set(),
+        coarseBackbone: new Set()
+    },
+    [PolymerType.Protein]: {
         trace: new Set(['CA']),
         directionFrom: new Set(['C']),
         directionTo: new Set(['O', 'OC1', 'O1', 'OX1', 'OXT']),
@@ -73,7 +92,23 @@ export const MoleculeTypeAtomRoleId: { [k: number]: { [k in AtomRole]: Set<strin
         // BB is often used for coarse grained models
         coarseBackbone: new Set(['CA', 'BB', 'CA1'])
     },
-    [MoleculeType.RNA]: {
+    [PolymerType.GammaProtein]: {
+        trace: new Set(['CA']),
+        directionFrom: new Set(['C']),
+        directionTo: new Set(['O']),
+        backboneStart: new Set(['N']),
+        backboneEnd: new Set(['CD']),
+        coarseBackbone: new Set(['CA'])
+    },
+    [PolymerType.BetaProtein]: {
+        trace: new Set(['CA']),
+        directionFrom: new Set(['C']),
+        directionTo: new Set(['O']),
+        backboneStart: new Set(['N']),
+        backboneEnd: new Set(['CG']),
+        coarseBackbone: new Set(['CA'])
+    },
+    [PolymerType.RNA]: {
         trace: new Set(['C4\'', 'C4*']),
         directionFrom: new Set(['C4\'', 'C4*']),
         directionTo: new Set(['C3\'', 'C3*']),
@@ -81,7 +116,7 @@ export const MoleculeTypeAtomRoleId: { [k: number]: { [k in AtomRole]: Set<strin
         backboneEnd: new Set(['O3\'', 'O3*']),
         coarseBackbone: new Set(['P'])
     },
-    [MoleculeType.DNA]: {
+    [PolymerType.DNA]: {
         trace: new Set(['C3\'', 'C3*']),
         directionFrom: new Set(['C3\'', 'C3*']),
         directionTo: new Set(['C1\'', 'C1*']),
@@ -89,7 +124,7 @@ export const MoleculeTypeAtomRoleId: { [k: number]: { [k in AtomRole]: Set<strin
         backboneEnd: new Set(['O3\'', 'O3*']),
         coarseBackbone: new Set(['P'])
     },
-    [MoleculeType.PNA]: {
+    [PolymerType.PNA]: {
         trace: new Set(['N4\'', 'N4*']),
         directionFrom: new Set(['N4\'', 'N4*']),
         directionTo: new Set(['C7\'', 'C7*']),
@@ -127,6 +162,16 @@ export const LProteinComponentTypeNames = new Set([
     'L-BETA-PEPTIDE, C-GAMMA LINKING'
 ])
 
+/** Chemical component type names for gamma protein, overlaps with D/L-linked */
+export const GammaProteinComponentTypeNames = new Set([
+    'D-GAMMA-PEPTIDE, C-DELTA LINKING', 'L-GAMMA-PEPTIDE, C-DELTA LINKING'
+])
+
+/** Chemical component type names for beta protein, overlaps with D/L-linked */
+export const BetaProteinComponentTypeNames = new Set([
+    'D-BETA-PEPTIDE, C-GAMMA LINKING', 'L-BETA-PEPTIDE, C-GAMMA LINKING'
+])
+
 /** Chemical component type names for pepdite-like protein */
 export const OtherProteinComponentTypeNames = new Set([
     'PEPTIDE LINKING', 'PEPTIDE-LIKE',
@@ -206,32 +251,53 @@ export const isPyrimidineBase = (compId: string) => PyrimidineBaseNames.has(comp
 export const PolymerNames = SetUtils.unionMany(AminoAcidNames, BaseNames)
 
 /** get the molecule type from component type and id */
-export function getMoleculeType(compType: string, compId: string) {
+export function getMoleculeType(compType: string, compId: string): MoleculeType {
     compType = compType.toUpperCase()
     compId = compId.toUpperCase()
     if (PeptideBaseNames.has(compId)) {
         return MoleculeType.PNA
     } else if (ProteinComponentTypeNames.has(compType)) {
-        return MoleculeType.protein
+        return MoleculeType.Protein
     } else if (RNAComponentTypeNames.has(compType)) {
         return MoleculeType.RNA
     } else if (DNAComponentTypeNames.has(compType)) {
         return MoleculeType.DNA
     } else if (SaccharideComponentTypeNames.has(compType)) {
-        return MoleculeType.saccharide
+        return MoleculeType.Saccharide
     } else if (WaterNames.has(compId)) {
-        return MoleculeType.water
+        return MoleculeType.Water
     } else if (IonNames.has(compId)) {
-        return MoleculeType.ion
+        return MoleculeType.Ion
     } else if (OtherComponentTypeNames.has(compType)) {
         if (SaccharideCompIdMap.has(compId)) {
             // trust our saccharide table more than given 'non-polymer' or 'other' component type
-            return MoleculeType.saccharide
+            return MoleculeType.Saccharide
+        } else {
+            return MoleculeType.Other
+        }
+    } else {
+        return MoleculeType.Unknown
+    }
+}
+
+export function getPolymerType(compType: string, molType: MoleculeType): PolymerType {
+    compType = compType.toUpperCase()
+    if (molType === MoleculeType.Protein) {
+        if (GammaProteinComponentTypeNames.has(compType)) {
+            return PolymerType.GammaProtein
+        } else if (BetaProteinComponentTypeNames.has(compType)) {
+            return PolymerType.BetaProtein
         } else {
-            return MoleculeType.other
+            return PolymerType.Protein
         }
+    } else if (molType === MoleculeType.RNA) {
+        return PolymerType.RNA
+    } else if (molType === MoleculeType.DNA) {
+        return PolymerType.DNA
+    } else if (molType === MoleculeType.PNA) {
+        return PolymerType.PNA
     } else {
-        return MoleculeType.unknown
+        return PolymerType.NA
     }
 }
 
@@ -316,7 +382,7 @@ export function isNucleic(moleculeType: MoleculeType) {
 }
 
 export function isProtein(moleculeType: MoleculeType) {
-    return moleculeType === MoleculeType.protein
+    return moleculeType === MoleculeType.Protein
 }
 
 /**

+ 1 - 1
src/mol-model/structure/structure/accessible-surface-area.ts

@@ -192,7 +192,7 @@ namespace AccessibleSurfaceArea {
 
             if (isNucleic(residueType)) {
                  ctx.atomRadius[aI] = determineRadiusNucl(atomId, element, compId);
-            } else if (residueType === MoleculeType.protein) {
+            } else if (residueType === MoleculeType.Protein) {
                 ctx.atomRadius[aI] = determineRadiusAmino(atomId, element, compId);
             } else {
                 ctx.atomRadius[aI] = handleNonStandardCase(element);

+ 6 - 6
src/mol-model/structure/util.ts

@@ -5,7 +5,7 @@
  */
 
 import { Model, ResidueIndex, ElementIndex } from './model';
-import { MoleculeType, AtomRole, MoleculeTypeAtomRoleId, getMoleculeType } from './model/types';
+import { MoleculeType, AtomRole, PolymerTypeAtomRoleId, getMoleculeType, PolymerType } from './model/types';
 import { Vec3 } from '../../mol-math/linear-algebra';
 import { Unit } from './structure';
 import Matrix from '../../mol-math/linear-algebra/matrix/matrix';
@@ -28,7 +28,7 @@ export function getElementMoleculeType(unit: Unit, element: ElementIndex): Molec
             const cc = unit.model.properties.chemicalComponentMap.get(compId)
             if (cc) return getMoleculeType(cc.type, compId)
     }
-    return MoleculeType.unknown
+    return MoleculeType.Unknown
 }
 
 export function getAtomicMoleculeType(model: Model, rI: ResidueIndex): MoleculeType {
@@ -36,10 +36,10 @@ export function getAtomicMoleculeType(model: Model, rI: ResidueIndex): MoleculeT
 }
 
 const EmptyAtomIds = new Set<string>()
-export function getAtomIdForAtomRole(moleculeType: MoleculeType, atomRole: AtomRole) {
-    const m = MoleculeTypeAtomRoleId[moleculeType]
-    if (m !== undefined) {
-        const a = m[atomRole]
+export function getAtomIdForAtomRole(polymerType: PolymerType, atomRole: AtomRole) {
+    const p = PolymerTypeAtomRoleId[polymerType]
+    if (p !== undefined) {
+        const a = p[atomRole]
         if (a !== undefined) return a
     }
     return EmptyAtomIds

+ 1 - 1
src/mol-plugin/behavior/dynamic/labels.ts

@@ -159,7 +159,7 @@ export const SceneLabels = PluginBehavior.create<SceneLabelsProps>({
 
                     if (p.levels.includes('ligand') && !u.polymerElements.length) {
                         const moleculeType = getElementMoleculeType(u, u.elements[0])
-                        if (moleculeType === MoleculeType.other || moleculeType === MoleculeType.saccharide) {
+                        if (moleculeType === MoleculeType.Other || moleculeType === MoleculeType.Saccharide) {
                             label = `${StructureProperties.entity.pdbx_description(l).join(', ')} (${getAsymId(u)(l)})`
                         }
                     }

+ 1 - 1
src/mol-repr/structure/visual/util/polymer/trace-iterator.ts

@@ -56,7 +56,7 @@ function createPolymerTraceElement (unit: Unit): PolymerTraceElement {
         initial: false, final: false,
         secStrucFirst: false, secStrucLast: false,
         secStrucType: SecStrucTypeNA,
-        moleculeType: MoleculeType.unknown,
+        moleculeType: MoleculeType.Unknown,
         coarseBackboneFirst: false, coarseBackboneLast: false,
         isCoarseBackbone: false,
         p0: Vec3(), p1: Vec3(), p2: Vec3(), p3: Vec3(), p4: Vec3(),

+ 4 - 4
src/mol-theme/color/molecule-type.ts

@@ -41,13 +41,13 @@ export function getMoleculeTypeColorThemeParams(ctx: ThemeDataContext) {
 export function moleculeTypeColor(colorMap: MoleculeTypeColors, unit: Unit, element: ElementIndex): Color {
     const moleculeType = getElementMoleculeType(unit, element)
     switch (moleculeType) {
-        case MoleculeType.water: return colorMap.water
-        case MoleculeType.ion: return colorMap.ion
-        case MoleculeType.protein: return colorMap.protein
+        case MoleculeType.Water: return colorMap.water
+        case MoleculeType.Ion: return colorMap.ion
+        case MoleculeType.Protein: return colorMap.protein
         case MoleculeType.RNA: return colorMap.RNA
         case MoleculeType.DNA: return colorMap.DNA
         case MoleculeType.PNA: return colorMap.PNA
-        case MoleculeType.saccharide: return colorMap.saccharide
+        case MoleculeType.Saccharide: return colorMap.saccharide
     }
     return DefaultMoleculeTypeColor
 }

+ 2 - 2
src/mol-theme/color/secondary-structure.ts

@@ -75,9 +75,9 @@ export function secondaryStructureColor(colorMap: SecondaryStructureColors, unit
             return colorMap.dna
         } else if (moleculeType === MoleculeType.RNA) {
             return colorMap.rna
-        } else if (moleculeType === MoleculeType.saccharide) {
+        } else if (moleculeType === MoleculeType.Saccharide) {
             return colorMap.carbohydrate
-        } else if (moleculeType === MoleculeType.protein) {
+        } else if (moleculeType === MoleculeType.Protein) {
             return colorMap.coil
         }
     }