Browse Source

color provider for accessible surface area

Sebastian Bittrich 6 years ago
parent
commit
d48efc696a

+ 95 - 0
src/mol-model/structure/model/properties/utils/accessible-surface-area.ts

@@ -0,0 +1,95 @@
+import { ResidueIndex } from 'mol-model/structure';
+import { MoleculeType } from 'mol-model/structure/model/types';
+import { GridLookup3D } from 'mol-math/geometry';
+import { Vec3 } from 'mol-math/linear-algebra';
+import { SortedArray } from 'mol-data/int';
+import { ElementIndex } from 'mol-model/structure/model/indexing';
+import { AtomicHierarchy, AtomicConformation } from '../atomic';
+
+export function computeModelASA(hierarchy: AtomicHierarchy, conformation: AtomicConformation) {
+    const { lookup3d, proteinResidues } = calcAtomicTraceLookup3D(hierarchy, conformation)
+    const backboneIndices = calcBackboneAtomIndices(hierarchy, proteinResidues)
+
+    const residueCount = proteinResidues.length
+    const numberOfSpherePoints = 960
+
+    const ctx: ASAContext = {
+        probeSize: 1.4,
+        spherePoints: generateSpherePoints(numberOfSpherePoints),
+        cons: 4.0 * Math.PI / numberOfSpherePoints,
+
+        hierarchy,
+        proteinResidues
+   }
+
+    calculateASA(ctx)
+}
+
+function calculateASA(ctx: ASAContext) {
+
+}
+
+function generateSpherePoints(numberOfSpherePoints: number): Vec3[] {
+    const points: Vec3[] = []
+    const inc = Math.PI
+
+    return points
+}
+
+interface ASAContext {
+    probeSize: number,
+    spherePoints: Vec3[],
+    cons: number,
+
+    hierarchy: AtomicHierarchy,
+    proteinResidues: SortedArray<ResidueIndex>
+}
+
+interface BackboneAtomIndices {
+    cIndices: ArrayLike<ElementIndex | -1>
+    hIndices: ArrayLike<ElementIndex | -1>
+    oIndices: ArrayLike<ElementIndex | -1>
+    nIndices: ArrayLike<ElementIndex | -1>
+}
+
+function calcAtomicTraceLookup3D(hierarchy: AtomicHierarchy, conformation: AtomicConformation) {
+    const { x, y, z } = conformation;
+    const { moleculeType, traceElementIndex } = hierarchy.derived.residue
+    const indices: number[] = []
+    const _proteinResidues: number[] = []
+    for (let i = 0, il = moleculeType.length; i < il; ++i) {
+        if (moleculeType[i] === MoleculeType.protein) {
+            indices[indices.length] = traceElementIndex[i]
+            _proteinResidues[_proteinResidues.length] = i
+        }
+    }
+    const lookup3d = GridLookup3D({ x, y, z, indices: SortedArray.ofSortedArray(indices) }, 4);
+    const proteinResidues = SortedArray.ofSortedArray<ResidueIndex>(_proteinResidues)
+    return { lookup3d, proteinResidues }
+}
+
+
+function calcBackboneAtomIndices(hierarchy: AtomicHierarchy, proteinResidues: SortedArray<ResidueIndex>): BackboneAtomIndices {
+    const residueCount = proteinResidues.length
+    const { index } = hierarchy
+
+    const c = new Int32Array(residueCount)
+    const h = new Int32Array(residueCount)
+    const o = new Int32Array(residueCount)
+    const n = new Int32Array(residueCount)
+
+    for (let i = 0, il = residueCount; i < il; ++i) {
+        const rI = proteinResidues[i]
+        c[i] = index.findAtomOnResidue(rI, 'C')
+        h[i] = index.findAtomOnResidue(rI, 'H')
+        o[i] = index.findAtomOnResidue(rI, 'O')
+        n[i] = index.findAtomOnResidue(rI, 'N')
+    }
+
+    return {
+        cIndices: c as unknown as ArrayLike<ElementIndex | -1>,
+        hIndices: h as unknown as ArrayLike<ElementIndex | -1>,
+        oIndices: o as unknown as ArrayLike<ElementIndex | -1>,
+        nIndices: n as unknown as ArrayLike<ElementIndex | -1>,
+    }
+}

+ 2 - 0
src/mol-theme/color.ts

@@ -7,6 +7,7 @@
 import { Color } from 'mol-util/color';
 import { Location } from 'mol-model/location';
 import { ColorType } from 'mol-geo/geometry/color-data';
+import { AccessibleSurfaceAreaColorThemeProvider } from './color/accessible-surface-area'
 import { CarbohydrateSymbolColorThemeProvider } from './color/carbohydrate-symbol';
 import { UniformColorThemeProvider } from './color/uniform';
 import { deepEqual } from 'mol-util';
@@ -62,6 +63,7 @@ namespace ColorTheme {
 }
 
 export const BuiltInColorThemes = {
+    'accessible-surface-area': AccessibleSurfaceAreaColorThemeProvider,
     'carbohydrate-symbol': CarbohydrateSymbolColorThemeProvider,
     'chain-id': ChainIdColorThemeProvider,
     'cross-link': CrossLinkColorThemeProvider,

+ 52 - 0
src/mol-theme/color/accessible-surface-area.ts

@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Color } from 'mol-util/color';
+import { Location } from 'mol-model/location';
+import { ColorTheme } from '../color';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from '../theme';
+import { ColorListOptions, ColorListName, ColorScale } from 'mol-util/color/scale';
+
+// const DefaultAccessibleSurfaceAreaColor = Color(0xCCCCCC)
+const Description = 'Assigns a color based on the relative accessible surface area of a residue.'
+
+export const AccessibleSurfaceAreaColorThemeParams = {
+    list: PD.ColorScale<ColorListName>('Rainbow', ColorListOptions),
+}
+export type AccessibleSurfaceAreaColorThemeParams = typeof AccessibleSurfaceAreaColorThemeParams
+export function getAccessibleSurfaceAreaColorThemeParams(ctx: ThemeDataContext) {
+    return AccessibleSurfaceAreaColorThemeParams // TODO return copy
+}
+
+export function AccessibleSurfaceAreaColorTheme(ctx: ThemeDataContext, props: PD.Values<AccessibleSurfaceAreaColorThemeParams>): ColorTheme<AccessibleSurfaceAreaColorThemeParams> {
+    const scale = ColorScale.create({
+        listOrName: props.list,
+        minLabel: 'Start',
+        maxLabel: 'End',
+    })
+    const color = (location: Location): Color => {
+        return scale.color(Math.random())
+        // TODO impl
+    }
+
+    return {
+        factory: AccessibleSurfaceAreaColorTheme,
+        granularity: 'group',
+        color,
+        props,
+        description: Description,
+        legend: scale ? scale.legend : undefined
+    }
+}
+
+export const AccessibleSurfaceAreaColorThemeProvider: ColorTheme.Provider<AccessibleSurfaceAreaColorThemeParams> = {
+    label: 'Accessible Surface Area',
+    factory: AccessibleSurfaceAreaColorTheme,
+    getParams: getAccessibleSurfaceAreaColorThemeParams,
+    defaultValues: PD.getDefaultValues(AccessibleSurfaceAreaColorThemeParams),
+    isApplicable: (ctx: ThemeDataContext) => !!ctx.structure
+}

+ 8 - 8
src/tests/browser/render-structure.ts

@@ -12,7 +12,7 @@ import { ColorTheme } from 'mol-theme/color';
 import { SizeTheme } from 'mol-theme/size';
 import { CartoonRepresentationProvider } from 'mol-repr/structure/representation/cartoon';
 import { trajectoryFromMmCIF } from 'mol-model-formats/structure/mmcif';
-import { computeModelDSSP } from 'mol-model/structure/model/properties/utils/secondary-structure';
+import { computeModelASA } from 'mol-model/structure/model/properties/utils/accessible-surface-area';
 
 const parent = document.getElementById('app')!
 parent.style.width = '100%'
@@ -62,21 +62,21 @@ function getCartoonRepr() {
 }
 
 async function init() {
-    const cif = await downloadFromPdb('3j3q')
+    const cif = await downloadFromPdb('1acj')
     const models = await getModels(cif)
-    console.time('computeModelDSSP')
-    const secondaryStructure = computeModelDSSP(models[0].atomicHierarchy, models[0].atomicConformation)
-    console.timeEnd('computeModelDSSP')
-    ;(models[0].properties as any).secondaryStructure = secondaryStructure
+    console.time('computeModelASA')
+    const asa = computeModelASA(models[0].atomicHierarchy, models[0].atomicConformation)
+    console.timeEnd('computeModelASA');
+    (models[0].properties as any).asa = asa
     const structure = await getStructure(models[0])
     const cartoonRepr = getCartoonRepr()
 
     cartoonRepr.setTheme({
-        color: reprCtx.colorThemeRegistry.create('secondary-structure', { structure }),
+        color: reprCtx.colorThemeRegistry.create('accessible-surface-area', { structure }),
         size: reprCtx.sizeThemeRegistry.create('uniform', { structure })
     })
     await cartoonRepr.createOrUpdate({ ...CartoonRepresentationProvider.defaultValues, quality: 'auto' }, structure).run()
-    
+
     canvas3d.add(cartoonRepr)
     canvas3d.resetCamera()
 }