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';
import { CustomStructureProperty } from '../common/custom-structure-property';
import { CustomProperty } from '../common/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 { MembraneOrientation } from '../../mol-model/structure/model/properties/membrane-orientation';
function getMembraneOrientationParams(data?: Structure) {
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
async function computeAnvil(ctx: CustomProperty.Context, data: Structure, props: ANVILProps): Promise<MembraneOrientation> {
await AccessibleSurfaceAreaProvider.attach(ctx, data);
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> {
......
......@@ -15,6 +15,7 @@ import { Vec3 } from '../../../mol-math/linear-algebra';
import { AccessibleSurfaceArea } from '../accessible-surface-area/shrake-rupley';
import { AccessibleSurfaceAreaProvider } from '../accessible-surface-area';
import { ANVILContext } from './anvil/common';
import { MembraneOrientation } from '../../../mol-model/structure/model/properties/membrane-orientation';
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.' }),
......@@ -27,10 +28,6 @@ export const ANVILParams = {
export type ANVILParams = typeof ANVILParams
export type ANVILProps = PD.Values<ANVILParams>
export { MembraneOrientation };
interface MembraneOrientation extends Array<Vec3> {}
namespace MembraneOrientation {
/**
* Implements:
* Membrane positioning for high- and low-resolution protein structures through a binary classification approach
......@@ -38,7 +35,7 @@ namespace MembraneOrientation {
* Protein Engineering, Design & Selection, 2015, 1–5
* 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 };
return Task.create('Compute Membrane Topology', async runtime => {
return await calculate(runtime, structure, p);
......@@ -47,7 +44,6 @@ namespace MembraneOrientation {
const l = StructureElement.Location.create(void 0);
const centroidHelper = new CentroidHelper();
const vec = Vec3();
function initialize(structure: Structure, params: ANVILProps): ANVILContext {
const { label_atom_id, x, y, z } = StructureProperties.atom;
const elementCount = structure.polymerResidueCount;
......@@ -57,10 +53,10 @@ namespace MembraneOrientation {
let offsets = new Int32Array(elementCount);
let exposed: boolean[] = new Array<boolean>(elementCount);
// ensure ASA
const accessibleSurfaceArea = structure && AccessibleSurfaceAreaProvider.get(structure);
const asa = accessibleSurfaceArea.value!;
const vec = Vec3();
let m = 0;
for (let i = 0, il = structure.units.length; i < il; ++i) {
const unit = structure.units[i];
......@@ -134,47 +130,7 @@ namespace MembraneOrientation {
const membrane = initialMembrane.qmax! > alternativeMembrane.qmax! ? initialMembrane : alternativeMembrane;
return createMembraneLayers(ctx, membrane);
}
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);
}
}
}
}
return MembraneOrientation(membrane.planePoint1, membrane.planePoint2, membrane.normalVector!, ctx.extent * ctx.extent);
}
interface MembraneCandidate {
......@@ -183,7 +139,6 @@ namespace MembraneOrientation {
stats: HphobHphil,
normalVector?: Vec3,
spherePoint?: Vec3,
centroid?: Vec3,
qmax?: number,
membraneAtoms?: Vec3[]
}
......@@ -206,7 +161,6 @@ namespace MembraneOrientation {
stats: stats,
normalVector: diam_vect,
spherePoint: spherePoint,
centroid: centroid,
qmax: qmax,
membraneAtoms: []
};
......@@ -402,4 +356,3 @@ namespace MembraneOrientation {
l.element = structure.serialMapping.elementIndices[serialIndex];
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';
import { Spheres } from '../../mol-geo/geometry/spheres/spheres';
import { Color } from '../../mol-util/color';
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')!;
parent.style.width = '100%';
......@@ -122,12 +123,12 @@ function getGaussianSurfaceRepr() {
return GaussianSurfaceRepresentationProvider.factory(reprCtx, GaussianSurfaceRepresentationProvider.getParams);
}
function getMembraneRepr(membrane: MembraneOrientation) {
// TODO is a representation provider the right place for this?
const spheresBuilder = SpheresBuilder.create(membrane.length, 1);
for (let i = 0, il = membrane.length; i < il; i++) {
spheresBuilder.add(membrane[i][0], membrane[i][1], membrane[i][2], 0);
}
function getMembraneRepr(structure: Structure, membrane: MembraneOrientation) {
const density = 1;
const radius = membrane.radius;
const spheresBuilder = SpheresBuilder.create();
createMembraneLayer(spheresBuilder, membrane.p1, membrane.normal, density, radius);
createMembraneLayer(spheresBuilder, membrane.p2, membrane.normal, density, radius);
const spheres = spheresBuilder.getSpheres();
const values = Spheres.Utils.createValuesSimple(spheres, {}, Color(0xCCCCCC), 1);
......@@ -138,6 +139,19 @@ function getMembraneRepr(membrane: MembraneOrientation) {
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() {
const ctx = { runtime: SyncRuntimeContext, assetManager: new AssetManager() };
......@@ -172,7 +186,7 @@ async function init() {
const ballAndStickRepr = getBallAndStickRepr();
const molecularSurfaceRepr = getMolecularSurfaceRepr();
const gaussianSurfaceRepr = getGaussianSurfaceRepr();
const membraneRepr = getMembraneRepr(MembraneOrientationProvider.get(structure).value!);
const membraneRepr = getMembraneRepr(structure, MembraneOrientationProvider.get(structure).value!);
if (show.cartoon) {
cartoonRepr.setTheme({
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment