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

wip superposition

parent a8b2d8a1
No related branches found
No related tags found
No related merge requests found
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Mat4, Vec3 } from 'mol-math/linear-algebra';
import { PluginContext } from 'mol-plugin/context';
import { PluginStateObject as PSO } from 'mol-plugin/state/objects';
import { StateTransforms } from 'mol-plugin/state/transforms';
import { StructureRepresentation3DHelpers } from 'mol-plugin/state/transforms/representation';
import { MolScriptBuilder as MS } from 'mol-script/language/builder';
import { StateBuilder } from 'mol-state';
type SupportedFormats = 'cif' | 'pdb'
export namespace StateHelper {
export function download(b: StateBuilder.To<PSO.Root>, url: string, ref?: string) {
return b.apply(StateTransforms.Data.Download, { url, isBinary: false }, { ref });
}
export function getModel(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats, modelIndex = 0) {
const parsed = format === 'cif'
? b.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif)
: b.apply(StateTransforms.Model.TrajectoryFromPDB);
return parsed.apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex });
}
export function structure(b: StateBuilder.To<PSO.Molecule.Model>) {
return b.apply(StateTransforms.Model.StructureFromModel, { tags: 'struct' })
};
export function selectChain(b: StateBuilder.To<PSO.Molecule.Structure>, auth_asym_id: string) {
const query = MS.struct.generator.atomGroups({
'chain-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.auth_asym_id(), auth_asym_id])
})
return b.apply(StateTransforms.Model.StructureSelection, { query, label: `Chain ${auth_asym_id}` });
}
export function identityTransform(b: StateBuilder.To<PSO.Molecule.Structure>, m: Mat4) {
return b.apply(StateTransforms.Model.TransformStructureConformation,
{ axis: Vec3.create(1, 0, 0), angle: 0, translation: Vec3.zero() },
{ tags: 'transform' });
}
export function transform(b: StateBuilder.To<PSO.Molecule.Structure>, matrix: Mat4) {
return b.apply(StateTransforms.Model.TransformStructureConformationByMatrix, { matrix }, { tags: 'transform' });
}
export function assemble(b: StateBuilder.To<PSO.Molecule.Model>, id?: string) {
return b.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: id || 'deposited' }, { tags: 'asm' })
}
export function visual(ctx: PluginContext, visualRoot: StateBuilder.To<PSO.Molecule.Structure>) {
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'cartoon'), { tags: 'seq-visual' });
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick'), { tags: 'het-visual' });
// visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' })
// .apply(StateTransforms.Representation.StructureRepresentation3D,
// StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', { alpha: 0.51 }), { tags: 'water-visual' });
return visualRoot;
}
}
\ No newline at end of file
...@@ -75,8 +75,9 @@ ...@@ -75,8 +75,9 @@
BasicMolStarWrapper.init('app' /** or document.getElementById('app') */); BasicMolStarWrapper.init('app' /** or document.getElementById('app') */);
BasicMolStarWrapper.setBackground(0xffffff); BasicMolStarWrapper.setBackground(0xffffff);
BasicMolStarWrapper.load({ url: url, format: format, assemblyId: assemblyId }); // BasicMolStarWrapper.load({ url: url, format: format, assemblyId: assemblyId });
BasicMolStarWrapper.toggleSpin(); // BasicMolStarWrapper.toggleSpin();
addControl('Load Asym Unit', () => BasicMolStarWrapper.load({ url: url, format: format })); addControl('Load Asym Unit', () => BasicMolStarWrapper.load({ url: url, format: format }));
addControl('Load Assembly', () => BasicMolStarWrapper.load({ url: url, format: format, assemblyId: assemblyId })); addControl('Load Assembly', () => BasicMolStarWrapper.load({ url: url, format: format, assemblyId: assemblyId }));
...@@ -104,6 +105,10 @@ ...@@ -104,6 +105,10 @@
addControl('Apply Stripes', () => BasicMolStarWrapper.coloring.applyStripes()); addControl('Apply Stripes', () => BasicMolStarWrapper.coloring.applyStripes());
addHeader('Tests');
addControl('Static Super', () => BasicMolStarWrapper.tests.staticSuperposition());
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
function addControl(label, action) { function addControl(label, action) {
......
...@@ -15,7 +15,8 @@ import { PluginStateObject as PSO } from 'mol-plugin/state/objects'; ...@@ -15,7 +15,8 @@ import { PluginStateObject as PSO } from 'mol-plugin/state/objects';
import { AnimateModelIndex } from 'mol-plugin/state/animation/built-in'; import { AnimateModelIndex } from 'mol-plugin/state/animation/built-in';
import { StateBuilder } from 'mol-state'; import { StateBuilder } from 'mol-state';
import { StripedResidues } from './coloring'; import { StripedResidues } from './coloring';
import { BasicWrapperControls } from './controls'; // import { BasicWrapperControls } from './controls';
import { StaticSuperpositionTestData, buildStaticSuperposition } from './superposition';
require('mol-plugin/skin/light.scss') require('mol-plugin/skin/light.scss')
type SupportedFormats = 'cif' | 'pdb' type SupportedFormats = 'cif' | 'pdb'
...@@ -33,8 +34,8 @@ class BasicWrapper { ...@@ -33,8 +34,8 @@ class BasicWrapper {
showControls: false showControls: false
}, },
controls: { controls: {
left: 'none', // left: 'none',
right: BasicWrapperControls // right: BasicWrapperControls
} }
} }
}); });
...@@ -140,6 +141,14 @@ class BasicWrapper { ...@@ -140,6 +141,14 @@ class BasicWrapper {
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree }); await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
} }
} }
tests = {
staticSuperposition: async () => {
const state = this.plugin.state.dataState;
const tree = buildStaticSuperposition(this.plugin, StaticSuperpositionTestData);
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
}
}
} }
(window as any).BasicMolStarWrapper = new BasicWrapper(); (window as any).BasicMolStarWrapper = new BasicWrapper();
\ No newline at end of file
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
// TODO: move to an "example"
import { PluginContext } from 'mol-plugin/context';
import { Mat4 } from 'mol-math/linear-algebra';
import { StateHelper } from './helpers';
export type SuperpositionTestInput = {
pdbId: string,
auth_asym_id: string,
matrix: Mat4
}[];
// function getAxisAngleTranslation(m: Mat4) {
// const translation = Mat4.getTranslation(Vec3.zero(), m);
// const axis = Vec3.zero();
// const angle = 180 / Math.PI * Quat.getAxisAngle(axis, Mat4.getRotation(Quat.zero(), m));
// return { translation, axis, angle };
// }
export function buildStaticSuperposition(ctx: PluginContext, src: SuperpositionTestInput) {
const b = ctx.state.dataState.build().toRoot();
for (const s of src) {
StateHelper.visual(ctx,
StateHelper.transform(
StateHelper.selectChain(
StateHelper.structure(
StateHelper.getModel(StateHelper.download(b, `https://www.ebi.ac.uk/pdbe/static/entry/${s.pdbId}_updated.cif`), 'cif')),
s.auth_asym_id
),
s.matrix
)
);
}
return b;
}
export const StaticSuperpositionTestData: SuperpositionTestInput = [
{ pdbId: '1aj5', auth_asym_id: 'A', matrix: Mat4.identity() },
{ pdbId: '1df0', auth_asym_id: 'B', matrix: Mat4.ofRows(
[[0.406, 0.879, 0.248, -200.633],
[0.693, -0.473, 0.544, 73.403],
[0.596, -0.049, -0.802, -14.209],
[0, 0, 0, 1]] )},
{ pdbId: '1dvi', auth_asym_id: 'A', matrix: Mat4.ofRows(
[[-0.053, -0.077, 0.996, -45.633],
[-0.312, 0.949, 0.057, -12.255],
[-0.949, -0.307, -0.074, 53.562],
[0, 0, 0, 1]] )}
];
\ No newline at end of file
...@@ -33,13 +33,13 @@ namespace SymmetryOperator { ...@@ -33,13 +33,13 @@ namespace SymmetryOperator {
export const DefaultName = '1_555' export const DefaultName = '1_555'
export const Default: SymmetryOperator = create(DefaultName, Mat4.identity(), { id: '', operList: [] }); export const Default: SymmetryOperator = create(DefaultName, Mat4.identity(), { id: '', operList: [] });
const RotationEpsilon = 0.0001; export const RotationTranslationEpsilon = 0.005;
export function create(name: string, matrix: Mat4, assembly: SymmetryOperator['assembly'], ncsId?: string, hkl?: Vec3): SymmetryOperator { export function create(name: string, matrix: Mat4, assembly: SymmetryOperator['assembly'], ncsId?: string, hkl?: Vec3): SymmetryOperator {
const _hkl = hkl ? Vec3.clone(hkl) : Vec3.zero(); const _hkl = hkl ? Vec3.clone(hkl) : Vec3.zero();
ncsId = ncsId || '' ncsId = ncsId || ''
if (Mat4.isIdentity(matrix)) return { name, assembly, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl, ncsId }; if (Mat4.isIdentity(matrix)) return { name, assembly, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl, ncsId };
if (!Mat4.isRotationAndTranslation(matrix, RotationEpsilon)) throw new Error(`Symmetry operator (${name}) must be a composition of rotation and translation.`); if (!Mat4.isRotationAndTranslation(matrix, RotationTranslationEpsilon)) throw new Error(`Symmetry operator (${name}) must be a composition of rotation and translation.`);
return { name, assembly, matrix, inverse: Mat4.invert(Mat4.zero(), matrix), isIdentity: false, hkl: _hkl, ncsId }; return { name, assembly, matrix, inverse: Mat4.invert(Mat4.zero(), matrix), isIdentity: false, hkl: _hkl, ncsId };
} }
...@@ -51,7 +51,7 @@ namespace SymmetryOperator { ...@@ -51,7 +51,7 @@ namespace SymmetryOperator {
} }
} }
Mat4.setTranslation(matrix, offset); Mat4.setTranslation(matrix, offset);
return Mat4.isRotationAndTranslation(matrix, RotationEpsilon); return Mat4.isRotationAndTranslation(matrix, RotationTranslationEpsilon);
} }
export function ofRotationAndOffset(name: string, rot: Mat3, offset: Vec3, ncsId?: string) { export function ofRotationAndOffset(name: string, rot: Mat3, offset: Vec3, ncsId?: string) {
......
...@@ -428,7 +428,7 @@ namespace Structure { ...@@ -428,7 +428,7 @@ namespace Structure {
export function transform(s: Structure, transform: Mat4) { export function transform(s: Structure, transform: Mat4) {
if (Mat4.isIdentity(transform)) return s; if (Mat4.isIdentity(transform)) return s;
if (!Mat4.isRotationAndTranslation(transform)) throw new Error('Only rotation/translation combination can be applied.'); if (!Mat4.isRotationAndTranslation(transform, SymmetryOperator.RotationTranslationEpsilon)) throw new Error('Only rotation/translation combination can be applied.');
const units: Unit[] = []; const units: Unit[] = [];
for (const u of s.units) { for (const u of s.units) {
......
...@@ -36,7 +36,8 @@ export { ModelFromTrajectory }; ...@@ -36,7 +36,8 @@ export { ModelFromTrajectory };
export { StructureFromModel }; export { StructureFromModel };
export { StructureAssemblyFromModel }; export { StructureAssemblyFromModel };
export { StructureSymmetryFromModel }; export { StructureSymmetryFromModel };
export { TransformStructureConformation } export { TransformStructureConformation };
export { TransformStructureConformationByMatrix };
export { StructureSelection }; export { StructureSelection };
export { UserStructureSelection }; export { UserStructureSelection };
export { StructureComplexElement }; export { StructureComplexElement };
...@@ -307,6 +308,26 @@ const TransformStructureConformation = PluginStateTransform.BuiltIn({ ...@@ -307,6 +308,26 @@ const TransformStructureConformation = PluginStateTransform.BuiltIn({
} }
}); });
type TransformStructureConformationByMatrix = typeof TransformStructureConformation
const TransformStructureConformationByMatrix = PluginStateTransform.BuiltIn({
name: 'transform-structure-conformation-by-matrix',
display: { name: 'Transform Conformation' },
from: SO.Molecule.Structure,
to: SO.Molecule.Structure,
params: {
matrix: PD.Value<Mat4>(Mat4.identity(), { isHidden: true })
}
})({
canAutoUpdate() {
return true;
},
apply({ a, params }) {
const s = Structure.transform(a.data, params.matrix);
const props = { label: `${a.label}`, description: `Transformed` };
return new SO.Molecule.Structure(s, props);
}
});
type StructureSelection = typeof StructureSelection type StructureSelection = typeof StructureSelection
const StructureSelection = PluginStateTransform.BuiltIn({ const StructureSelection = PluginStateTransform.BuiltIn({
name: 'structure-selection', name: 'structure-selection',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment