123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- /**
- * Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author David Sehnal <david.sehnal@gmail.com>
- */
- import { BehaviorSubject } from 'rxjs';
- import { debounceTime, skip } from 'rxjs/operators';
- import { AlphaOrbital, Basis } from '../../extensions/alpha-orbitals/data-model';
- import { SphericalBasisOrder } from '../../extensions/alpha-orbitals/spherical-functions';
- import { BasisAndOrbitals, CreateOrbitalDensityVolume, CreateOrbitalRepresentation3D, CreateOrbitalVolume, StaticBasisAndOrbitals } from '../../extensions/alpha-orbitals/transforms';
- import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
- import { PluginStateObject } from '../../mol-plugin-state/objects';
- import { createPluginUI } from '../../mol-plugin-ui/react18';
- import { PluginUIContext } from '../../mol-plugin-ui/context';
- import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
- import { PluginCommands } from '../../mol-plugin/commands';
- import { PluginConfig } from '../../mol-plugin/config';
- import { StateObjectSelector, StateTransformer } from '../../mol-state';
- import { Color } from '../../mol-util/color';
- import { ColorNames } from '../../mol-util/color/names';
- import { ParamDefinition } from '../../mol-util/param-definition';
- import { mountControls } from './controls';
- import { DemoMoleculeSDF, DemoOrbitals } from './example-data';
- import './index.html';
- require('mol-plugin-ui/skin/light.scss');
- import { setDebugMode, setTimingMode, consoleStats } from '../../mol-util/debug';
- interface DemoInput {
- moleculeSdf: string,
- basis: Basis,
- order: SphericalBasisOrder,
- orbitals: AlphaOrbital[]
- }
- interface Params {
- show: { name: 'orbital', params: { index: number } } | { name: 'density', params: {} },
- isoValue: number,
- gpuSurface: boolean
- }
- type Selectors = {
- type: 'orbital',
- volume: StateObjectSelector<PluginStateObject.Volume.Data, typeof CreateOrbitalVolume>,
- positive: StateObjectSelector<PluginStateObject.Volume.Representation3D, typeof CreateOrbitalRepresentation3D>
- negative: StateObjectSelector<PluginStateObject.Volume.Representation3D, typeof CreateOrbitalRepresentation3D>
- } | {
- type: 'density',
- volume: StateObjectSelector<PluginStateObject.Volume.Data, typeof CreateOrbitalDensityVolume>,
- positive: StateObjectSelector<PluginStateObject.Volume.Representation3D, typeof CreateOrbitalRepresentation3D>
- }
- export class AlphaOrbitalsExample {
- plugin: PluginUIContext;
- async init(target: string | HTMLElement) {
- const defaultSpec = DefaultPluginUISpec();
- this.plugin = await createPluginUI(typeof target === 'string' ? document.getElementById(target)! : target, {
- ...defaultSpec,
- layout: {
- initial: {
- isExpanded: false,
- showControls: false
- },
- },
- components: {
- controls: { left: 'none', right: 'none', top: 'none', bottom: 'none' },
- },
- canvas3d: {
- camera: {
- helper: { axes: { name: 'off', params: {} } }
- }
- },
- config: [
- [PluginConfig.Viewport.ShowExpand, false],
- [PluginConfig.Viewport.ShowControls, false],
- [PluginConfig.Viewport.ShowSelectionMode, false],
- [PluginConfig.Viewport.ShowAnimation, false],
- ]
- });
- this.plugin.managers.interactivity.setProps({ granularity: 'element' });
- if (!canComputeGrid3dOnGPU(this.plugin.canvas3d?.webgl)) {
- PluginCommands.Toast.Show(this.plugin, {
- title: 'Error',
- message: `Browser/device does not support required WebGL extension (OES_texture_float).`
- });
- return;
- }
- this.load({
- moleculeSdf: DemoMoleculeSDF,
- ...DemoOrbitals
- });
- mountControls(this, document.getElementById('controls')!);
- }
- readonly params = new BehaviorSubject<ParamDefinition.For<Params>>({} as any);
- readonly state = new BehaviorSubject<Params>({ show: { name: 'orbital', params: { index: 32 } }, isoValue: 1, gpuSurface: true });
- private selectors?: Selectors = void 0;
- private basis?: StateObjectSelector<BasisAndOrbitals> = void 0;
- private currentParams: Params = { ...this.state.value };
- private clearVolume() {
- if (!this.selectors) return;
- const v = this.selectors.volume;
- this.selectors = void 0;
- return this.plugin.build().delete(v).commit();
- }
- private async syncVolume() {
- if (!this.basis?.isOk) return;
- const state = this.state.value;
- if (state.show.name !== this.selectors?.type) {
- await this.clearVolume();
- }
- const update = this.plugin.build();
- if (state.show.name === 'orbital') {
- if (!this.selectors) {
- const volume = update
- .to(this.basis)
- .apply(CreateOrbitalVolume, { index: state.show.params.index });
- const positive = volume.apply(CreateOrbitalRepresentation3D, this.volumeParams('positive', ColorNames.blue)).selector;
- const negative = volume.apply(CreateOrbitalRepresentation3D, this.volumeParams('negative', ColorNames.red)).selector;
- this.selectors = { type: 'orbital', volume: volume.selector, positive, negative };
- } else {
- const index = state.show.params.index;
- update.to(this.selectors.volume).update(CreateOrbitalVolume, () => ({ index }));
- }
- } else {
- if (!this.selectors) {
- const volume = update
- .to(this.basis)
- .apply(CreateOrbitalDensityVolume);
- const positive = volume.apply(CreateOrbitalRepresentation3D, this.volumeParams('positive', ColorNames.blue)).selector;
- this.selectors = { type: 'density', volume: volume.selector, positive };
- }
- }
- await update.commit();
- if (this.currentParams.gpuSurface !== this.state.value.gpuSurface) {
- await this.setIsovalue();
- }
- this.currentParams = this.state.value;
- }
- private setIsovalue() {
- if (!this.selectors) return;
- this.currentParams = this.state.value;
- const update = this.plugin.build();
- update.to(this.selectors.positive).update(this.volumeParams('positive', ColorNames.blue));
- if (this.selectors?.type === 'orbital') {
- update.to(this.selectors.negative).update(this.volumeParams('negative', ColorNames.red));
- }
- return update.commit();
- }
- private volumeParams(kind: 'positive' | 'negative', color: Color): StateTransformer.Params<typeof CreateOrbitalRepresentation3D> {
- return {
- alpha: 0.85,
- color,
- kind,
- relativeIsovalue: this.state.value.isoValue,
- pickable: false,
- xrayShaded: true,
- tryUseGpu: true
- };
- }
- async load(input: DemoInput) {
- await this.plugin.clear();
- const data = await this.plugin.builders.data.rawData({ data: input.moleculeSdf }, { state: { isGhost: true } });
- const trajectory = await this.plugin.builders.structure.parseTrajectory(data, 'mol');
- const model = await this.plugin.builders.structure.createModel(trajectory);
- const structure = await this.plugin.builders.structure.createStructure(model);
- const all = await this.plugin.builders.structure.tryCreateComponentStatic(structure, 'all');
- if (all) await this.plugin.builders.structure.representation.addRepresentation(all, { type: 'ball-and-stick', color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } });
- this.basis = await this.plugin.build().toRoot()
- .apply(StaticBasisAndOrbitals, { basis: input.basis, order: input.order, orbitals: input.orbitals })
- .commit();
- await this.syncVolume();
- this.params.next({
- show: ParamDefinition.MappedStatic('orbital', {
- 'orbital': ParamDefinition.Group({
- index: ParamDefinition.Numeric(32, { min: 0, max: input.orbitals.length - 1 }, { immediateUpdate: true, isEssential: true }),
- }),
- 'density': ParamDefinition.EmptyGroup()
- }, { cycle: true }),
- isoValue: ParamDefinition.Numeric(this.currentParams.isoValue, { min: 0.5, max: 3, step: 0.1 }, { immediateUpdate: true, isEssential: false }),
- gpuSurface: ParamDefinition.Boolean(this.currentParams.gpuSurface, { isHidden: true })
- });
- this.state.pipe(skip(1), debounceTime(1000 / 24)).subscribe(async params => {
- if (params.show.name !== this.currentParams.show.name
- || (params.show.name === 'orbital' && this.currentParams.show.name === 'orbital' && params.show.params.index !== this.currentParams.show.params.index)) {
- this.syncVolume();
- } else if (params.isoValue !== this.currentParams.isoValue || params.gpuSurface !== this.currentParams.gpuSurface) {
- this.setIsovalue();
- }
- });
- }
- }
- (window as any).AlphaOrbitalsExample = new AlphaOrbitalsExample();
- (window as any).AlphaOrbitalsExample.setDebugMode = setDebugMode;
- (window as any).AlphaOrbitalsExample.setTimingMode = setTimingMode;
- (window as any).AlphaOrbitalsExample.consoleStats = consoleStats;
|