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

Merge branch 'master' into alpha-orbitals

parents eace3f42 ea8b7a1d
No related branches found
No related tags found
No related merge requests found
......@@ -28,6 +28,12 @@ import { ANVILMembraneOrientation } from '../../extensions/anvil/behavior';
import { DnatcoConfalPyramids } from '../../extensions/dnatco';
import { G3DFormat, G3dProvider } from '../../extensions/g3d/format';
import { DataFormatProvider } from '../../mol-plugin-state/formats/provider';
import { BuildInVolumeFormat } from '../../mol-plugin-state/formats/volume';
import { Color } from '../../mol-util/color';
import { StateObjectSelector } from '../../mol-state';
import { PluginStateObject } from '../../mol-plugin-state/objects';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers/volume-representation-params';
require('mol-plugin-ui/skin/light.scss');
......@@ -68,6 +74,7 @@ const DefaultViewerOptions = {
viewportShowAnimation: PluginConfig.Viewport.ShowAnimation.defaultValue,
pluginStateServer: PluginConfig.State.DefaultServer.defaultValue,
volumeStreamingServer: PluginConfig.VolumeStreaming.DefaultServer.defaultValue,
volumeStreamingDisabled: !PluginConfig.VolumeStreaming.Enabled.defaultValue,
pdbProvider: PluginConfig.Download.DefaultPdbProvider.defaultValue,
emdbProvider: PluginConfig.Download.DefaultEmdbProvider.defaultValue,
};
......@@ -116,6 +123,7 @@ export class Viewer {
[PluginConfig.State.DefaultServer, o.pluginStateServer],
[PluginConfig.State.CurrentServer, o.pluginStateServer],
[PluginConfig.VolumeStreaming.DefaultServer, o.volumeStreamingServer],
[PluginConfig.VolumeStreaming.Enabled, !o.volumeStreamingDisabled],
[PluginConfig.Download.DefaultPdbProvider, o.pdbProvider],
[PluginConfig.Download.DefaultEmdbProvider, o.emdbProvider]
]
......@@ -152,6 +160,15 @@ export class Viewer {
}));
}
async loadAllModelsOrAssemblyFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false) {
const plugin = this.plugin;
const data = await plugin.builders.data.download({ url, isBinary }, { state: { isGhost: true } });
const trajectory = await plugin.builders.structure.parseTrajectory(data, format);
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'all-models', { useDefaultIfSingleModel: true });
}
async loadStructureFromData(data: string | number[], format: BuiltInTrajectoryFormat, options?: { dataLabel?: string }) {
const _data = await this.plugin.builders.data.rawData({ data, label: options?.dataLabel });
const trajectory = await this.plugin.builders.structure.parseTrajectory(_data, format);
......@@ -209,4 +226,40 @@ export class Viewer {
}
}));
}
async loadVolumeFromUrl(url: string, format: BuildInVolumeFormat, isBinary: boolean, isovalues: VolumeIsovalueInfo[], entryId?: string) {
const plugin = this.plugin;
if (!plugin.dataFormats.get(format)) {
throw new Error(`Unknown density format: ${format}`);
}
return plugin.dataTransaction(async () => {
const data = await plugin.builders.data.download({ url, isBinary, label: entryId }, { state: { isGhost: true } });
const parsed = await plugin.dataFormats.get(format)!.parse(plugin, data, { entryId });
const volume = (parsed.volume || parsed.volumes[0]) as StateObjectSelector<PluginStateObject.Volume.Data>;
if (!volume?.isOk) throw new Error('Failed to parse any volume.');
const repr = plugin.build().to(volume);
for (const iso of isovalues) {
repr.apply(StateTransforms.Representation.VolumeRepresentation3D, createVolumeRepresentationParams(this.plugin, volume.data!, {
type: 'isosurface',
typeParams: { alpha: iso.alpha ?? 1, isoValue: iso.type === 'absolute' ? { kind: 'absolute', absoluteValue: iso.value } : { kind: 'relative', relativeValue: iso.value } },
color: 'uniform',
colorParams: { value: iso.color }
}));
}
await repr.commit();
});
}
}
export interface VolumeIsovalueInfo {
type: 'absolute' | 'relative',
value: number,
color: Color,
alpha?: number
}
......@@ -27,6 +27,10 @@ function ccbKey(compId: string, atomId1: string, atomId2: string) {
return atomId1 < atomId2 ? `${compId}:${atomId1}-${atomId2}` : `${compId}:${atomId2}-${atomId1}`;
}
function ccaKey(compId: string, atomId: string) {
return `${compId}:${atomId}`;
}
function addChemCompBondToSet(set: Set<string>, ccb: CCB) {
for (let i = 0, il = ccb._rowCount; i < il; ++i) {
set.add(ccbKey(ccb.comp_id.value(i), ccb.atom_id_1.value(i), ccb.atom_id_2.value(i)));
......@@ -36,7 +40,7 @@ function addChemCompBondToSet(set: Set<string>, ccb: CCB) {
function addChemCompAtomToSet(set: Set<string>, cca: CCA) {
for (let i = 0, il = cca._rowCount; i < il; ++i) {
set.add(cca.atom_id.value(i));
set.add(ccaKey(cca.comp_id.value(i), cca.atom_id.value(i)));
}
return set;
}
......@@ -82,6 +86,27 @@ function checkAddingBondsFromPVCD(pvcd: DatabaseCollection<CCD_Schema>) {
}
}
function checkAddingAtomsFromPVCD(pvcd: DatabaseCollection<CCD_Schema>) {
const ccaSetByParent = DefaultMap<string, Set<string>>(() => new Set());
for (const k in pvcd) {
const { chem_comp, chem_comp_atom } = pvcd[k];
if (chem_comp_atom._rowCount) {
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0);
if (parentIds.length === 0) {
const set = ccaSetByParent.getDefault(chem_comp.id.value(0));
addChemCompAtomToSet(set, chem_comp_atom);
} else {
for (let i = 0, il = parentIds.length; i < il; ++i) {
const parentId = parentIds[i];
const set = ccaSetByParent.getDefault(parentId);
addChemCompAtomToSet(set, chem_comp_atom);
}
}
}
}
}
async function createBonds(
ccd: DatabaseCollection<CCD_Schema>,
pvcd: DatabaseCollection<CCD_Schema>,
......@@ -152,10 +177,12 @@ async function createBonds(
{ chem_comp_bond: bondTable }
);
return { bonds: bondDatabase, atoms: atomsRequested ? createAtoms(ccd) : void 0 };
return { bonds: bondDatabase, atoms: atomsRequested ? createAtoms(ccd, pvcd) : void 0 };
}
function createAtoms(ccd: DatabaseCollection<CCD_Schema>) {
function createAtoms(ccd: DatabaseCollection<CCD_Schema>, pvcd: DatabaseCollection<CCD_Schema>) {
const ccaSet = new Set<string>();
const comp_id: string[] = [];
const atom_id: string[] = [];
const charge: number[] = [];
......@@ -163,10 +190,33 @@ function createAtoms(ccd: DatabaseCollection<CCD_Schema>) {
function addAtoms(compId: string, cca: CCA) {
for (let i = 0, il = cca._rowCount; i < il; ++i) {
atom_id.push(cca.atom_id.value(i));
const atomId = cca.atom_id.value(i);
const k = ccaKey(compId, atomId);
if (!ccaSet.has(k)) {
atom_id.push(atomId);
comp_id.push(compId);
charge.push(cca.charge.value(i));
pdbx_stereo_config.push(cca.pdbx_stereo_config.value(i));
ccaSet.add(k);
}
}
}
// check adding atoms from PVCD
checkAddingAtomsFromPVCD(pvcd);
// add atoms from PVCD
for (const k in pvcd) {
const { chem_comp, chem_comp_atom } = pvcd[k];
if (chem_comp_atom._rowCount) {
const parentIds = chem_comp.mon_nstd_parent_comp_id.value(0);
if (parentIds.length === 0) {
addAtoms(chem_comp.id.value(0), chem_comp_atom);
} else {
for (let i = 0, il = parentIds.length; i < il; ++i) {
addAtoms(parentIds[i], chem_comp_atom);
}
}
}
}
......
......@@ -142,7 +142,7 @@ async function getTraj(ctx: RuntimeContext, data: G3dDataBlock) {
entity: entityBuilder.getEntityTable(),
ihm_model_list: Table.ofPartialColumns(BasicSchema.ihm_model_list, {
model_id: Column.ofIntArray([1]),
model_name: Column.ofStringArray(['3DG Model']),
model_name: Column.ofStringArray(['G3D Model']),
}, 1),
ihm_sphere_obj_site
});
......@@ -153,7 +153,8 @@ async function getTraj(ctx: RuntimeContext, data: G3dDataBlock) {
haplotypes: Object.keys(data.data),
haplotype: normalized.haplotype,
resolution: data.resolution,
start: normalized.start
start: normalized.start,
chroms: normalized.chromosome,
});
return models;
......@@ -174,6 +175,22 @@ export const G3dSymbols = {
const seqId = ctx.element.unit.model.coarseHierarchy.spheres.seq_id_begin.value(ctx.element.element);
return info.haplotype[seqId] || '';
}
),
chromosome: QuerySymbolRuntime.Dynamic(CustomPropSymbol('g3d', 'chromosome', Type.Str),
ctx => {
if (Unit.isAtomic(ctx.element.unit)) return '';
const { asym_id } = ctx.element.unit.model.coarseHierarchy.spheres;
return asym_id.value(ctx.element.element) || '';
}
),
region: QuerySymbolRuntime.Dynamic(CustomPropSymbol('g3d', 'region', Type.Num),
ctx => {
if (Unit.isAtomic(ctx.element.unit)) return '';
const info = (G3dInfoDataProperty as any).get(ctx.element.unit.model);
if (!info) return 0;
const seqId = ctx.element.unit.model.coarseHierarchy.spheres.seq_id_begin.value(ctx.element.element);
return info.start[seqId] || 0;
}
)
};
......@@ -185,11 +202,31 @@ export function g3dHaplotypeQuery(haplotype: string) {
});
}
export function g3dChromosomeQuery(chr: string) {
return MS.struct.generator.atomGroups({
'chain-test': MS.core.logic.and([
MS.core.rel.eq([MS.ammp('objectPrimitive'), 'sphere']),
MS.core.rel.eq([G3dSymbols.chromosome.symbol(), chr])
])
});
}
export function g3dRegionQuery(chr: string, start: number, end: number) {
return MS.struct.generator.atomGroups({
'chain-test': MS.core.logic.and([
MS.core.rel.eq([MS.ammp('objectPrimitive'), 'sphere']),
MS.core.rel.eq([G3dSymbols.chromosome.symbol(), chr])
]),
'residue-test': MS.core.rel.inRange([G3dSymbols.region.symbol(), start, end])
});
}
export interface G3dInfoData {
haplotypes: string[],
haplotype: string[],
start: Int32Array,
resolution: number
resolution: number,
chroms: string[]
};
export const G3dLabelProvider: LociLabelProvider = {
......
......@@ -56,7 +56,11 @@ export namespace ComponentAtom {
const entries: Map<string, Entry> = new Map();
function addEntry(id: string) {
let e = new Entry(id);
// weird behavior when 'PRO' is requested - will report a single bond between N and H because a later operation would override real content
if (entries.has(id)) {
return entries.get(id)!;
}
const e = new Entry(id);
entries.set(id, e);
return e;
}
......
......@@ -73,6 +73,11 @@ const defaultPreset = TrajectoryHierarchyPresetProvider({
}
});
const AllModelsParams = (a: PluginStateObject.Molecule.Trajectory | undefined, plugin: PluginContext) => ({
useDefaultIfSingleModel: PD.Optional(PD.Boolean(false)),
...CommonParams(a, plugin)
});
const allModels = TrajectoryHierarchyPresetProvider({
id: 'preset-trajectory-all-models',
display: {
......@@ -82,11 +87,15 @@ const allModels = TrajectoryHierarchyPresetProvider({
isApplicable: o => {
return o.data.frameCount > 1;
},
params: CommonParams,
params: AllModelsParams,
async apply(trajectory, params, plugin) {
const tr = StateObjectRef.resolveAndCheck(plugin.state.data, trajectory)?.obj?.data;
if (!tr) return { };
if (tr.frameCount === 1 && params.useDefaultIfSingleModel) {
return defaultPreset.apply(trajectory, params as any, plugin);
}
const builder = plugin.builders.structure;
const models = [], structures = [];
......
......@@ -292,7 +292,7 @@ export class DefaultStructureTools extends PluginUIComponent {
<StructureMeasurementsControls />
<StructureSuperpositionControls />
<StructureComponentControls />
<VolumeStreamingControls />
{this.plugin.config.get(PluginConfig.VolumeStreaming.Enabled) && <VolumeStreamingControls />}
<VolumeSourceControls />
<CustomStructureControls />
......
......@@ -32,6 +32,7 @@ export const PluginConfig = {
HistoryCapacity: item('history-capacity.server', 5)
},
VolumeStreaming: {
Enabled: item('volume-streaming.enabled', true),
DefaultServer: item('volume-streaming.server', 'https://ds.litemol.org'),
CanStream: item('volume-streaming.can-stream', (s: Structure, plugin: PluginContext) => {
return s.models.length === 1 && Model.probablyHasDensityMap(s.models[0]);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment