Skip to content
Snippets Groups Projects
Commit ee886244 authored by JonStargaryen's avatar JonStargaryen
Browse files

begin separating calc and representation

parent f2557fe8
No related branches found
No related tags found
No related merge requests found
...@@ -10,8 +10,9 @@ import { Structure } from '../../mol-model/structure'; ...@@ -10,8 +10,9 @@ import { Structure } from '../../mol-model/structure';
import { CustomStructureProperty } from '../common/custom-structure-property'; import { CustomStructureProperty } from '../common/custom-structure-property';
import { CustomProperty } from '../common/custom-property'; import { CustomProperty } from '../common/custom-property';
import { CustomPropertyDescriptor } from '../../mol-model/custom-property'; import { CustomPropertyDescriptor } from '../../mol-model/custom-property';
import { ANVILParams, MembraneOrientation, ANVILProps } from './membrane-orientation/ANVIL'; import { ANVILParams, ANVILProps, computeANVIL } from './membrane-orientation/ANVIL';
import { AccessibleSurfaceAreaProvider } from './accessible-surface-area'; import { AccessibleSurfaceAreaProvider } from './accessible-surface-area';
import { MembraneOrientation } from '../../mol-model/structure/model/properties/membrane-orientation';
function getMembraneOrientationParams(data?: Structure) { function getMembraneOrientationParams(data?: Structure) {
let defaultType = 'anvil' as 'anvil' | 'opm'; // TODO flip - OPM should be default if PDB identifier is known let defaultType = 'anvil' as 'anvil' | 'opm'; // TODO flip - OPM should be default if PDB identifier is known
...@@ -49,7 +50,7 @@ export const MembraneOrientationProvider: CustomStructureProperty.Provider<Membr ...@@ -49,7 +50,7 @@ export const MembraneOrientationProvider: CustomStructureProperty.Provider<Membr
async function computeAnvil(ctx: CustomProperty.Context, data: Structure, props: ANVILProps): Promise<MembraneOrientation> { async function computeAnvil(ctx: CustomProperty.Context, data: Structure, props: ANVILProps): Promise<MembraneOrientation> {
await AccessibleSurfaceAreaProvider.attach(ctx, data); await AccessibleSurfaceAreaProvider.attach(ctx, data);
const p = { ...PD.getDefaultValues(MembraneOrientationParams), ...props }; const p = { ...PD.getDefaultValues(MembraneOrientationParams), ...props };
return await MembraneOrientation.compute(data, p).runInContext(ctx.runtime); return await computeANVIL(data, p).runInContext(ctx.runtime);
} }
async function computeOpm(structure: Structure): Promise<MembraneOrientation> { async function computeOpm(structure: Structure): Promise<MembraneOrientation> {
......
...@@ -15,6 +15,7 @@ import { Vec3 } from '../../../mol-math/linear-algebra'; ...@@ -15,6 +15,7 @@ import { Vec3 } from '../../../mol-math/linear-algebra';
import { AccessibleSurfaceArea } from '../accessible-surface-area/shrake-rupley'; import { AccessibleSurfaceArea } from '../accessible-surface-area/shrake-rupley';
import { AccessibleSurfaceAreaProvider } from '../accessible-surface-area'; import { AccessibleSurfaceAreaProvider } from '../accessible-surface-area';
import { ANVILContext } from './anvil/common'; import { ANVILContext } from './anvil/common';
import { MembraneOrientation } from '../../../mol-model/structure/model/properties/membrane-orientation';
export const ANVILParams = { export const ANVILParams = {
numberOfSpherePoints: PD.Numeric(120, { min: 35, max: 700, step: 1 }, { description: 'Number of spheres/directions to test for membrane placement. Original value is 350.' }), numberOfSpherePoints: PD.Numeric(120, { min: 35, max: 700, step: 1 }, { description: 'Number of spheres/directions to test for membrane placement. Original value is 350.' }),
...@@ -27,10 +28,6 @@ export const ANVILParams = { ...@@ -27,10 +28,6 @@ export const ANVILParams = {
export type ANVILParams = typeof ANVILParams export type ANVILParams = typeof ANVILParams
export type ANVILProps = PD.Values<ANVILParams> export type ANVILProps = PD.Values<ANVILParams>
export { MembraneOrientation };
interface MembraneOrientation extends Array<Vec3> {}
namespace MembraneOrientation {
/** /**
* Implements: * Implements:
* Membrane positioning for high- and low-resolution protein structures through a binary classification approach * Membrane positioning for high- and low-resolution protein structures through a binary classification approach
...@@ -38,7 +35,7 @@ namespace MembraneOrientation { ...@@ -38,7 +35,7 @@ namespace MembraneOrientation {
* Protein Engineering, Design & Selection, 2015, 1–5 * Protein Engineering, Design & Selection, 2015, 1–5
* doi: 10.1093/protein/gzv063 * doi: 10.1093/protein/gzv063
*/ */
export function compute(structure: Structure, props: Partial<ANVILProps> = {}) { export function computeANVIL(structure: Structure, props: Partial<ANVILProps> = {}) {
const p = { ...PD.getDefaultValues(ANVILParams), ...props }; const p = { ...PD.getDefaultValues(ANVILParams), ...props };
return Task.create('Compute Membrane Topology', async runtime => { return Task.create('Compute Membrane Topology', async runtime => {
return await calculate(runtime, structure, p); return await calculate(runtime, structure, p);
...@@ -47,7 +44,6 @@ namespace MembraneOrientation { ...@@ -47,7 +44,6 @@ namespace MembraneOrientation {
const l = StructureElement.Location.create(void 0); const l = StructureElement.Location.create(void 0);
const centroidHelper = new CentroidHelper(); const centroidHelper = new CentroidHelper();
const vec = Vec3();
function initialize(structure: Structure, params: ANVILProps): ANVILContext { function initialize(structure: Structure, params: ANVILProps): ANVILContext {
const { label_atom_id, x, y, z } = StructureProperties.atom; const { label_atom_id, x, y, z } = StructureProperties.atom;
const elementCount = structure.polymerResidueCount; const elementCount = structure.polymerResidueCount;
...@@ -57,10 +53,10 @@ namespace MembraneOrientation { ...@@ -57,10 +53,10 @@ namespace MembraneOrientation {
let offsets = new Int32Array(elementCount); let offsets = new Int32Array(elementCount);
let exposed: boolean[] = new Array<boolean>(elementCount); let exposed: boolean[] = new Array<boolean>(elementCount);
// ensure ASA
const accessibleSurfaceArea = structure && AccessibleSurfaceAreaProvider.get(structure); const accessibleSurfaceArea = structure && AccessibleSurfaceAreaProvider.get(structure);
const asa = accessibleSurfaceArea.value!; const asa = accessibleSurfaceArea.value!;
const vec = Vec3();
let m = 0; let m = 0;
for (let i = 0, il = structure.units.length; i < il; ++i) { for (let i = 0, il = structure.units.length; i < il; ++i) {
const unit = structure.units[i]; const unit = structure.units[i];
...@@ -134,47 +130,7 @@ namespace MembraneOrientation { ...@@ -134,47 +130,7 @@ namespace MembraneOrientation {
const membrane = initialMembrane.qmax! > alternativeMembrane.qmax! ? initialMembrane : alternativeMembrane; const membrane = initialMembrane.qmax! > alternativeMembrane.qmax! ? initialMembrane : alternativeMembrane;
return createMembraneLayers(ctx, membrane); return MembraneOrientation(membrane.planePoint1, membrane.planePoint2, membrane.normalVector!, ctx.extent * ctx.extent);
}
function createMembraneLayers(ctx: ANVILContext, membrane: MembraneCandidate): Vec3[] {
const { extent, membranePointDensity } = ctx;
const out: Vec3[] = [];
const radius = extent * extent;
const normalVector = membrane.normalVector!;
createMembraneLayer(ctx, out, membrane.planePoint1, normalVector, membranePointDensity, radius);
createMembraneLayer(ctx, out, membrane.planePoint2, normalVector, membranePointDensity, radius);
return out;
}
function createMembraneLayer(ctx: ANVILContext, out: Vec3[], point: Vec3, normalVector: Vec3, density: number, radius: number) {
const { x, y, z } = StructureProperties.atom;
const { offsets, structure } = ctx;
const test = Vec3();
const d = -Vec3.dot(normalVector, point);
for (let i = -1000, il = 1000; i < il; i += density) {
for (let j = -1000, jl = 1000; j < jl; j += density) {
const rep = Vec3.create(i, j, -(d + i * normalVector[0] + j * normalVector[1]) / normalVector[2]);
if (Vec3.squaredDistance(rep, point) < radius) {
// it has a nice effect to ensure that membrane points don't overlap with structure representation
let valid = true;
for (let k = 0, kl = ctx.offsets.length; k < kl; k++) {
setLocation(l, structure, offsets[k]);
Vec3.set(test, x(l), y(l), z(l));
const dsq = Vec3.squaredDistance(test, rep);
if (dsq < 16) {
valid = false;
}
}
if (valid) {
out.push(rep);
}
}
}
}
} }
interface MembraneCandidate { interface MembraneCandidate {
...@@ -183,7 +139,6 @@ namespace MembraneOrientation { ...@@ -183,7 +139,6 @@ namespace MembraneOrientation {
stats: HphobHphil, stats: HphobHphil,
normalVector?: Vec3, normalVector?: Vec3,
spherePoint?: Vec3, spherePoint?: Vec3,
centroid?: Vec3,
qmax?: number, qmax?: number,
membraneAtoms?: Vec3[] membraneAtoms?: Vec3[]
} }
...@@ -206,7 +161,6 @@ namespace MembraneOrientation { ...@@ -206,7 +161,6 @@ namespace MembraneOrientation {
stats: stats, stats: stats,
normalVector: diam_vect, normalVector: diam_vect,
spherePoint: spherePoint, spherePoint: spherePoint,
centroid: centroid,
qmax: qmax, qmax: qmax,
membraneAtoms: [] membraneAtoms: []
}; };
...@@ -402,4 +356,3 @@ namespace MembraneOrientation { ...@@ -402,4 +356,3 @@ namespace MembraneOrientation {
l.element = structure.serialMapping.elementIndices[serialIndex]; l.element = structure.serialMapping.elementIndices[serialIndex];
return l; return l;
} }
\ No newline at end of file
}
\ No newline at end of file
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
*/
import { Vec3 } from '../../../../mol-math/linear-algebra';
interface MembraneOrientation {
// point in membrane boundary
readonly p1: Vec3,
// point in opposite side of membrane boundary
readonly p2: Vec3,
// normal vector of membrane layer
readonly normal: Vec3,
// the radius of the membrane layer
readonly radius: number
}
function MembraneOrientation(p1: Vec3, p2: Vec3, normal: Vec3, radius: number): MembraneOrientation {
return { p1, p2, normal, radius };
}
export { MembraneOrientation };
\ No newline at end of file
...@@ -31,7 +31,8 @@ import { SpheresBuilder } from '../../mol-geo/geometry/spheres/spheres-builder'; ...@@ -31,7 +31,8 @@ import { SpheresBuilder } from '../../mol-geo/geometry/spheres/spheres-builder';
import { Spheres } from '../../mol-geo/geometry/spheres/spheres'; import { Spheres } from '../../mol-geo/geometry/spheres/spheres';
import { Color } from '../../mol-util/color'; import { Color } from '../../mol-util/color';
import { createRenderObject } from '../../mol-gl/render-object'; import { createRenderObject } from '../../mol-gl/render-object';
import { MembraneOrientation } from '../../mol-model-props/computed/membrane-orientation/ANVIL'; import { MembraneOrientation } from '../../mol-model/structure/model/properties/membrane-orientation';
import { Vec3 } from '../../mol-math/linear-algebra';
const parent = document.getElementById('app')!; const parent = document.getElementById('app')!;
parent.style.width = '100%'; parent.style.width = '100%';
...@@ -122,12 +123,12 @@ function getGaussianSurfaceRepr() { ...@@ -122,12 +123,12 @@ function getGaussianSurfaceRepr() {
return GaussianSurfaceRepresentationProvider.factory(reprCtx, GaussianSurfaceRepresentationProvider.getParams); return GaussianSurfaceRepresentationProvider.factory(reprCtx, GaussianSurfaceRepresentationProvider.getParams);
} }
function getMembraneRepr(membrane: MembraneOrientation) { function getMembraneRepr(structure: Structure, membrane: MembraneOrientation) {
// TODO is a representation provider the right place for this? const density = 1;
const spheresBuilder = SpheresBuilder.create(membrane.length, 1); const radius = membrane.radius;
for (let i = 0, il = membrane.length; i < il; i++) { const spheresBuilder = SpheresBuilder.create();
spheresBuilder.add(membrane[i][0], membrane[i][1], membrane[i][2], 0); createMembraneLayer(spheresBuilder, membrane.p1, membrane.normal, density, radius);
} createMembraneLayer(spheresBuilder, membrane.p2, membrane.normal, density, radius);
const spheres = spheresBuilder.getSpheres(); const spheres = spheresBuilder.getSpheres();
const values = Spheres.Utils.createValuesSimple(spheres, {}, Color(0xCCCCCC), 1); const values = Spheres.Utils.createValuesSimple(spheres, {}, Color(0xCCCCCC), 1);
...@@ -138,6 +139,19 @@ function getMembraneRepr(membrane: MembraneOrientation) { ...@@ -138,6 +139,19 @@ function getMembraneRepr(membrane: MembraneOrientation) {
return repr; return repr;
} }
function createMembraneLayer(spheresBuilder: SpheresBuilder, point: Vec3, normalVector: Vec3, density: number, radius: number) {
const d = -Vec3.dot(normalVector, point);
const rep = Vec3();
for (let i = -1000, il = 1000; i < il; i += density) {
for (let j = -1000, jl = 1000; j < jl; j += density) {
Vec3.set(rep, i, j, -(d + i * normalVector[0] + j * normalVector[1]) / normalVector[2]);
if (Vec3.squaredDistance(rep, point) < radius) {
spheresBuilder.add(rep[0], rep[1], rep[2], 0);
}
}
}
}
async function init() { async function init() {
const ctx = { runtime: SyncRuntimeContext, assetManager: new AssetManager() }; const ctx = { runtime: SyncRuntimeContext, assetManager: new AssetManager() };
...@@ -172,7 +186,7 @@ async function init() { ...@@ -172,7 +186,7 @@ async function init() {
const ballAndStickRepr = getBallAndStickRepr(); const ballAndStickRepr = getBallAndStickRepr();
const molecularSurfaceRepr = getMolecularSurfaceRepr(); const molecularSurfaceRepr = getMolecularSurfaceRepr();
const gaussianSurfaceRepr = getGaussianSurfaceRepr(); const gaussianSurfaceRepr = getGaussianSurfaceRepr();
const membraneRepr = getMembraneRepr(MembraneOrientationProvider.get(structure).value!); const membraneRepr = getMembraneRepr(structure, MembraneOrientationProvider.get(structure).value!);
if (show.cartoon) { if (show.cartoon) {
cartoonRepr.setTheme({ cartoonRepr.setTheme({
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment