Skip to content
Snippets Groups Projects
Commit 65ed5c98 authored by David Sehnal's avatar David Sehnal
Browse files

mol-plugin: refactor StructureFromModel

parent f0ecf74a
Branches
No related tags found
No related merge requests found
......@@ -29,7 +29,7 @@ export namespace StateHelper {
}
export function structure(b: StateBuilder.To<PSO.Molecule.Model>) {
return b.apply(StateTransforms.Model.StructureFromModel, { tags: 'structure' })
return b.apply(StateTransforms.Model.StructureFromModel, void 0, { tags: 'structure' })
};
export function selectChain(b: StateBuilder.To<PSO.Molecule.Structure>, auth_asym_id: string) {
......
......@@ -59,7 +59,7 @@ function createTemplate(plugin: PluginContext, state: State, id: string) {
const b = new StateBuilder.Root(state.tree);
const data = b.toRoot().apply(StateTransforms.Data.Download, { url: `https://www.ebi.ac.uk/pdbe/static/entry/${id}_updated.cif` }, { state: { isGhost: true }});
const model = createModelTree(data, 'cif');
const structure = model.apply(StateTransforms.Model.StructureFromModel, {});
const structure = model.apply(StateTransforms.Model.StructureFromModel);
complexRepresentation(plugin, structure, { hideWater: true });
return { tree: b.getTree(), structure: structure.ref };
}
......
......@@ -40,9 +40,6 @@ export const DefaultPluginSpec: PluginSpec = {
PluginSpec.Action(StateTransforms.Model.TrajectoryFromMmCif),
PluginSpec.Action(StateTransforms.Model.TrajectoryFromPDB),
PluginSpec.Action(StateTransforms.Model.StructureAssemblyFromModel),
PluginSpec.Action(StateTransforms.Model.StructureSymmetryFromModel),
PluginSpec.Action(StateTransforms.Model.StructureSymmetryMatesFromModel),
PluginSpec.Action(TransformStructureConformation),
PluginSpec.Action(StateTransforms.Model.StructureFromModel),
PluginSpec.Action(StateTransforms.Model.StructureFromTrajectory),
......
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Model, Structure, StructureSymmetry } from '../../../mol-model/structure';
import { stringToWords } from '../../../mol-util/string';
import { SpacegroupCell } from '../../../mol-math/geometry';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { Vec3 } from '../../../mol-math/linear-algebra';
import { ensureSecondaryStructure } from '../transforms/helpers';
import { RuntimeContext } from '../../../mol-task';
import { PluginContext } from '../../context';
import { Assembly, ModelSymmetry } from '../../../mol-model/structure/model/properties/symmetry';
import { PluginStateObject as SO } from '../objects';
export namespace ModelStructureRepresentation {
export function getParams(model?: Model, defaultValue?: 'deposited' | 'assembly' | 'symmetry' | 'symmetry-mates') {
const assemblyIds = model ? model.symmetry.assemblies.map(a => [a.id, `${a.id}: ${stringToWords(a.details)}`] as [string, string]) : [];
const showSymm = !model ? true : !SpacegroupCell.isZero(model.symmetry.spacegroup.cell);
const modes = {
deposited: PD.EmptyGroup(),
assembly: PD.Group({
id: PD.Optional(model
? PD.Select(assemblyIds[0][0], assemblyIds, { label: 'Asm Id', description: 'Assembly Id' })
: PD.Text('', { label: 'Asm Id', description: 'Assembly Id (use empty for the 1st assembly)' }))
}, { isFlat: true }),
'symmetry-mates': PD.Group({
radius: PD.Numeric(5)
}, { isFlat: true }),
'symmetry': PD.Group({
ijkMin: PD.Vec3(Vec3.create(-1, -1, -1), { label: 'Min IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } }),
ijkMax: PD.Vec3(Vec3.create(1, 1, 1), { label: 'Max IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } })
}, { isFlat: true })
};
const options: [keyof typeof modes, string][] = [
['deposited', 'Deposited']
];
if (assemblyIds) {
options.push(['assembly', 'Assembly']);
}
if (showSymm) {
options.push(['symmetry-mates', 'Symmetry Mates']);
options.push(['symmetry', 'Symmetry (indices)']);
}
return {
kind: PD.MappedStatic(defaultValue || 'deposited', modes, { options })
};
}
export type Params = PD.Values<ReturnType<typeof getParams>>
async function buildAssembly(plugin: PluginContext, ctx: RuntimeContext, model: Model, id?: string) {
let asm: Assembly | undefined = void 0;
// if no id is specified, use the 1st assembly.
if (!id && model.symmetry.assemblies.length !== 0) {
id = model.symmetry.assemblies[0].id;
}
if (model.symmetry.assemblies.length === 0) {
if (id !== 'deposited') {
plugin.log.warn(`Model '${model.entryId}' has no assembly, returning deposited structure.`);
}
} else {
asm = ModelSymmetry.findAssembly(model, id || '');
if (!asm) {
plugin.log.warn(`Model '${model.entryId}' has no assembly called '${id}', returning deposited structure.`);
}
}
const base = Structure.ofModel(model);
if (!asm) {
await ensureSecondaryStructure(base)
const label = { label: 'Deposited', description: Structure.elementDescription(base) };
return new SO.Molecule.Structure(base, label);
}
id = asm.id;
const s = await StructureSymmetry.buildAssembly(base, id!).runInContext(ctx);
await ensureSecondaryStructure(s)
const props = { label: `Assembly ${id}`, description: Structure.elementDescription(s) };
return new SO.Molecule.Structure(s, props);
}
async function buildSymmetry(ctx: RuntimeContext, model: Model, ijkMin: Vec3, ijkMax: Vec3) {
const base = Structure.ofModel(model);
const s = await StructureSymmetry.buildSymmetryRange(base, ijkMin, ijkMax).runInContext(ctx);
await ensureSecondaryStructure(s)
const props = { label: `Symmetry [${ijkMin}] to [${ijkMax}]`, description: Structure.elementDescription(s) };
return new SO.Molecule.Structure(s, props);
}
async function buildSymmetryMates(ctx: RuntimeContext, model: Model, radius: number) {
const base = Structure.ofModel(model);
const s = await StructureSymmetry.builderSymmetryMates(base, radius).runInContext(ctx);
await ensureSecondaryStructure(s)
const props = { label: `Symmetry Mates`, description: Structure.elementDescription(s) };
return new SO.Molecule.Structure(s, props);
}
export async function create(plugin: PluginContext, ctx: RuntimeContext, model: Model, params?: Params): Promise<SO.Molecule.Structure> {
if (!params || !params.kind || params.kind.name === 'deposited') {
const s = Structure.ofModel(model);
await ensureSecondaryStructure(s);
return new SO.Molecule.Structure(s, { label: 'Deposited', description: Structure.elementDescription(s) });
}
if (params.kind.name === 'assembly') {
return buildAssembly(plugin, ctx, model, params.kind.params.id)
}
if (params.kind.name === 'symmetry') {
return buildSymmetry(ctx, model, params.kind.params.ijkMin, params.kind.params.ijkMax)
}
if (params.kind.name === 'symmetry-mates') {
return buildSymmetryMates(ctx, model, params.kind.params.radius)
}
throw new Error(`Unknown represetation type: ${(params.kind as any).name}`);
}
}
\ No newline at end of file
......@@ -23,12 +23,12 @@ import { trajectoryFromGRO } from '../../../mol-model-formats/structure/gro';
import { parseGRO } from '../../../mol-io/reader/gro/parser';
import { shapeFromPly } from '../../../mol-model-formats/shape/ply';
import { SymmetryOperator } from '../../../mol-math/geometry';
import { ensureSecondaryStructure } from './helpers';
import { Script } from '../../../mol-script/script';
import { parse3DG } from '../../../mol-io/reader/3dg/parser';
import { trajectoryFrom3DG } from '../../../mol-model-formats/structure/3dg';
import { StructureSelectionQueries } from '../../util/structure-selection-helper';
import { StructureQueryHelper } from '../../util/structure-query';
import { ModelStructureRepresentation } from '../representation/model';
export { TrajectoryFromBlob };
export { TrajectoryFromMmCif };
......@@ -39,8 +39,6 @@ export { ModelFromTrajectory };
export { StructureFromTrajectory };
export { StructureFromModel };
export { StructureAssemblyFromModel };
export { StructureSymmetryFromModel };
export { StructureSymmetryMatesFromModel };
export { TransformStructureConformation };
export { TransformStructureConformationByMatrix };
export { StructureSelectionFromExpression };
......@@ -204,20 +202,19 @@ const StructureFromTrajectory = PluginStateTransform.BuiltIn({
type StructureFromModel = typeof StructureFromModel
const StructureFromModel = PluginStateTransform.BuiltIn({
name: 'structure-from-model',
display: { name: 'Structure from Model', description: 'Create a molecular structure from the specified model.' },
display: { name: 'Structure', description: 'Create a molecular structure (deposited, assembly, or symmetry) from the specified model.' },
from: SO.Molecule.Model,
to: SO.Molecule.Structure
to: SO.Molecule.Structure,
params(a) { return ModelStructureRepresentation.getParams(a && a.data); }
})({
apply({ a }) {
apply({ a, params }, plugin: PluginContext) {
return Task.create('Build Structure', async ctx => {
const s = Structure.ofModel(a.data);
await ensureSecondaryStructure(s)
const props = { label: 'Deposited', description: Structure.elementDescription(s) };
return new SO.Molecule.Structure(s, props);
return ModelStructureRepresentation.create(plugin, ctx, a.data, params);
})
}
});
// TODO: deprecate this in favor of StructureFromModel
type StructureAssemblyFromModel = typeof StructureAssemblyFromModel
const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({
name: 'structure-assembly-from-model',
......@@ -232,94 +229,13 @@ const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({
const ids = model.symmetry.assemblies.map(a => [a.id, `${a.id}: ${stringToWords(a.details)}`] as [string, string]);
ids.push(['deposited', 'Deposited']);
return {
id: PD.Optional(PD.Select(ids[0][0], ids, { label: 'Asm Id', description: 'Assembly Id' })) };
id: PD.Optional(PD.Select(ids[0][0], ids, { label: 'Asm Id', description: 'Assembly Id' }))
};
}
})({
apply({ a, params }, plugin: PluginContext) {
return Task.create('Build Assembly', async ctx => {
const model = a.data;
let id = params.id;
let asm: Assembly | undefined = void 0;
// if no id is specified, use the 1st assembly.
if (!id && model.symmetry.assemblies.length !== 0) {
id = model.symmetry.assemblies[0].id;
}
if (model.symmetry.assemblies.length === 0) {
if (id !== 'deposited') {
plugin.log.warn(`Model '${a.data.entryId}' has no assembly, returning deposited structure.`);
}
} else {
asm = ModelSymmetry.findAssembly(model, id || '');
if (!asm) {
plugin.log.warn(`Model '${a.data.entryId}' has no assembly called '${id}', returning deposited structure.`);
}
}
const base = Structure.ofModel(model);
if (!asm) {
await ensureSecondaryStructure(base)
const label = { label: 'Deposited', description: Structure.elementDescription(base) };
return new SO.Molecule.Structure(base, label);
}
id = asm.id;
const s = await StructureSymmetry.buildAssembly(base, id!).runInContext(ctx);
await ensureSecondaryStructure(s)
const props = { label: `Assembly ${id}`, description: Structure.elementDescription(s) };
return new SO.Molecule.Structure(s, props);
})
}
});
type StructureSymmetryFromModel = typeof StructureSymmetryFromModel
const StructureSymmetryFromModel = PluginStateTransform.BuiltIn({
name: 'structure-symmetry-from-model',
display: { name: 'Structure Symmetry', description: 'Create a molecular structure symmetry.' },
from: SO.Molecule.Model,
to: SO.Molecule.Structure,
params(a) {
return {
ijkMin: PD.Vec3(Vec3.create(-1, -1, -1), { label: 'Min IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } }),
ijkMax: PD.Vec3(Vec3.create(1, 1, 1), { label: 'Max IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } })
}
}
})({
apply({ a, params }, plugin: PluginContext) {
return Task.create('Build Symmetry', async ctx => {
const { ijkMin, ijkMax } = params
const model = a.data;
const base = Structure.ofModel(model);
const s = await StructureSymmetry.buildSymmetryRange(base, ijkMin, ijkMax).runInContext(ctx);
await ensureSecondaryStructure(s)
const props = { label: `Symmetry [${ijkMin}] to [${ijkMax}]`, description: Structure.elementDescription(s) };
return new SO.Molecule.Structure(s, props);
})
}
});
type StructureSymmetryMatesFromModel = typeof StructureSymmetryMatesFromModel
const StructureSymmetryMatesFromModel = PluginStateTransform.BuiltIn({
name: 'structure-symmetry-mates-from-model',
display: { name: 'Structure Symmetry Mates', description: 'Create molecular structure symmetry mates.' },
from: SO.Molecule.Model,
to: SO.Molecule.Structure,
params(a) {
return {
radius: PD.Numeric(5),
}
}
})({
apply({ a, params }, plugin: PluginContext) {
return Task.create('Build Symmetry Mates', async ctx => {
const { radius } = params
const model = a.data;
const base = Structure.ofModel(model);
const s = await StructureSymmetry.builderSymmetryMates(base, radius).runInContext(ctx);
await ensureSecondaryStructure(s)
const props = { label: `Symmetry Mates`, description: Structure.elementDescription(s) };
return new SO.Molecule.Structure(s, props);
return ModelStructureRepresentation.create(plugin, ctx, a.data, { kind: { name: 'assembly', params } });
})
}
});
......@@ -703,7 +619,7 @@ const StructureComplexElement = PluginStateTransform.BuiltIn({
type CustomModelProperties = typeof CustomModelProperties
const CustomModelProperties = PluginStateTransform.BuiltIn({
name: 'custom-model-properties',
display: { name: 'Custom Model Properties' },
display: { name: 'Custom Properties' },
from: SO.Molecule.Model,
to: SO.Molecule.Model,
params: (a, ctx: PluginContext) => {
......
......@@ -179,6 +179,9 @@ export namespace ParamDefinition {
if (info && info.isFlat) ret.isFlat = info.isFlat;
return ret;
}
export function EmptyGroup(info?: Info) {
return Group({}, info);
}
export interface NamedParams<T = any, K = string> { name: K, params: T }
export type NamedParamUnion<P extends Params, K extends keyof P = keyof P> = K extends any ? NamedParams<P[K]['defaultValue'], K> : never
......@@ -200,10 +203,11 @@ export namespace ParamDefinition {
const options: [string, string][] = info && info.options
? info.options as [string, string][]
: Object.keys(map).map(k => [k, k]) as [string, string][];
const name = checkDefaultKey(defaultKey, options);
return setInfo<Mapped<NamedParamUnion<C>>>({
type: 'mapped',
defaultValue: { name: defaultKey, params: map[defaultKey].defaultValue } as any,
select: Select<string>(defaultKey as string, options, info),
defaultValue: { name, params: map[name].defaultValue } as any,
select: Select<string>(name as string, options, info),
map: key => map[key]
}, info);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment