|
@@ -6,31 +6,29 @@
|
|
|
|
|
|
import { PluginStateTransform } from '../objects';
|
|
import { PluginStateTransform } from '../objects';
|
|
import { PluginStateObject as SO } from '../objects';
|
|
import { PluginStateObject as SO } from '../objects';
|
|
-import { Task } from 'mol-task';
|
|
|
|
|
|
+import { Task, RuntimeContext } from 'mol-task';
|
|
import { Model, Format, Structure, ModelSymmetry, StructureSymmetry, QueryContext, StructureSelection as Sel, StructureQuery, Queries } from 'mol-model/structure';
|
|
import { Model, Format, Structure, ModelSymmetry, StructureSymmetry, QueryContext, StructureSelection as Sel, StructureQuery, Queries } from 'mol-model/structure';
|
|
import { ParamDefinition as PD } from 'mol-util/param-definition';
|
|
import { ParamDefinition as PD } from 'mol-util/param-definition';
|
|
import Expression from 'mol-script/language/expression';
|
|
import Expression from 'mol-script/language/expression';
|
|
import { compile } from 'mol-script/runtime/query/compiler';
|
|
import { compile } from 'mol-script/runtime/query/compiler';
|
|
import { MolScriptBuilder } from 'mol-script/language/builder';
|
|
import { MolScriptBuilder } from 'mol-script/language/builder';
|
|
import { StateObject } from 'mol-state';
|
|
import { StateObject } from 'mol-state';
|
|
|
|
+import { PluginContext } from 'mol-plugin/context';
|
|
|
|
|
|
export { TrajectoryFromMmCif }
|
|
export { TrajectoryFromMmCif }
|
|
-namespace TrajectoryFromMmCif { export interface Params { blockHeader?: string } }
|
|
|
|
-const TrajectoryFromMmCif = PluginStateTransform.Create<SO.Data.Cif, SO.Molecule.Trajectory, TrajectoryFromMmCif.Params>({
|
|
|
|
|
|
+type TrajectoryFromMmCif = typeof TrajectoryFromMmCif
|
|
|
|
+const TrajectoryFromMmCif = PluginStateTransform.BuiltIn({
|
|
name: 'trajectory-from-mmcif',
|
|
name: 'trajectory-from-mmcif',
|
|
- display: {
|
|
|
|
- name: 'Models from mmCIF',
|
|
|
|
- description: 'Identify and create all separate models in the specified CIF data block'
|
|
|
|
- },
|
|
|
|
- from: [SO.Data.Cif],
|
|
|
|
- to: [SO.Molecule.Trajectory],
|
|
|
|
|
|
+ display: { name: 'Trajectory from mmCIF', description: 'Identify and create all separate models in the specified CIF data block' },
|
|
|
|
+ from: SO.Format.Cif,
|
|
|
|
+ to: SO.Molecule.Trajectory,
|
|
params(a) {
|
|
params(a) {
|
|
const { blocks } = a.data;
|
|
const { blocks } = a.data;
|
|
- if (blocks.length === 0) return { };
|
|
|
|
return {
|
|
return {
|
|
- blockHeader: PD.Select(blocks[0].header, blocks.map(b => [b.header, b.header] as [string, string]), { description: 'Header of the block to parse' })
|
|
|
|
|
|
+ blockHeader: PD.makeOptional(PD.Select(blocks[0] && blocks[0].header, blocks.map(b => [b.header, b.header] as [string, string]), { description: 'Header of the block to parse' }))
|
|
};
|
|
};
|
|
- },
|
|
|
|
|
|
+ }
|
|
|
|
+})({
|
|
isApplicable: a => a.data.blocks.length > 0,
|
|
isApplicable: a => a.data.blocks.length > 0,
|
|
apply({ a, params }) {
|
|
apply({ a, params }) {
|
|
return Task.create('Parse mmCIF', async ctx => {
|
|
return Task.create('Parse mmCIF', async ctx => {
|
|
@@ -47,16 +45,14 @@ const TrajectoryFromMmCif = PluginStateTransform.Create<SO.Data.Cif, SO.Molecule
|
|
|
|
|
|
export { ModelFromTrajectory }
|
|
export { ModelFromTrajectory }
|
|
const plus1 = (v: number) => v + 1, minus1 = (v: number) => v - 1;
|
|
const plus1 = (v: number) => v + 1, minus1 = (v: number) => v - 1;
|
|
-namespace ModelFromTrajectory { export interface Params { modelIndex: number } }
|
|
|
|
-const ModelFromTrajectory = PluginStateTransform.Create<SO.Molecule.Trajectory, SO.Molecule.Model, ModelFromTrajectory.Params>({
|
|
|
|
|
|
+type ModelFromTrajectory = typeof ModelFromTrajectory
|
|
|
|
+const ModelFromTrajectory = PluginStateTransform.BuiltIn({
|
|
name: 'model-from-trajectory',
|
|
name: 'model-from-trajectory',
|
|
- display: {
|
|
|
|
- name: 'Model from Trajectory',
|
|
|
|
- description: 'Create a molecular structure from the specified model.'
|
|
|
|
- },
|
|
|
|
- from: [SO.Molecule.Trajectory],
|
|
|
|
- to: [SO.Molecule.Model],
|
|
|
|
- params: a => ({ modelIndex: PD.Converted(plus1, minus1, PD.Numeric(1, { min: 1, max: a.data.length, step: 1 }, { description: 'Model Index' })) }),
|
|
|
|
|
|
+ display: { name: 'Model from Trajectory', description: 'Create a molecular structure from the specified model.' },
|
|
|
|
+ from: SO.Molecule.Trajectory,
|
|
|
|
+ to: SO.Molecule.Model,
|
|
|
|
+ params: a => ({ modelIndex: PD.Converted(plus1, minus1, PD.Numeric(1, { min: 1, max: a.data.length, step: 1 }, { description: 'Model Index' })) })
|
|
|
|
+})({
|
|
isApplicable: a => a.data.length > 0,
|
|
isApplicable: a => a.data.length > 0,
|
|
apply({ a, params }) {
|
|
apply({ a, params }) {
|
|
if (params.modelIndex < 0 || params.modelIndex >= a.data.length) throw new Error(`Invalid modelIndex ${params.modelIndex}`);
|
|
if (params.modelIndex < 0 || params.modelIndex >= a.data.length) throw new Error(`Invalid modelIndex ${params.modelIndex}`);
|
|
@@ -67,15 +63,13 @@ const ModelFromTrajectory = PluginStateTransform.Create<SO.Molecule.Trajectory,
|
|
});
|
|
});
|
|
|
|
|
|
export { StructureFromModel }
|
|
export { StructureFromModel }
|
|
-namespace StructureFromModel { export interface Params { } }
|
|
|
|
-const StructureFromModel = PluginStateTransform.Create<SO.Molecule.Model, SO.Molecule.Structure, StructureFromModel.Params>({
|
|
|
|
|
|
+type StructureFromModel = typeof StructureFromModel
|
|
|
|
+const StructureFromModel = PluginStateTransform.BuiltIn({
|
|
name: 'structure-from-model',
|
|
name: 'structure-from-model',
|
|
- display: {
|
|
|
|
- name: 'Structure from Model',
|
|
|
|
- description: 'Create a molecular structure from the specified model.'
|
|
|
|
- },
|
|
|
|
- from: [SO.Molecule.Model],
|
|
|
|
- to: [SO.Molecule.Structure],
|
|
|
|
|
|
+ display: { name: 'Structure from Model', description: 'Create a molecular structure from the specified model.' },
|
|
|
|
+ from: SO.Molecule.Model,
|
|
|
|
+ to: SO.Molecule.Structure
|
|
|
|
+})({
|
|
apply({ a }) {
|
|
apply({ a }) {
|
|
let s = Structure.ofModel(a.data);
|
|
let s = Structure.ofModel(a.data);
|
|
const label = { label: a.data.label, description: s.elementCount === 1 ? '1 element' : `${s.elementCount} elements` };
|
|
const label = { label: a.data.label, description: s.elementCount === 1 ? '1 element' : `${s.elementCount} elements` };
|
|
@@ -88,29 +82,33 @@ function structureDesc(s: Structure) {
|
|
}
|
|
}
|
|
|
|
|
|
export { StructureAssemblyFromModel }
|
|
export { StructureAssemblyFromModel }
|
|
-namespace StructureAssemblyFromModel { export interface Params { /** if not specified, use the 1st */ id?: string } }
|
|
|
|
-const StructureAssemblyFromModel = PluginStateTransform.Create<SO.Molecule.Model, SO.Molecule.Structure, StructureAssemblyFromModel.Params>({
|
|
|
|
|
|
+type StructureAssemblyFromModel = typeof StructureAssemblyFromModel
|
|
|
|
+const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({
|
|
name: 'structure-assembly-from-model',
|
|
name: 'structure-assembly-from-model',
|
|
- display: {
|
|
|
|
- name: 'Structure Assembly',
|
|
|
|
- description: 'Create a molecular structure assembly.'
|
|
|
|
- },
|
|
|
|
- from: [SO.Molecule.Model],
|
|
|
|
- to: [SO.Molecule.Structure],
|
|
|
|
|
|
+ display: { name: 'Structure Assembly', description: 'Create a molecular structure assembly.' },
|
|
|
|
+ from: SO.Molecule.Model,
|
|
|
|
+ to: SO.Molecule.Structure,
|
|
params(a) {
|
|
params(a) {
|
|
const model = a.data;
|
|
const model = a.data;
|
|
const ids = model.symmetry.assemblies.map(a => [a.id, a.id] as [string, string]);
|
|
const ids = model.symmetry.assemblies.map(a => [a.id, a.id] as [string, string]);
|
|
- return { id: PD.Select(ids.length ? ids[0][0] : '', ids, { label: 'Asm Id', description: 'Assembly Id' }) };
|
|
|
|
- },
|
|
|
|
- apply({ a, params }) {
|
|
|
|
|
|
+ return { id: PD.makeOptional(PD.Select(ids.length ? ids[0][0] : '', ids, { label: 'Asm Id', description: 'Assembly Id' })) };
|
|
|
|
+ }
|
|
|
|
+})({
|
|
|
|
+ apply({ a, params }, plugin: PluginContext) {
|
|
return Task.create('Build Assembly', async ctx => {
|
|
return Task.create('Build Assembly', async ctx => {
|
|
- let id = params.id;
|
|
|
|
|
|
+ let id = (params.id || '').trim();
|
|
const model = a.data;
|
|
const model = a.data;
|
|
if (!id && model.symmetry.assemblies.length) id = model.symmetry.assemblies[0].id;
|
|
if (!id && model.symmetry.assemblies.length) id = model.symmetry.assemblies[0].id;
|
|
- const asm = ModelSymmetry.findAssembly(model, id || '');
|
|
|
|
- if (!asm) throw new Error(`Assembly '${id}' not found`);
|
|
|
|
|
|
+ const asm = ModelSymmetry.findAssembly(model, id);
|
|
|
|
+ if (id && !asm) throw new Error(`Assembly '${id}' not found`);
|
|
|
|
|
|
const base = Structure.ofModel(model);
|
|
const base = Structure.ofModel(model);
|
|
|
|
+ if (!asm) {
|
|
|
|
+ plugin.log.warn(`Model '${a.label}' has no assembly, returning default structure.`);
|
|
|
|
+ const label = { label: a.data.label, description: structureDesc(base) };
|
|
|
|
+ return new SO.Molecule.Structure(base, label);
|
|
|
|
+ }
|
|
|
|
+
|
|
const s = await StructureSymmetry.buildAssembly(base, id!).runInContext(ctx);
|
|
const s = await StructureSymmetry.buildAssembly(base, id!).runInContext(ctx);
|
|
const label = { label: `Assembly ${id}`, description: structureDesc(s) };
|
|
const label = { label: `Assembly ${id}`, description: structureDesc(s) };
|
|
return new SO.Molecule.Structure(s, label);
|
|
return new SO.Molecule.Structure(s, label);
|
|
@@ -119,19 +117,17 @@ const StructureAssemblyFromModel = PluginStateTransform.Create<SO.Molecule.Model
|
|
});
|
|
});
|
|
|
|
|
|
export { StructureSelection }
|
|
export { StructureSelection }
|
|
-namespace StructureSelection { export interface Params { query: Expression, label?: string } }
|
|
|
|
-const StructureSelection = PluginStateTransform.Create<SO.Molecule.Structure, SO.Molecule.Structure, StructureSelection.Params>({
|
|
|
|
|
|
+type StructureSelection = typeof StructureSelection
|
|
|
|
+const StructureSelection = PluginStateTransform.BuiltIn({
|
|
name: 'structure-selection',
|
|
name: 'structure-selection',
|
|
- display: {
|
|
|
|
- name: 'Structure Selection',
|
|
|
|
- description: 'Create a molecular structure from the specified model.'
|
|
|
|
- },
|
|
|
|
- from: [SO.Molecule.Structure],
|
|
|
|
- to: [SO.Molecule.Structure],
|
|
|
|
- params: () => ({
|
|
|
|
|
|
+ display: { name: 'Structure Selection', description: 'Create a molecular structure from the specified model.' },
|
|
|
|
+ from: SO.Molecule.Structure,
|
|
|
|
+ to: SO.Molecule.Structure,
|
|
|
|
+ params: {
|
|
query: PD.Value<Expression>(MolScriptBuilder.struct.generator.all, { isHidden: true }),
|
|
query: PD.Value<Expression>(MolScriptBuilder.struct.generator.all, { isHidden: true }),
|
|
- label: PD.Text('', { isOptional: true, isHidden: true })
|
|
|
|
- }),
|
|
|
|
|
|
+ label: PD.makeOptional(PD.Text('', { isHidden: true }))
|
|
|
|
+ }
|
|
|
|
+})({
|
|
apply({ a, params }) {
|
|
apply({ a, params }) {
|
|
// TODO: use cache, add "update"
|
|
// TODO: use cache, add "update"
|
|
const compiled = compile<Sel>(params.query);
|
|
const compiled = compile<Sel>(params.query);
|
|
@@ -143,25 +139,25 @@ const StructureSelection = PluginStateTransform.Create<SO.Molecule.Structure, SO
|
|
});
|
|
});
|
|
|
|
|
|
export { StructureComplexElement }
|
|
export { StructureComplexElement }
|
|
-namespace StructureComplexElement { export interface Params { type: 'sequence' | 'water' | 'ligands' } }
|
|
|
|
-const StructureComplexElement = PluginStateTransform.Create<SO.Molecule.Structure, SO.Molecule.Structure, StructureComplexElement.Params>({
|
|
|
|
|
|
+namespace StructureComplexElement { export type Types = 'atomic-sequence' | 'water' | 'atomic-het' | 'spheres' }
|
|
|
|
+type StructureComplexElement = typeof StructureComplexElement
|
|
|
|
+const StructureComplexElement = PluginStateTransform.BuiltIn({
|
|
name: 'structure-complex-element',
|
|
name: 'structure-complex-element',
|
|
- display: {
|
|
|
|
- name: 'Complex Element',
|
|
|
|
- description: 'Create a molecular structure from the specified model.'
|
|
|
|
- },
|
|
|
|
- from: [SO.Molecule.Structure],
|
|
|
|
- to: [SO.Molecule.Structure],
|
|
|
|
- params: () => ({ type: PD.Text('sequence', { isHidden: true }) }),
|
|
|
|
|
|
+ display: { name: 'Complex Element', description: 'Create a molecular structure from the specified model.' },
|
|
|
|
+ from: SO.Molecule.Structure,
|
|
|
|
+ to: SO.Molecule.Structure,
|
|
|
|
+ params: { type: PD.Text<StructureComplexElement.Types>('atomic-sequence', { isHidden: true }) }
|
|
|
|
+})({
|
|
apply({ a, params }) {
|
|
apply({ a, params }) {
|
|
// TODO: update function.
|
|
// TODO: update function.
|
|
|
|
|
|
let query: StructureQuery, label: string;
|
|
let query: StructureQuery, label: string;
|
|
switch (params.type) {
|
|
switch (params.type) {
|
|
- case 'sequence': query = Queries.internal.sequence(); label = 'Sequence'; break;
|
|
|
|
|
|
+ case 'atomic-sequence': query = Queries.internal.atomicSequence(); label = 'Sequence'; break;
|
|
case 'water': query = Queries.internal.water(); label = 'Water'; break;
|
|
case 'water': query = Queries.internal.water(); label = 'Water'; break;
|
|
- case 'ligands': query = Queries.internal.lidangs(); label = 'Ligands'; break;
|
|
|
|
- default: throw new Error(`${params.type} is a valid complex element.`);
|
|
|
|
|
|
+ case 'atomic-het': query = Queries.internal.atomicHet(); label = 'HET Groups/Ligands'; break;
|
|
|
|
+ case 'spheres': query = Queries.internal.spheres(); label = 'Coarse Spheres'; break;
|
|
|
|
+ default: throw new Error(`${params.type} is a not valid complex element.`);
|
|
}
|
|
}
|
|
|
|
|
|
const result = query(new QueryContext(a.data));
|
|
const result = query(new QueryContext(a.data));
|
|
@@ -172,3 +168,25 @@ const StructureComplexElement = PluginStateTransform.Create<SO.Molecule.Structur
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+export { CustomModelProperties }
|
|
|
|
+type CustomModelProperties = typeof CustomModelProperties
|
|
|
|
+const CustomModelProperties = PluginStateTransform.BuiltIn({
|
|
|
|
+ name: 'custom-model-properties',
|
|
|
|
+ display: { name: 'Custom Model Properties' },
|
|
|
|
+ from: SO.Molecule.Model,
|
|
|
|
+ to: SO.Molecule.Model,
|
|
|
|
+ params: (a, ctx: PluginContext) => ({ properties: ctx.customModelProperties.getSelect(a.data) })
|
|
|
|
+})({
|
|
|
|
+ apply({ a, params }, ctx: PluginContext) {
|
|
|
|
+ return Task.create('Custom Props', async taskCtx => {
|
|
|
|
+ await attachProps(a.data, ctx, taskCtx, params.properties);
|
|
|
|
+ return new SO.Molecule.Model(a.data, { label: 'Props', description: `${params.properties.length} Selected` });
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+});
|
|
|
|
+async function attachProps(model: Model, ctx: PluginContext, taskCtx: RuntimeContext, names: string[]) {
|
|
|
|
+ for (const name of names) {
|
|
|
|
+ const p = ctx.customModelProperties.get(name);
|
|
|
|
+ await p.attach(model).runInContext(taskCtx);
|
|
|
|
+ }
|
|
|
|
+}
|