Browse Source

tweaks to represent ihm models

Alexander Rose 7 years ago
parent
commit
166edc61d9

+ 15 - 92
src/apps/render-test/state.ts

@@ -17,10 +17,10 @@ import Spacefill, { SpacefillProps } from 'mol-geo/representation/structure/spac
 import Point, { PointProps } from 'mol-geo/representation/structure/point'
 
 import { Run } from 'mol-task'
-import { Symmetry, Structure } from 'mol-model/structure'
+import { Symmetry, Structure, Model } from 'mol-model/structure'
 
 // import mcubes from './utils/mcubes'
-import { getStructuresFromPdbId, getStructuresFromFile, log } from './utils'
+import { getModelFromPdbId, getModelFromFile, log } from './utils'
 import { StructureRepresentation } from 'mol-geo/representation/structure';
 import { Color } from 'mol-util/color';
 // import Cylinder from 'mol-geo/primitive/cylinder';
@@ -87,18 +87,24 @@ export default class State {
         this.viewer.animate()
     }
 
-    async initStructure (structure: Structure) {
+    async initStructure (model: Model) {
         const { viewer, loading } = this
         viewer.clear()
 
-        const struct = await Run(Symmetry.buildAssembly(structure, '1'), log, 100)
+        let structure: Structure
+        const assemblies = model.symmetry.assemblies
+        if (assemblies.length) {
+            structure = await Run(Symmetry.buildAssembly(Structure.ofModel(model), '1'), log, 100)
+        } else {
+            structure = Structure.ofModel(model)
+        }
 
         this.pointRepr = StructureRepresentation(Point)
-        await Run(this.pointRepr.create(struct, this.getPointProps()), log, 100)
+        await Run(this.pointRepr.create(structure, this.getPointProps()), log, 100)
         viewer.add(this.pointRepr)
 
         this.spacefillRepr = StructureRepresentation(Spacefill)
-        await Run(this.spacefillRepr.create(struct, this.getSpacefillProps()), log, 100)
+        await Run(this.spacefillRepr.create(structure, this.getSpacefillProps()), log, 100)
         viewer.add(this.spacefillRepr)
 
         this.updateVisibility()
@@ -112,7 +118,7 @@ export default class State {
         this.viewer.clear()
         this.loading.next(true)
 
-        const structures = await getStructuresFromFile(file)
+        const structures = await getModelFromFile(file)
         this.initStructure(structures[0])
     }
 
@@ -121,7 +127,7 @@ export default class State {
         if (this.pdbId.length !== 4) return
         this.loading.next(true)
 
-        const structures = await getStructuresFromPdbId(this.pdbId)
+        const structures = await getModelFromPdbId(this.pdbId)
         this.initStructure(structures[0])
     }
 
@@ -154,87 +160,4 @@ export default class State {
         }
         this.viewer.requestDraw()
     }
-}
-
-
-
-// async foo () {
-//     const p1 = Vec3.create(0, 4, 0)
-//     const p2 = Vec3.create(-3, 0, 0)
-
-//     // const position = ValueCell.create(new Float32Array([0, -1, 0, -1, 0, 0, 1, 1, 0]))
-//     // const normal = ValueCell.create(new Float32Array([0, 0, 0, 0, 0, 0, 0, 0, 0]))
-
-//     const transformArray1 = ValueCell.create(new Float32Array(16))
-//     const transformArray2 = ValueCell.create(new Float32Array(16 * 3))
-//     const m4 = Mat4.identity()
-//     Mat4.toArray(m4, transformArray1.ref.value, 0)
-//     Mat4.toArray(m4, transformArray2.ref.value, 0)
-//     Mat4.setTranslation(m4, p1)
-//     Mat4.toArray(m4, transformArray2.ref.value, 16)
-//     Mat4.setTranslation(m4, p2)
-//     Mat4.toArray(m4, transformArray2.ref.value, 32)
-
-//     const color = ValueCell.create(createColorTexture(3))
-//     color.ref.value.set([
-//         0, 0, 255,
-//         0, 255, 0,
-//         255, 0, 0
-//     ])
-
-//     // const points = createRenderObject('point', {
-//     //     position,
-//     //     transform: transformArray1
-//     // })
-//     // // renderer.add(points)
-
-//     // const mesh = createRenderObject('mesh', {
-//     //     position,
-//     //     normal,
-//     //     color,
-//     //     transform: transformArray2
-//     // })
-//     // renderer.add(mesh)
-
-//     // const cylinder = Cylinder({ height: 3, radiusBottom: 0.5, radiusTop: 0.5 })
-//     // console.log(cylinder)
-//     // const cylinderMesh = createRenderObject('mesh', {
-//     //     position: ValueCell.create(cylinder.vertices),
-//     //     normal: ValueCell.create(cylinder.normals),
-//     //     color,
-//     //     transform: transformArray2
-//     // }, cylinder.indices)
-//     // renderer.add(cylinderMesh)
-
-//     // const sphere = Icosahedron()
-//     // console.log(sphere)
-
-//     // const box = Box()
-//     // console.log(box)
-
-//     // const points2 = createRenderObject('point', {
-//     //     position: ValueCell.create(new Float32Array(box.vertices)),
-//     //     transform: transformArray1
-//     // })
-//     // renderer.add(points2)
-
-//     // let rr = 0.7;
-//     // function cubesF(x: number, y: number, z: number) {
-//     //     return x * x + y * y + z * z - rr * rr;
-//     // }
-//     // let cubes = await mcubes(cubesF);
-
-//     // const makeCubesMesh = () => createRenderObject('mesh', {
-//     //     position: cubes.surface.vertexBuffer,
-//     //     normal: cubes.surface.normalBuffer,
-//     //     color,
-//     //     transform: transformArray2,
-//     //     elements: cubes.surface.indexBuffer,
-
-//     //     instanceCount: transformArray2.ref.value.length / 16,
-//     //     elementCount: cubes.surface.triangleCount,
-//     //     positionCount: cubes.surface.vertexCount
-//     // }, {});
-//     // const mesh2 = makeCubesMesh();
-//     // renderer.add(mesh2)
-// }
+}

+ 5 - 5
src/apps/render-test/utils/index.ts

@@ -6,7 +6,7 @@
 
 import CIF from 'mol-io/reader/cif'
 import { Run, Progress } from 'mol-task'
-import { Structure } from 'mol-model/structure'
+import { Model } from 'mol-model/structure'
 
 export function log(progress: Progress) {
     const p = progress.root.progress
@@ -20,10 +20,10 @@ export async function parseCif(data: string|Uint8Array) {
     return parsed
 }
 
-export async function getStructuresFromPdbId(pdbid: string) {
+export async function getModelFromPdbId(pdbid: string) {
     const data = await fetch(`https://files.rcsb.org/download/${pdbid}.cif`)
     const parsed = await parseCif(await data.text())
-    return Structure.ofData({ kind: 'mmCIF', data: CIF.schema.mmCIF(parsed.result.blocks[0]) })
+    return Model.create({ kind: 'mmCIF', data: CIF.schema.mmCIF(parsed.result.blocks[0]) })
 }
 
 const readFileAsText = (file: File) => {
@@ -38,7 +38,7 @@ const readFileAsText = (file: File) => {
     })
 }
 
-export async function getStructuresFromFile(file: File) {
+export async function getModelFromFile(file: File) {
     const parsed = await parseCif(await readFileAsText(file))
-    return Structure.ofData({ kind: 'mmCIF', data: CIF.schema.mmCIF(parsed.result.blocks[0]) })
+    return Model.create({ kind: 'mmCIF', data: CIF.schema.mmCIF(parsed.result.blocks[0]) })
 }

+ 48 - 8
src/mol-geo/representation/structure/spacefill.ts

@@ -18,6 +18,7 @@ import { VdwRadius } from 'mol-model/structure/model/properties/atomic';
 import { createTransforms, createColors } from './utils';
 import { ColorTheme } from '../../theme';
 import VertexMap from '../../shape/vertex-map';
+import CoarseGrained from 'mol-model/structure/model/properties/coarse-grained';
 
 export const DefaultSpacefillProps = {
     detail: 0,
@@ -25,9 +26,9 @@ export const DefaultSpacefillProps = {
 }
 export type SpacefillProps = Partial<typeof DefaultSpacefillProps>
 
-function createSpacefillMesh(unit: Unit, elementGroup: ElementGroup, detail: number) {
-    return Task.create('Spacefill', async ctx => {
-        const meshBuilder = MeshBuilder.create()
+function buildAtomSpheres(meshBuilder: MeshBuilder, unit: Unit, elementGroup: ElementGroup, detail: number) {
+    return Task.create('Atom spheres', async ctx => {
+        if (!Unit.isAtomic(unit)) return
 
         const v = Vec3.zero()
         const m = Mat4.identity()
@@ -43,15 +44,54 @@ function createSpacefillMesh(unit: Unit, elementGroup: ElementGroup, detail: num
             Mat4.setTranslation(m, v)
 
             meshBuilder.setId(i)
-            meshBuilder.addIcosahedron(m, {
-                radius: VdwRadius(type_symbol.value(e)),
-                detail
-            })
+            meshBuilder.addIcosahedron(m, { radius: VdwRadius(type_symbol.value(e)), detail })
+
+            if (i % 10000 === 0 && ctx.shouldUpdate) {
+                await ctx.update({ message: 'Atom spheres', current: i, max: elementCount });
+            }
+        }
+    })
+}
+
+function buildCoarseSpheres(meshBuilder: MeshBuilder, unit: Unit, elementGroup: ElementGroup, detail: number) {
+    return Task.create('Coarse spheres', async ctx => {
+        if (!Unit.isCoarse(unit) || unit.elementType !== CoarseGrained.ElementType.Sphere) return
+
+        const v = Vec3.zero()
+        const m = Mat4.identity()
+
+        const { x, y, z, radius } = unit.model.coarseGrained.spheres
+        const elementCount = OrderedSet.size(elementGroup.elements)
+        console.log('building coarse spheres', elementCount)
+        for (let i = 0; i < elementCount; i++) {
+            const e = OrderedSet.getAt(elementGroup.elements, i)
+            v[0] = x[e]
+            v[1] = y[e]
+            v[2] = z[e]
+            Mat4.setTranslation(m, v)
+
+            meshBuilder.setId(i)
+            meshBuilder.addIcosahedron(m, { radius: radius.value(e), detail })
 
             if (i % 10000 === 0 && ctx.shouldUpdate) {
-                await ctx.update({ message: 'Spacefill', current: i, max: elementCount });
+                await ctx.update({ message: 'Coarse spheres', current: i, max: elementCount });
             }
         }
+    })
+}
+
+function createSpacefillMesh(unit: Unit, elementGroup: ElementGroup, detail: number) {
+    return Task.create('Spacefill', async ctx => {
+        const meshBuilder = MeshBuilder.create()
+
+        if (Unit.isAtomic(unit)) {
+            await ctx.runChild(buildAtomSpheres(meshBuilder, unit, elementGroup, detail))
+        }
+
+        if (Unit.isCoarse(unit) && unit.elementType === CoarseGrained.ElementType.Sphere) {
+            console.log('building coarse spheres')
+            await ctx.runChild(buildCoarseSpheres(meshBuilder, unit, elementGroup, detail))
+        }
 
         return meshBuilder.getMesh()
     })

+ 2 - 2
src/mol-geo/representation/structure/utils.ts

@@ -12,7 +12,7 @@ import { createUniformSize } from '../../util/size-data';
 import { vdwSizeData } from '../../theme/structure/size/vdw';
 import VertexMap from '../../shape/vertex-map';
 import { ColorTheme, SizeTheme } from '../../theme';
-import { atomIndexColorData, elementSymbolColorData, instanceIndexColorData, chainIdColorData } from '../../theme/structure/color';
+import { elementIndexColorData, elementSymbolColorData, instanceIndexColorData, chainIdColorData } from '../../theme/structure/color';
 
 export function createTransforms(units: ReadonlyArray<Unit>) {
     const unitCount = units.length
@@ -26,7 +26,7 @@ export function createTransforms(units: ReadonlyArray<Unit>) {
 export function createColors(units: ReadonlyArray<Unit>, elementGroup: ElementGroup, vertexMap: VertexMap, props: ColorTheme) {
     switch (props.name) {
         case 'atom-index':
-            return atomIndexColorData({ units, elementGroup, vertexMap })
+            return elementIndexColorData({ units, elementGroup, vertexMap })
         case 'chain-id':
             return chainIdColorData({ units, elementGroup, vertexMap })
         case 'element-symbol':

+ 31 - 15
src/mol-geo/theme/structure/color/chain-id.ts

@@ -4,21 +4,32 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { ElementGroup, Model } from 'mol-model/structure';
+import { ElementGroup, Unit, Queries, Element } from 'mol-model/structure';
 
 import { StructureColorDataProps } from '.';
 import { createAttributeOrElementColor } from '../../../util/color-data';
 import { ColorScale } from 'mol-util/color';
+import { Column } from 'mol-data/db';
 
-function createChainIdMap(model: Model) {
-    const { chains } = model.hierarchy
-    const { label_asym_id } = chains
-
+function createChainIdMap(unit: Unit) {
     const map = new Map<string, number>()
     let index = 0
 
-    for (let i = 0, il = chains._rowCount; i < il; ++i) {
-        const chainId = label_asym_id.value(i)
+    let count: number
+    let asym_id: Column<string>
+    if (Unit.isAtomic(unit)) {
+        asym_id = unit.hierarchy.chains.label_asym_id
+        count = unit.hierarchy.chains._rowCount
+    } else if (Unit.isCoarse(unit)) {
+        asym_id = unit.siteBases.asym_id
+        count = unit.siteBases.count
+    } else {
+        console.warn('Unknown unit type')
+        return { map, count: index }
+    }
+
+    for (let i = 0; i < count; ++i) {
+        const chainId = asym_id.value(i)
         if (map.get(chainId) === undefined) {
             map.set(chainId, index)
             index += 1
@@ -31,20 +42,25 @@ export function chainIdColorData(props: StructureColorDataProps) {
     const { units, elementGroup, vertexMap } = props
     const unit = units[0]
 
-    const { chains, chainSegments } = unit.model.hierarchy
-    const { label_asym_id } = chains
-    const { map, count } = createChainIdMap(unit.model)
+    const { map, count } = createChainIdMap(unit)
 
     const domain = [ 0, count - 1 ]
     const scale = ColorScale.create({ domain })
 
+    let asym_id: Element.Property<string>
+    if (Unit.isAtomic(unit)) {
+        asym_id = Queries.props.chain.label_asym_id
+    } else if (Unit.isCoarse(unit)) {
+        asym_id = Queries.props.coarse_grained.asym_id
+    }
+
+    const l = Element.Location()
+    l.unit = unit
+
     return createAttributeOrElementColor(vertexMap, {
         colorFn: (elementIdx: number) => {
-            const aI = ElementGroup.getAt(elementGroup, elementIdx);
-            const cI = chainSegments.segmentMap[aI]
-            const chainId = label_asym_id.value(cI)
-
-            return scale.color(map.get(chainId) || 0)
+            l.element = ElementGroup.getAt(elementGroup, elementIdx)
+            return scale.color(map.get(asym_id(l)) || 0)
         },
         vertexMap
     })

+ 1 - 1
src/mol-geo/theme/structure/color/atom-index.ts → src/mol-geo/theme/structure/color/element-index.ts

@@ -9,7 +9,7 @@ import { StructureColorDataProps } from '.';
 import { OrderedSet } from 'mol-data/int';
 import { createElementInstanceColor } from '../../../util/color-data';
 
-export function atomIndexColorData(props: StructureColorDataProps) {
+export function elementIndexColorData(props: StructureColorDataProps) {
     const { units, elementGroup, vertexMap } = props
     const instanceCount = units.length
     const elementCount = OrderedSet.size(elementGroup.elements)

+ 1 - 1
src/mol-geo/theme/structure/color/index.ts

@@ -13,7 +13,7 @@ export interface StructureColorDataProps {
     vertexMap: VertexMap
 }
 
-export { atomIndexColorData } from './atom-index'
+export { elementIndexColorData } from './element-index'
 export { chainIdColorData } from './chain-id'
 export { elementSymbolColorData } from './element-symbol'
 export { instanceIndexColorData } from './instance-index'

+ 1 - 1
src/mol-view/viewer.ts

@@ -55,7 +55,7 @@ namespace Viewer {
         input.resize.subscribe(handleResize)
 
         const camera = PerspectiveCamera.create({
-            near: 0.01,
+            near: 0.1,
             far: 10000,
             position: Vec3.create(0, 0, 50)
         })